Module 3 · Data and Multimodal Work · 45 min
Lab: Produce an Evidence-Backed Decision Memo
Is lesson ke baad tum
A decision memo is defensible when every claim traces to authorized evidence, every number can be regenerated, assumptions and unknowns remain visible, sensitivity tests challenge the recommendation, and a named human owns the reversible next step.
In this lesson
Write a short recommendation from the supplied two-option dataset, then test what changes when one assumption changes. You will separate scores from eligibility: an option can rank well and still be blocked by unverified terms.
This is a fictional comparison for a four-week delivery pilot. Use Python and pandas from Lesson 3.1. No vendor contact, purchase, audio recording, PDF creation, or model account is needed.
Frame a Decision That Evidence Can Answer
The decision is: “Which option may enter a four-week controlled pilot, given these sample completion, cost, support, and terms records?” The fictional owner is the operations lead. Both options are assumed to cover comparable routes over the same 90-day period; that comparability is an explicit assumption to verify before a real recommendation.
Use E001 = options.csv as the source ID, with row identifiers Option A and Option B. Create its hash with the Lesson 3.2 helper. You have no verified quotation or interview in this exercise, so do not cite one or invent contract clauses.
Worked Example: Calculate Before Asking for Narrative
Create options.csv:
option,completed_deliveries,attempted_deliveries,total_cost_pkr,median_support_hours,terms_verified
Option A,88,100,30800,5,true
Option B,81,90,27000,2,falseThese figures are invented only to demonstrate calculations. Create score.py:
from pathlib import Path
import json
import math
import pandas as pd
df = pd.read_csv("options.csv", dtype=str, keep_default_na=False)
required = {
"option", "completed_deliveries", "attempted_deliveries",
"total_cost_pkr", "median_support_hours", "terms_verified"
}
missing = required - set(df.columns)
if missing:
raise ValueError(f"Missing columns: {sorted(missing)}")
if len(df) != 2 or df["option"].duplicated().any() or df["option"].str.strip().eq("").any():
raise ValueError("Expected two distinct named options")
numeric = ["completed_deliveries", "attempted_deliveries", "total_cost_pkr", "median_support_hours"]
for column in numeric:
if not df[column].str.fullmatch(r"[0-9]+(?:\.[0-9]+)?").all():
raise ValueError(f"Invalid numeric value in {column}")
df[column] = pd.to_numeric(df[column], errors="raise")
if not df[column].map(lambda x: math.isfinite(x)).all():
raise ValueError(f"Nonfinite value in {column}")
for column in ["completed_deliveries", "attempted_deliveries"]:
if (df[column] % 1 != 0).any():
raise ValueError("Delivery counts must be whole numbers")
if not df["terms_verified"].isin(["true", "false"]).all():
raise ValueError("Terms must explicitly be true or false")
df["terms_verified"] = df["terms_verified"].map({"true": True, "false": False})
if (df["attempted_deliveries"] <= 0).any():
raise ValueError("attempted_deliveries must be positive")
if (df["completed_deliveries"] <= 0).any():
raise ValueError("completed_deliveries must be positive before calculating cost per completion")
if (df["completed_deliveries"] > df["attempted_deliveries"]).any():
raise ValueError("completed cannot exceed attempted")
if (df["total_cost_pkr"] < 0).any():
raise ValueError("cost cannot be negative in this fixture")
df["completion_rate"] = df["completed_deliveries"] / df["attempted_deliveries"]
df["cost_per_completed_pkr"] = df["total_cost_pkr"] / df["completed_deliveries"]
# Normalize only within this comparison. Lower cost/support is better.
def benefit(series):
span = series.max() - series.min()
return pd.Series([1.0] * len(series), index=series.index) if span == 0 else (series - series.min()) / span
def inverse_benefit(series):
span = series.max() - series.min()
return pd.Series([1.0] * len(series), index=series.index) if span == 0 else (series.max() - series) / span
weights = {"reliability": 0.50, "cost": 0.30, "support": 0.20}
df["score"] = (
weights["reliability"] * benefit(df["completion_rate"])
+ weights["cost"] * inverse_benefit(df["cost_per_completed_pkr"])
+ weights["support"] * inverse_benefit(df["median_support_hours"])
)
# A missing verified term is a gate, not a hidden scoring penalty.
df["decision_status"] = df["terms_verified"].map(
{True: "eligible_for_pilot", False: "blocked_pending_terms"}
)
columns = [
"option", "completion_rate", "cost_per_completed_pkr",
"median_support_hours", "score", "decision_status"
]
result = df[columns].round(4)
Path("calculated_options.csv").write_text(result.to_csv(index=False), encoding="utf-8")
Path("calculation_record.json").write_text(
json.dumps({"weights": weights, "rows": result.to_dict(orient="records")}, indent=2),
encoding="utf-8",
)
print(result.to_string(index=False))Run python score.py. The code checks impossible values, calculates completion rate and cost per completed delivery, records weights, and blocks an option whose terms are unverified. A high score must not override a failed gate.
The normalization is only illustrative. With two options, small differences can become extreme normalized scores. Report original units beside any score, explain the weights, and never present the score as objective truth.
Add Documentary and Qualitative Evidence
The source rows give A 88/100 completions and B 81/90. Calculations give A 88% and PKR 350 per completion; B 90% and about PKR 333.33. With the stated weights and two-option normalization, A scores 0 and B scores 1. These extreme scores reflect relative ranking within just two rows, not absolute quality.
A is eligible under the fixture's terms gate; B is blocked. A defensible memo says A is currently eligible for a limited pilot, while B needs terms verification before consideration. It does not call A the performance winner or treat the CSV flag as proof of a real accepted contract.
Keep categories separate: counts are source facts, rates are calculations, weights/comparable routes are assumptions, unprovided contract wording is unknown, and a limited pilot is a recommendation. If documentary evidence later arrives, record its file hash and actual page or timestamp; verify it before changing the gate.
Use a Memo Structure That Exposes Weakness
Use these headings for the short exercise memo; omit an empty section rather than invent evidence:
# Decision Memo: [specific decision]
Owner / decision date / review date / memo version
## Recommendation
[action, scope, duration, and conditions]
## Decision rule
[gates, metrics, weights, and threshold]
## Evidence
- [claim] — [E001 rows/filter or E002 page/section]
## Calculations and assumptions
[formula, units, weights, missingness, exclusions]
## Risks, counterevidence, and unknowns
[what could reverse the recommendation]
## Pilot and stop conditions
[what will be measured; who can stop it]
## Source register
[hash, owner, date, permission, pointer]The recommendation should be conditional when evidence is incomplete: “Run a four-week pilot after terms are verified” is defensible; “Option B is definitely best” is not.
Sensitivity Analysis: Try to Reverse Your Own Answer
First predict this change: increase only B's total_cost_pkr by 10%, from 27000 to 29700. Its cost per completion becomes about PKR 366.67. A now wins the cost component, giving A 0.30 and B 0.70 under the same weights. B remains blocked; a better score still cannot replace terms verification.
Changing weights alone in the original data cannot reverse the score ranking when B leads on every measured metric and all weights are non-negative. That is why this exercise changes a data assumption. In a later comparison with real tradeoffs, weight sensitivity can be informative; always show original units beside normalized scores.
Failure Cases That Make a Memo Unreliable
Cherry-picked period
state why the window was chosen and show material excluded periods.
Mismatched populations
compare similar routes, order types, and service conditions or disclose the limitation.
Average hides distribution
include denominators and appropriate median, range, or segment results.
Correlation becomes causation
a pattern does not prove why it happened.
Unverified quotation fact
distinguish an unsigned or stale fixture from an accepted term.
Audio opinion becomes policy
label the speaker, consent, scope, and whether the statement is fact or preference.
False citation
open every page, row filter, and timestamp; a plausible pointer is not proof.
Scoring conceals a gate
authorization, missing terms, privacy, or safety cannot be traded away for points.
AI edits a number
regenerate tables from code and compare memo values automatically where possible.
No dissent
include the strongest counterargument and evidence that would change the decision.
No owner or review date
recommendations become stale folklore instead of controlled decisions.
Hands-On Exercise: Deliver the Full Decision Pack
Run the supplied script on the original options.csv. Write a 150–250 word memo using the template's headings. Include A/B rates and unit costs, the failed gate, the comparable-route assumption, and one reversible next step owned by the fictional operations lead. For this exercise, propose review after four weeks and stopping earlier if required terms cease to be verified; do not invent a live agreement.
Save the original outputs. Change B cost to 29700 in a copy, point the script at the copy, rerun, and add two sentences explaining the new scores and unchanged eligibility. Check the expected numbers in the sensitivity section. Restore the original source path afterward.
Finally evaluate a second supplied change on paper: B's terms become verified through a separate authorized review. B would become eligible; with the original cost data it would lead the measured comparison. Record that as a hypothetical condition, not a verification you performed.
Completion Rubric
- The original memo shows 88%/90%, PKR 350/about 333.33, and B's blocked status with E001 row references.
- The 10% B-cost stress test gives about 366.67 and scores A 0.30/B 0.70 without lifting the gate.
- The memo labels comparable routes and weights as assumptions and unprovided contract wording as unknown.
- A named fictional owner has a reversible pilot/review proposal; no actual contract or vendor outcome is claimed.
Sources
Practice quiz
Check yourself
4 questions · practise what you just learned
1 / 4 · diagnose
An analyst reports only a favorable two-week slice from a ninety-day comparison without explaining the excluded period. What should the memo add?
Apna kaam check karo.
Practice complete ki? Result ko example aur lesson ke checks se compare karo.
This is your own completion record, not a graded assessment.