# RUN.md: departure drill demo

Synthetic and local. Python 3.11 standard library only. No installs, no network, no real data.

## Order of work

1. `scenarios.json`, `expected.json` and `HYPOTHESIS.md` were written and hashed into `frozen-hashes.txt` before `drill.py` existed.
2. `drill.py` and `run_drill.py` written, then run once: all six scenarios matched, 0 reads outside allowed roots.
3. `test_drill.py` added to check the drill can fail. Its first run had 3 failures, all bugs in the tests (restoring a patched staticmethod lost the wrapper; one assertion assumed the leaked notes would make D4 pass, but the notes aren't in KEY=value form). Fixed; the drill code was not changed.

## Changes after independent review (2026-10-26)

Frozen files unchanged (hashes verified). Code and tests changed:

- `Reader.allowed` now normalizes paths, rejects absolute paths and `..`, and matches exact files or whole directories. Before, `repo/../private/prev-owner-notes.md` and `catalog.json.bak` were wrongly allowed. New test: `test_path_tricks_are_out_of_bounds`.
- `find_guidance` now looks one hop upstream when the failing component has no guidance, so D6 reports "guidance exists on upstream component ingest_orders" and D1 reports "nowhere". New test: `test_d1_and_d6_are_reported_differently`. Stall stages are unchanged.
- Renamed `test_mutant_without_verify_passes_wrong_output` to `test_wrong_answer_key_lets_d3_pass`, which is what it does.
- Result: 6 of 6 scenarios still match; 7 tests OK.

## Commands

```
cd docs/drafts/operational-ownership-departure-test-2026-10-26/demo
python3 run_drill.py            # see run-output.txt
python3 -m unittest test_drill.py -v   # see test-log.txt: 7 tests OK
shasum -a 256 -c <(head -3 frozen-hashes.txt)   # frozen files unchanged
```

`run-output.txt` (verbatim, after the review fixes):

```
D1-ownership-only: PASS  passed=False stalled_at=find_guidance  no recovery guidance for this error on the failing component or its upstream
D2-partial: PASS  passed=False stalled_at=execute  UPSTREAM_PARTITION_MISSING
D3-missing-decision: PASS  passed=False stalled_at=verify  restored revenue 245.5, expected 231.0
D4-outside-access: PASS  passed=False stalled_at=within_access  guidance depends on private/prev-owner-notes.md
D5-complete: PASS  passed=True stalled_at=None
D6-wrong-component: PASS  passed=False stalled_at=find_guidance  guidance exists on upstream component ingest_orders, not on revenue_daily
reads outside allowed roots: 0
6 of 6 scenarios matched expected.json; access bound held
```

Fixtures are regenerated under `work/<scenario>/` on every run.
