Files
Syphon_Filter_3/docs
Christopher Williams e53086a59e phase12: T0 — regenerate the STALE maspsx patch and guard it with a test + sf3_free reads the CURRENT phase's ledger
Both defects were found by the Phase 12 open checklist, and both were then PROVEN by
direct test rather than by inspection.

*** 1. THE TRACKED PATCH WAS STALE, AND THE TOOLCHAIN WAS NOT REPRODUCIBLE ***

ea51ac9 ("the epilogue transform now handles BOTH shapes") corrected maspsx=epilogue in
the working tree but never regenerated the tracked patch, which still carried the
superseded shape-A-only transform from 05be974.

  patch -p1 < tools/patches/maspsx-phase10-r1r2.patch   (pristine 86ccd7d)
  -> exit 1, 4 of 10 hunks FAILED, .rej files for BOTH files

The superseded transform emits `nop / jr $31 / addiu sp,sp,32` where 0x800F44D0 has
`jr $31 / addiu sp,sp,32`, so every shape-B row comes out 4 bytes long. 15 registered
regions carry maspsx=epilogue, so a fresh clone could NOT have rebuilt the 611-region
green gate from tracked files. The working tree was right, so every gate was green; the
patch was wrong, so nothing failed. That is why it survived the rest of Phase 11.

Regenerated as pristine -> working tree for exactly the two files the patch touches, and
verified: applies with exit 0 and no rejects; reconstructs both files byte-identically
(cmp exit 0); reverse-applies cleanly, proving the tree IS pristine+patch; still carries
all four opt-in modes.

  4bd21823402d73659f76b3afbf60f8f93daaa3e8 (stale, 167 lines)
  0d7f643ba1c31d1ae28de257737c16c623a9eb00 (regenerated, 229 lines)

*** A TEST, NOT ANOTHER RULE ***

The standing §11 rule — "do not edit a git-ignored tool without carrying the change as a
tracked patch" — WAS followed in Phase 11: 05be974 regenerated the patch and explicitly
verified it. It was stale by the very next commit that touched the transform. The
generalisable defect is that the artifact which is verified is not the artifact that is
enforced: a verification performed once by hand decays the moment the OTHER side of the
diff changes, and the ignored side is the side no review sees. Cookbook 188.

So the remedy is executable. tools/tests/test_maspsx_patch.py reconstructs the vendored
tool from pristine + the tracked patch and requires a byte-identical match against the
working tree; it also requires the pinned commit, requires ONLY those two files to be
modified, requires all four opt-in mode flags to survive a regeneration, and exercises
BOTH epilogue shapes through the reconstructed script. It skips cleanly when the ignored
checkout is absent, like the existing local-toolchain skips.

PROVEN TO CATCH THE DEFECT: run against the superseded patch it fails 4 of its 7 tests
(2 failures, 2 errors); against the regenerated patch it is green. A stale patch now
fails `make test` instead of being found by a human reading a diff — which is exactly how
it was found this time.

*** 2. sf3_free HARD-CODED .run/p11/, AND WOULD HAVE READ A DEAD LEDGER ***

The tracked free-check hard-coded INFLIGHT = .run/p11/inflight.tsv. .run/ is git-ignored
and the ledger is session-scoped BY DESIGN: it coordinates the workers who are alive now.
In Phase 12 the tool would have read a 306-line p11 ledger and never the ledger its own
workers were writing to.

The direction of that failure is the opposite of cookbook 187's, and worse. A stale `wip`
row produces a false TAKEN — a worker is told a free row is held and wastes an
opportunity. A BLIND ledger produces a false FREE — a worker is told a row another worker
is actively holding is free. That is the 0x800320D8 incident: two workers matching the
same region independently, one overwriting the other's source file. Cookbook 189.

The fix encodes the semantics the ledger already had: one phase's ledger is dead to the
next. Resolution is --ledger, then --phase N, then the highest existing .run/pN/ — and a
previous phase is deliberately NOT a fallback, because a row held `wip` by a worker
retired at that phase's close must read FREE. The resolved path is printed to stderr, so
"which ledger did that read?" is always answerable while stdout stays parseable.

21 new tests (tools/tests/test_sf3_free.py) pin end-exclusive containment, last-row-wins,
the phase resolution order, and the no-fallback rule.

*** VERIFICATION ***

  make clean && make all   exit 0
  cmp                      exit 0
  SHA-1 (both files)       e173426c157384ebf1b6caf8c6fea18a85a14af9   (unchanged)
  make test                281 tests, OK   (from 253; the clean run captured 253 before
                                            these suites existed, independently
                                            reconfirming the Phase 11 baseline count)
  make extents-verify      regions=611 disagreements=0 result=AGREE
  make gate                c_regions=611 differing_bytes=0 result=MATCH

No src/, config/ or toolchain working-tree change, so the gate cannot be affected.
2026-09-24 16:41:01 -04:00
..