feat(phase-31): S54 — wave T selector (--one-per-gid, --rank total) + the pre-gate ladder learns to see overlays (§192)

build_wave_atlas: --one-per-gid collapses same-skeleton siblings to one card and defers
them to <out>.siblings.json for the post-bank family_sweep remap (R32 accounting asserted);
--rank total ranks gate groups by DELIVERED mass (card + deferred siblings). Measured on the
wave-T draw: 6,557 drafted ins carrying 12,709 sibling ins behind 69 of 71 gids = 19,266
instructions of potential for 71 agents, vs 9,985 behind 57 under --rank mass. R39 NC: the
flag is byte-inert on a pool whose gids are unique.

gate_main/pregate_check (§192): three defects that made the pre-gate ladder main-only while
reporting "clean" on overlay slates — (1) resolve_conflicts/substitute hardcoded
corpus.stubs('main') -> per-binary _stubs_for(); (2) sym_of returned the keyword `void` for
every `extern void (*D_x[])(...)`, manufacturing 192 phantom CONFLICTING-EXTERNs (NC over
5,526,100 declarations: 189,301 changed verdicts, 0 regressions); (3) `void f()` and
`void f(void)` were normalized together, costing 40 more phantoms — C89's unspecified-
parameter rule is now gate_main.sig_conflict. §192b: the tool refuses when it substituted 0
files, and prints the per-draft [DROP] reasons it used to compute and discard.

