e53086a59e
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 from05be974. 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:05be974regenerated 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.