Commit Graph

204 Commits

Author SHA1 Message Date
Drew T eb2e72328b fix(phase-30 T6): byte-neutral decl conforms unblock the SC07 EXTEND lane
The dedup_extend SC07 lane banked 0/36. Captured every failure's own compiler
error rather than guessing: 5 PLUMBING (declaration conflicts) + 4 DIFF per
binary, and the PLUMBING set reduces to 4 distinct symbols repeated across all
four binaries.

Fixed at the lowest available blast radius, each byte-neutral BY CONSTRUCTION
and proven by R22:

- func_80146C3C (8 of 36): T2, but 1 token. DEFINE_func_8016A08C /
  DEFINE_func_8016A1CC declared it `(void)` while the SC07 TUs declare
  `(u8 *a0)`. Both macros already CAST at the call site, so the prototype is
  codegen-irrelevant -> relax to `()` (no-prototype). Measured first: all 4,020
  fleet decls are (void)/()/(u8*)/(u8 *a0) — no default-promotion param
  anywhere, so `()` is compatible with every one of them (the gcc-2.7.2 `()`
  dead-end needs a promoting param; there is none).
- func_8014F4C0 (4 of 36, self-axis), D_80126CC4 (3), func_8012E5CC (1): T1
  binary-local. Conformed the SC07 decls to the fleet-canonical form. Every one
  has ZERO uncast uses in its TU (verified per file), so the decls were pure
  splat boilerplate with no codegen effect.

