Example

Stop at the first stage boundary that disagrees with intent

Checkpoint a revenue pipeline in execution order, mark the first boundary that disagrees with the spec, then take the backward slice to name the rows behind the shortfall.

The final number is wrong and the last stage is where it is wrong, so the obvious fix is to patch the last stage. That cannot work: three different causes produce the same wrong total, and only the ordered intermediates separate them. This program checkpoints a pipeline in execution order, stops at the first boundary that disagrees with the spec, then takes the backward slice to name the rows responsible. It composes the chapter’s clean stage and contributing_orders slice over a fixture whose shortfall is €212.40.

Run it

Save this as first_divergence.py and run it with Python 3.11 or later. It uses the standard library only.

"""Chapter 2: checkpoint the chain, stop at the first mismatch, then slice back."""

ORDERS = [{"id": f"R{i}", "status": "refunded", "amount": a}
           for i, a in enumerate([15.00] * 13 + [17.40])]
ORDERS += [{"id": f"P{i}", "status": "paid", "amount": a}
           for i, a in enumerate([100.00, 120.00, 90.00, 110.00, 80.00, 100.00])]


def normalize(order):
    """Refunded orders are kept as negative-amount lines."""
    amount = -order["amount"] if order["status"] == "refunded" else order["amount"]
    return {"id": order["id"], "status": order["status"], "amount": amount}


def clean(orders):
    """Chapter 2's stage, with the defect: refunded orders are dropped entirely."""
    out = []
    for o in orders:
        if o["status"] == "refunded":
            continue          # suspect line: drops refunds entirely
        out.append(normalize(o))
    return out


def aggregate(orders):
    return round(sum(o["amount"] for o in orders), 2)


def contributing_orders(orders, predicate):
    """Backward slice, data-pipeline flavour: rows that reached the wrong bucket."""
    return [o for o in orders if predicate(o)]


def checkpoints(orders):
    """Capture each boundary value once, without editing anything."""
    kept = [normalize(o) for o in orders]
    dropped = clean(orders)
    return [("after ingest", len(orders), None, len(orders), None),
            ("after clean", len(kept), None, len(dropped), None),
            ("after aggregate", len(kept), aggregate(kept),
             len(dropped), aggregate(dropped))]


def show(value):
    return "-" if value is None else f"{value:.2f}"


print("boundary          count            revenue")
first = None
for name, exp_n, exp_r, obs_n, obs_r in checkpoints(ORDERS):
    mismatch = exp_n != obs_n or exp_r != obs_r
    if mismatch and first is None:
        first = name
    verdict = "MISMATCH" if mismatch else "match"
    print(f"{name:16} {exp_n:>5} vs {obs_n:<5} {show(exp_r):>10} vs {show(obs_r):<10}  {verdict}")

print(f"first divergence: {first}")

guilty = contributing_orders(ORDERS, lambda o: o["status"] == "refunded")
shortfall = round(aggregate(clean(ORDERS)) - aggregate([normalize(o) for o in ORDERS]), 2)
print(f"backward slice: {len(guilty)} of {len(ORDERS)} rows reach the wrong bucket")
print(f"their amounts sum to {sum(o['amount'] for o in guilty):.2f}")
print(f"revenue shortfall at aggregate: {shortfall:.2f}")

Expected outcome

boundary          count            revenue
after ingest        20 vs 20             - vs -           match
after clean         20 vs 6              - vs -           MISMATCH
after aggregate     20 vs 6         387.60 vs 600.00      MISMATCH
first divergence: after clean
backward slice: 14 of 20 rows reach the wrong bucket
their amounts sum to 212.40
revenue shortfall at aggregate: 212.40

The last three lines are the chapter’s numbers: fourteen contributing rows and a €212.40 shortfall, matching its assert len(guilty) == 14 and assert round(sum(...), 2) == 212.40.

Order is what localizes

ingest matches intent, so the input snapshot is fine. clean does not, so clean owns the investigation and everything after it is effect. A rounding fix in render would move the final number and leave the defect where it is.

The slice turns a stage into a set of rows, using the chapter’s instrument:

def contributing_orders(orders, predicate):
    """Backward slice, data-pipeline flavour: rows that reached the wrong bucket."""
    return [o for o in orders if predicate(o)]

Mechanism and limitations

Documented: the chapter states that final-output reasoning underdetermines the cause in any multi-stage execution, that exactly one stage is the first to mismatch, that downstream mismatches are effects until proven otherwise, and that the backward dynamic slice is the principled bound on what to read. Its worked example drops fourteen refunded orders worth €212.40 and confirms H1 while rejecting H2 (aggregate double-counts shipments).

Observed: the run above. The first mismatch was at clean, where twenty orders became six, and the aggregate row was a downstream consequence. The slice named fourteen refunded rows summing to €212.40, the exact shortfall the aggregate row shows.

Not shown. The fixture is small and constructed; the chapter’s incident involved 3,842 orders, and no production data is used here. H2 is rejected only by the absence of quantity inflation at aggregate, which this fixture cannot express strongly. No bisection is performed, so the monotonicity precondition and masking failure mode are untested.

Read the chapter .

Understand this example

Copy this prompt into your AI tool. No code runs here.

Apply this example

Copy this prompt into your AI tool. No code runs here.