The derived-offset recompute swept the whole func_8013D53C family: 119 banked / 0 failed on top of
the 4 earlier; func_8013D53C is now stubbed in ZERO overlays. R22 clean-fleet 140/140 BYTE-IDENTICAL;
tools-health OK; dedup 1886/0; 0 NON_MATCHING (G4).
RECIPE (and it is NOT the return-axis recipe — sampling caught this):
§84 derived-offset -> per-member literal recompute AND the gate_stage ladder.
With the recompute alone the sample was 0/8; through the ladder it was 3/3, then 119/119.
Had I reused the return-axis recipe (plain harvest_verify, which banked 272/272 there) I would
have swept 123 members to zero banks and mis-concluded the fix was wrong. Probe-before-scale.
METRIC FINDING worth carrying: this harvest moved instr +29,280 AND distinct-code +27,840, while the
return-axis harvest moved instr +26,928 and distinct-code +0. §84-class members are byte-VARIANTS so
each is a new unique function; propagation-class members were already counted once via their shared
exemplar. => §84-class work moves the RE-COMPLETENESS number; propagation moves only the DISPLAY one.
Session fleet: 80.6 -> 81.0% instr · 68.2 -> 68.8% distinct-code · 89.18 -> 89.30% fn-count.
THE §85 WIDEN PAID OFF AS PREDICTED. It is a ONE-TIME fleet edit, so once committed the
`conflicting types` blocker was gone for EVERY member of both families at once:
- sample 8 first (probe-before-scale): 8/8 banked with PLAIN harvest_verify, no ladder needed
- full sweep: 264 banked / 0 failed across 132 overlays; 10 skipped as not-stub
- total 272 members ~= 27k ins, ZERO agent tokens
R22 clean-fleet 140/140 BYTE-IDENTICAL; dedup 1886/0; 0 NON_MATCHING (G4).
Fleet: instr 80.6 -> 80.8% (10,589,503 -> 10,616,431, +26,928) · fn-count 89.19 -> 89.26%.
distinct-code UNCHANGED at 68.3% — propagation moves the DISPLAY metric, not the RE-completeness
one (the SESSION-19 split, reconfirmed).
§84 RECOMPUTE now implemented in tools/family_remap.py (fix_derived_offsets), wired into all three
apply_remap call sites as a PRE-pass on the exemplar body (the literal is ambiguous as a substitution
token, so it cannot be a table entry):
correct_literal = mapped(aliased_sym) - mapped(base_sym)
Verified by negative control: the hand-solved case recomputes 0x20 -> 0x18 exactly, and a site whose
target endpoint is NOT a mapped symbol is left byte-for-byte alone AND REPORTED in info
["derived_offsets"] (R32 — a silent skip is a defect, and a silent skip is how this bug survived).
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%.
- dedup_extend banked 132 / 179 planned across 135 binaries: func_80174CB0 VERIFIED in 132,
FAILED in exactly 3. 123 ins × 132 = 16,236 ins.
- THE PREDICTION HELD TO THE OVERLAY. The blocker breakdown across the original 134-binary sweep
was 131 class-B (func_8012F14C arity split) / 3 class-A (func_80012ABC, census 73 s32 vs 7
s16). Fixing class B alone banked 132 and left 3 -- precisely the class-A set. A diagnosis that
predicts WHICH members will still fail, and is right, is much stronger evidence than one that
explains failures after the fact; same shape as §75b predicting that the 3 stuck members would
be exactly the 3 files carrying the __volatile__ spelling of SHB.
- FLEET: instr-weighted 80.2% -> 80.3% (10,539,723 -> 10,555,959); fn-count 89.14% -> 89.18%;
distinct-code 67.7% UNCHANGED (propagation moves coverage, not distinct-RE -- fresh cracks are
the only lever there). dedup 1886 validated / 0 failed, C1 coverage 239,604/239,604.
0 NON_MATCHING (G4).
- R22 clean-fleet: make clean && extract-all && check-all -> 140 passed, 0 failed of 140.
- cookbook §75c committed with this batch. The 3 residual overlays need the 7 `s16` func_80012ABC
decls normalized -- worth 3 overlays only, so do it only if trivially cheap.
- dedup_extend banked 157 / 478 planned across 135 binaries: func_80165CA0 (99 ins) ×135
(~+0.10pp) + 22 other functions ×1 picked up in the 3 overlays the first sweep excluded.
- FLEET: instr-weighted 80.1% -> 80.2% (10,525,534 -> 10,539,723, +14,189 ins); fn-count
89.09% -> 89.14%; distinct-code 67.7% (unchanged — propagation moves coverage, not distinct-RE).
dedup 1886 validated / 0 failed, C1 coverage 239,472/239,472. 0 NON_MATCHING (G4).
- R22 clean-fleet: make clean && extract-all && check-all -> 140 passed, 0 failed of 140.
- §75b — extraction lifts `extern`s but NOT file-scope `#define`s, so a body matched with a macro
in its preamble compiles only where that overlay's define is in scope ABOVE the splice point.
Signature is a LINK error (`undefined reference`), never `conflicting types`: an unexpanded
SHB(x) parses as a call to an undeclared function. The diagnosis PREDICTED the membership —
the 3 stuck members are exactly the 3 files carrying the __volatile__ spelling of SHB, i.e. the
function's own preamble still sitting above its own instantiation.
- R14/R35 IN ACTION: the full-sweep census REVERSED the ranking I had just committed. I put the
class-A normalization first at "~+0.13pp if it reaches ×138"; measured across all 134 it is
worth 3 overlays (func_80012ABC 3, func_8012F14C 131). The cheap win was the one I ranked
third. §75a's "collect across the whole sweep before scoping" earned itself immediately.
- NEXT (specified, not guessed): func_80174CB0 is class B on func_8012F14C (1944 `(s32)` vs 968
`(s32,s32,s32)`). The macro carries the 3-param prototype; the failing TU declares the 1-param
one FIRST (ov_SC01_001: TU@328 vs instantiation@2616) -> two prototypes, different arity ->
reject. Per cdecl.compatible's MEASURED rule a K&R `extern void func_8012F14C();` is accepted
BOTH ways round here (prototype-first + `()`-second always; `()`-first + prototype-second when
no param default-promotes, and s32 does not) -> it should satisfy both populations in either
order. One-line probe on the carried decl, byte-gate the 3 members, then extend.
- THE NORMALIZATION PAID: one `dedup_extend --binaries <the 134 excluded>` banked 134/400
planned -- func_8014F3E8 VERIFIED in ALL 134 -> ×138 total (+4,288 ins), no drafting at all.
A 4-overlay island became full fleet reach because the carried extern finally agreed.
- FLEET: instr-weighted 80.0% -> 80.1% (10,509,526 -> 10,525,534 = +16,008 ins, exactly the
projected 84×138 + 32×138); fn-count 89.02% -> 89.09%; distinct-code 67.7% (unchanged, as
expected -- propagation moves coverage, not distinct-RE). dedup 1884 -> 1886 validated / 0
failed, C1 coverage 239,315/239,315. 0 NON_MATCHING (G4).
- R22 clean-fleet: make clean && extract-all && check-all -> 140 passed, 0 failed of 140.
- §75a — "PROPAGATION-CAPPED" IS AT LEAST THREE CLASSES, and the classifier names which:
A minority spelling `conflicting types` + a lopsided census (1710 vs 4) -> normalize, cheap
B genuine arity split same message, TWO real populations (func_8012F14C: 1944 `(s32)` vs
968 `(s32,s32,s32)`) -> the §29 loose-typing wall; a K&R `()` MAY satisfy
both but is order-dependent -> PROBE, do not normalize on a guess
C missing extern `undefined reference to 'SHB'` -- a LINK error, unrelated to types
The discriminator is one grep (census the symbol cc1 named) and it decides the remedy.
- R14 self-correction recorded: I predicted func_80174CB0 was "the identical class". It is class
A in KIND but on DIFFERENT symbols, and different ones per overlay (func_80012ABC at
ov_SC01_000 where the minority is on the TARGET side; func_8012F14C at ov_SC01_001 = class B).
One member's error names one blocker, not the blocker set -- collect the classifier's line
across the whole sweep before scoping a fix.
- func_80174CB0 (×3) and func_80165CA0 stay capped, each now with a named cause and a named next
probe -- not a wall verdict.
- 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.
- 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).
- 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.
- 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.
- 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.
- 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.
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.
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.
- 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.
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.
- 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.
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).
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).
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.
Builds tools/lift_types.py: targeted fleet-wide lift of a SPECIFIC type list into
src/shared/engine_types.h, using build_engine_types' brace-aware parser (NOT the
[^;]* regex that under-counted multi-field structs — R35, caught twice). It picks
each type's CANONICAL (majority) def across the fleet, writes it once to the header,
strips every local copy, and reports variant overlays. The whole-binary gate (R22)
is the byte-arbiter.
Applied to the 2 CLEAN types the §20-blocked fresh-138 cores need:
- Mat32 (138 canonical + 1 copy-only draft variant in ov_SC07_006) + Cam8012E138
(unique) -> lifted, 139 local copies stripped. R22 clean-fleet 140/140.
- Unblocks func_8012B4B8 + func_8012E138 for x138 propagation (next).
DEFERRED (variant-heavy, high-risk — fleet genuinely split): MATRIX (3 defs), Vec8
(2 near-even 180/139), Buf (3), M8 (2) — lifting them would force ~929 files to one
camp's field layout and break variant field-access. Needs a per-camp reconcile pass.
func_80175308/func_8012A1BC still blocked (need those or other types).
Propagation of the 7 fresh-138 cores banked in commit:0855. Only the 2 self-contained
ones cleared all three integration walls:
- func_80130C08 x138, func_80137178 x138 (+274 stubs). R22 clean-fleet 140/140.
The other 5 are blocked, each by a different integration wall (drafting was solved —
all 7 bodies byte-matched; INTEGRATION is the bottleneck):
- func_8012B4B8/func_80175308/func_8012E138/func_8012A1BC: §20 local-type
propagation cap ("not self-contained") — need build_engine_types type-lift to
propagate x138 (roadmap B4; ~+552 stubs when unblocked). Stay x1.
- func_80169228: per-member divergence (whole SC03 cluster byte-diverges) — a
genuine partial family; --recover thrashes it (killed + reverted). Stays x1.
decision-log: fix_header_decl fragility correction (shared multi-caller decls break;
gate_stage's call-site-cast is the integration spine, not header-decl rewriting).
Bounded probe (SESSION-13, token-free) that REVERSED the same-session "fresh
reach-138 well is spent" verdict. Target func_8014CD80: 138 live, 0 matched, NO
DEFINE macro, a universal body (only universal callees + param offsets, zero
overlay-local D_* refs), clean MATCH draft from batch-1.
- Blocker was a def-side header decl: engine_core.h DEFINE_func_8014CD0C()
forward-declares it `void func_8014CD80(s32,void*,void*)` while the byte-true
def is `int func_8014CD80(s32,u16*,u16*)`. gate_stage's arity pre-pass is
param-COUNT-only (misses return/ptr-type); §54 reconcile_def_sig fixes the
wrong direction.
- One byte-neutral header edit (void->int, void*->u16*; call site passes u16[3]
arrays + ignores the return -> codegen unchanged) -> harvest_verify banked x1
BYTE-IDENTICAL -> dedup_propagate --addr propagated 138/138 overlays
byte-identical (live 138->0) -> R22 clean-fleet 140/140.
- Fleet 78.7->78.8% instr, 88.22->88.26% fn-count from this one family;
tools-health green (dedup 1851/0).
Quantified market (decision-log 2026-07-23): of the 75 fresh (>=100-live)
families, 46 carry an engine_core.h caller forward-decl, 38 SIMPLIFIED = the
func_8014CD80 pattern -> each a candidate x138 (~+1.5-2.8pp instr). NEXT: build
tools/fix_header_decl.py + a fresh-family wave. func_80165CA0's 0/135 was a
non-universal BODY (different failure mode), not this blocker.
- binary-aware crack wave (new tools/workflows/wave_binary.js): 8-target calibration
over ov_SC06_018 substantial stubs, 7/8 match_one MATCH
- func_801365B8 (155, reach 133): cracked FRESH in ov_SC06_018, swept 132/132 siblings
via family_sweep --hseq --source ov_SC06_018 --allow-pins -- SESSION-10 refused this
family 0/133 from an ov077 exemplar. THESIS CONFIRMED (fresh exemplar unlocks it).
- func_80133AB0 (137, reach 137): cracked fresh + banked x1 (+ a byte-neutral s17a-1
cast reconcile of banked caller func_801343C4), but the family sweep FAILED 0/136 even
from the fresh exemplar (reverted clean) -- THESIS REFUTED for this family.
- FINDING (R14/R31 -> decision-log): the fresh-exemplar sweep is FAMILY-SPECIFIC, not a
blanket mechanical x137. A fresh crack is necessary but not sufficient; the byte-gate
arbitrates each family (~50% on this 2-family sample -> discount the ~1.5pp estimate).
- tooling (R33): family_sweep --source override now searches matched_members (a fresh
member leaves 'members' after a sig-regen); cdecl._depth0_spans consumes backslash
line-continuations so a raw-draft #define macro no longer trips audit-cdecl.
- R22 clean-fleet 140/140 byte-identical; tools-health green (dedup 1849/0, C1 234615);
0 NON_MATCHING. fleet 78.4->78.5% instr / 67.1->67.5% distinct / 88.14->88.18% fn-count.
PROPAGATION (§55b, its own targeted batch): dedup_propagate --addr 0x80141B90 --recover
-> "138 overlays byte-identical after propagation"; 117 remaining stubs -> 0; 1 new
dedup group. This was the ONLY one of the 21 directed-run banks worth propagating.
THE REPRICING (R14 — measure a bucket's VALUE, not just its conversion rate):
the directed run converted 27% (21/77) but moved the fleet ~0.03pp, because h_exact
reach of the 21 is: func_80141B90=138, TEN at reach-1 (nothing to propagate), rest 2-10.
Instruction-weighted, the ENTIRE permuter bucket is worth ~0.36pp at 100% conversion.
The mechanism is validated; the fuel was small. Priced frontier (ins-weighted / 13.08M):
LENGTH-DRIFT |d|<=2 472,178 ~3.6pp (339 fns) <- the real permuter-adjacent lever
integration 419,162 ~3.2pp (305 fns) <- Task 14's ladder
WIDTH 71,593 ~0.55pp (45)
permuter (current) 46,571 ~0.36pp (74)
BRANCH-POLARITY 9,462 ~0.07pp (22)
So WIDTH/BRANCH-POLARITY are NOT worth prioritizing; my earlier "~200 candidates"
framing undersold LENGTH-DRIFT 10x and oversold WIDTH.
NEW: permuter_weights._LENGTH profile (perm_temp_for_expr/perm_expand_expr are the only
passes that change instruction COUNT; the reorder/decl-order levers that dominate the
regalloc+schedule profiles cannot, so they are down-weighted here) + residual_class
._drift_route (|d|<=2 -> permuter/`length`, larger stays structural — same class,
opposite tool) + classify() accepts a PROFILE NAME directly (the measured profile beats
re-parsing a free-text label). 17 unit tests green.
grinder: --profile filter (probe ONE residual class's conversion) + a PERSISTENT attempt
ledger. `tried` was in-process only, so every fresh --once run re-permuted the previous
run's losers — the permuter is deterministic given (base.c, target.o), so that CPU can
never produce a new win. Measured: a 20-target probe drew 19 already-tried targets.
Keyed by draft_sig so an improved draft legitimately re-opens the function.
Propagated the func_8015C32C jump-table exemplar to 110 more overlays via
jtbl_family_bank (carve + ld_interleave + remap, per-sibling whole-binary gated).
Run halted by an uncaught exception at member 111 (ov_SC06_018); 110/119 attempted
banked clean. Remaining ~19 members to follow.
Exemplar cast (§56b) unblocked propagation: the bare func_80161208(p) call
relied on ov_SC01_077's no-proto decl, but member TUs carry a (void) prototype.
Casting the call member-proofs the templated body. All banks whole-binary byte-gated.
Propagated from the ov_SC01_000 exemplar (void func_8013D9B0(int param_1), a 141-ins
handwritten GTE color-interp loop w/ $s0-$s4 register pins). Each sibling TU carries
extern-void-(void) self-decls of func_8013D9B0 that conflict with the (int) def; NSD is
unsafe here (it reads the else-func_8013D9B0(N) call statements as decls and mis-casts,
§57a), so the self-decls were mechanically reconciled to K&R empty-args (byte-neutral,
compatible with the (int) def + every 0-arg/1-arg/fn-ptr-cast call site) across 132 TUs
before the sweep. 135/135 members banked, 0 failed (pins templated clean across the
structurally-identical engine siblings).
Propagated from the ov_SC01_000 exemplar. remap_hseq's gather_externs synthesizes a
non-volatile `extern u16 D_8011511A;` per sibling, which defeats the §18 volatile-strip
CSE (cast reads reload instead of folding to one load) -> byte-DIFF. Every sibling TU
(jr_8013FFD8) already declares D_8011511A volatile at file scope via the banked
func_801418F8, so the fix is to strip the draft's own decl and let the cast-at-use over
the TU's volatile decl produce the single-load match. 135/135 banked, 0 failed.
Both banked fully (0 stubs remaining). func_8013EF88 templates clean because E4 (its
matching-critical local typedef) is already file-scope in every target TU via the
already-banked sibling func_8013EE10. func_8013D8FC's $s0-$s3 register pins template
fine across the structurally-identical engine siblings. 271/271 members, 0 failed.
hseq family sweep of 2 absent-family cores, templated from the clean ov_SC01_000
bank (s16-array + cast-at-use spellings) instead of the ov077 heavy-struct exemplar
that pick_exemplar defaults to. 258/272 members banked; 14 SC07-layout residuals.
These reference a per-overlay tail work-buffer whose base address DIFFERS per
overlay (h_seq relocated data). remap_hseq keyed the byte-OFFSET addresses
(D_801D9C21..) not the base symbol D_801D9C20/D_801D9C60 the exemplar C uses, so
it left them unresolved -> 0/137. Per overlay: base = symbol_map[D_801D9C21]-1;
declare dlabel D_<base> in config/symbols.<ov>.txt (byte-neutral, re-extract emits
the linker def), remap D_801D9C20->D_<base1> / D_801D9C60->D_<base2>. 3 SC07 stragglers
needed the carried ApplyMatrixSV/RotMatrixYXZ externs dropped (TU already declares
them with a different sig -> conflicting types). Each gated whole-overlay byte-identical.
The h_seq remap dropped the exemplar's local `struct W4` type; without it the
per-sibling struct-copy lowered to a differently-sized memcpy -> byte-DIFF (0/137).
Prepending `struct W4 { u32 w; } __attribute__((packed, aligned(1)));` to each
member draft restores byte-identity. Gated per-overlay via harvest_verify.
The hexR=138 dedup core (banked ×1 in commit:0716) -> dedup_propagate --addr
0x80150170 --source-overlay ov_SC01_077 --recover: 138 overlays rebuilt
byte-identical, 1 new group registered in config/dedup.us.yaml (0 stubs left).
~+13k ins (95 ins × 137 new members). (First attempt SIGTERM'd mid-gate at the
2-min timeout -> reverted the half-gated state, re-ran clean fail-closed.)