Same overlay slate now reports 2 failures, both real (duplicate typedef; memcpy declared two
ways). Cookbook §192/§192b + index regenerated (585 sections).
This commit is contained in:
Drew T
2026-08-17 11:00:14 -06:00
parent 034c46bc28
commit 85671bc1f7
9 changed files with 466 additions and 139 deletions
+126 -75
View File
@@ -2,7 +2,7 @@
> **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section.
>
> `docs/matching-cookbook.md` is ~716 KB / 564 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
> `docs/matching-cookbook.md` is ~716 KB / 585 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
**How to use:** name what you SEE in the diff (a stolen delay slot, an extra `la`, a swapped register pair, a `conflicting types` error), find that symptom below, read those sections first. If nothing fits, THEN grind — and add a section when you win.
@@ -34,7 +34,7 @@
## By symptom
### delay slots & branches (8)
### delay slots & branches (9)
- **§3-T4** — Branch polarity: invert the source condition to flip gcc's chosen branch <sub>L90</sub>
- **§5a** — Cross-jump tail-merge — gcc collapses two byte-identical blocks the original kept separate (FIX FOUND) <sub>L211</sub>
@@ -43,9 +43,10 @@
- **§162** — CROSS-JUMP DIRECTION: the surviving copy is always the LATER one, so a BACKWARD `j` into a sibling arm is a source `goto` (P30 S48) <sub>L11263</sub>
- **§162** — The cross-jump "CALL veto" is a COUNT law, not a CALL law (BOUNDS §88a; P30 S48, `func_80189540`) <sub>L11299</sub>
- **§177** — 🔴 THE EPILOGUE RETURN-DELAY SLOT IS DECIDED BY YOUR SAVED-REGISTER SET, NOT BY SCHEDULING <sub>L17156</sub>
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L17602</sub>
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L17613</sub>
- **§186** — CROSS-JUMPING RUNS **AFTER** SCHEDULING, SO NO C-LEVEL BARRIER CAN STEER IT <sub>L18060</sub>
### instruction scheduling (24)
### instruction scheduling (25)
- **§3-T2** — Source statement order drives instruction scheduling <sub>L78</sub>
- **§3** — When a diff is pure scheduling → decomp-permuter (harness built, Phase 6) <sub>L107</sub>
@@ -68,11 +69,12 @@
- **§16Z** — SHARPENS *(sharpens §37 "the /s-DEP LATTICE", §136-13, §136-14, §16Xy, §162q, `gcc-2.7.2-map/sched.md` §64)* <sub>L14337</sub>
- **§175** — A CALLER-SAVED REGISTER PIN CAN BE A CORRECTNESS BUG, NOT JUST A SCHEDULING CHOICE (P31 wave H, 2026-08-15) <sub>L16709</sub>
- **§177** — 🔴 THE EPILOGUE RETURN-DELAY SLOT IS DECIDED BY YOUR SAVED-REGISTER SET, NOT BY SCHEDULING <sub>L17156</sub>
- **§3-B.** — A `return <const>` IS A PRIORITY-1 HARD-REG SET THE SCHEDULER PLACES FIRST (func_8001BE30, 92 ins) <sub>L17230</sub>
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L17602</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17666</sub>
- **§3-B.** — A `return <const>` IS A PRIORITY-1 HARD-REG SET THE SCHEDULER PLACES FIRST (func_8001BE30, 92 ins) <sub>L17241</sub>
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L17613</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17677</sub>
- **§186** — CROSS-JUMPING RUNS **AFTER** SCHEDULING, SO NO C-LEVEL BARRIER CAN STEER IT <sub>L18060</sub>
### register allocation & pins (51)
### register allocation & pins (54)
- **§10** — Closing the regalloc/scheduling hard tail by hand (LZSS, Phase 7 session F — the full close) <sub>L835</sub>
- **Residual** — A — commutative `|`/`&`/`+` result lands in the wrong source-operand register <sub>L856</sub>
@@ -119,19 +121,22 @@
- **§175** — A CALLER-SAVED REGISTER PIN CAN BE A CORRECTNESS BUG, NOT JUST A SCHEDULING CHOICE (P31 wave H, 2026-08-15) <sub>L16709</sub>
- **§176j** — STOPPING A WAVE MID-FLIGHT COSTS THE IN-FLIGHT TAIL (and how much is recoverable) <sub>L17093</sub>
- **§177** — 🔴 THE EPILOGUE RETURN-DELAY SLOT IS DECIDED BY YOUR SAVED-REGISTER SET, NOT BY SCHEDULING <sub>L17156</sub>
- **§179-A** — 🔴 A LOOP-WALKED POINTER **PARAMETER** HANDS ITS ARGUMENT REGISTER TO THE GIV (9 byte-proofs) <sub>L17299</sub>
- **§179-F** — PINNING A LOOP-WALKED POINTER IS A TOTAL OFF-SWITCH FOR STRENGTH REDUCTION <sub>L17495</sub>
- **§179-G** — 🟡 A PIN CAN **CREATE** A COMBINE `LOG_LINK` AND DELETE AN `andi` (sixth RC-5 channel, n=1) <sub>L17518</sub>
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L17596</sub>
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L17626</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17666</sub>
- **§179-A** — 🔴 A LOOP-WALKED POINTER **PARAMETER** HANDS ITS ARGUMENT REGISTER TO THE GIV (9 byte-proofs) <sub>L17310</sub>
- **§179-F** — PINNING A LOOP-WALKED POINTER IS A TOTAL OFF-SWITCH FOR STRENGTH REDUCTION <sub>L17506</sub>
- **§179-G** — 🟡 A PIN CAN **CREATE** A COMBINE `LOG_LINK` AND DELETE AN `andi` (sixth RC-5 channel, n=1) <sub>L17529</sub>
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L17607</sub>
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L17637</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17677</sub>
- **§3-18** — of 20 reconciled while keeping the match. The two that did not are mechanism, not effort. <sub>L17930</sub>
- **§186** — CROSS-JUMPING RUNS **AFTER** SCHEDULING, SO NO C-LEVEL BARRIER CAN STEER IT <sub>L18060</sub>
- **§186c** — WHERE A VALUE IS LOADED DECIDES WHICH ALLOCATOR OWNS IT, AND THEREFORE ITS REGISTER <sub>L18089</sub>
### CSE / redundancy / rematerialization (4)
- **§46** — The `func_80178D40` crack (890 ins ×134, the heaviest core in the game): four LOOP-STRUCTURE levers cheap-Opus found by reading loop.c/jump.c/cse.c (Phase 26 session 8, 2026-07-13) <sub>L3313</sub>
- **§83d** — CSE's quantity budget is WHOLE-FUNCTION, so a local rewrite cannot fix a local symptom <sub>L6452</sub>
- **§153** — THE ADDRESS-REMATERIALISATION LAUNDER: a third zero-emission asm lever (P30 S43, `func_8018D98C`, 710 ins) <sub>L10463</sub>
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L17692</sub>
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L17703</sub>
### loops & induction variables (13)
@@ -145,11 +150,11 @@
- **§145** — Three loop/combine levers from the S40 wave-2 drafters (16/16 match_one) <sub>L9924</sub>
- **§148** — The loop.c hoisting THRESHOLD is arithmetic you can compute, and the `?:` clamp that folds to MIN_EXPR (P30 S42, `func_8017C6F4`, 947 ins) <sub>L10142</sub>
- **§171a** — THE MECHANICAL A-PROP DRAFT (P30 S50): 256 members banked with no agent in the loop <sub>L16417</sub>
- **§179-A** — 🔴 A LOOP-WALKED POINTER **PARAMETER** HANDS ITS ARGUMENT REGISTER TO THE GIV (9 byte-proofs) <sub>L17299</sub>
- **§179-E** — A `>2*MAX_MOVE_BYTES` BLOCK COPY IS A **STRUCT ASSIGNMENT**, NOT A HAND LOOP <sub>L17469</sub>
- **§179-F** — PINNING A LOOP-WALKED POINTER IS A TOTAL OFF-SWITCH FOR STRENGTH REDUCTION <sub>L17495</sub>
- **§179-A** — 🔴 A LOOP-WALKED POINTER **PARAMETER** HANDS ITS ARGUMENT REGISTER TO THE GIV (9 byte-proofs) <sub>L17310</sub>
- **§179-E** — A `>2*MAX_MOVE_BYTES` BLOCK COPY IS A **STRUCT ASSIGNMENT**, NOT A HAND LOOP <sub>L17480</sub>
- **§179-F** — PINNING A LOOP-WALKED POINTER IS A TOTAL OFF-SWITCH FOR STRENGTH REDUCTION <sub>L17506</sub>
### structs, block moves & memcpy (39)
### structs, block moves & memcpy (40)
- **§3-T2** — Source statement order drives instruction scheduling <sub>L78</sub>
- **§5** — Known hard-residual classes (instruction-identical, one byte-exact blocker) <sub>L199</sub>
@@ -187,11 +192,12 @@
- **§16Z** — SHARPENS *(sharpens §37 "the /s-DEP LATTICE", §136-13, §136-14, §16Xy, §162q, `gcc-2.7.2-map/sched.md` §64)* <sub>L14337</sub>
- **§3-The** — ADDRESS-CLASS TABLE: which load/store pairs even REACH the `/s` clause (P30 S48 wave 4, `func_80185B44`, ov_SC03_014) <sub>L14339</sub>
- **§176g** — SIZE A WAVE BY INSTRUCTIONS, NOT BY CARDS (P31 S52 — the adopted doctrine) <sub>L16927</sub>
- **§3-F.** — `MEM_IN_STRUCT_P` ASYMMETRY IN `true_dependence` (func_80037144, 124 ins) <sub>L17267</sub>
- **§179-E** — A `>2*MAX_MOVE_BYTES` BLOCK COPY IS A **STRUCT ASSIGNMENT**, NOT A HAND LOOP <sub>L17469</sub>
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L17626</sub>
- **§3-F.** — `MEM_IN_STRUCT_P` ASYMMETRY IN `true_dependence` (func_80037144, 124 ins) <sub>L17278</sub>
- **§179-E** — A `>2*MAX_MOVE_BYTES` BLOCK COPY IS A **STRUCT ASSIGNMENT**, NOT A HAND LOOP <sub>L17480</sub>
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L17637</sub>
- **§189** — FIVE COMPILER LAWS MINED FROM THE WAVE R/S JOURNALS (P31 S53), each source-cited and re-derived by a second agent <sub>L18194</sub>
### types, signedness & load/store width (36)
### types, signedness & load/store width (38)
- **§3-I1** — Unsigned range check: `(x - lo) < (hi-lo)` → `addiu`+`sltiu` <sub>L41</sub>
- **§3-I2** — Byte mask forces `andi` even after `lbu` <sub>L47</sub>
@@ -228,9 +234,11 @@
- **§3-C.** — PAC type 1 = the same payload class as type 4, just NOT compressed <sub>L10545</sub>
- **§155b** — check the TYPE your oracle returns before comparing against it (S45 p5) <sub>L10584</sub>
- **§3-B.** — Typedef handling — the only strategy that survives contact <sub>L16991</sub>
- **§3-D.** — A NARROW TYPE BLOCKS COPY ELISION (func_8001D3FC — new idiom) <sub>L17251</sub>
- **§3-D.** — A NARROW TYPE BLOCKS COPY ELISION (func_8001D3FC — new idiom) <sub>L17262</sub>
- **§185** — EDIT THE SIDE THAT IS CHEAP TO VERIFY, AND CHECK A TU RETYPE AT ITS USE SITES <sub>L18028</sub>
- **§186b** — A NO-SAVE 16-BYTE FRAME IN A LEAF FUNCTION MEANS `s16` LOCALS, NOT A HIDDEN CALL <sub>L18081</sub>
### declarations, prototypes & K&R (58)
### declarations, prototypes & K&R (59)
- **§3-T4** — Branch polarity: invert the source condition to flip gcc's chosen branch <sub>L90</sub>
- **§8c** — Splitting a TU means rebuilding its DECLARATION ENVIRONMENT, not moving text (Phase 26 session 6) <sub>L437</sub>
@@ -290,8 +298,9 @@
- **§159** — THE DECLARATION AXIS: conform to byte-truth, and make every guard state its COVERAGE (P30 S47; ~10,930 sites across 8 axes, fleet byte-identical) <sub>L10825</sub>
- **§168** — THE COUSIN TIER (P30 S49, 2026-08-12): h_seq's exact-hash brittleness, measured — and the similarity map above it <sub>L16208</sub>
- **§176f** — THE DECLARATION FORM IS A MATCHING LEVER, SO RECONCILE TOWARD THE FORM THE MATCH NEEDS (P31 S52) <sub>L16896</sub>
- **§183** — THE DECLARATION-RECONCILIATION PLAYBOOK (P31 S53, measured on 20 byte-verified drafts) <sub>L17929</sub>
### jump tables & switches (28)
### jump tables & switches (29)
- **§8** — rodata island (compiler jump tables) — the `.data→.rodata→.data` sandwich (Phase 7) <sub>L320</sub>
- **§8a** — rodata island in a flat OVERLAY — the tail sandwich, per matched jr-function (Phase 26 — PoC PROVEN) <sub>L342</sub>
@@ -320,7 +329,8 @@
- **§132b** — When the span's already-matched owner is ITSELF multi-switch: `--span-rel` (P30 S1, `func_8014032C`) <sub>L8660</sub>
- **§139** — A GATE THAT GREPS FOR VERDICTS MUST ASSERT 1:1 ACCOUNTING; and a `--src` filter must not survive a carve (P30 S38, wave 6: 10 of 16 drafts vanished) <sub>L9591</sub>
- **§161** — THE RETRY-WAVE HARVEST: a jump table indexed from zero, and two allocator traps (P30 S47) <sub>L10966</sub>
- **§179-F** — PINNING A LOOP-WALKED POINTER IS A TOTAL OFF-SWITCH FOR STRENGTH REDUCTION <sub>L17495</sub>
- **§179-F** — PINNING A LOOP-WALKED POINTER IS A TOTAL OFF-SWITCH FOR STRENGTH REDUCTION <sub>L17506</sub>
- **§188** — 🔴 THE `jr $ra` + `addiu $sp` TAIL IS AN **ASSEMBLER** ARTIFACT, NOT A FRAME SHAPE <sub>L18144</sub>
### optimisation level (-O0/-O2) (12)
@@ -425,9 +435,9 @@
- **§168** — THE COUSIN TIER (P30 S49, 2026-08-12): h_seq's exact-hash brittleness, measured — and the similarity map above it <sub>L16208</sub>
- **§171a** — THE MECHANICAL A-PROP DRAFT (P30 S50): 256 members banked with no agent in the loop <sub>L16417</sub>
- **§171b** — THREE CARRIES THE MECHANICAL DRAFT NEEDS (P30 S50, banking the top-reach families) <sub>L16467</sub>
- **§3-G.** — TWO MODELLING TRAPS THAT COST THESE AGENTS SWEEPS OF HUNDREDS OF COMPILES <sub>L17273</sub>
- **§3-G.** — TWO MODELLING TRAPS THAT COST THESE AGENTS SWEEPS OF HUNDREDS OF COMPILES <sub>L17284</sub>
### integration / TU plumbing (41)
### integration / TU plumbing (43)
- **§8c** — Splitting a TU means rebuilding its DECLARATION ENVIRONMENT, not moving text (Phase 26 session 6) <sub>L437</sub>
- **§8d** — Templating a body INTO a TU must not CHANGE its declaration environment — demote the carried data externs (Phase 26 session 8, byte-proven on `func_8015AE2C` ×133) <sub>L483</sub>
@@ -470,8 +480,10 @@
- **§166** — THE DESTINATION-TU ORACLE (P30 S48): the seven-attempt bug that was never codegen <sub>L14899</sub>
- **§173** — THE STORED-PLUMBING RECOVERY RECIPE (P31 T6): symfix-first, per-group isolation, and where the verdicts have no drafts <sub>L16603</sub>
- **§176d** — THE CONFLICT TABLE MUST BE SEEDED FROM THE TU, AND KEYED PER FILE (P31 S52, 2026-08-15) <sub>L16800</sub>
- **§180b** — WHAT THE PRE-GATE LADDER ACTUALLY FINDS IN A COLD PILE (the shape of integration debt) <sub>L17810</sub>
- **§185** — EDIT THE SIDE THAT IS CHEAP TO VERIFY, AND CHECK A TU RETYPE AT ITS USE SITES <sub>L18028</sub>
### build graph, splat & the harness (117)
### build graph, splat & the harness (125)
- **§4** — Flag/toolchain gotchas <sub>L190</sub>
- **Build** — mechanism — per-file opt override (splat resegmentation) <sub>L288</sub>
@@ -587,11 +599,19 @@
- **§3-C2.** — RECONCILE BEFORE THE FIRST GATE — a parked draft gets HARDER to bank, not easier <sub>L17020</sub>
- **§3-D.** — The measured cost shape, and what to build next <sub>L17043</sub>
- **§176i** — WHAT A STATIC PRE-GATE CHECK CAN AND CANNOT PROVE (P31 S52, wave Q) <sub>L17061</sub>
- **§179** — IDIOMS MINED FROM THE WAVE P/Q JOURNALS (P31 S52, harvest pass) <sub>L17289</sub>
- **§179-G** — 🟡 A PIN CAN **CREATE** A COMBINE `LOG_LINK` AND DELETE AN `andi` (sixth RC-5 channel, n=1) <sub>L17518</sub>
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L17585</sub>
- **§179** — IDIOMS MINED FROM THE WAVE P/Q JOURNALS (P31 S52, harvest pass) <sub>L17300</sub>
- **§179-G** — 🟡 A PIN CAN **CREATE** A COMBINE `LOG_LINK` AND DELETE AN `andi` (sixth RC-5 channel, n=1) <sub>L17529</sub>
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L17596</sub>
- **§180** — THE LEFTOVER-DRAFT HARVEST: RE-VERIFY WHAT YOU ALREADY HAVE BEFORE DRAFTING ANYTHING NEW <sub>L17781</sub>
- **§180b** — WHAT THE PRE-GATE LADDER ACTUALLY FINDS IN A COLD PILE (the shape of integration debt) <sub>L17810</sub>
- **§181** — WHAT A WAVE'S GATE ACTUALLY REJECTS (P31 S53, measured on wave R's 45-draft main pile) <sub>L17847</sub>
- **§184** — COMMENT-BLINDNESS IS A DEFECT CLASS, NOT A BUG (P31 S53: three tools, one root cause, one session) <sub>L18000</sub>
- **§187** — 🔴 "SAME SOURCE" IS NOT "SAME OBJECT": THE SDK BUILD AND THE GAME BUILD DISAGREE ON GTE NOPS <sub>L18106</sub>
- **§190** — THREE PRESCRIPTIONS FROM THE SAME HARVEST (weaker evidence than §189, honestly labelled) <sub>L18255</sub>
- **§191** — WHAT THIS HARVEST DID **NOT** BANK (4 rejected, 4 narrowed) — recorded so it is not re-derived <sub>L18292</sub>
- **§192** — THE PRE-GATE LADDER WAS MAIN-ONLY, AND NOBODY COULD SEE IT (P31 S54) <sub>L18314</sub>
### process, measurement & doctrine (79)
### process, measurement & doctrine (85)
- **§8e** — The jtbl ALIGNMENT LAW + the pad-spec filter — multi-table .rodata spans (Phase 29, byte-proven; `.run/probe_jtbl/verdict.md`) <sub>L530</sub>
- **§3-The** — mechanism: game-code dedup is SOURCE-LEVEL, not an object swap (R-D1, the key lesson) <sub>L926</sub>
@@ -670,10 +690,16 @@
- **§176h** — THE BATCH-SUBSTITUTION HAZARD MAP (P31 S52): seven holes, three wrong fixes, one law <sub>L16965</sub>
- **§3-D.** — The measured cost shape, and what to build next <sub>L17043</sub>
- **§176j-2** — THE REPAIR PASS, MEASURED (do this instead of resuming) <sub>L17119</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17666</sub>
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L17718</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17677</sub>
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L17729</sub>
- **§180** — THE LEFTOVER-DRAFT HARVEST: RE-VERIFY WHAT YOU ALREADY HAVE BEFORE DRAFTING ANYTHING NEW <sub>L17781</sub>
- **§181** — WHAT A WAVE'S GATE ACTUALLY REJECTS (P31 S53, measured on wave R's 45-draft main pile) <sub>L17847</sub>
- **§182** — §177's HONEST NEGATIVE: the epilogue lever cracked 4 of 16, and the `800c3` cluster held <sub>L17903</sub>
- **§183** — THE DECLARATION-RECONCILIATION PLAYBOOK (P31 S53, measured on 20 byte-verified drafts) <sub>L17929</sub>
- **§185** — EDIT THE SIDE THAT IS CHEAP TO VERIFY, AND CHECK A TU RETYPE AT ITS USE SITES <sub>L18028</sub>
- **§190** — THREE PRESCRIPTIONS FROM THE SAME HARVEST (weaker evidence than §189, honestly labelled) <sub>L18255</sub>
### (unbucketed — title matched no symptom vocabulary) (188)
### (unbucketed — title matched no symptom vocabulary) (192)
- **§3-How** — to use this <sub>L30</sub>
- **§1** — Idiom catalog (asm pattern → C that produces it) <sub>L39</sub>
@@ -852,17 +878,21 @@
- **§176b** — BATCH-GATING MECHANICS (P31): what changes when N drafts land in ONE .c <sub>L16774</sub>
- **§3-C.** — The limit that remains (recorded, not solved) <sub>L17013</sub>
- **§176k** — TWO SELECTOR BUGS THAT SILENTLY SHRINK A WAVE <sub>L17139</sub>
- **§178** — SIX LEVERS MINED FROM THE WAVE-P JOURNALS (P31 S52), each byte-proven and source-cited <sub>L17202</sub>
- **§3-A.** — THE `$0`-ADD OPAQUE COPY defeats `make_regs_eqv` (func_80033398, 93 ins) <sub>L17214</sub>
- **§3-C.** — SINGLE-SET TEMPS GET THE BIRTHING BOOST (func_8001D3FC, 196 ins) <sub>L17243</sub>
- **§3-E.** — THE ZERO-OFFSET ALIAS HOLE (func_80037028, 71 ins) <sub>L17258</sub>
- **§179-B** — 🔴 THE HAND-WRITTEN-ASM TRANSCRIPTION CHECKLIST (maspsx + masked_diff; 10 byte-proofs) <sub>L17348</sub>
- **§179-C** — 🔴 A FUNCTION WITH NO EPILOGUE (falls into a sibling's shared tail) MUST BE FILE-SCOPE `__asm__` <sub>L17398</sub>
- **§179-D** — `gte_stflg` MUST CLOBBER `"$12"` OR THE WHOLE TEMP FILE ROTATES BY ONE <sub>L17449</sub>
- **§179-H** — A MID-BODY `.global LABEL` PAIR SLICES A BYTE-COMPARABLE FRAGMENT OUT OF A LARGER ROUTINE <sub>L17545</sub>
- **Considered** — and NOT banked <sub>L17568</sub>
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L17740</sub>
- **What** — is NOT banked here <sub>L17757</sub>
- **§178** — SIX LEVERS MINED FROM THE WAVE-P JOURNALS (P31 S52), each byte-proven and source-cited <sub>L17213</sub>
- **§3-A.** — THE `$0`-ADD OPAQUE COPY defeats `make_regs_eqv` (func_80033398, 93 ins) <sub>L17225</sub>
- **§3-C.** — SINGLE-SET TEMPS GET THE BIRTHING BOOST (func_8001D3FC, 196 ins) <sub>L17254</sub>
- **§3-E.** — THE ZERO-OFFSET ALIAS HOLE (func_80037028, 71 ins) <sub>L17269</sub>
- **§179-B** — 🔴 THE HAND-WRITTEN-ASM TRANSCRIPTION CHECKLIST (maspsx + masked_diff; 10 byte-proofs) <sub>L17359</sub>
- **§179-C** — 🔴 A FUNCTION WITH NO EPILOGUE (falls into a sibling's shared tail) MUST BE FILE-SCOPE `__asm__` <sub>L17409</sub>
- **§179-D** — `gte_stflg` MUST CLOBBER `"$12"` OR THE WHOLE TEMP FILE ROTATES BY ONE <sub>L17460</sub>
- **§179-H** — A MID-BODY `.global LABEL` PAIR SLICES A BYTE-COMPARABLE FRAGMENT OUT OF A LARGER ROUTINE <sub>L17556</sub>
- **Considered** — and NOT banked <sub>L17579</sub>
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L17751</sub>
- **What** — is NOT banked here <sub>L17768</sub>
- **§180c** — WHEN A BINARY'S MASS BAND IS SPENT, THE FLEET-WIDE DRAW IS STRICTLY BETTER <sub>L17829</sub>
- **Only** — ONE of 27 blocked drafts was wrong. The other 26 were correct and unbankable. <sub>L17848</sub>
- **§180d** — THE `pgrep` BRACKET TRICK PROTECTS THE PATTERN, NOT THE COMMAND LINE <sub>L17917</sub>
- **Three** — defects in one call path; the overlay slates that carry most of the wave work were being waved through <sub>L18315</sub>
## All sections, in order
@@ -1404,30 +1434,51 @@
- **§176j-2** — THE REPAIR PASS, MEASURED (do this instead of resuming) <sub>L17119</sub>
- **§176k** — TWO SELECTOR BUGS THAT SILENTLY SHRINK A WAVE <sub>L17139</sub>
- **§177** — 🔴 THE EPILOGUE RETURN-DELAY SLOT IS DECIDED BY YOUR SAVED-REGISTER SET, NOT BY SCHEDULING <sub>L17156</sub>
- **§178** — SIX LEVERS MINED FROM THE WAVE-P JOURNALS (P31 S52), each byte-proven and source-cited <sub>L17202</sub>
- **§3-A.** — THE `$0`-ADD OPAQUE COPY defeats `make_regs_eqv` (func_80033398, 93 ins) <sub>L17214</sub>
- **§3-B.** — A `return <const>` IS A PRIORITY-1 HARD-REG SET THE SCHEDULER PLACES FIRST (func_8001BE30, 92 ins) <sub>L17230</sub>
- **§3-C.** — SINGLE-SET TEMPS GET THE BIRTHING BOOST (func_8001D3FC, 196 ins) <sub>L17243</sub>
- **§3-D.** — A NARROW TYPE BLOCKS COPY ELISION (func_8001D3FC — new idiom) <sub>L17251</sub>
- **§3-E.** — THE ZERO-OFFSET ALIAS HOLE (func_80037028, 71 ins) <sub>L17258</sub>
- **§3-F.** — `MEM_IN_STRUCT_P` ASYMMETRY IN `true_dependence` (func_80037144, 124 ins) <sub>L17267</sub>
- **§3-G.** — TWO MODELLING TRAPS THAT COST THESE AGENTS SWEEPS OF HUNDREDS OF COMPILES <sub>L17273</sub>
- **§179** — IDIOMS MINED FROM THE WAVE P/Q JOURNALS (P31 S52, harvest pass) <sub>L17289</sub>
- **§179-A** — 🔴 A LOOP-WALKED POINTER **PARAMETER** HANDS ITS ARGUMENT REGISTER TO THE GIV (9 byte-proofs) <sub>L17299</sub>
- **§179-B** — 🔴 THE HAND-WRITTEN-ASM TRANSCRIPTION CHECKLIST (maspsx + masked_diff; 10 byte-proofs) <sub>L17348</sub>
- **§179-C** — 🔴 A FUNCTION WITH NO EPILOGUE (falls into a sibling's shared tail) MUST BE FILE-SCOPE `__asm__` <sub>L17398</sub>
- **§179-D** — `gte_stflg` MUST CLOBBER `"$12"` OR THE WHOLE TEMP FILE ROTATES BY ONE <sub>L17449</sub>
- **§179-E** — A `>2*MAX_MOVE_BYTES` BLOCK COPY IS A **STRUCT ASSIGNMENT**, NOT A HAND LOOP <sub>L17469</sub>
- **§179-F** — PINNING A LOOP-WALKED POINTER IS A TOTAL OFF-SWITCH FOR STRENGTH REDUCTION <sub>L17495</sub>
- **§179-G** — 🟡 A PIN CAN **CREATE** A COMBINE `LOG_LINK` AND DELETE AN `andi` (sixth RC-5 channel, n=1) <sub>L17518</sub>
- **§179-H** — A MID-BODY `.global LABEL` PAIR SLICES A BYTE-COMPARABLE FRAGMENT OUT OF A LARGER ROUTINE <sub>L17545</sub>
- **Considered** — and NOT banked <sub>L17568</sub>
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L17585</sub>
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L17596</sub>
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L17602</sub>
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L17626</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17666</sub>
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L17692</sub>
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L17718</sub>
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L17740</sub>
- **What** — is NOT banked here <sub>L17757</sub>
- **§178** — SIX LEVERS MINED FROM THE WAVE-P JOURNALS (P31 S52), each byte-proven and source-cited <sub>L17213</sub>
- **§3-A.** — THE `$0`-ADD OPAQUE COPY defeats `make_regs_eqv` (func_80033398, 93 ins) <sub>L17225</sub>
- **§3-B.** — A `return <const>` IS A PRIORITY-1 HARD-REG SET THE SCHEDULER PLACES FIRST (func_8001BE30, 92 ins) <sub>L17241</sub>
- **§3-C.** — SINGLE-SET TEMPS GET THE BIRTHING BOOST (func_8001D3FC, 196 ins) <sub>L17254</sub>
- **§3-D.** — A NARROW TYPE BLOCKS COPY ELISION (func_8001D3FC — new idiom) <sub>L17262</sub>
- **§3-E.** — THE ZERO-OFFSET ALIAS HOLE (func_80037028, 71 ins) <sub>L17269</sub>
- **§3-F.** — `MEM_IN_STRUCT_P` ASYMMETRY IN `true_dependence` (func_80037144, 124 ins) <sub>L17278</sub>
- **§3-G.** — TWO MODELLING TRAPS THAT COST THESE AGENTS SWEEPS OF HUNDREDS OF COMPILES <sub>L17284</sub>
- **§179** — IDIOMS MINED FROM THE WAVE P/Q JOURNALS (P31 S52, harvest pass) <sub>L17300</sub>
- **§179-A** — 🔴 A LOOP-WALKED POINTER **PARAMETER** HANDS ITS ARGUMENT REGISTER TO THE GIV (9 byte-proofs) <sub>L17310</sub>
- **§179-B** — 🔴 THE HAND-WRITTEN-ASM TRANSCRIPTION CHECKLIST (maspsx + masked_diff; 10 byte-proofs) <sub>L17359</sub>
- **§179-C** — 🔴 A FUNCTION WITH NO EPILOGUE (falls into a sibling's shared tail) MUST BE FILE-SCOPE `__asm__` <sub>L17409</sub>
- **§179-D** — `gte_stflg` MUST CLOBBER `"$12"` OR THE WHOLE TEMP FILE ROTATES BY ONE <sub>L17460</sub>
- **§179-E** — A `>2*MAX_MOVE_BYTES` BLOCK COPY IS A **STRUCT ASSIGNMENT**, NOT A HAND LOOP <sub>L17480</sub>
- **§179-F** — PINNING A LOOP-WALKED POINTER IS A TOTAL OFF-SWITCH FOR STRENGTH REDUCTION <sub>L17506</sub>
- **§179-G** — 🟡 A PIN CAN **CREATE** A COMBINE `LOG_LINK` AND DELETE AN `andi` (sixth RC-5 channel, n=1) <sub>L17529</sub>
- **§179-H** — A MID-BODY `.global LABEL` PAIR SLICES A BYTE-COMPARABLE FRAGMENT OUT OF A LARGER ROUTINE <sub>L17556</sub>
- **Considered** — and NOT banked <sub>L17579</sub>
- **§176c** — MAIN (SLUS_007.26) CANNOT BE GATED INCREMENTALLY <sub>L17596</sub>
- **§176** — SEVEN LEVERS FROM THE P31 OVERNIGHT WAVES (2026-08-15): statement order, false regalloc, and the pin that fights back <sub>L17607</sub>
- **§176-A** — "SCHEDULE / DELAY-SLOT / LENGTH-DRIFT ±1" ⇒ check STATEMENT ORDER around the call first <sub>L17613</sub>
- **§176-B** — "REGALLOC-PERM, 1-4 instructions off" ⇒ it is usually NOT register allocation <sub>L17637</sub>
- **§176-C** — 🔴 WALL REFUTATION: a hard-register pin CANNOT schedule around a call, because of a genuine gcc-2.7.2 bug <sub>L17677</sub>
- **§176-D** — CSE-class levers used in reverse (two sharpenings of §153 and cse_expr §2) <sub>L17703</sub>
- **§176-E** — Two cheap source spellings, both cc1-probed <sub>L17729</sub>
- **§176-F** — Misdiagnosis triage: four residual verdicts that were lying <sub>L17751</sub>
- **What** — is NOT banked here <sub>L17768</sub>
- **§180** — THE LEFTOVER-DRAFT HARVEST: RE-VERIFY WHAT YOU ALREADY HAVE BEFORE DRAFTING ANYTHING NEW <sub>L17781</sub>
- **§180b** — WHAT THE PRE-GATE LADDER ACTUALLY FINDS IN A COLD PILE (the shape of integration debt) <sub>L17810</sub>
- **§180c** — WHEN A BINARY'S MASS BAND IS SPENT, THE FLEET-WIDE DRAW IS STRICTLY BETTER <sub>L17829</sub>
- **§181** — WHAT A WAVE'S GATE ACTUALLY REJECTS (P31 S53, measured on wave R's 45-draft main pile) <sub>L17847</sub>
- **Only** — ONE of 27 blocked drafts was wrong. The other 26 were correct and unbankable. <sub>L17848</sub>
- **§182** — §177's HONEST NEGATIVE: the epilogue lever cracked 4 of 16, and the `800c3` cluster held <sub>L17903</sub>
- **§180d** — THE `pgrep` BRACKET TRICK PROTECTS THE PATTERN, NOT THE COMMAND LINE <sub>L17917</sub>
- **§183** — THE DECLARATION-RECONCILIATION PLAYBOOK (P31 S53, measured on 20 byte-verified drafts) <sub>L17929</sub>
- **§3-18** — of 20 reconciled while keeping the match. The two that did not are mechanism, not effort. <sub>L17930</sub>
- **§184** — COMMENT-BLINDNESS IS A DEFECT CLASS, NOT A BUG (P31 S53: three tools, one root cause, one session) <sub>L18000</sub>
- **§185** — EDIT THE SIDE THAT IS CHEAP TO VERIFY, AND CHECK A TU RETYPE AT ITS USE SITES <sub>L18028</sub>
- **§186** — CROSS-JUMPING RUNS **AFTER** SCHEDULING, SO NO C-LEVEL BARRIER CAN STEER IT <sub>L18060</sub>
- **§186b** — A NO-SAVE 16-BYTE FRAME IN A LEAF FUNCTION MEANS `s16` LOCALS, NOT A HIDDEN CALL <sub>L18081</sub>
- **§186c** — WHERE A VALUE IS LOADED DECIDES WHICH ALLOCATOR OWNS IT, AND THEREFORE ITS REGISTER <sub>L18089</sub>
- **§187** — 🔴 "SAME SOURCE" IS NOT "SAME OBJECT": THE SDK BUILD AND THE GAME BUILD DISAGREE ON GTE NOPS <sub>L18106</sub>
- **§188** — 🔴 THE `jr $ra` + `addiu $sp` TAIL IS AN **ASSEMBLER** ARTIFACT, NOT A FRAME SHAPE <sub>L18144</sub>
- **§189** — FIVE COMPILER LAWS MINED FROM THE WAVE R/S JOURNALS (P31 S53), each source-cited and re-derived by a second agent <sub>L18194</sub>
- **§190** — THREE PRESCRIPTIONS FROM THE SAME HARVEST (weaker evidence than §189, honestly labelled) <sub>L18255</sub>
- **§191** — WHAT THIS HARVEST DID **NOT** BANK (4 rejected, 4 narrowed) — recorded so it is not re-derived <sub>L18292</sub>
- **§192** — THE PRE-GATE LADDER WAS MAIN-ONLY, AND NOBODY COULD SEE IT (P31 S54) <sub>L18314</sub>
- **Three** — defects in one call path; the overlay slates that carry most of the wave work were being waved through <sub>L18315</sub>
+17 -17
View File
@@ -1,6 +1,6 @@
# P30 S49 — cousin-unit survey (similarity tier over the open frontier)
> Generated by `tools/family_cousins.py` at HEAD `commit:2416` from `.run/family_hseq.json` + the binary sigs (R32-checked against an independent stub recount — a stale map fails loud). Compare digests only at the same HEAD.
> Generated by `tools/family_cousins.py` at HEAD `commit:2454` from `.run/family_hseq.json` + the binary sigs (R32-checked against an independent stub recount — a stale map fails loud). Compare digests only at the same HEAD.
>
> **A unit is a CANDIDATE grouping** — same-source cousins split by skeleton drift (insertion/deletion; the li-expansion class). Cousins need a per-member seeded CRACK, never a `family_sweep` remap. The whole-binary byte-gate stays the sole arbiter.
@@ -8,11 +8,11 @@
| category | units | open fns | open ins | lever |
|---|--:|--:|--:|---|
| A-prop | 395 | 2002 | 87143 | family_sweep (propagation) |
| seeded | 339 | 849 | 30050 | seeded crack — edit a >=0.85-similar MATCHED body |
| cousin-multi | 1349 | 4531 | 208991 | 1 crack seeds the unit's other members |
| cold | 3168 | 3168 | 211433 | full-price crack (the honest unique tail) |
| **total** | **5251** | **10550** | **537617** | |
| A-prop | 398 | 2013 | 87978 | family_sweep (propagation) |
| seeded | 339 | 845 | 30326 | seeded crack — edit a >=0.85-similar MATCHED body |
| cousin-multi | 1340 | 4503 | 206207 | 1 crack seeds the unit's other members |
| cold | 3069 | 3069 | 201371 | full-price crack (the honest unique tail) |
| **total** | **5146** | **10430** | **525882** | |
## Top units by open instructions (whole-cluster weight)
@@ -46,15 +46,15 @@
| 26 | cousin-multi | 810 | 10 | 2 | · | · | `ov_SC01_005:0x8017e108` (84 ins ×5) |
| 27 | A-prop | 798 | 3 | 1 | 1.0 | `ov_SC01_000:0x80130d48` | `ov_SC01_077:0x80130d48` (266 ins ×3) |
| 28 | cousin-multi | 784 | 4 | 1 | · | · | `ov_SC03_108:0x8017ffd0` (196 ins ×4 jr) |
| 29 | cousin-multi | 767 | 15 | 7 | 0.776 | · | `ov_SC03_028:0x8018966c` (63 ins ×4) |
| 29 | cousin-multi | 767 | 15 | 7 | 0.839 | · | `ov_SC03_028:0x8018966c` (63 ins ×4) |
| 30 | seeded | 752 | 14 | 10 | 0.921 | `ov_SC02_027:0x8017f6d4` | `ov_SC02_027:0x8017f858` (48 ins ×3) |
| 31 | cousin-multi | 696 | 10 | 3 | · | · | `ov_SC02_041:0x80181164` (72 ins ×4) |
| 32 | cousin-multi | 680 | 8 | 2 | 0.7 | · | `md_SC03_077:0x801efb58` (87 ins ×4 jr) |
| 33 | seeded | 673 | 6 | 4 | 0.921 | `ov_SC02_011:0x80185c7c` | `ov_SC03_118:0x80181e58` (113 ins ×2) |
| 34 | cousin-multi | 668 | 3 | 3 | · | · | `ov_SC02_017:0x80186770` (230 ins ×1) |
| 35 | cousin-multi | 658 | 14 | 5 | · | · | `ov_SC04_018:0x80181124` (52 ins ×4) |
| 36 | cold | 657 | 1 | 1 | · | · | `md_MAIN_003:0x800d12d0` (657 ins ×1) |
| 37 | A-prop | 656 | 29 | 10 | 1.0 | `ov_SC03_001:0x8017f0ec` | `ov_SC03_001:0x8017f0ec` (20 ins ×13) |
| 38 | A-prop | 655 | 16 | 6 | 1.0 | `ov_SC02_005:0x8017df78` | `ov_SC02_005:0x8017df78` (39 ins ×10) |
| 39 | cousin-multi | 648 | 6 | 1 | · | · | `ov_SC06_011:0x8017eeec` (108 ins ×6 jr) |
| 40 | A-prop | 647 | 16 | 6 | 1.0 | `ov_SC01_074:0x8017dba0` | `ov_SC01_077:0x8017d840` (39 ins ×9) |
| 31 | cousin-multi | 680 | 8 | 2 | 0.7 | · | `md_SC03_077:0x801efb58` (87 ins ×4 jr) |
| 32 | seeded | 673 | 6 | 4 | 0.921 | `ov_SC02_011:0x80185c7c` | `ov_SC03_118:0x80181e58` (113 ins ×2) |
| 33 | cousin-multi | 668 | 3 | 3 | · | · | `ov_SC02_017:0x80186770` (230 ins ×1) |
| 34 | cousin-multi | 658 | 14 | 5 | · | · | `ov_SC04_018:0x80181124` (52 ins ×4) |
| 35 | cold | 657 | 1 | 1 | · | · | `md_MAIN_003:0x800d12d0` (657 ins ×1) |
| 36 | A-prop | 656 | 29 | 10 | 1.0 | `ov_SC03_001:0x8017f0ec` | `ov_SC03_001:0x8017f0ec` (20 ins ×13) |
| 37 | A-prop | 655 | 16 | 6 | 1.0 | `ov_SC02_005:0x8017df78` | `ov_SC02_005:0x8017df78` (39 ins ×10) |
| 38 | cousin-multi | 648 | 6 | 1 | · | · | `ov_SC06_011:0x8017eeec` (108 ins ×6 jr) |
| 39 | A-prop | 647 | 16 | 6 | 1.0 | `ov_SC01_074:0x8017dba0` | `ov_SC01_077:0x8017d840` (39 ins ×9) |
| 40 | A-prop | 642 | 16 | 5 | 1.0 | `ov_SC01_000:0x8017d024` | `ov_SC01_000:0x8017d024` (38 ins ×8) |
+4 -4
View File
@@ -5,13 +5,13 @@
> Generated by `tools/family_hseq.py` from the 212 binary sigs + per-binary src stubs. Ranked by TEMPLATABLE byte-weight (PURE+IMM members × nins × 4). The byte-gate is the arbiter.
>
> **Scope (212 binaries): 141 location overlays + 70 md_* modules + the resident · MAIN IS EXCLUDED** · generated at HEAD `commit:2416` · stub set derived from `corpus.stubs` — the same oracle `progress.py` counts, so same-tree overlay totals agree by construction; compare digests only at the same HEAD.
> **Scope (212 binaries): 141 location overlays + 70 md_* modules + the resident · MAIN IS EXCLUDED** · generated at HEAD `commit:2454` · stub set derived from `corpus.stubs` — the same oracle `progress.py` counts, so same-tree overlay totals agree by construction; compare digests only at the same HEAD.
**Fleet (overlays):** 97.1% fn / 96.0% instr / 91.6% distinct-code matched. Unmatched: 10,550 instances / 537,617 ins (9,165 distinct classes).
**Fleet (overlays):** 97.1% fn / 96.1% instr / 91.8% distinct-code matched. Unmatched: 10,430 instances / 525,882 ins (9,045 distinct classes).
**Tail cross-check (Phase-25 close):** 7,036 tail fns / 359,343 ins → 403 h_seq families ≥2, **69 substantial (nins≥80) / 30,270 ins**.
**Tail cross-check (Phase-25 close):** 6,922 tail fns / 348,199 ins → 403 h_seq families ≥2, **69 substantial (nins≥80) / 30,270 ins**.
**Full frontier (all unmatched by h_seq):** 1917 target families (≥2 members or a matched sibling) + 4378 singletons (Step-D residue). Substantial: **252 families / 88,123 templatable ins**, 68 with a matched sibling (zero-crack). Substantial member classes: 614 PURE · 21 IMM · 6 STRUCT-excluded.
**Full frontier (all unmatched by h_seq):** 1917 target families (≥2 members or a matched sibling) + 4262 singletons (Step-D residue). Substantial: **252 families / 87,970 templatable ins**, 69 with a matched sibling (zero-crack). Substantial member classes: 613 PURE · 21 IMM · 6 STRUCT-excluded.
## Top substantial families (by templatable byte-weight)
+22 -22
View File
@@ -1,44 +1,44 @@
# The Frontier Atlas (P31 T5)
> Generated at HEAD `commit:2416` by `tools/atlas.py` — REGENERATE, never edit. Groups are ADVISORY (the byte-gate is the arbiter). Calibration: warm merge at norm-ratio ≥ 0.7, kNN floor 0.55.
> Generated at HEAD `commit:2454` by `tools/atlas.py` — REGENERATE, never edit. Groups are ADVISORY (the byte-gate is the arbiter). Calibration: warm merge at norm-ratio ≥ 0.7, kNN floor 0.55.
**Scope:** 11352 open instances / 6911 skeletons across 213 binaries (main: 802 — atlas-layer join (family maps stay non-main)).
**Tiers:** T1.5 h_seqn merges 2 · warm merges 880 (from 19345 ratio calls) · seed sweep: 4714 skeletons carry a ≥0.55 seed from the 3078-skeleton matched pool.
**Scope:** 11183 open instances / 6747 skeletons across 213 binaries (main: 753 — atlas-layer join (family maps stay non-main)).
**Tiers:** T1.5 h_seqn merges 2 · warm merges 876 (from 18404 ratio calls) · seed sweep: 4686 skeletons carry a ≥0.55 seed from the 3197-skeleton matched pool.
## Groups by category
| cat | groups | instances | ins |
|---|--:|--:|--:|
| A-prop | 394 | 2034 | 87416 |
| cold | 2244 | 2244 | 181913 |
| cousin-multi | 1551 | 5700 | 247842 |
| main-only | 358 | 358 | 31486 |
| seeded | 339 | 851 | 30074 |
| tiny | 99 | 165 | 840 |
| A-prop | 397 | 2045 | 88251 |
| cold | 2149 | 2149 | 172422 |
| cousin-multi | 1539 | 5664 | 244413 |
| main-only | 315 | 315 | 27653 |
| seeded | 339 | 847 | 30350 |
| tiny | 97 | 163 | 827 |
## Groups by lever (confidence)
| lever | groups | instances | ins |
|---|--:|--:|--:|
| head-crack[default] | 1085 | 3492 | 147552 |
| UNKNOWN[none] | 1882 | 1882 | 130091 |
| head-crack[default] | 1074 | 3458 | 144362 |
| UNKNOWN[none] | 1738 | 1738 | 116262 |
| extend-tell[tell] | 579 | 1035 | 77588 |
| jtbl-carve[tell] | 190 | 281 | 45673 |
| redraft[measured] | 268 | 1046 | 44562 |
| family-sweep[default] | 201 | 830 | 28324 |
| integration[measured] | 47 | 492 | 21675 |
| seeded-crack[default] | 257 | 572 | 17235 |
| redraft[measured] | 260 | 1037 | 43554 |
| family-sweep[default] | 204 | 841 | 29159 |
| integration[measured] | 47 | 494 | 21707 |
| seeded-crack[default] | 257 | 568 | 17511 |
| len-vein[measured] | 148 | 666 | 14310 |
| plumbing[ledger] | 43 | 196 | 9956 |
| plumbing[ledger] | 55 | 211 | 11228 |
| swaprepeat-tell[tell] | 70 | 119 | 9316 |
| o0-lane[tell] | 31 | 69 | 6564 |
| cc1[measured] | 12 | 104 | 6382 |
| needs-autopsy[measured] | 52 | 265 | 5110 |
| cc1[ledger] | 13 | 63 | 4506 |
| needs-autopsy[measured] | 52 | 263 | 5090 |
| cc1[ledger] | 17 | 67 | 4845 |
| frame-172[measured] | 8 | 32 | 4078 |
| needs-autopsy[ledger] | 9 | 33 | 3914 |
| near-crack[measured] | 11 | 62 | 1765 |
| tiny-direct[default] | 74 | 106 | 536 |
| near-crack[measured] | 8 | 56 | 1416 |
| tiny-direct[default] | 72 | 104 | 523 |
| s16-div-tell[tell] | 4 | 6 | 419 |
| signload[measured] | 1 | 1 | 15 |
@@ -46,7 +46,7 @@
| gid | cat | lever | inst | ins | exemplar | seed |
|---|---|---|--:|--:|---|---|
| 57f9bec16c2a | cousin-multi | integration[measured] | 254 | 5864 | ov_SC01_084:func_80180CBC (31) | 0.72 |
| 9607a77b73fe | cousin-multi | integration[measured] | 256 | 5896 | ov_SC01_084:func_80180CBC (31) | 0.72 |
| e8bf2260391b | cousin-multi | frame-172[measured] | 16 | 3936 | ov_SC01_077:func_8017C294 (246) | |
| 14bc91cb76b0 | cousin-multi | redraft[measured] | 112 | 2879 | main:func_8001FB8C (31) | 0.72 |
| 4a254010e122 | A-prop | needs-autopsy[ledger] | 4 | 2444 | ov_SC03_001:func_801898E4 (611) | 1.00 |
@@ -82,7 +82,7 @@
| 78627a0eec5d | cousin-multi | redraft[measured] | 10 | 810 | ov_SC01_004:func_8017D964 (84) | 0.62 |
| b1509c2e091c | A-prop | integration[measured] | 3 | 798 | ov_MAIN_012:func_80130D48 (266) | 1.00 |
| 97e813dd2393 | cousin-multi | integration[measured] | 4 | 784 | ov_SC03_108:func_8017FFD0 (196) | 0.65 |
| dcc70a8601c4 | cousin-multi | head-crack[default] | 15 | 767 | ov_SC03_028:func_8018966C (63) | 0.67 |
| dcc70a8601c4 | cousin-multi | head-crack[default] | 15 | 767 | ov_SC03_028:func_8018966C (63) | 0.74 |
| 334bc03beb1f | cousin-multi | integration[measured] | 68 | 760 | md_SC07_003:func_801A38A8 (15) | 0.90 |
| ab1569f4386c | seeded | redraft[measured] | 14 | 752 | ov_SC03_096:func_8017D130 (66) | 0.83 |
| 101b914c4520 | cousin-multi | extend-tell[tell] | 22 | 721 | ov_SC03_092:func_8017E6A0 (45) | 0.75 |
+65
View File
@@ -18308,3 +18308,68 @@ banked).
artifacts. Every confirmed entry above changed shape under verification — bounds added, a mechanism
re-attributed, a sub-claim refuted — and the ones that did not survive were rejected for exactly the
reasons §179 predicted: not banked, or banked C contradicting the narrative written about it.
---
## §192 — THE PRE-GATE LADDER WAS MAIN-ONLY, AND NOBODY COULD SEE IT (P31 S54)
### Three defects in one call path; the overlay slates that carry most of the wave work were being waved through
**The symptom.** Running `pregate_check.py` on an *overlay* slate printed:
```
slate 7 -> 7 after resolve_conflicts (0 dropped); checking 0 substituted file(s)
clean — no textual defect found; the batch is worth a rebuild
```
Seven byte-perfect drafts, a green light, and **zero files examined**. Every wave since O has been
overlay work; the check that §181 credits with catching 4 of the 5 rejection classes has never once
run on any of it.
**DEFECT 1 — `gate_main.resolve_conflicts` and `gate_main.substitute` both hardcoded
`corpus.stubs('main')`.** A non-main entry resolved to no stub, so `resolve_conflicts` compared it
against a `'<unknown>'` pseudo-file (never clashing with anything) and `substitute` dropped it on the
floor without a word. This is the R36 citizenship class again — a consumer structurally blind to a
real binary — and the slate shape already carried the answer (`gate_lane` records have a `binary`
field). Fixed with a memoized `_stubs_for(binary)`; absent, the key defaults to `main`, so every
historical main slate behaves byte-identically.
**DEFECT 2 — `sym_of` returned a KEYWORD for any pointer-to-function declaration.** The regex took
the first identifier followed by `[` or `(`, *by position*, so
```c
extern void (*D_801923D0[])(void *);
```
reported its symbol as `void` — and then every such declaration in the TU "conflicted" with every
other one under that name: **192 phantom CONFLICTING-EXTERN failures on one overlay TU**. Project
symbols are now matched by NAME first, C keywords are excluded from the generic branch, and the
parenthesised declarator `T (*NAME[])(...)` is read explicitly. Negative control across the whole
tree: **5,526,100 declarations, 189,301 changed verdicts, 0 regressions** — every single change is a
keyword becoming the real symbol (`void` → `D_800A4F24`, `s32` → `D_801274D0`), which also means
`gate_main`'s own conflict table has been blind to function-pointer globals in **main** all along.
**DEFECT 3 — `void f()` and `void f(void)` were normalized to the same thing.** C89 6.5.4.3 makes an
*unspecified* parameter list compatible with any prototype (this project leans on it — §37/§124), but
an *explicit* `(void)` against `f(s32)` is a hard error. Collapsing both to `()` cost 40 more phantom
failures against a TU that compiles today. Now: unspecified → a `UNSPEC` wildcard, explicit `(void)` →
`()`, and the comparison is `gate_main.sig_conflict`, not `!=`. Seven synthetic controls, including
both directions of the pair that matters.
**The residue is the point.** After the three fixes the same overlay slate reports **2 failures**, and
both are real: a `D_80195AF6_t` typedef defined twice, and `memcpy` declared `(void*, const void*,
u32)` in the TU against a draft's `(void*, void*, s32)`. Each of those is one lost clean rebuild —
which is the whole reason the ladder exists.
**§192b — A CHECKER THAT CHECKED NOTHING MUST NEVER READ AS A PASS.** Two guards, both earned above:
`pregate_check` now REFUSES (exit 2) when the slate is non-empty and zero files were substituted, and
it prints one `[DROP]` line per draft `resolve_conflicts` rejected — with the clashing symbol, the
side it clashed with, and both signatures. Those drops were already being computed and thrown away, so
a slate that lost **every** draft to declaration conflicts still ended with "clean — the batch is worth
a rebuild". The drop list is not a footnote: it is the §183 playbook's worklist, and it is now the
tool's headline output.
**The generalizable law.** *A tool written against one binary is a tool with an untested hypothesis
about every other one.* The main-vs-overlay split here is exactly the shape of R36's SC07 bug and
R32's `build_engine_types` bug: the code did not fail, it silently narrowed its own domain and then
reported success over the part it kept. When a checker's verdict is "clean", ask what it counted — and
make the tool answer that question in its own output.
+41
View File
@@ -57,6 +57,47 @@ R22 clean-fleet **213/213** after every banked batch · tools-health green · 0
- 2026-08-14 — **T9 COMPLETE.** `tools/warmstart.py` (the permuter/grinder FEEDER): `--from-banked` walks a banked exemplar's h_seq family's still-open members, builds remapped proven-body drafts (`symbol_map` + `aprop_autodraft.build_draft`, refusing on reloc-count mismatch), **stream-classifies member-vs-seed with ZERO compiles** (masked_diff-shaped dicts from ground-truth bytes → `residual_class.classify_streams`), enqueues ONLY permuter-shaped (bucket==permuter or LENGTH-DRIFT |Δ|≤2) as backlog near-records; `--lenmiss` ingests T8's 49-route. **Grinder patch NOT needed** (its candidates() deliberately keeps unclassified records — "unknown is not a reason to skip" — so pre-filtered enqueues flow as-is; documented in the feeder's docstring). Armed live: **49 + 10 enqueued, 120 refused** by the stream filter (the anti-92%-wasted-CPU discipline working). `family_cousins --weak-cards`: **954 units** (the 0.70–0.85 annotate-only band, never before consumed) as seeded-crack cards, ins-ranked, §168 laws embedded, model-routed **haiku 804 / v3 43 / sonnet 86 / opus 21** (cheap tiers dominate — the token-efficiency shape), 0 unresolved `.s`.
## SESSION S54 (2026-08-17, ultracode) — wave T + the pre-gate ladder learns to see overlays
- 2026-08-17 — **Session opened with the §180 leftover sweep, before drafting anything new.**
`scan_leftovers.py` over 644 stored drafts in 5 binaries: **29 byte-perfect, still-stubbed drafts =
2,478 instructions** (main 3/217 · ov_SC04_011 15/1,392 · ov_SC02_005 5/261 · ov_SC06_029 5/521 ·
ov_SC03_028 1/87), plus 39 honest NEAR. Zero agent tokens. `reloc_identity --batch`: **29/29 AGREE**.
`fragment_check`: 1 FAIL — `gfx2D_BG0_OBJ_4D8` owns `.L80050D5C`, which `gfx2D_BG0_OBJ_1B4` branches
into (the §181 mirror class; it is also a `GsSortBg` fragment-merge target, so it routes there).
- 2026-08-17 — **Wave T built and launched (71 cards / 6,557 ins / 5 gate groups / 14.2 drafts per
rebuild), and the selector learned two new principles.** `make atlas` first (it predated 161 banks):
4,836 groups / 11,183 open instances / 563,916 ins. Then two additions to `build_wave_atlas.py`:
* **`--one-per-gid`** — a fleet-wide draw over SIBLING overlays fills half a wave with the SAME
skeleton at two addresses (the naive draw put 22 of 44 groups in twice), paying an agent for work
`family_sweep --hseq` does free behind the banked exemplar. Collapse to one card per atlas group,
defer the siblings to `<out>.siblings.json`, assert reps + siblings == candidates (R32).
* **`--rank total`** — rank gate groups by the mass a card DELIVERS (its own instructions plus its
deferred siblings'), not by face mass. Measured on this draw: face 6,509 ins with 9,985 sibling ins
behind 57 gids under `--rank mass`, versus **6,557 ins with 12,709 sibling ins behind 69 of 71
gids** under `--rank total`. **Wave T's potential is 19,266 instructions for 71 agents.**
R39 negative control: on a pool with unique gids, `--one-per-gid` output is byte-identical.
The wave prompt carries the S53 harvest as laws 8-20 (§183.1/§183.3, §186, §186b, §186c, §189-A..E,
§190-A..C), STEP 0 (the cross-overlay magic-literal grep), a per-card sibling note, and a new
**Reconcile phase**: one agent per gate group runs the deterministic ladder over its own slate and
resolves the refusals with the §183 playbook — reconciliation moved INSIDE the wave (§176h.C2).
- 2026-08-17 — **§192: the pre-gate ladder was main-only and said "clean" about it.** Running
`pregate_check` on an overlay slate printed `checking 0 substituted file(s) ... clean`. Three
defects, all fixed with controls: (1) `resolve_conflicts`/`substitute` hardcoded
`corpus.stubs('main')` → per-binary `_stubs_for()` (main path byte-identical); (2) `sym_of` returned
`void` for every `extern void (*D_x[])(...)` → 192 phantom CONFLICTING-EXTERNs; project symbols now
matched by name, keywords excluded, declarator read explicitly — **NC over 5,526,100 declarations:
189,301 changed verdicts, 0 regressions**; (3) `void f()` vs `void f(void)` were collapsed together →
40 more phantoms; C89's unspecified-parameter rule is now `gate_main.sig_conflict` (7 synthetic
controls). Same slate now reports **2 failures, both real**. Plus **§192b**: the tool REFUSES when it
substituted 0 files, and prints one `[DROP]` line per rejected draft — the drop reasons were being
computed and discarded while the tool printed "worth a rebuild".
- 2026-08-17 — **Leftover-recovery lane launched** (5 agents, one per binary): each gets its slate, its
TU, and the deterministic `[DROP]`/refusal evidence, and applies the §183 playbook draft-side only.
## SESSION S53 (2026-08-16, ultracode) — wave R + the leftover-draft harvest
- 2026-08-16 — **S53-1 PREFLIGHT + ATLAS REGEN.** Tree clean at `commit:2416`, no gate in flight. `make atlas`
+65 -3
View File
@@ -41,7 +41,7 @@ ap.add_argument('--exclude-bins', default='',
'INCREMENTALLY, because its extract runs psyq_integrate/ld_interleave and '
'rewrites the .ld. Draft main like any binary; gate it with '
'tools/gate_main.py, never gate_lane/gate_stage.)')
ap.add_argument('--rank', choices=('groups','mass'), default='groups',
ap.add_argument('--rank', choices=('groups','mass','total'), default='groups',
help="'groups' (default) ranks gate groups by MEMBER COUNT -- right for overlays, "
"where every (binary,TU) group costs its own rebuild. 'mass' ranks purely by "
"instruction size across all groups -- right for MAIN, whose gate cost is per "
@@ -58,6 +58,17 @@ ap.add_argument('--only-bins', default='',
help='comma-separated allow-list; if set, ONLY these binaries are eligible. '
'Use --only-bins main for a main wave: gate_main.py rebuilds the whole EXE '
'once per SLATE, so main has no per-TU gate cost and --max-bins can be large.')
ap.add_argument('--one-per-gid', action='store_true',
help="draft ONE card per atlas group and defer its same-gid siblings to "
"<out>.siblings.json for the post-bank mechanical remap "
"(make sig-overlays -> family_hseq.py -> family_sweep --hseq --only). "
"Rationale (P31 S54): a fleet-wide draw over SIBLING overlays (ov_SC04_002 vs "
"ov_SC04_005) fills half the wave with the SAME skeleton at two addresses -- "
"paying an agent twice for work the deterministic remap does for free. The "
"representative is the sibling in the heaviest gate group (then largest nins, "
"then lexical fn) so concentration is unharmed. Every deferred sibling is "
"written to the companion file and accounted (R32): representatives + "
"siblings == candidates, asserted.")
a = ap.parse_args()
EXCLUDE = {b for b in a.exclude_bins.split(',') if b}
ONLY = {b for b in a.only_bins.split(',') if b}
@@ -132,13 +143,51 @@ for g in atlas['groups']:
'seed_sim': seed.get('sim'),
})
# principle 4 (P31 S54): ONE CARD PER ATLAS GROUP. Same-gid members are the SAME skeleton in
# different overlays; the deterministic remap (family_sweep --hseq) banks the siblings behind a
# banked exemplar for zero tokens, so drafting both is paying twice. Collapse here, BEFORE the
# gate-group ranking, so the ranking sees distinct work; defer the rest to <out>.siblings.json.
siblings = collections.defaultdict(list)
if a.one_per_gid:
_mass = collections.Counter()
for c in cands:
_mass[(c['binary'], c['tu'])] += c['nins']
keep = {}
for c in cands:
cur = keep.get(c['gid'])
rank = (_mass[(c['binary'], c['tu'])], c['nins'], c['fn'])
if cur is None or rank > cur[0]:
if cur is not None:
siblings[c['gid']].append(cur[1])
keep[c['gid']] = (rank, c)
else:
siblings[c['gid']].append(c)
reps = [v[1] for v in keep.values()]
n_sib = sum(len(v) for v in siblings.values())
assert len(reps) + n_sib == len(cands), \
f"coverage (R32): {len(reps)} reps + {n_sib} siblings != {len(cands)} candidates"
print(f"--one-per-gid: {len(cands)} candidates -> {len(reps)} groups "
f"({n_sib} same-gid siblings deferred to the mechanical remap)")
cands = reps
# principle 1: CONCENTRATE ON GATE GROUPS. gate_lane groups by (binary, home .c) and each group
# is one whole-binary rebuild, so drafts-per-GROUP is the throughput number that matters -- not
# drafts per binary. Wave D was 42 drafts over 23 groups (1.8/group, ~40 min of gate).
by_tu = collections.defaultdict(list)
for c in cands:
by_tu[(c['binary'], c['tu'])].append(c)
if a.rank == 'mass':
if a.rank == 'total':
# P31 S54: rank by the mass a card actually DELIVERS -- its own instructions plus the same-gid
# siblings the post-bank remap banks for free. Measured on the wave-T draw: the 70 selected
# cards carried 9,985 sibling instructions, 1.5x the wave's own 6,509, and that leverage is
# very unevenly spread across gate groups (some carry 3 siblings per card, some carry none).
# Ranking by face mass is therefore ranking by the smaller half of the number.
if not a.one_per_gid:
sys.exit("--rank total requires --one-per-gid (there are no deferred siblings otherwise)")
_sibins = {g: sum(c['nins'] for c in v) for g, v in siblings.items()}
ranked = sorted(by_tu, key=lambda k: -sum(c['nins'] + _sibins.get(c['gid'], 0)
for c in by_tu[k]))[:a.max_bins]
elif a.rank == 'mass':
ranked = sorted(by_tu, key=lambda k: -sum(c['nins'] for c in by_tu[k]))[:a.max_bins]
else:
ranked = sorted(by_tu, key=lambda k: -len(by_tu[k]))[:a.max_bins]
@@ -153,8 +202,10 @@ def _full():
if a.target_ins:
return tot_ins >= a.target_ins or len(wave) >= a.n
return len(wave) >= a.n
_deliver = (lambda c: c['nins'] + sum(s['nins'] for s in siblings.get(c['gid'], ()))) \
if a.rank == 'total' else (lambda c: c['nins'])
for k in ranked: # principle 2: within a group, mass first
for c in sorted(by_tu[k], key=lambda c: -c['nins']):
for c in sorted(by_tu[k], key=lambda c: -_deliver(c)):
if _full(): break
wave.append(c); tot_ins += c['nins']
if _full(): break
@@ -163,6 +214,17 @@ if a.target_ins and tot_ins < a.target_ins:
f"widen --min-ins/--max-ins/--levers or raise n ({len(wave)} of max {a.n} cards used)")
json.dump(wave, open(a.out, 'w'), indent=1)
if a.one_per_gid:
# Only the siblings of gids that ACTUALLY made the wave are actionable this session; the rest
# stay in the atlas for a later draw. Both counts are printed so nothing is silently dropped.
in_wave = {c['gid'] for c in wave}
sib_out = {g: v for g, v in siblings.items() if g in in_wave}
sib_path = a.out.replace('.json', '') + '.siblings.json'
json.dump(sib_out, open(sib_path, 'w'), indent=1)
n_act = sum(len(v) for v in sib_out.values())
print(f"-> {n_act} siblings ({sum(c['nins'] for v in sib_out.values() for c in v)} ins) behind "
f"{len(sib_out)} of this wave's gids -> {sib_path} (remap after the bank); "
f"{sum(len(v) for v in siblings.values()) - n_act} more sit behind un-drawn gids")
tot = sum(c['nins'] for c in wave)
print(f"candidates {len(cands)} in {len(by_tu)} gate groups (skipped {dict(skipped)})")
ngroups = len({(c['binary'], c['tu']) for c in wave})
+93 -7
View File
@@ -53,9 +53,28 @@ TYPES = {'void','char','short','int','long','unsigned','signed','float','double'
DECL = re.compile(r'^\s*extern\s+([^;]+?)\s*;[ \t]*(?://[^\n]*|/\*(?:[^*]|\*(?!/))*\*/[ \t]*)?$',
re.M)
# A DECLARATOR KEYWORD IS NEVER THE SYMBOL (P31 S54). The old single regex took the FIRST
# identifier followed by '[' or '(', wherever it sat -- so a pointer-to-function declaration,
# extern void (*D_801923D0[])(void *);
# reported its symbol as `void`, because `void (` matches first by POSITION. Every such
# declaration in a TU then "collided" with every other one under the name `void`: 192 phantom
# CONFLICTING-EXTERN failures on one overlay TU the first time pregate_check could see overlays.
# Project symbols are matched by NAME first, keywords are excluded from the generic branch, and
# the parenthesised declarator is read explicitly.
_NOT_A_SYMBOL = {
'void', 'char', 'short', 'int', 'long', 'float', 'double', 'signed', 'unsigned',
'const', 'volatile', 'struct', 'union', 'enum', 'static', 'extern', 'register', 'typedef',
's8', 'u8', 's16', 'u16', 's32', 'u32', 's64', 'u64', 'f32', 'f64',
}
def sym_of(d):
m = re.search(r'\b(D_[0-9A-Fa-f]{8}|func_[0-9A-Fa-f]{8}|[A-Za-z_]\w*)\s*(?:\[|\()', d)
m = re.search(r'\b(D_[0-9A-Fa-f]{8}|func_[0-9A-Fa-f]{8})\s*(?:\[|\()', d)
if m: return m.group(1)
m = re.search(r'\b([A-Za-z_]\w*)\s*(?:\[|\()', d)
if m and m.group(1) not in _NOT_A_SYMBOL: return m.group(1)
m = re.search(r'\(\s*\*+\s*([A-Za-z_]\w*)', d) # T (*NAME)(...) / T (*NAME[])(...)
if m and m.group(1) not in _NOT_A_SYMBOL: return m.group(1)
m = re.search(r'\b(D_[0-9A-Fa-f]{8}|func_[0-9A-Fa-f]{8})\b', d)
return m.group(1) if m else None
@@ -110,6 +129,43 @@ def typesig(d):
for p in m.group(1).split(','))
return (ret, params)
UNSPEC = '?' # an UNSPECIFIED parameter list -- `void f();`, not `void f(void);`
def norm_sig(sig):
"""Normalize a `typesig` for COMPATIBILITY comparison, keeping the one distinction C89 makes.
`extern void f();` declares an UNSPECIFIED parameter list, and C89 6.5.4.3 forms a composite
type with any prototype whose parameters survive the default promotions -- gcc-2.7.2 accepts
the pair, and this project's TUs are full of it (§37/§124, the no-prototype escape). But
`extern void f(void);` declares EXACTLY ZERO parameters, and that against `f(s32)` is a hard
error. Collapsing both to () -- as pregate_check did until P31 S54 -- makes the tool report 40
phantom failures on one overlay TU that compiles today, while still missing nothing.
So: unspecified -> UNSPEC (a wildcard for `sig_conflict`), explicit (void) -> ()."""
ret, params = sig
if isinstance(params, tuple):
if params in ((), ('',)):
params = UNSPEC
elif params == ('void',):
params = ()
return (ret, params)
def sig_conflict(a, b):
"""True when two normalized signatures cannot both describe one symbol.
Return types must agree (S53: even G3P* vs G4P* was rejected by gcc). Parameter lists conflict
only when BOTH are specified and differ."""
a, b = norm_sig(a), norm_sig(b)
if a[0] != b[0]:
return True
pa, pb = a[1], b[1]
if pa == UNSPEC or pb == UNSPEC:
return False
return pa != pb
def run(cmd, **kw):
return subprocess.run(cmd, shell=True, capture_output=True, text=True, **kw)
@@ -117,6 +173,28 @@ def sha():
r = run("sha1sum build/us/SLUS_007.26")
return r.stdout.split()[0] if r.returncode == 0 and r.stdout else None
_STUBS_BY_BIN = {}
def _stubs_for(binary):
"""symbol -> Stub for ONE binary, memoized.
WHY THIS EXISTS (P31 S54, R36/R33). `resolve_conflicts` and `substitute` both hardcoded
`corpus.stubs('main')`, so every non-main entry resolved to no stub: `resolve_conflicts` compared
it against the '<unknown>' pseudo-file and `substitute` skipped it silently. The visible symptom
was `pregate_check` printing "checking 0 substituted file(s) ... clean" for an OVERLAY slate --
a green light from a checker that had examined nothing, which is the exact R32 defect class this
project keeps re-finding. Overlay slates are the majority of wave work (every wave since O), and
4 of the 5 rejection classes measured in §181 are precisely what these two functions detect.
The slate shape already carries the answer: gate_lane's records have a 'binary' field. Absent
(every historical main slate), it defaults to 'main', so the main path is byte-identical."""
b = binary or 'main'
if b not in _STUBS_BY_BIN:
_STUBS_BY_BIN[b] = {st.symbol: st for st in corpus.stubs(b).values()}
return _STUBS_BY_BIN[b]
def resolve_conflicts(slate):
"""Drop drafts whose externs contradict (a) the destination TU's OWN existing declarations,
or (b) an earlier draft landing in the SAME file.
@@ -137,7 +215,6 @@ def resolve_conflicts(slate):
and cast at the use site -- including through a function pointer when the TU's prototype takes
no argument and your call passes one: ((void (*)(s32))func_8001C9D0)(a0) (byte-identical;
verified on all 3 of the above)."""
stubs = {st.symbol: st for st in corpus.stubs('main').values()}
kept, dropped = [], []
seen_by_file, from_tu = {}, {}
@@ -155,7 +232,7 @@ def resolve_conflicts(slate):
return seen_by_file[path]
for e in slate:
st = stubs.get(e['fn'])
st = _stubs_for(e.get('binary')).get(e['fn'])
path = st.path if st else '<unknown>'
seen = table(path)
body = open(e['draft']).read()
@@ -169,7 +246,7 @@ def resolve_conflicts(slate):
body, re.M)
if dm:
ds.append((e['fn'], typesig('%s %s(%s)' % (dm.group(1).strip(), e['fn'], dm.group(2)))))
clash = [(s, seen[s], t) for s, t in ds if s in seen and seen[s] != t]
clash = [(s, seen[s], t) for s, t in ds if s in seen and sig_conflict(seen[s], t)]
if clash:
sym = clash[0][0]
dropped.append({'fn': e['fn'], 'symbol': sym, 'file': path,
@@ -328,12 +405,21 @@ def substitute(entries, write=True):
write=False produces the substituted text WITHOUT touching the tree, which is what
tools/pregate_check.py needs: every batch failure this project has hit is a textual property
of the file that will be compiled, so it can be checked in ~2s instead of a 5-minute rebuild.
Returns (count, {path: text})."""
stubs = {st.symbol: st for st in corpus.stubs('main').values()}
Returns (count, {path: text}).
Per-binary since P31 S54 (see `_stubs_for`): an entry's own 'binary' selects its stub map, and
an entry whose symbol is in NO stub map is reported loudly instead of being dropped on the floor
(R32 -- a silent skip here is what made pregate_check green on overlay slates)."""
byfile = collections.defaultdict(list)
unresolved = []
for e in entries:
st = stubs.get(e['fn'])
st = _stubs_for(e.get('binary')).get(e['fn'])
if st: byfile[st.path].append((st.addr, e['fn'], st.asm_dir, e['draft']))
else: unresolved.append((e.get('binary') or 'main', e['fn']))
if unresolved:
print(" substitute: %d entr%s resolved to NO stub (not open in that binary?): %s"
% (len(unresolved), 'y' if len(unresolved) == 1 else 'ies',
', '.join('%s:%s' % u for u in unresolved[:8])))
n, texts = 0, {}
for path, items in byfile.items():
t = open(path).read()
+33 -11
View File
@@ -68,13 +68,15 @@ STRUCT_EXTERN = re.compile(
def _norm_sig(sig):
"""`void f()` and `void f(void)` are not a conflict worth blocking a rebuild over: C89 calls
the first an unspecified parameter list, and gcc-2.7.2 accepts the pair. Normalize both to
(). Signedness, pointer depth and array-vs-scalar are left alone -- those are real."""
ret, params = sig
if isinstance(params, tuple) and params in ((), ('',), ('void',)):
params = ()
return (ret, params)
"""Delegates to the single normalization oracle in gate_main (R33).
It used to collapse `void f()` AND `void f(void)` to the same (), which is right about the
first (C89's unspecified parameter list, compatible with any prototype) and wrong about the
second (exactly zero parameters, incompatible with `f(s32)`). Since this tool could only ever
see main's TUs, the difference never showed; the first overlay slate it ran on produced 40
phantom CONFLICTING-EXTERN failures against a file that compiles today. Use `gm.sig_conflict`
for comparisons -- `!=` on these tuples is not the compatibility relation."""
return gm.norm_sig(sig)
def _typedefs(text):
@@ -180,7 +182,7 @@ def check_text(path, text):
if not s:
continue
sig = _norm_sig(gm.typesig(d))
if s in decls and decls[s][1] != sig:
if s in decls and gm.sig_conflict(decls[s][1], sig):
findings.append(('FAIL', 'CONFLICTING-EXTERN',
f'{path}: `{s}` declared {decls[s][1]} at offset {decls[s][0]} and '
f'{sig} at offset {m.start()}'))
@@ -190,7 +192,7 @@ def check_text(path, text):
# 5. definition vs a visible prototype
for name, (off, sig) in _func_defs(masked).items(): # masked, not raw — see the note above
sig = _norm_sig(sig)
if name in decls and decls[name][1] != sig:
if name in decls and gm.sig_conflict(decls[name][1], sig):
# SEVERITY CALIBRATED AGAINST THE COMPILER, not against C89 pedantry. Measured on the
# wave-P slate that built BYTE-IDENTICAL: gcc-2.7.2 accepted `void f(void*,s32)` vs a
# `void f(s8*,s32)` definition, and even `G3P *f(...)` vs `G4P *f(...)`. What it
@@ -222,6 +224,16 @@ def main():
kept, dropped = gm.resolve_conflicts(slate)
_n, texts = gm.substitute(kept, write=False)
# R32 COVERAGE ASSERTION (P31 S54). Until `gate_main` learned per-binary stub maps, an OVERLAY
# slate resolved to zero stubs and this tool printed "checking 0 substituted file(s) ... clean"
# -- a green light from a checker that had examined nothing, on exactly the slates (overlay
# waves) that carry most of the work. A checker that checked nothing must never read as a pass.
if kept and not texts:
print(f'REFUSING: {len(kept)} kept draft(s) but 0 substituted files — every entry resolved '
f'to no stub. Does each slate record carry its "binary"? Is the binary extracted '
f'(make extract BINARY=...)? This is not a clean result.')
sys.exit(2)
findings = []
for path, text in sorted(texts.items()):
findings += check_text(path, text)
@@ -230,15 +242,25 @@ def main():
if not a.quiet:
print(f'slate {len(slate)} -> {len(kept)} after resolve_conflicts '
f'({len(dropped)} dropped); checking {len(texts)} substituted file(s)')
# A DROP IS THE HEADLINE, NOT A FOOTNOTE (P31 S54). The drop reasons were computed and
# thrown away, so a slate that lost EVERY draft to declaration conflicts still printed
# "clean — the batch is worth a rebuild". They are the §183 playbook's actual worklist.
for d in dropped:
print(f' [DROP] {d["fn"]}: `{d["symbol"]}` clashes with {d["against"]} in '
f'{d["file"]} — kept {d["kept"]} vs this {d["this"]}')
for sev, code, msg in findings:
print(f' [{sev}] {code}: {msg}')
if not findings:
if not findings and not dropped:
print(' clean — no textual defect found; the batch is worth a rebuild')
elif not findings:
print(f' no textual defect in what SURVIVED, but {len(dropped)} draft(s) were dropped '
f'above — reconcile those before gating (they are unbanked work, not noise)')
elif not fails:
print(f' {len(findings)} warning(s), no hard failure — worth a rebuild')
else:
print(f'\n{len(fails)} FAILURE(S) — fix these BEFORE spending a clean rebuild.')
sys.exit(1 if fails else 0)
# exit 1 also when the slate was emptied: 0 kept is not a pass, it is total refusal.
sys.exit(1 if (fails or (slate and not kept)) else 0)
if __name__ == '__main__':