Deliberately NOT touched: engine_core.h beyond those 2 lines. The §29 law is
about BULK header edits (the 2,046-file sed that still didn't build); 2 targeted
macro lines with a measured compatibility argument is not that.

R22 clean-fleet: make clean && extract-all && check-all -> 140 passed, 0 failed
of 140. Enabling change only; no function banked in this commit.

Method note (mine, recorded): I read `corpus.stubs` while `make extract-all` was
mid-flight and got garbage — R32's coverage assertion refused to answer instead
of returning a wrong stub set. A measurement taken during a rebuild is not a
measurement (S27's law, re-earned). Also: `nohup CMD &` inside a backgrounded
Bash call makes the harness signal completion of the WRAPPER, not the campaign —
the R22 "finished" at 63/140. Waited on `pgrep -x make` instead.
2026-08-03 22:49:58 -06:00
Drew T 6dab5a446b feat(phase-30 UC): func_80159A20 + func_80139BE0 banked via gate_stage ladder (13,386 ins) 2026-08-01 10:37:24 -06:00
Drew T 3b3accd5a2 feat(phase-30 UC): func_80163764 banked via targeted decl reconcile (compiler-named edits only) 2026-08-01 10:35:22 -06:00
Drew T b5362c7b7f feat(phase-30): the -O0 cluster HARVEST — 1,364 banks for ZERO agent tokens; fleet 92.71->93.09% fn / 88.3->88.6% instr / 78.7->79.3% distinct
The payoff of routing the cluster to -O0 (commit:1270). These functions were ALREADY
CRACKED in ov_SC01_077 and could not be banked anywhere else purely because every
destination file compiled -O2. With the destinations now -O0, they template in
deterministically -- no drafting, no agents.

  dedup_propagate --recover  0x8013C360 (h_exact x138)  -> 137 overlays byte-identical
  family_sweep --hseq        10 variant families         -> 1,227 banked / 133 failed (90%)
                                                            1360 staged across 136 groups
  ------------------------------------------------------------------------------------
  1,364 new banks

FLEET: fn-count 92.71 -> 93.09% · instr 88.3 -> 88.6% · distinct-code 78.7 -> 79.3%
(71,756 / 87,459 unique fns; +1,162 unique). dedup 1904 -> 1905 groups, 0 failed;
C1 coverage 240496/240496. 0 NON_MATCHING in any default build (G4).
R22 CLEAN-FLEET: extract-all 139/139 (+main); check-all 140 passed, 0 failed of 140.

--recover WAS LOAD-BEARING (SS75): without it dedup_propagate took its historical
all-or-nothing branch -- one failing overlay (the SOURCE, ov_SC01_077) dropped the whole
function and it printed "all candidates dropped", which reads exactly like a wall. Reading
the exclusion code instead of believing the message showed the remedy: --recover excludes
only that overlay (kept x1 with its own inline match) and propagates to the other 137.

The two has_mid_jr families in the cluster were REFUSED BY DESIGN, not attempted (SS53
interlock): 0x8013C0F8 (154 ins) and 0x8013C414 (329 ins), ~137 members each = ~466
members queued behind the jtbl carve path they actually need, rather than a fake 0% from
the wrong tool.

REMAINING in the cluster: the 133 sweep failures + the 2 jr families + the 3 addresses
never cracked anywhere (0x8013B83C, 0x8013BD74, 0x8013C08C) -- the last are genuine
drafting work, now finally possible since their TU is -O0.
2026-07-31 11:00:42 -06:00
Drew T 0130fb340a feat(phase-30): wave-4 resumed 10/10 MATCH banked + h_exact leg (14 propagated); R22 140/140
The 12 agents killed by the usage-limit pause were resumed and ALL returned MATCH (2 had already
banked from their partial drafts, so 10 ran). h_exact propagation leg completed over all 112 banked
exemplars: 14 propagated, 42 benign skips (h_seq tier, correctly routed away per §123), 0 failures
— the 0x801466F0 'halt' was a third benign-refusal phrase, not a partial write.

fn-count 92.61 -> 92.67% | instr 88.2 -> 88.3% | distinct 70,581 -> 70,590 unique fns.
2026-07-31 07:25:47 -06:00
Drew T 159317d3fe feat(phase-30): T3 wave-1 — 8 cores banked + 4 propagated fleet-wide; R22 140/140 (fn-count 92.00 -> 92.16%)
Ultracode wave of 14 agents over fresh reach-138 cores: 14/14 match_one MATCH, 8 accepted by the
whole-binary gate (the §52b law reproduced exactly). Propagated per-function (the incident fix):
0x8012E014, 0x80151C54, 0x8012F49C, 0x80151B98 -> +573 instances. R22 clean-fleet 140/140;
instr 87.5 -> 87.7%, fn-count 92.00 -> 92.16%, distinct 69,828 -> 69,836.

The other 4 banked cores are h_seq (PURE/IMM) families: dedup_propagate is h_exact-only, so its
'reach<2' / 'not self-contained' refusals were statements about the TOOL's tier, not the functions
-> cookbook §123 (the §53 carve-law generalized to the propagation-tier axis) + a routing table.
They bank via family_sweep --hseq next.
2026-07-30 19:57:54 -06:00
Drew T ceae8bb4cd feat(phase-29): T97 — func_80151944 138/138; the "three-edit job" was ONE edit
- The last big NAMED blocker, costed across four checkpoints as §112 header + §20 call-site cast +
  a scripted §99 pass over 2,022 overlay-local decls. Probing first showed two of the three were
  unnecessary: the conflict is entirely between DEFINE_func_80151924()'s own forward-decl
  (extern s32 func_80151944(void)) and the byte-true definition (void f(void *a0)), four lines
  apart in the assembled TU. The 2,022 decls live in OTHER TUs and never entered it.
- ONE 4-line edit in engine_core.h: decl -> byte-true, call site -> ((s32 (*)(void))f)() so the
  caller's codegen is unchanged. rtu_match: conflicting types -> MATCH (15 ins). Sweep 138/138.
- Family 0x80131eec fully closed: 149 (T87) + 138 (T97) + 1 immediate-refusal = all 288 members.
- SHARED-HEADER RISK VERIFIED, NOT ARGUED: engine_core.h is included by all 138 overlays, so §20
  cast-folding is a hypothesis. Per-binary gates 138/138 are necessary but not sufficient; the
  fleet check is the one that counts. R22 clean-fleet 140/140 + tools-health RC=0 (corpus 0
  PHANTOM/0 TRUNCATED, cdecl, audit-binaries, dedup 1886/0, C1 239604/239604).
- METRICS: fn-count 91.96 -> 92.00% (+138, exact) · instr 87.4 -> 87.5% (+2,070) · distinct +72.
- COSTING LESSON: the estimate came from reading the symptom (2,022 decls of this name exist)
  instead of probing the failure (which decl actually conflicts). Probe before COSTING, not just
  before scaling.
2026-07-30 13:44:22 -06:00
Drew T 14bc520c96 fix(phase-29): engine_core.h — §99 no-prototype for func_80147364 (sidesteps a 4,021-site conform)
Item 3, and the cheap route won. conform_decls' dry run priced the direct fix and warned it off:

  byte-true def : void func_80147364(u16 param_1, u16 param_2)
  4,021 decl sites: 2,030 (u16,s32) + 1,983 (u16 a0,s32 a1) + 4 byte-true + 4 (u16,u16)
  ⚠ SCALAR-NARROWING (s32 -> u16) — NOT caller-neutral; argument promotion changes at every call
    site, so callers emit different code (byte-proven on func_80175DA8)

So conforming 4,021 sites would likely trade a PLUMBING failure for a BYTE failure. The §99
no-prototype form on the HEADER is compatible with both the byte-true definition and the existing
(u16, s32) prototypes, and touches 9 sites instead of 4,021:

  extern void func_80147364(u16, s32);  ->  extern void func_80147364();

Verified: header change ALONE, no src change, R22 clean-fleet 140 passed, 0 failed of 140.

This is the T67 failure resolved — that batch failed 2/140 with  because it corrected the header's TYPES while 272 TUs disagreed. Dropping the
prototype instead disagrees with nobody.
2026-07-29 00:47:01 -06:00
Drew T 86c315ec08 fix(phase-29): engine_core.h — §99 no-prototype for the three CALLED ARITY functions
Item 1's payoff. §113's call-vs-address re-check found func_80144B14 was the ONLY address-taken one
(already fully retyped, T72); func_8013BD34 / func_8014358C / func_8017D808 are genuinely CALLED, so
their arity IS constrained by the macro's own call site and the full retype is unavailable.

§99 no-prototype is the fix: `extern void func_X();` accepts the macro's fixed-arity call AND the
definition's differing arity, and a no-prototype call passing the same arguments generates the same
code.

  extern void func_8013BD34(void);  ->  extern void func_8013BD34();   (def takes s32 a0)
  extern void func_8014358C(void);  ->  extern void func_8014358C();   (def takes s32 param_1)
  extern void func_8017D808(s32, s32); -> extern void func_8017D808(); (def takes void *a0)

Verified in one step per the T48 discipline: the header change ALONE, no src change, R22 clean-fleet
140 passed, 0 failed of 140. Batched three because the technique was the variable, not the targets —
a bisect over three is cheap if it fails.
2026-07-29 00:39:22 -06:00
Drew T df86fcce50 fix(phase-29): engine_core.h — func_80144B14 declared int(int), not void(void)
The ARITY blocker did not apply: DEFINE_func_* does not CALL func_80144B14, it takes its ADDRESS
(`*(s32 *)((s32)a0 + 0xDC) = (s32)&func_80144B14;`). There is no call site to break, so the FULL
correction is available rather than the §99 no-prototype workaround.

That is a refinement the audit needs: the ARITY precondition asks whether the macro's own call site
would break, but an address-taken use has no call site. Over-fires on that shape.

§85: 0 consumers, so the void->int return widening is byte-neutral.

Verified in two steps (T48 discipline): header change ALONE, no src change, R22 clean-fleet 140
passed, 0 failed of 140. Fleet-shared (§61/§63), R22 mandatory.

Probe target switched from func_8013BD34 on measured evidence: that one's definition lives in
ov_SC07_010_o0.c, and _o0 families sweep ~1/137, making it a poor test of an unproven technique.
func_80144B14 is the same class, 137 stubs, not -O0, with a real 34x137 family.
2026-07-29 00:23:14 -06:00
Drew T 0c5df25faf feat(phase-29): T67 — audit_header_sigs.py; 61 header decls contradict byte truth, 6 corrected
THE TOOL (tools/audit_header_sigs.py, cookbook §112). A DEFINE_func_*() macro forward-declares the
functions its body calls, and that decl is visible in EVERY overlay instantiating the macro — so when
it disagrees with the byte-true definition the whole family becomes untemplatable and the failure
wears a compiler wall's clothes. Three such were found ONE AT A TIME earlier this phase
(func_80156044, func_8016163C, func_8014D610), each worth ~137 members, each costing a
diagnose/fix/re-sweep cycle. This audits all of them in one pass: parse every `extern func_X(...)` in
src/shared/*.h, find every DEFINITION in src/**/*.c (via §110's _def_head_at, not "ends in ;"),
compare with cdecl, and report only where NO definition agrees — one overlay disagreeing is loose
typing (§16/T49), all of them disagreeing means the header is the outlier.

RESULT: 3,043 decls across 1,023 functions; 265 have definitions; 61 contradict every one. The top 10
are full-fleet families (137/136/134 live stubs, 1,366 total), all with an unambiguous byte truth.

APPLIED: 6 functions / 11 decl sites, R22 clean-fleet 140 passed, 0 failed of 140 —
func_80138DE0, func_80146750, func_80161374, func_80161774, func_80161888, func_801778A8.

TWO PRECONDITIONS THE AUDIT DOES NOT YET CHECK, both found by gating rather than by reasoning:
 1. ARITY. func_80144B14 / func_8013BD34 / func_8014358C declare (void) but are DEFINED with one
    parameter. Correcting the header would break the macro's OWN call site (too few arguments), so
    they need the §99 no-prototype treatment instead. Excluded before the batch, by measurement.
 2. OTHER IN-SCOPE DECLS. The first batch of 7 FAILED the gate 2/140 with `conflicting types for
    func_80147364` — the overlays' own TUs declare it the old way (9 header sites rewritten, but
    src/ov_*/…:347 disagrees). A header correction is only safe when no other in-scope declaration
    disagrees; that one additionally needs a conform_decls pass. Excluded; the other 6 then gated
    140/140 clean.

The gate caught the bad batch immediately and the culprit was found by reading one object's real cc1
output rather than by a 7-way bisect (7 fleet gates = ~2.5h; one serial compile = seconds).
2026-07-28 23:00:55 -06:00
Drew T 3c380fec83 fix(phase-29): engine_core.h — func_8014D610 declared s32(s32,s32,u16*), not void(s32,void*,void*)
Same class as func_80156044 and func_8016163C: the shared header contradicted the byte truth. The
exemplar's banked definition is `s32 func_8014D610(s32 param_1, s32 param_2, u16 *param_3)`
(ov_SC07_006_jr_80140608.c:4576); DEFINE_func_8014D438 declared
`void func_8014D610(s32 a0, void *a1, void *a2)`.

That mismatch is what made --fix-def-sig retype param_3 to `void *` while the body does
`param_3[0]` -> `void value not ignored as it ought to be` (T61's param-use guard now refuses it,
naming the header as the real fix — this is that fix).

§85 sized first: 0 callers consume the return. The macro's call site passes `s16 buf1[4]`/`buf2`
into the s32/u16* params — same 4-byte values in $a1/$a2, so the retype is a warning, not a codegen
change.

Verified in two steps (T48 discipline): the header change ALONE, no src change, R22 clean-fleet ->
140 passed, 0 failed of 140. Fleet-shared (§61/§63), so R22 was mandatory.

NOTE: ov_SC07_006_jr_80140608.c:4529 records an earlier, DIFFERENT resolution of the same conflict —
a per-overlay de-macroized local decl ("do NOT re-macroize"). That remains correct and untouched;
this fixes the shared decl the other 137 overlays see.
2026-07-28 21:52:38 -06:00
Drew T 2d91ed54fb fix(phase-29): engine_core.h — func_8016163C declared s32(s32,u32), not void(void*,s32)
The shared header contradicted the byte truth. The exemplar's banked definition is
`s32 func_8016163C(s32 arg0, u32 arg1)`; both DEFINE_ macro decl sites said
`void func_8016163C(void *a0, s32 a1)`.

That mismatch is why the family could not template, and it is what made --fix-def-sig DEMOTE the
return to void — gcc then deleted the computation feeding it and the draft compiled to 58
instructions against a 78-instruction target (T62's self-inflicted SIZE-MISMATCH).

§85 sized first: conform_decls.consumers(func_8016163C) = 0 — both macro call sites discard the
return (`func_8016163C(a0, func_801615C4(a0, 0));`), so the return-axis flip is byte-neutral.

Verified in two steps (T48 discipline): the header change ALONE, no src change, R22 clean-fleet
`make clean && extract-all && check-all` -> 140 passed, 0 failed of 140. Fleet-shared edit
(engine_core.h reaches all 138 overlays), so R22 was mandatory (§61/§63).
2026-07-28 21:37:58 -06:00
Drew T 51bac9f3e6 fix(phase-29): engine_core.h — DEFINE_func_80155FF8 declares func_80156044 void, not int
The exemplar's own @stuck note asked for this (ov_SC01_077_jr_80154C24.c L1349-1350): the
handwritten func_80155FF8 wrapper calls func_80156044 via inline-asm `jal`, so nothing consumes
the return, and ov_SC01_077 already declares it `void` inline — the MACRO was the outlier.

§85 precondition measured before touching it: conform_decls.consumers(func_80156044) = 0 callers
consume the return, so the return-axis flip is byte-neutral.

Verified in two steps (T48 discipline): the header change ALONE, with no src change, R22 clean-fleet
`make clean && extract-all && check-all` -> 140 passed, 0 failed of 140. Fleet-shared edit
(engine_core.h reaches all 138 overlays), so R22 was mandatory (§61/§63).
2026-07-28 21:30:41 -06:00
Drew T f3e8317bd1 feat(phase-29): T49 — func_80135260 x4 siblings + the 3,744-site decl conform
The §53 carve path banked only 4 of 137 siblings, ALL of them SC07 — the exact signature
func_80177DA8 showed before its §99 fix, so the same lever applies.

- jtbl_family_bank func_80135260: 4 BANKED / 133 gate-fail. The 4 are SC07 overlays.
- conform_decls dry run confirmed the class: byte-true def is
  `s32 func_80135260(s32, s32, s16 *, s16 *)` but 3,744 declaration sites say
  `(s32, s32, s32, s32)` — params 3 and 4 declared s32 where the byte truth is s16 *.
  Return type agrees, so the §85 return-axis precondition does not fire.
- Applied: 3,744 sites rewritten across 2,021 files; the tool's R32 assertion reports
  "non-canonical declarations remaining: 0  OK (axis complete)". It correctly SKIPPED the 5
  DEFINING TUs (the 4 SC07 banks + ov_SC01_077) — a defining TU owns its own declarations, since
  per-overlay byte-true signatures legitimately differ under §16 loose typing.
- This touches src/shared/engine_core.h, so it is FLEET-SHARED and R22 was mandatory (§61/§63):
  R22 clean-fleet 140 passed, 0 failed of 140.

Also recorded: jtbl_family_bank's [gather_externs] warning named func_80135D20 as an undeclared
referenced symbol, but that symbol appears ONLY in the draft's header COMMENTS (lines 3 and 29) —
a comment-scanning false positive, same class as the Phase-19 gen_harvest_targets garbled-hint bug.
It was not the cause of the 133 failures.

Next: re-run the carve path for the remaining 133 siblings now that the decl axis is conformed.
2026-07-28 15:47:52 -06:00
Drew T 05430eb26e feat(phase-29): T32 — NEAR-6 crack wave banks 4 reach-138 cores ×1; R22 140/140
Ultracode fan-out (12 agents, 1.70M subagent tokens): 6 crack agents, one per NEAR target, each
carrying its byte-measured residual + T31's disproved routes, then a distill agent per target that
adversarially re-checks the claim.

- BANKED ×1 (whole-binary gate, gate_stage --no-propagate per §55b law 1): func_80140958 (260 ins),
  func_80177B5C (147), func_80132F40 (72), func_8012E364 (67). Every agent MATCH claim was
  RE-MEASURED BY ME with match_one before it was believed (G3/P9: match_one is a candidate, a bank
  is the whole-binary gate), and verified against the SOURCE not gate_stage's accumulating
  verified-list (§55b trap 4). R22 clean-fleet: 140 passed, 0 failed of 140.
- engine_core.h moved by exactly one byte-neutral arity fix (void -> no-proto) = fleet-shared, so
  R22 was mandatory (§61/§63), not the per-binary gate.
- func_80140D68 MATCHes standalone but NOT whole-binary — the §30a integration class; its distill
  agent named the likely cause in advance (DEFINE_func_* extern must return u32*, not void).
- func_80176734 217 -> 13 with the instruction count now EXACT (371/371). cse_expr.md §H's "no bank,
  5 permuter-shaped clusters" is BYTE-REFUTED: 4 of 5 were steerable from C; the -1 length delta was
  a combine/LOG_LINK effect (flow.c links a SET only to the next use in the SAME bb), not frame
  pressure. Two coupled allocator/sched ties survive.
- FOUND: docs/gcc-2.7.2-map/sched.md cites gcc-2.8.1 line numbers (birthing_insn_p 2498->2469,
  adjust_priority 2534->2507, potential_hazard 1345->1318, schedule_select 2646->2616) — surviving
  papermario numbers Phase 23's source-version correction never swept. One is LOAD-BEARING: §1.7 and
  §S12 claim the S2 boost needs SET(REG_pseudo,...) so pins must be removed; sched.c:2477 tests only
  GET_CODE(SET_DEST)==REG with NO pseudo check, discriminator is reg_n_sets==1 (2490). Verified by me
  against tools/reference/gcc-2.7.2, not taken from the agents. Map edits owed (next task).
- MY DEFECT: all 6 agents shared one scratch dir (1,452 files); deliverables are uniquely named and
  verified intact, but short-named scratch could collide. Per-agent subdirs next wave.
2026-07-28 11:28:59 -06:00
Drew T 599a33c056 feat(phase-29): wave22 — 5 exemplars banked from an 18-target Ultracode wave (R22 140/140)
THE WAVE: 18 h_seq family exemplars (~255k templated instructions), one agent each, drafting from
cached Ghidra-C + the target .s with canonical callee/data decls resolved from the real TU scope.
Result 12 MATCH / 6 NEAR / 0 FAIL (2.59M subagent tokens). No agent touched the tree — the
draft-only constraint held (verified: git status clean across src/config/tools/include).

BANKED 5: func_80148E54, func_80171B4C, func_8014A738, func_8012A328, func_80163534.
R22 clean-fleet 140 passed / 0 failed of 140.

A BUG I INTRODUCED EARLIER TODAY, FOUND BY WORKING THE 12->5 GAP. My block-scope descent in
reconcile_tu fed ordinary STATEMENTS to cdecl.parse; some parse without raising into a declarator
with an EMPTY base type and the statement's symbol as its name. That fake row overwrote the genuine
plan entry for the same symbol, so the span rewrite landed on a statement instead of the declaration
— and my own R32 completion assertion still PASSED, because the conformed text appeared somewhere.
Byte-witnessed on D_80126B5C: planned twice ("draft 's32'" and "draft ''"), output unchanged, gate
PLUMBING. Now block-scope rows are accepted only from a real `extern` with a non-empty base type.

TWO BANKS CAME FROM TODAY'S OWN FINDINGS:
- func_8012E014's single 0-arg call site took --cast-zero-arg-calls (built this morning for
  func_801789AC's 138 sites).
- §99 HELD A THIRD TIME: K&R conversion dissolved func_80163534's s32->u16 narrowing across 1,072
  declarations, leaving only a caller-neutral pointer change on the last param.

STILL UNBANKED (measured blockers, not guesses): func_8013B6A0 + func_8013B598 CC1-FAIL in the _o0
split; func_80133298 + func_80135260 + func_8012E014 genuine DIFF (match_one MATCH did not hold
whole-binary = TU-context); func_80138C60 parse-order (an extern referencing a body-local typedef
declared after it); func_80177DA8 prototype-vs-K&R mismatch.
2026-07-28 00:16:08 -06:00
Drew T ee55bd5cae feat(phase-29): func_801330E0 banked — conform_decls taught to read K&R definitions
THE GAP: conform_decls could not parse a K&R definition at all — it exited "no DEFINITION found,
refusing to guess". Honest, but §43 (a narrow param declared K&R-style, producing the in-place
`sll $a2,$a2,16` tell) is a documented, load-bearing idiom here for exactly the narrow-param class.
So the tool was silently refusing the drafts that most need it: a whole idiom family read as
"nothing to conform" (R32 coverage).

THE SUBTLE PART IS PROMOTION (C89 6.3.2.2). A K&R definition promotes each narrow parameter, so a
prototype in scope must declare the PROMOTED type or gcc rejects the pair with `argument 'x' doesn't
match prototype`. That is why the fleet prototype reads `s32 a2` for a parameter the definition
declares `s16` — and why emitting the declared (unpromoted) type would RE-CREATE the narrow-param
conflict this tool exists to remove. The parser now promotes s8/u8/char/s16/u16/short -> s32 and
float -> f64, pointers untouched, and reports (R32) any K&R param with no declaration.

RESULT: byte-true signature read as `void func_801330E0(void *, s16 *, s32)`; the only real change
vs the fleet's 973 declarations was param_1 `s16 *` -> `void *` (a pointer shape, caller-neutral).
973 sites / 973 files rewritten, axis complete. Gate: verified 1 / failed 0, d19c9580 BYTE-IDENTICAL.
R22 clean-fleet 140 passed / 0 failed of 140.

Reach 138 x 110 ins = 15,180 templated instructions unlocked for the family sweep.
2026-07-27 19:14:53 -06:00
Drew T ad57c16e61 feat(phase-29): func_8014CF04 + func_8015D1B8 banked; conform_decls had 3 defects R22 caught (§98)
THE BANK: the T14 PLUMBING census showed func_8014CF04 blocking THREE drafts at once. Conforming its
decl axis banked func_8014CF04 + func_8015D1B8 (func_80135260 is a genuine DIFF, agreeing with its
independent SESSION-21 diagnosis). R22 clean-fleet 140/140; report fail-closed green (dedup 1886/0,
0 NON_MATCHING). fn-count 317,896 -> 317,898; distinct 66,110 -> 66,111.

BUT THE AXIS WAS A 1,748-FILE T2 WRITE SET (the --check per-form counts read "1"), and R22 came back
139/140 -- TWICE -- on a change the per-binary gate called BYTE-IDENTICAL. Three defects (§98):

1. THE REGEX CROSSED NEWLINES. `[^;]*` matches '\n', so a match starting at a DEFINITION line ran
   past the `{` to the first `;`, swallowing `s32 func_8014CF04(...) {` PLUS the register pin on the
   next line and replacing both with a prototype -> undefined reference. Fixed to `[^;{\n]*`: a
   definition is now unmatchable by construction.
2. IT REWROTE INSIDE COMMENTS (H5, 3 lines). Now scans cdecl._mask() and rewrites by SPAN (R33 --
   that length-preserving primitive already existed for exactly this).
3. THE REAL CAUSE -- IT ASSUMED ONE SIGNATURE FITS THE FLEET. ov_SC07_006 carries its own banked
   definition with a DIFFERENT byte-true signature ((s32,s32,void*) vs (s32,void*,void*)), under a
   decl marked "per-overlay-local decl (byte-true sig); do NOT re-macroize". That is the Phase-16
   loose-typing wall inside a tool that structurally assumes it away. NEW RULE: a TU that DEFINES the
   function owns its own declarations; a fleet axis is meaningful only for CONSUMING TUs. This grows
   more common as banking proceeds -- every overlay that banks a function becomes an exception.

Then the R32 completion assertion cried wolf on its own by-design skip ("HALF-AXIS -- DO NOT BUILD"
for a complete rewrite): an assertion must be exact about its DOMAIN, not just its condition. Scoped
to consuming TUs -> 1,747 sites, 1 excluded by design. Also hardened to PLAN -> VALIDATE -> WRITE;
the refusal path had aborted mid-write while claiming nothing was modified, creating the very
half-axis §85 calls a guaranteed break.

META (R22's premise, re-earned): after fixing defect 1 I EXPECTED R22 to pass; it failed again for an
unrelated reason, and an individual `make build` of the failing binary SUCCEEDED by reusing objects
the clean run rebuilds. An incremental pass does not refute a clean-tree failure.
2026-07-27 17:47:57 -06:00
Drew T 1670fe293c feat(phase-29): func_8016B6BC 0/137 -> 137/137 — it was a TYPE-CARRY failure, not a wall
The family that failed its sweep twice (once in the 274-member batch, once after the §91 guard) and
looked like the §86 bimodal 'some families just don't template' case. It was not.

DIAGNOSIS (§59 + §93): spliced ONE sibling and read cc1 directly. It reported `c`, `v`, `off`
undeclared — ordinary locals that ARE declared in the remapped body. cc1 says 'undeclared' because it
aborted the declaration block at an unknown TYPE and every later declaration fell out with it. Read
the FIRST error, not the loudest: a visibly-declared variable reported undeclared means suspect its
type.

THE LIFT MUST BE TRANSITIVE. Lifting the type the body names directly (M8_8016B6BC) changed nothing —
still 0/137. The real set was four, found by following each definition's own references:
M8_8016B6BC -> Prim_8016B6BC -> Vtx_8016B6BC (named only inside Prim's body) -> DVec_8016B6BC.
lift_types.py --apply, byte-gated ALONE first (neutral, d19c9580 unchanged), then swept.

RESULT 0/137 -> 137/137, zero failures. R22 clean-fleet 140/140. cookbook §94.

Cost of not diagnosing: this family sat recorded as 'doesn't template' across two sessions. Pointed
at one sibling's real stderr it took under an hour and was worth 137 members.
2026-07-27 16:26:26 -06:00
Drew T 2985f306d9 feat(phase-29): func_80179B74 banked — conform_decls cleared it as pointer-type-only (R22 140/140)
1,600 decl sites across 523 files, in THREE different forms (s16 *a0 / short * / short *p),
conformed to the byte-true 'void func_80179B74(u16 *p)'. conform_decls ALLOWED this one: the arity
is unchanged, so no 0-arg call site can break, and the return is unchanged, so §85's precondition
does not apply. Gated BYTE-IDENTICAL; R22 clean-fleet 140/140.

The tool has now refused one axis (func_8015B950, correctly — it would have broken 138 binaries)
and cleared another (this one, correctly). Both verdicts held under R22.
2026-07-27 12:47:44 -06:00
Drew T f459f53083 feat(phase-29): func_8015B950 banked — ONE cast unlocked the 925-site axis that broke 138 binaries
The same axis that broke 138 of 140 binaries an hour ago now lands clean, because conform_decls'
NEW arity guard located the actual obstruction instead of leaving me to absorb it by hand.

THE OBSTRUCTION WAS ONE LINE. Conforming `extern s32 func_8015B950(void)` -> `(s32 arg0)` turns
every 0-arg CALL SITE into `too few arguments`. My hand attempt assumed those were spread across the
926 TUs and would need 926 casts (the func_8012AAAC precedent, where it really was 137 separate
sites). They are not: there is exactly ONE call, in `src/shared/engine_core.h`'s
`DEFINE_func_8015BEE4()` macro body — expanded into all 926 TUs by the preprocessor.

func_8015BEE4 is a THUNK: `return func_8015B950();` with $a0 passing straight through from its own
caller. So the 0-arg call shape is byte-CORRECT and must be preserved, not fixed —
`return ((s32 (*)(void))func_8015B950)();` keeps it exactly (§17a-1; gcc folds the cast of a known
symbol to a direct jal, and the s32 return is unchanged so the thunk's value still flows).

Sequence: 1 cast -> conform_decls --apply (925 sites, R32 completion assertion: 0 remaining) ->
gate BANKED byte-identical -> R22 clean-fleet extract-all 139/139, check-all 140 passed / 0 failed.
The draft's 2 callee-decl conflicts (func_801725A4, func_80147078) dissolved with the axis.

Worth 37,398 templatable ins; the ×137 family sweep is next.
2026-07-27 11:56:23 -06:00
Drew T 2cc49d0310 feat(phase-29): SESSION-21 — func_8012AAAC banked via the §81 carve chain (R22 140/140)
The first jtbl-routed bank of the session, and it validates the whole chain end-to-end:
 1. jtbl_carve SPLIT-TABLE repair (this session): jtbl_801D7FB0 28 -> 50 words (112 -> 200 B),
    authorized by func_8012AAAC's own `sltiu 0x32`.
 2. NEW FIX — SINGLE-TABLE PREDECESSOR: adding a second table to a subseg whose existing carve was
    single-table lost the FIRST table's start entirely (new_offs has only the new one;
    overlay_jtbl_addrs cannot see the old one because its owner is banked and extract PRUNED the
    stub .s; and single-table carves persist no tables= to rebase). The span then failed its own
    validator with "first must equal the span start" — the invariant naming the missing entry.
    A single-table carve spans exactly its one table, so ITS SPAN START *IS* THAT TABLE'S START:
    inference, not persistence, so it also works for spans carved before tables= existed. This is
    the RECOVERABLE half of the documented func_8013F350 lesson (that one was a pre-§8e merged
    DOUBLE — two tables, no record, genuinely unrecoverable).
    Result: ov_SC01_077_a JTBL_PADS := 0,0 tables=+0x0,+0x14. Carve alone byte-gated BYTE-IDENTICAL
    BEFORE the bank was attempted (§81 step 2).
 3. ARITY axis, all-or-nothing: 1,244 decl sites / 1,240 files `(void)` -> `()` + an R32 completion
    assertion (old-form remaining: 0).
 4. ONE call-site cast: the definition lands at line 811 and a 0-arg call sits at 822, so gcc sees
    the prototype and rejects it — `((void (*)(void))func_8012AAAC)()` (§17a-1; gcc folds the cast
    of a known symbol to a direct jal). Only 1 of the 1,386 fleet-wide 0-arg call sites needed it:
    the others see only the `extern ()` decl, which permits a 0-arg call.

DIAGNOSIS NOTE: the failure read CC1-FAIL with only a warning visible under make. Running the
pipeline stage-by-stage (cpp | cc1 | maspsx | jtbl_rodata_pads | as) put it on cc1 rc=33, and cc1's
own stderr named it exactly: "too few arguments to function func_8012AAAC" at line 994. Isolating
the stage was what turned an opaque Error 33 into a one-line fix.

R22 clean-fleet: extract-all 139/139, check-all 140 passed / 0 failed.
family_sweep correctly REFUSED this exemplar (§53: a jr-family must route through
jtbl_family_bank.py; "a 0% from this path would be a TOOL artifact, not a wall") — the ×137 member
sweep is the next step and needs a clean tree, which this commit provides.
2026-07-27 10:38:10 -06:00
Drew T 2ce6c5fade feat(phase-29): SESSION-21 — 3 family exemplars banked + the §85 return-axis widen (R22 140/140)
BANKED (whole-binary byte-gate, the sole arbiter): func_8014D2A0 (80 ins ×138) · func_80158638
(87 ×138) · func_8016B6BC (94 ×138). Stubs in ov_SC01_077: 150 -> 147, 0 new stubs.
R22 CLEAN-FLEET: extract-all 139/139, check-all 140 passed / 0 failed. dedup 1886/0,
0 NON_MATCHING (G4). Fleet 81.7% instr / 69.3% distinct-code / 89.52% fn-count.

- WAVE STOPPED at Drew's request with 15/24 agents returned, ALL 15 status=match. Only the
  completed drafts were gated; in-flight ones are still being written (§90d).
- PRE-GATE, both oracles, all 15: match_one MATCH + reloc_verify ALL RESOLVED. Routed 7 plain /
  8 to the §81 jtbl carve chain.
- THE BLOCKER, MEASURED: 7 of 7 plain drafts failed PLUMBING, 0 DIFF, 0 compiler walls — the same
  shape as SESSION-20's T0.2. §58b applies: the draft sig is byte-TRUTH (it MATCHed), the header
  decl is the stale stub-era guess, so conform the DECLS.
- §85 RETURN-AXIS WIDEN, all-or-nothing: 3,471 decl sites / 1,736 files, precondition verified
  (ZERO callers consume the return => byte-neutral by construction) + an R32 completion assertion
  (old-form decls remaining: 0). func_8014D820's s32 return is load-bearing — forcing `void` costs
  2 instructions (302 vs 304), so the decls had to move, not the draft.

TWO HONESTY ITEMS:
 1. I REPORTED "0 of 7 banked"; the true number was already 2. My diagnostic pass printed only
    lines starting with "- func_" (the failures) and hid its own successes while I read it for
    error text. A script that prints only failures cannot tell you it succeeded — the R32
    silent-skip shape aimed at my own instrumentation. Ground truth is the stub count (§55b(3)).
 2. A REAL FINDING fell out of that mistake: same drafts, same tree, minutes apart — gate_stage's
    full ladder banked 0/7 while bare harvest_verify banked 2/7. The LADDER REGRESSED two drafts
    the bare gate accepts (§19's "sig_unify regresses already-canonical drafts", one level up, and
    the exact mirror of SESSION-20's missing-ladder false 33%). Neither "always ladder" nor "never
    ladder" is right — run both, let the byte-gate arbitrate. One build per draft.

OPEN: func_8014D820 still a stub — after the widen its error moved from `conflicting types` to an
assembler-stage failure, not finished diagnosing. Recorded as open, NOT as a wall.
2026-07-27 09:58:17 -06:00
Drew T 09b1993059 feat(phase-29): T0.7 sweep (104 members) + BEHEMOTH func_8017D2DC banked (1,586 ins)
T0.7 — the §86 one-member probe applied to the remaining FREE families: 9 LIVE / 6 DEAD / 5 unstaged.
The three highest-value families by raw size (18,084 / 11,234 / 10,880 ins) all probed DEAD — the
probe skipped them instead of burning ~400 gate cycles rediscovering it. Swept the 9 live: 104 banked,
8 of 9 families fully cleared (func_8017BEF8 has 8 stragglers).

BEHEMOTH 2 of 3: func_8017D2DC (1,586 ins, ov_SC01_001) MATCHED and BANKED — closed in ONE agent
round, pin-free. Verified independently (R14): match_one MATCH (1586 ins).
  §81 carve chain: the agent predicted step 1 unnecessary; jtbl_carve REFUSED (the subseg already
  hosts a .rodata carve and the new table's start != span start). The refusal was RIGHT and is the
  instruction to run step 1 — jr_isolate_all --only (2 fns/1 object) -> BYTE-IDENTICAL, then
  jtbl_carve -> BYTE-IDENTICAL, then the ladder banked it.

R22 clean-fleet 140/140 BYTE-IDENTICAL; tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4).
Fleet: instr 81.5 -> 81.6% · distinct-code 69.0 -> 69.1% · fn-count 89.49 -> 89.52%.
2026-07-26 22:02:37 -06:00
Drew T 772b5c4e02 feat(phase-29): the RETURN-axis fleet widen — 2 more families unlocked (cookbook §85); 140/140
Continues the "see why and try again" chain. Diagnosed all 4 T0.2 failures to 4 DISTINCT causes:
  func_8013D53C  240x123  §84 derived-offset remap bug        -> BANKED (previous commit)
  func_8012CC88  105x137  §73/§30#2 RETURN-axis conflict      -> BANKED here
  func_8014D12C   93x137  §73/§30#2 RETURN-axis conflict      -> BANKED here
  func_80144090  154x136  LENGTH-DRIFT (+13 B, ~3 ins long)   -> genuine codegen, real work

THE FAILURE THAT TAUGHT THE FIX: widening only src/shared/engine_core.h banked the member in the
TARGET overlay and BROKE ov_SC01_077 (R22 139/140) — the source overlay carries its OWN local
`extern void func_X(...)` decls, so a shared-header-only widen puts them in direct conflict. The
per-binary gate passed while breaking a binary it never built (§63/§61: a T2 write set is only
provable by R22). A half-done axis is a guaranteed break, not a smaller win.

THE FIX: do the WHOLE axis — 3,668 `extern void` decl sites across 2,688 files widened to `s32`,
0 remaining (R32 completion assertion). Precondition verified first: 0 callers consume the return
value, so the widen is byte-neutral by construction. R22 clean-fleet 140/140 BYTE-IDENTICAL;
tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4).

MY OWN ERROR, recorded (§85 trap): I first spot-checked ov_SC01_077 with
`make build | grep | head; echo rc=$?` and read rc=0 as success — that is the exit status of `head`,
not make, and the output had no BYTE-IDENTICAL line. I reported a false BYTE-IDENTICAL in the
interim. Assert on the SUCCESS STRING, never on $? after a pipe.

Fleet: instr 80.6% (10,589,503) · distinct-code 68.3% (3,846,656) · fn-count 89.19%.
2026-07-26 15:22:21 -06:00
Drew T 3ffff74f5b feat(phase-29): BEHEMOTH #3 func_8017F510 CRACKED — 97 -> MATCH (1,511 ins), pin-free
- BANKED into ov_SC03_006 through the whole-binary byte-gate (G3/P9); R22 clean-fleet
  140 passed, 0 failed of 140. Verified independently before believing the agent's report
  (R14): match_one -> MATCH (1511 ins), then harvest_verify -> BYTE-IDENTICAL.
- DISTINCT-CODE 3,813,512 -> 3,815,023 = +1,511, EXACTLY the function's instruction count and
  the ONLY distinct-code movement of the entire session. Reach is ×1 by sig, no propagation --
  which is precisely why it moves the metric propagation cannot touch. instr 80.3%, fn 89.18%.
- EFFORT EXPERIMENT (Drew): behemoths #1-#3 were worked at High; this is the first at xHigh
  (Opus 5 agent). It closed a residual the lower tier had fully localized but could not move,
  and that 3,663 permuter candidates at base 97 had failed to improve by even 1.
- MECHANISM -> cookbook §76: the allocno CLASS (local vs global) is the dominant regalloc lever
  and C reaches it ONLY through declaration scope and variable reuse -- unreachable by statement
  order, expression shape, pins, or random search, which is exactly why the permuter was spent.
  (1) `otp` per emit ARM: 4 deaths -> four 1-death local pseudos (local-alloc.c:472); its
  second-order effect via global.c:668-671 (local placements re-marked as HARD regs for
  global-alloc) had made the target's otp=$a0 STRUCTURALLY IMPOSSIBLE, visible as hard-reg 4 in
  the `;; N conflicts:` tail of the .greg dump. (2) `cb` reused as the unlit rgbc temp: refs
  27->39 lifts its global.c:594 allocno_compare priority past `tp`, flipping the 3-colouring ->
  97 -> 10. (3) one shared `rgbw` temp -> 10 -> 2. (4) mny-before-my + one zero-byte __asm__ at
  the head of the tri cull block -> MATCH.
- THREE CORRECTIONS TO MY OWN BRIEF, all byte-evidenced: residual B was never a scheduling
  residual (it fell out free with lever 2 -- a register grant seen as a schedule diff); residual
  A is RTL EXPANSION order, proven with -fno-schedule-insns AND -fno-schedule-insns2 (source
  order survives both -- that attribution primitive is the reusable bit); residual C had no
  single c3 seed (c3 has no lever of its own, it moves only when cb out-ranks tp).
- FIXED a latent SHARED-HEADER defect, pre-existing and unrelated to the draft:
  src/shared/engine_types.h closed its include guard at line 1174 of 1259, leaving 11 typedefs /
  85 lines OUTSIDE the guard since the crack-wave lift. A TU including it twice re-declares them
  and gcc-2.7.2 rejects a repeated typedef even when identical -> `conflicting types for
  Blk16_956C`. Guard moved to EOF; byte-neutral.
- ARTIFACTS TRACKED (R20): .run/giants/s19_func_8017F510_b4.c (130-line dossier) +
  s19_f510_report.md, whose ~50-row do-not-re-buy table is arguably worth more than the match,
  + the s19_* analysis tooling.
- STRETCH, MEASURED: func_8017F5B4 (1,511 ins, ov_SC02_031) has a DIFFERENT h_exact -- not a
  dedup sibling, a family_remap TEMPLATE candidate off the b4 source.
2026-07-25 14:41:08 -06:00
Drew T 398e653c92 fix(phase-29): §75a class-B remedy is the FULL §17a-1 pair — decl AND call-site cast
- The K&R-decl-only probe was HALF the fix, and cc1 said so exactly:
    ov_SC01_001_jr_801734BC.c:2616: too many arguments to function `func_8012F14C'
  `()` dissolves the DECLARATION conflict (the failure class moved PLUMBING -> CC1-FAIL), but the
  composite type after the TU's earlier `void func_8012F14C(s32);` prototype is still 1-param, so
  the macro's 3-arg CALL is a hard error. Reproduced by hand-splicing the macro into
  ov_SC01_001 and reading real cc1 stderr rather than trusting the classifier's `Error 33`.
- FIX = the other half of §17a-1 (what cast_call_sites.py does, and what §20 established): cast
  the call site so it does not depend on the TU's prototype at all —
    ((void (*)(s32, s32, s32))func_8012F14C)((s32)&mtx, (s32)&vec, (s32)&out)
  gcc-2.7.2 folds a cast of a KNOWN function symbol back to a direct `jal`, so the bytes are
  unchanged. Decl stays `()` so it cannot conflict in either declaration order.
- BYTE-GATED on the full existing radius: ov_SC07_006 7ca772be · 007 b3b95547 · 011 9885af74 —
  all BYTE-IDENTICAL.
- LESSON for §75a class B: the remedy is the PAIR, never the decl alone. A decl-only change moves
  the error from `conflicting types` to `too many arguments` and looks like a new wall.
2026-07-25 13:34:53 -06:00
Drew T 8f63c1a8e0 probe(phase-29): §75a class-B — K&R () for the carried func_8012F14C decl (func_80174CB0)
- The class-B arity split (1944 `(s32)` vs 968 `(s32,s32,s32)`) blocked func_80174CB0 in 131 of
  134 overlays: the macro carried the 3-param prototype, the failing TU declares the 1-param one
  FIRST (ov_SC01_001: TU@328 vs instantiation@2616), so cc1 sees two prototypes of different
  arity and rejects.
- Per cdecl.compatible's MEASURED gcc-2.7.2 behaviour a no-prototype `()` is accepted in BOTH
  orders here: prototype-first + ()-second always; ()-first + prototype-second when no parameter
  is altered by default promotion -- and all three args are s32, which does not promote. So one
  K&R decl should satisfy both populations regardless of where each TU declares it.
- Call site UNCHANGED (`func_8012F14C((s32)&mtx, (s32)&vec, (s32)&out)`): with a K&R decl the
  args pass under default promotions, and s32 args are unaffected -> same codegen.
- BYTE-GATED on the full existing radius before extending: ov_SC07_006 7ca772be · 007 b3b95547 ·
  011 9885af74 -- all BYTE-IDENTICAL. The extend result is the real test of the prediction.
2026-07-25 13:19:20 -06:00
Drew T 364ddd7055 fix(phase-29): ENGINE_SHB — the carried-#define gap that capped func_80165CA0 at ×3
- CAUSE (measured, not guessed): the 132 extend failures were `undefined reference to 'SHB'` --
  a LINK error, not a type conflict. SHB is not a symbol; it is a file-scope
  `#define SHB(x) __asm__(...)` sign-extension barrier. A body's preamble can carry `#define`s
  as well as `extern`s, but extraction lifts only the externs -- so the `#define` was left behind
  in the source overlay. In ov_SC01_077 it sits literally BETWEEN the two carried externs and the
  instantiation:
      extern s32 D_8011D030;
      extern s32 D_80126728;
      #define SHB(x) __asm__ __volatile__("" : "=r"(x) : "0"(x))
      DEFINE_func_80165CA0()
  The other 132 overlays DO define SHB -- ~300 lines further down the file (stub @4462 vs
  #define @4781 in ov_SC01_001), i.e. BELOW the splice point, so the preprocessor never expands
  it and cc1 emits a call to an undeclared `SHB`. Pure ORDERING; nothing was missing.
- Also explains why the 3 current members are EXACTLY the 3 files carrying the __volatile__ SHB
  spelling: that define is the function's own preamble, still sitting above its instantiation.
- FIX: engine_core.h owns the barrier as ENGINE_SHB (distinct name, so the overlays' own SHB --
  which exists in BOTH a volatile and a non-volatile spelling -- can never collide), and
  DEFINE_func_80165CA0's 7 uses now call it. Volatile form: what the 3 banked members compile
  with today. The body is now self-contained wherever it is instantiated.
- BYTE-GATED the full existing blast radius: ov_SC01_077 d19c9580 · ov_SC01_000 9052dc0e ·
  ov_SC07_006 7ca772be -- all BYTE-IDENTICAL.
- This is the dedup_propagate counterpart of Phase-27's family_remap._carry_macros (§75b).
2026-07-25 13:04:15 -06:00
Drew T 2fcb8de6bf fix(phase-29): normalize func_8014F468 to the fleet-canonical s32 (unblocks the ×138 reach) + §75
- THE PROPAGATION CAP WAS A MINORITY-SPELLING SOURCE OVERLAY, byte-censused:
    extern s32 func_8014F468(void);   1710   |  s32 func_8014F468(void)  134   <- fleet canon
    extern void func_8014F468(void);    20   |  void func_8014F468(void)   4   <- the outlier
  and ALL 4 `void` definitions are ov_SC07_{006,007,010,011} — the overlay the F3E8 body was
  banked from. dedup_propagate carries the source overlay's file-scope externs into the shared
  macro VERBATIM, so the macro inherited `extern void` and the 134 overlays that define the
  symbol `s32` rejected it. Propagation landed on exactly that 4-overlay island.
- The exclusion message ("byte-diverge / irreconcilable") is provably the wrong cause: members
  are selected BY h_exact, so all 138 are byte-identical by construction. It is a COMPILE
  conflict, never a byte one (same defect family as §68's mislabel, same tool).
- NORMALIZED the 24 minority occurrences to s32 (4 definitions + 19 overlay externs + the 1
  line in the freshly-authored macro). func_8014F468 is a pure inline-asm $sp-switch trampoline
  — no C-level value flow — and 134 overlays already PROVED s32 is byte-correct for the
  identical function. Fleet is now uniform: 1730 extern s32 + 138 s32 defs, 0 `void`.
- BYTE-GATED the complete blast radius (the 4 instantiators of DEFINE_func_8014F3E8):
  ov_SC07_006 7ca772be · 007 b3b95547 · 010 d7b5875d · 011 9885af74 — all BYTE-IDENTICAL.
- cookbook §75: census the carried extern before believing an exclusion message; prefer a
  majority-spelling source overlay; always pass --recover; after normalizing use dedup_extend
  (the body is already a macro) not dedup_propagate --addr.
2026-07-25 12:45:11 -06:00
Drew T 10ea5ff653 feat(phase-29): propagate the widen batch — func_8014D4C0 ×138; func_8014F3E8 ×4 (cause measured)
- func_8014D4C0 (84 ins) PROPAGATED ×138: all 138 overlays rebuilt byte-identical, group
  E_func_8014D4C0 registered. 84×138 = 11,592 ins.
- func_8014F3E8 (32 ins) propagated ×4 only (the ov_SC07_{006,007,010,011} island), 134
  overlays excluded one at a time.
- TWO FINDINGS, both measured:
  (1) THE FIRST RUN'S "drop" WAS A FLAG OMISSION, NOT A WALL. Without --recover,
      dedup_propagate takes the historical all-or-nothing path on the first culprit overlay,
      so ONE divergent member cost the whole group (×0). With --recover, Part A excludes just
      the culprit -> ×4 instead of dropped. Always pass --recover on a targeted --addr run.
  (2) THE EXCLUSION CAUSE IS A MINORITY-SPELLING SOURCE OVERLAY, not byte divergence. The
      sigs prove all 138 members share ONE h_exact (2ccf344d), so nothing diverges in bytes.
      The macro carries the source overlay's `extern void func_8014F468(void);` while the
      fleet census is 1,710 `extern s32` + 134 `s32` definitions vs 20 `extern void` + 4
      `void` definitions -- and all 4 `void` definitions are ov_SC07_{006,007,010,011}, i.e.
      the source overlay I banked from is the OUTLIER. The macro inherited the minority
      spelling and silently capped its own reach at that island.
- => the fix is NORMALIZATION (24 occurrences), not a reconciliation engine; the follow-up
  commit flips the SC07 minority to the fleet-canonical s32 and re-propagates.
- R22 clean-fleet: make clean && extract-all && check-all -> 140 passed, 0 failed of 140.
2026-07-25 12:42:24 -06:00
Drew T 1c0d29d91d feat(phase-29): §30#2 widen batch — func_8014F3E8 + func_8014D4C0 banked; §73 (the two axes)
- FLEET WIDEN (T2, one edit): extern void -> extern s32 for func_8014F3E8 + func_8014D4C0
  across src/** (16 decls in engine_core.h + 5,079 in 3,459 overlay .c; 0 `extern void`
  left, 0 pre-existing `extern s32`). Scope re-verified against the tree first (R14/R35):
  the SESSION-18 counts reproduce exactly and no decl exists outside the `extern void <name>`
  shape in any .c/.h under src/.
- BYTE-NEUTRALITY OF THE WIDEN ISOLATED FIRST: ov_SC07_006 7ca772be + ov_SC01_000 9052dc0e
  BYTE-IDENTICAL before splicing any draft (ov_SC01_000 chosen because it instantiates the two
  return-CASTING macros — the only sites a decl's return type could touch codegen).
- BANKED into ov_SC07_006 (both ×1, both reach ×138 by sig: single h_exact across 138/138):
  func_8014F3E8 (32 ins) on gate 1; func_8014D4C0 (84 ins) on gate 2.
- FINDING -> cookbook §73: the widen fixed only HALF the conflict. A def-side self-decl
  conflict has TWO independent axes — RETURN (fleet macro-widen, T2, R22-mandatory) and
  PARAMS (canonical param types + casts at each USE, T0, no fleet edit). func_8014D4C0
  failed the first gate on the PARAM axis (canon `void*` vs draft `u16*`); the §17a-1 move
  applied to the def's own signature banked it with nothing outside the draft touched.
  Diagnose the axis before reaching for the expensive fix.
- R22 clean-fleet: make clean && extract-all && check-all -> 140 passed, 0 failed of 140.
  make report: dedup 1884 validated / 0 failed, C1 coverage 239039/239039, 0 NON_MATCHING (G4).
  Fleet 80.0% instr / 67.7% distinct / 89.02% fn-count (the ×138 propagation is the value).
2026-07-25 12:24:30 -06:00
Drew T ba35785ec4 feat(phase-29): bank func_801777BC (59 ins) x138 — the giv-init base-register lever (§70)
- MATCH (59 ins), real-TU verified by the agent before handing back (cc1 rc=0, 59/59, 0 diffs).
- Propagated x138 with ZERO exclusions -> confirms the ×3 cap on func_80174CB0 was purely the
  carried-extern collision: a body with no externs propagates clean.
- R22 clean-fleet 140/140, 0 failed. dedup-check 1884 validated / 0 failed, C1 coverage complete.
- FLEET CROSSES 80.0% instr-weighted (10,509,526 / 13,141,652); fn-count 89.02%; distinct 67.7%.
- THE LEVER (cookbook §70): residual was ONE instruction, addiu $t0,$t1,0xC vs $t0,$a0,0xC -- a giv
  based on a copy of the param. Reading gcc-2.7.2 loop.c/cse.c proved the natural form can never
  emit the target: cse.c:make_regs_eqv makes the copy canonical (it out-lives a0) and
  loop.c:update_reg_last_use won't extend a0's last-use (giv-init UID >= max_uid_for_loop). Fix:
  walk the PARAMETER itself, so record_initial sees the biv init as hard reg (reg:SI 4),
  valid_initial_value_p accepts it (precondition: no calls), and emit_iv_add_mult bases the giv on
  $a0 -- yielding both required instructions free.
- META: this compiler-source reasoning was done by an ORDINARY Opus 5 drafting agent, unprompted --
  the tier Phase 23 reserved for Fable5. One data point, recorded as such; the cheap action is to
  give routine drafting agents the gcc source path.
2026-07-25 00:49:04 -06:00
Drew T e112eff601 fix(phase-29): find_site — a comment-only line halted the extern scan (§68); func_80174CB0 x1 -> x3
TWO mislabels in one tool, both found by making it print what the compiler actually said.

1) compiles_standalone() returned a bare False and the caller filed EVERY failure under
   "overlay-local TYPE (the real cap)". The dominant real cause is undeclared FILE-SCOPE EXTERNS.
   Now returns (ok, stderr) and the skip is classified by actual cc1 output.
2) find_site()'s backward walk over "preceding contiguous externs" skipped BLANK lines but not
   COMMENT-ONLY lines, so a full-line /* ---- */ between two extern groups dropped every extern
   above it. Comment lines are now skipped like blanks and filtered out of the emitted body so
   make_macro never meets a `//`.

RESULT, measured honestly: func_80174CB0 went from "not self-contained" to a 138-member PLAN, but
--recover banked only x3 (ov_SC07_006/007/011); 135 overlays excluded. Those exclusions are NOT
byte divergence (all 138 share h_exact) -- they are the CARRIED EXTERNS colliding with each target
overlay's own decls. The carry is necessary but not sufficient: it must reconcile per-target-TU
(cdecl.compatible(), the shape reconcile_tu already uses). Spec updated in CURRENT_PHASE.md.

- R22 clean-fleet 140/140, 0 failed. dedup-check 1883 validated / 0 failed, C1 coverage complete.
- fleet instr 79.9% (10,501,384 / 13,141,652); +246 ins from the x3.
- WHY THIS MATTERS beyond the numbers: the Phase-21 backlog already prescribed "macro-extern-
  injection frees them x134 (~+0.3%)" and it was never built, because the mislabel told every later
  session these were the known-hard type wall. A wrong diagnostic label cost ~4 phases.
- cookbook §68. NOTE the exclusion message is ALSO mislabelled ("byte-diverge / irreconcilable"
  conflates differing bytes with a non-compiling instantiation) -- logged to fix.
2026-07-25 00:17:08 -06:00
Drew T af59d8a630 feat(phase-29): bank func_80174CB0 (123 ins) — the §65g verdict was a wrong SIGNATURE
SESSION-17 filed this as §65g-class: "not 'run one more tool', but 'needs a transform that does
not exist yet'". Refuted. It needed the correct self-declaration.

- The TU expands DEFINE_func_80174C80() carrying `extern s32 func_80174CB0(s32, s32);`, while all
  ~100 prior drafts defined `void func_80174CB0(s32, s16)` — matches perfectly STANDALONE, dies in
  the real TU with `conflicting types`. Defining it `s32 (s32, s32)` and recovering param_2's
  s16-ness with an explicit (s16) cast at the func_80012558 use site is byte-identical.
- Drafted by an isolated agent (Opus 5 @ High, 65k tok) pointed at the NAMED blocker with the
  canonical callee sigs supplied — not asked to re-derive the C. It self-verified through the real
  cpp->cc1->maspsx->as chain (cc1 rc=0, 123/123 ins, 0 diffs) before reporting, so the bank was
  first-try clean.
- make check BINARY=ov_SC07_006 BYTE-IDENTICAL (7ca772be); R22 clean-fleet 140/140, 0 failed.
- Propagation ×138 follows as a separate targeted step (§55b: bank -> commit -> dedup_propagate --addr).
- FOLLOW-UP LOGGED: the recovery ladder also relaxed `extern s32 func_80174CB0(s32,s32)` -> `()` in
  src/shared/engine_core.h (+2 overlay files), escalating a binary-local bank to FLEET tier. The
  banked def AGREES with the original prototype, so that edit looks unnecessary — to be tested.
2026-07-24 23:43:15 -06:00
Drew T 25a02d6940 feat(phase-29): propagate 2 integration banks ×138 — fleet 79.7 -> 79.9% instr, R22 140/140
- func_8012B4B8 (84) + func_80169228 (105) propagated via targeted --addr (--check-only first,
  never --auto-from): 138 overlays byte-identical, 2 new dedup groups, ~+26,082 ins.
- R22 clean-fleet: check-all 140 passed, 0 failed of 140. Fleet fn-count 88.90 -> 88.98%.
- The 3 non-banks are diagnosed, not guessed (blocker_probe, both oracles agree): func_801463A0 is
  a real-cc1 MATCH in its own TU that the gate still rejects (§65c rtu-vs-gate divergence, link-level);
  func_80156670/func_80174CB0 carry "drop when banking" typedefs textually identical to the canonical
  ones. Blockers STACK — stripping the cc1-named typedef exposed the next (S8->B8; MATRIX->a callee
  conflict). Remedy named: strip ALL shared-provided typedefs, then run the DRIVER's ladder.
2026-07-24 20:01:31 -06:00
Drew T 32de37fff4 feat(phase-29): propagate func_80177940 x137 — 138 overlays byte-identical, R22 140/140
- Targeted `dedup_propagate --addr 0x80177940 --recover` (NEVER --auto-from; --check-only first
  confirmed the plan held exactly this one address, so the de-macroize hazard could not apply).
- 138 overlays rebuilt byte-identical; 0 stubs remain for the address; 1 new dedup group registered.
- R22 clean-fleet: check-all 140 passed, 0 failed of 140.
- Fleet: fn-count 88.86 -> 88.90%, instr-weighted 79.6 -> 79.7% (+13,938 ins = 101 x 138),
  distinct-code 64,874 -> 64,875 unique fns.
2026-07-24 16:41:44 -06:00
Drew T bf307f2827 feat(phase-29): s15 propagation (5 cores ×138) + crack-wave efficiency audit
- 5 of the 6 s15 fresh cores propagated ×138 (func_801483E8/8014680C/8017129C/80177AD4/801759D8;
  func_8014A51C §20-capped). R22 clean-fleet 140/140. fn-count 88.66->88.86%, instr 79.4->79.6%,
  distinct-code count 64854->64860, dedup 1879/0.
- EFFICIENCY AUDIT (decision-log): the 2 LLM waves ran 92% match_one MATCH but only ~27% whole-binary
  bank; 6 spot-checked non-banks are ALL match_one MATCH (byte-correct bodies). NOT a missing idiom —
  an INTEGRATION wall (def-side sig / data-extern / unshared struct). We strand ~16 paid-for correct
  functions per wave; a fleet-safe integration-recovery pass would ~3.7× yield for 0 new drafting
  tokens. Next investment = integration tooling, not more drafting. Waves held per Drew.
2026-07-24 11:17:05 -06:00
Drew T 6253238c43 feat(phase-29): s15 fresh-crack wave — 6 more reach-138 cores banked (R22 140/140)
wave_binary over 24 fresh reach-138 ov_SC07_006 families -> 22 match_one MATCH / 2 near.
Whole-binary byte-gate banked 6: func_8014A51C func_801483E8 func_8014680C func_8017129C
func_80177AD4 func_801759D8. R22 clean-fleet 140/140 (engine_core.h reconcile edits verified
fleet-wide, §61).

- The s15 drafter-prompt fix HELD AT SCALE: all 24 winners persisted to the canonical path
  (vs s14's 3/24, recovered from transcripts). match_one isolation (per-pid --work) confirmed.
- Consistent integration ceiling: ~22 match_one MATCH -> 6 whole-binary banks (27%), same as s14.
  The 16 nears are def-side plumbing / data-extern / struct-def reconcile the gate ladder doesn't
  clear; fix_header_decl is off-limits (fleet-blind, §63 UPDATE). Integration recovery is the lever
  to improve before the next batch, NOT the drafter prompt.
- 6 genuinely-unmatched cores -> distinct-code movers (propagation follows).
2026-07-24 11:07:11 -06:00
Drew T f1fd8993bf feat(phase-29): permuter overnight harvest — 29 fresh cores banked + distinct-code 64837->64854
The grinder ran the targeted permuter sweep to EXHAUSTION (all 75 permuter-shaped candidates;
correctly skipped 1575 redraft/structural/integration). It banked 29 distinct functions autonomously
(gate_stage commit=True, byte-gated, fail-closed, §55b un-propagated), 39% conversion.

- All 29 are LOW-REACH (1-5) overlay-unique code in the 0x8017-0x8018 range — confirming the map's
  finding that the permuter-admissible set is the low-leverage tail (the high-reach near-misses like
  func_8014F3E8 close=1 reach=134 are redraft/structural, NOT permuter-shaped).
- Propagation of the 22 reach>1 banks filled only 1 (0x80180710 ×2); the rest are genuinely
  overlay-unique (siblings byte-diverge) — as predicted.
- R22 clean-fleet 140/140 (the 27 overnight per-binary-gated commits verified fleet-wide, §61).
- distinct-code 64837 -> 64854 (+17 unique fns); session total +22 unique (wave +5, permuter +17) —
  the first real distinct-code progress in many sessions. instr 79.4%, fn-count 88.66%, dedup 1874/0.
2026-07-24 09:39:07 -06:00
Drew T 8ea5202135 feat(phase-29): propagate 1 fresh core ×138 + the session's FIRST distinct-code gain
Of the 6 s14 fresh cracks, func_80136F3C propagated ×138 (func_801749C8 dropped as an
ov_SC07_006 straggler; 4 are §20 local-type-capped — future uniquify fodder, low-value
de-duplication per the SESSION-14 finding).

THE POINT (byte-verified): distinct-code UNIQUE count rose 64832 -> 64837 (+5) — the FIRST
distinct-code movement all session. Every other lever today (154-type lift, 6 uniquify cores,
MATRIX rename) was de-duplication and moved distinct-code by 0. These 6 are genuinely UNMATCHED
cores, so banking them ×1 is real new coverage. Percentage is flat (67.6%, denom 87459) but the
direction and the count are the validation the pivot to fresh cracks was correct.

Fleet: instr 79.3 -> 79.4% | fn-count 88.61 -> 88.65% | distinct-code count +5 | dedup 1873/0.
R22 clean-fleet 140/140 BYTE-IDENTICAL.
2026-07-23 22:58:47 -06:00
Drew T e9c950a30c feat(phase-29): fresh-crack wave s14 — 6 reach-138 cores banked ×1 in ov_SC07_006 (R22 140/140)
Ultracode wave_binary over 24 FRESH (unmatched, live=138) ov_SC07_006 families -> 20 self-reported
match_one MATCH. The whole-binary byte-gate (sole arbiter, R14/G3) banked 6:
  func_8014C6F4 func_801463A0 func_8012B77C func_80136F3C func_80156670 func_801749C8
The gap (20 claimed -> 6 banked) is the integration wall the drafters named: §63 header-decl
(void->s32), data-extern reconcile, struct-guard — a recovery pass follows. R22 clean-fleet 140/140
(the gate_stage ladder's engine_core.h reconcile edits verified fleet-wide, not just per-binary).

These are GENUINELY UNMATCHED cores (unlike the session's earlier propagation work), so once
propagated ×138 they move distinct-code — the metric that sat flat at 67.6% all session.

⚠️ WORKFLOW RECOVERY: the 24 drafters reported MATCH but wrote winners under scratch filenames;
only 3 func_<name>.c persisted. All 24 were recovered from the per-agent transcripts (Write calls
+ Bash heredocs) -> .run/drafts-s14r/. wave_binary.js drafter prompt hardened to force a copy-back
+ existence check as the mandatory final step so a future wave can't lose its winners this way.
2026-07-23 22:44:58 -06:00
Drew T d1a1d756e0 fix(phase-29): PsyQ MATRIX name hazard — the true 32B layout now owns the canonical name (R22 140/140)
Oracle (G1, Ghidra types get, /LIBGTE.H, psyq400.gdt): MATRIX = 32 bytes (short m[3][3] @+0x00,
long t[3] @+0x14, 2B pad after m); SVECTOR = 8B; VECTOR = 16B (long vx,vy,vz,pad).

- HAZARD CONFIRMED: the fleet-wide name `MATRIX` held {s32 m[3][3]; s32 t[3]} = 48 BYTES, not a PsyQ
  type at all, while THREE other names (MATRIX_c1, MATRIX_c2, MATRIX2) held the true 32B layout. The
  canonical name carried an invention; any future reader assuming PsyQ semantics would be misled.
- FIXED by pure consistent rename across 205 files: 48B invention -> MATRIX_L48 (KEPT — ~131 files are
  byte-correct against it, and "fixing" it to 32B would change sizeof/array stride hence codegen);
  the true 32B layout now owns MATRIX. R22 clean-fleet 140/140 BYTE-IDENTICAL.
- VECTOR left UNCHANGED on purpose: ours is 12B vs PsyQ 16B (missing trailing pad). I first called it
  dead — wrong, it has 1 live use (engine_core.h gte_ldlv0((VECTOR*)sp)). Offsets already agree so a
  fix is likely byte-neutral, but it is a LAYOUT change and bundling it with a rename would make an
  R22 failure ambiguous. Own R22-gated commit, later.
- engine_types.h gains an oracle-sourced GROUND-TRUTH block: real PsyQ layouts, which of our names are
  true vs invented, why MATRIX_L48 must not be "corrected", and the draft-time rule (address-suffix
  anything you invent — 7 of the 8 collisions this fleet accumulated were bare generic names).
- SCOPE HELD: renamed + documented; did NOT force existing code onto real PsyQ definitions.
2026-07-23 21:35:07 -06:00
Drew T 22af9ab2c5 feat(phase-29): 3 Vec8-freed cores ×138, R22 140/140 — and the honest ROI verdict on the cap
- Propagated 0x8012A464 / 0x8014FFDC / 0x801502EC -> 138/138 byte-identical, 0 stragglers, 3 new
  groups. R22 clean-fleet 140/140; dedup 1872/0; C1 237654/237654.
- FINDING (R14/R31): the §20 propagation cap was gating source-level DE-DUPLICATION, not coverage.
  The whole uniquify campaign (Buf+MATRIX+Vec8, 223 files renamed, ~1559 copies stripped, 5
  propagations, 4 R22 cycles) moved the fleet by +6 functions / +558 ins / -6 stubs and 0.00pp on
  all three headline metrics. The freed cores' members were ALREADY matched individually;
  propagation just consolidated them into shared macros. "Unblocked" != "unmatched".
- SESSION ATTRIBUTION: of -837 stubs / +0.3pp instr / +0.23pp fn-count, -831 stubs came from the
  FIRST batch (broad lift -> 13 cores). The uniquify campaign contributed -6.
- Roadmap B4 re-labelled: a maintainability item, not a coverage lever. Remaining camps
  (Handler/Blk8/V8/Prim/Prim_8016E7C8) are small and now known low-yield — opportunistic only.
- distinct-code sat at EXACTLY 3811442/5634875 = 67.6% at open and close. Fresh cracks are the sole
  mover of that number; point the next session there.
2026-07-23 21:25:39 -06:00
Drew T 23b9b57505 feat(phase-29): uniquify+lift Vec8 camps + propagate 0x8012E778 ×138; blocked queue 10 -> 7
Two units, committed together because they touch overlapping overlay .c files.

- PROPAGATE: 0x8012E778 (freed by the MATRIX uniquify) -> 138/138 byte-identical, 0 stragglers,
  1 new dedup group.
- Vec8 UNIQUIFY+LIFT: camp1 {s16 unk0,unk2,unk4,unk6} (8 bytes) x139 files -> Vec8_c1; the 180-file
  {s32 w[8]} (32 bytes) majority keeps the name. These are two genuinely DIFFERENT types that had
  been sharing one identifier across TUs of the same overlay — the case §64a exists for; reconciling
  them to one layout would have merged a 32-byte and an 8-byte struct. Both camps lifted, 319 local
  copies stripped.
- Pre-filtered on an overlay from each camp, then R22 clean-fleet 140/140 BYTE-IDENTICAL.
- Blocked core queue 10 -> 7 (0x8012a464, 0x8014ffdc, 0x801502ec freed). Session arc 13 -> 7 via
  uniquify (Buf -> MATRIX -> Vec8). Remaining camps all small: Handler, Blk8, V8, Prim, Prim_8016E7C8.
2026-07-23 21:15:58 -06:00
Drew T 72b7a7227a feat(phase-29): uniquify+lift the MATRIX camps — 77 files renamed, 655 stripped, R22 140/140
- uniquify_type --type MATRIX: camp1 {short m[3][3]; long t[3]} x71 jr-split TUs -> MATRIX_c1;
  camp2 {short m[3][3]; short pad; s32 t[3]} x6 -> MATRIX_c2; the 578-file {s32 m[3][3]; s32 t[3]}
  majority keeps the name. All three camps then single-def -> LIFTABLE -> lifted (655 local copies
  stripped).
- Pre-filtered on one overlay from EACH camp (ov_SC01_000 / ov_SC01_077 / ov_SC06_033) — a
  pre-filter is evidence only about what it filtered — then R22 clean-fleet 140/140 BYTE-IDENTICAL.
- Blocked core queue 11 -> 10 (0x8012e778 freed; propagation follows separately per §55b).
- NB: the R22 job was reported by the harness as exit -1 (session fork killed the shell wrapper
  after make completed). Verdict taken from the log's terminal "check-all: 140 passed, 0 failed of
  140", which is only emitted on completion. Read the gate's output, not the wrapper's exit code.
2026-07-23 21:05:35 -06:00
Drew T e393c320e6 feat(phase-29): VARIANT camps -> UNIQUIFY (not reconcile); validated on Buf, R22 140/140 (§64a)
MEASUREMENT CORRECTED THE PLAN. The checkpoint called for a "per-camp field-access reconcile";
measuring the camps refutes that: Vec8 = {s32 w[8]} (32B) in 180 files AND {s16 unk0..} (8B) in
139 files; MATRIX 48B/32B/32B; Buf 16B / 0x20+ / DrawEnv. These are DIFFERENT types sharing an
identifier across TUs of the same overlay — reconciling to a canonical layout MERGES them, the
same failure that broke 103 binaries on Prim. The right op is UNIQUIFY: rename the non-majority
camp (byte-neutral — a type name emits no code; TU-local by construction), which makes every camp
single-def and liftable by the existing lift_types rules.

- NEW tools/uniquify_type.py: deterministic camp ordering (file-count desc, then normalized text,
  so re-runs assign the same suffixes); majority keeps the name, camp n -> <T>_c<n>; rewrites ONLY
  files that DEFINE that camp (a file that merely USES the name gets it elsewhere and is untouched);
  \bT\b word boundaries so `Buf` never matches `Buf80153978`.
- VALIDATED on Buf (578/6/1 files): 11 identifiers across 7 files -> 3 camps LIFTABLE -> lifted
  (585 local copies stripped) -> R22 140/140 -> blocked core queue 13 -> 11 (0x8012ea90, 0x801749c8
  freed). Propagated 0x8012EA90 ×138; 0x801749C8 dropped (straggler in ov_SC07_006).
- YIELD, HONESTLY (P9): ZERO new matched functions. fn-count 88.61% / instr 79.3% / stubs 40281 all
  UNCHANGED; dedup 1867->1868, C1 +138. 0x8012EA90's members were ALREADY matched in all 138
  overlays — the propagation consolidated duplication into one shared macro (DRY), not coverage.
  The value is the PROVEN RECIPE + the queue moving 13->11, not the numbers.
- dedup_propagate (R32): the skip line printed a COUNT and no names, and aggregated three unrelated
  causes into n_local — a body skipped merely for a `//` comment (macro-unsafe, 1-line fix) read
  identically to one genuinely using an overlay-local type. Now named and split by cause.
- cookbook §64a (uniquify-vs-reconcile + the validated recipe + remaining camps by cost).
2026-07-23 20:51:42 -06:00
Drew T 3642b5458a feat(phase-29): the type-lift's payoff — 13 cores propagated ×138, −831 stubs, R22 140/140
With the §20 local-type cap lifted (commit:0863), dedup_propagate --auto-from planned 17
self-contained cores that were previously skipped "not self-contained (local types)".

- BANKED: 12 cores via --auto-from + func_80175308 (propagated separately, 138/138) = 13 ×138.
  func_80175308 is the PROVABLE unblock — the core the SESSION-13 checkpoint named as
  local-type-blocked. No claim is made that all 17 were unblocked by the lift; measuring that
  needs a pre-lift re-scan I did not run (P9).
- 5 correctly DROPPED as cross-overlay stragglers (0x8012A018, 0x80172C50, 0x80173A60,
  0x80144090 in ov_SC01_000; 0x801495C4 in ov_SC07_006): h_exact sharing is all-or-nothing and
  those overlays' bytes diverge. --recover NOT used (the documented quadratic thrash hazard).
- GATES: R22 clean-fleet 140/140 BYTE-IDENTICAL (2nd full cycle this session); make report green;
  dedup-check 1854 -> 1867 validated / 0 failed, C1 236964/236964; 0 NON_MATCHING (G4).
- FLEET: instr 79.0 -> 79.3% | fn-count 88.38 -> 88.61% | INCLUDE_ASM stubs 41112 -> 40281 (-831).
  distinct-code stays 67.6% — correct: propagation replicates already-distinct-matched code;
  only a fresh crack moves that number.
- STILL BLOCKED: 13 cores "not self-contained (local types)", blocked by exactly the 8 deferred
  VARIANT entities (MATRIX 3-def, Buf 3-def, Vec8, Prim, Handler, Blk8, V8, Prim_8016E7C8).
  Next lever = a per-camp FIELD-ACCESS RECONCILE, not a lift (lifting them blindly is what broke
  103 overlays earlier this session).
2026-07-23 20:18:50 -06:00
Drew T 5ab80517de feat(phase-29): broad §20 type-lift lands — 154 types fleet-wide, R22 140/140 (§64)
The 3-session-carried blocker ("needs collision-vetting + -O0 strip precision") was
misdiagnosed on all three counts; fixing the instruments first (R35) changed every answer.

- (1) the "case-variant collision" is a TAGGED TYPEDEF counted twice with OVERLAPPING spans:
  the inner span starts at `struct` so it emits a VARIABLE definition, the alias is redeclared,
  and the highest-first strip leaves the outer end offset STALE -> over-deletes past the span.
  MEASURED 13 pairs / 6142 occurrences / 0 standalone tags. build_engine_types.resolve_type_defs()
  is now the ONE shared model (R33) + assert_disjoint() enforces span disjointness (R32).
  The case-insensitive exclude was a heuristic over a structural fact — it would also have
  wrongly dropped the legitimate Obj/obj + Vec/vec pairs. Key by (kind, name) — the C namespace.
- (2) the "-O0 strip precision" bug is a VISIBILITY bug: ov_SC01_077_o0.c is the 1 TU of 3226
  that deliberately omits engine_core.h, so the strip DELETED its types; `multiple definition of
  D_801DAA08` was 3 steps downstream (undeclared -> parse error -> implicit int -> tentative def
  -> link collision) and named a symbol no diff touched. bet.type_visible() derives the visible-
  header set from the include graph and keeps such defs local, named.
- (3) a third blocker, introduced this session and caught by R22: --candidates classifies per
  ENTITY but emits per NAME, so passing `Prim` dragged in the deferred VARIANT `typedef Prim` and
  repointed 103 overlays at the header's different layout. Compiled clean, per-binary pre-filter
  green, R22 37/140 — the 103 failures were EXACTLY the 103 Prim-stripped overlays (set equality).
  Fixed by the strip invariant "remove a local def only if what becomes visible is TEXTUALLY
  IDENTICAL", placed at the MUTATION so a selector bug cannot reach the source.
- lift_types.py: (kind,name) entity keying, --candidates derived selector (retires the ad-hoc
  102-type pipeline), divergence + visibility reports, whole-line strip (411 whitespace-churn
  lines -> 0), complement-based single-pass rewrite (no mid-loop offset mutation).
- RESULT: 154 types lifted, 2958 files stripped, engine_types.h +510 lines. R22 clean-fleet
  140/140 BYTE-IDENTICAL; tools-health OK (corpus 0/0, cdecl ALL GREEN, audit-binaries 140,
  dedup-check 1854/0, C1 235170/235170); 0 NON_MATCHING (G4). Metrics unchanged 79.0/67.6/88.38
  — honest: a type-lift banks no functions, it unblocks the NEXT propagate.
- DEFERRED + NAMED: 8 VARIANT entities (MATRIX 3-def, Buf 3-def, Vec8, Prim, Handler, Blk8, V8,
  Prim_8016E7C8) = the per-camp field-access reconcile, the remaining hard part of roadmap B4;
  14 carried tags; 5 types kept local in the -O0 TU.
- cookbook §64 (the three laws + the pre-filter lesson: a pre-filter is evidence ONLY about what
  it filtered — ov_SC01_077 passed the Prim-broken run too; pre-filter on a binary that FAILED),
  decision-log (R31), CURRENT_PHASE.md log.
2026-07-23 19:54:19 -06:00