func_8017D960 (3,338 ins): 3,334 ins drafted, 98.8% register-masked-identical, 88.3% byte-aligned,
byte-exact prologue AND epilogue, exact 0x320 frame, same 10 saved regs, identical ~110 stack slots,
SYMS-OK. NOT a match (G3) -- but an order of magnitude closer than behemoth #1.
- THE LEVER: it is the LIT VARIANT of func_8017CA80, the 952-ins renderer immediately above it in the
same file (already matched). Diffing the sibling gave ~90% of the C free and a 3334/3338 draft on
the FIRST compile. GENERALISED: before mapping any giant, grep for an already-matched adjacent
function that is the same routine. One grep can replace days of analysis.
- §69 PARTLY REFUTED: its law 1 (write whole body coarsely -> correct frame/saved-reg set) CONFIRMED
and decisive; law 2 (measure region-aligned) confirmed but its TOOL did not transfer (per-switch-
case); its HEADLINE ("the deliverable is the map, not a match") is refuted for non-dispatchers --
§69 was derived from a 359-call dispatcher with no sibling.
- TOOL SUPERSESSION: .run/giants/b2_mask.py + b2_full.py = shape-agnostic masked sequence aligner
(structural AND byte numbers). Replaces s18_regions_comparator.py for all giants.
- FAMILY: func_8017CD9C + func_8017E778 are the same 3,338-ins fn with only 3 light-descriptor
symbols changed -> one crack templates x3.
- MY OWN PROFILING ERROR, recorded (R14/R35): I briefed "no switch" from a sltiu jump-table grep; the
switch is a COMPARISON TREE (23 slti). A jtbl grep is not a switch detector.
- 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.
First attempt on the game's largest unmatched function. No match (never the goal); the deliverable
is the map, and every claim is byte-verified against the target .s.
- STRUCTURE: an actor state machine, not a straight-line giant. 21-case switch via jtbl_801F4CE4
(sltiu 0x15); 359 jals to only 37 DISTINCT callees (verified); 48-ins preamble + 19-ins shared tail.
- THE FINDING: it decomposes into repeated templates, not 5122 unique instructions —
35 instances of one "spawn-effect" packet (~1400 ins, crack one -> 34 free),
7 "wait/countdown" (already reproduced at 0 skeleton diffs), 12 "HUD/text",
plus twin cases (0≈3, 1≈4). Only 3 cross-jump edges couple anything.
- TWO GENERAL LAWS FOR GIANTS, measured: (1) register pressure is GLOBAL, so a partial draft gets
10 callee-saved regs instead of 8 and a matching PREFIX is structurally unavailable — write all
cases coarsely first, then refine; (2) match_one's global number is meaningless on a partial giant
(666 vs 5122) — measure REGION-ALIGNED instead.
- NEW REUSABLE TOOL: .run/giants/s18_regions_comparator.py (region-aligned skeleton comparator, works
on any giant). Caveat travels with it: masks register numbers + jal targets, so it proves STRUCTURE,
never closeness; finish on the whole-binary gate (G3/P9).
- 2 idioms cracked in passing (the D_x[t+K] constant-fold needing a separate index statement; the
(s16)*(u16*)p + /455 magic-0x90090091 form).
- VERDICT: tractable but a ~2000-line WRITE, not a hard puzzle — no scheduler wall, no unsteerable
regalloc. Recipe for the next attempt recorded.
- artifacts preserved under the tracked .run/giants/ path (.gitignore now allowlists *.py there).
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.
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.
Builds the guard SESSION-17 left as a TODO after the func_801463A0 `_s`-alias trap, where a draft
invented extern aliases no symbol table defines, read MATCH under rtu_match, and could never bank.
- diffs the symbols a draft's object references (reloc records) against the target .s's
%hi/%lo/jal set; reports MISSING (invented-alias signature) and INVENTED separately.
- fills a real hole: match_one/masked_diff compare relocation-MASKED words (object-vs-.s is
symbol-agnostic BY CONSTRUCTION) and rtu_match COMPILES WITHOUT LINKING -- so both are
structurally blind to this class. R34: a second oracle that can disagree with the first.
- NEGATIVE-CONTROL PROVEN: with one data extern renamed to an invented alias, match_one reports
the SAME 14 mismatched as the correct draft; symcheck exits 1 naming both symbols.
- --c compiles via match_one so the pinned triple/flags can never drift (R33); or --obj.
- applied to the live func_8014D820 close=14 draft: 12/12 symbols agree, so a match there will
link cleanly -- the §65c class is ruled out for it in advance.
- cookbook §67a + SETUP tooling-inventory row (R21). Necessary condition, NOT a match oracle:
still finish on the whole-binary byte-gate (G3/P9).
- PROBE ANSWERED (the SESSION-17 open item): a0's first use is body-line 41, a1's is 28
-> use order ALREADY matched the target's birth order while birth order was inverted.
The §31 RC-1/RC-2/RC-3 first-use-order hypothesis is REFUTED for this class; decl order
is inert too. Both retired, do not re-buy.
- ROOT CAUSE (byte-read): gcc schedules the arg->pseudo entry copies as ordinary in-block
insns and hoists an unconstrained one to the earliest slot. Mine raced `move $s4,$a0` to
idx 2, which freed $a0 to become the early load temp (target: $v1) and left the target's
idx-12 load-delay slot unfilled. The "wrong temp reg", the mirrored `sw $sN`/`move $sN`
prologue and the +1 instruction were ONE defect in three costumes.
- THE LEVER (cookbook §67, written in-session per R30): an UNPINNED launder
`__asm__ __volatile__("" : "=r"(pv) : "0"(p));` placed at the statement where the target's
copy lands, later uses rewritten to pv. Zero instructions. Prerequisite: collapse redundant
pointer aliases first (the two-pseudo split made gcc serve the first use from the incoming
arg reg). Placement is the knob and is NOT linear -- sweep 3-4 anchors (3-statement plateau).
- 25 -> 16 by reading; permuter_ils (REGALLOC, 10x180s) 16 -> 14 in cycle 1 then x9 unchanged
(§66d-3: a repeat means stop). Its edit is semantics-preserving (hoists desc.y+0x10) and
cleared the idx 271/272 cluster. Seeds tracked: s18_func_8014D820_close{16,14}.c.
- MEASURED NEGATIVES recorded so they are never re-bought: pinning the laundered var to $s4
(pre-stages via $t0, 305 ins); pinning the reused temp t to $3 (287/303); an artificial
"r"(t) dependency (inert -- gcc still hoists); laundering after the beqz (305); dropping the
a2 pin (29); wholesale pos/desc reorder or sinking z0=ent->z (+1 ins).
- NOT banked (G3) -- residual 14 in 2 clusters: idx 21/22 scratch $v1 vs $a0, idx 84-98 the
desc.y/currentLocationId schedule. SCHEDULE-weighted ILS running from the close=14 seed.
- Also measured: func_80140958 260/260 54 - func_80176734 371/371 56 - func_80176218 328 vs
327, whose +1 is NOT §67 (it hoists a global address into an extra callee-saved $s6 that the
target rematerializes -> the §17 array-decay lever).
- 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.
- Ladder-only recovery (no demacroize, so these are NORMAL banks that can propagate x138):
func_8012B4B8 (84 ins) + func_80169228 (105 ins), both confirmed gone from src, not read off
the report (§55b trap 4). 2 of 5 candidates.
- DRIFT-CHECK EARNED ITS KEEP (R14): the backlog's close=0 was wrong for 2 of the 7 spine entries —
func_8012CC88's draft is for ov_SC07_006 and is 13 off in ov_SC01_077 (the documented
'backlog drafts are overlay-specific' caveat, now confirmed), func_80158638 is 2 off, not 0.
- The cross-file churn is gate_stage's own fix_arity_callers --any-proto pass on the banked fns'
caller decls (byte-neutral no-proto widening; comments preserved, H5). R22 clean-fleet 140/140.
- Diagnosed the 3 non-banks with blocker_probe (both oracles agree 3/3): func_801463A0 = real-cc1
MATCH in its own TU yet gate-rejected (the §65c rtu-vs-gate divergence); func_80156670 and
func_80174CB0 = local_type collisions on 'S8' and 'MATRIX' -> uniquify (T0, draft-only).
- Stale spine claimed 223 live stubs / 870,668 ins and ranked 3 already-banked fns in its top 7
(func_801325B8, func_8014ADE0, func_8012CC88-in-077 verified 0-live in src).
- TRUE state: 160 live stubs / 583,077 ins remaining gain.
- SHARP EDGE (R35): worklist.py --assert-partition exits at the assertion and does NOT rewrite the
doc, so 'regenerating' with it leaves the stale file in place and still exits 0. Run it bare to write.
func_80177940 was structural(OPCODE-MIXED) at close=5 and the permuter still took it 5->1: the class
names only the DOMINANT residual. Policy: at low closeness run the search anyway (CPU, not tokens);
at high closeness read first.
- The two halves of a 'not steerable from source order' note belong to different tools: the permuter
closes INSN_LUID scheduler ties a hand sweep provably cannot enumerate; the reader closes semantic
fixes the mutation set cannot invent. residual_class's bucket ([permuter] vs [structural]), already
printed by match_one, is the free handoff signal; its profile feeds p16_permute --klass verbatim.
- Diagnose from a byte-verified SIBLING, and test the naive reading first: deleting the redundant mask
alone COLLAPSED the copy (100 vs 101 ins), which is what proved a distinct PINNED register was needed.
- §66d-1: the LOOP transfers between giants, the PIN does not (the same move cost func_8014D820
285 mismatched). §66d-2: setup() wipes the scratch dir; the cleanup pkill was global.
- 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.
The exclusion set built from the backlog alone missed .run/giants/ (false work: ~2.6M tokens of
characterized permuter-only drafts would have been re-bought); corrected to scan .run/**/func_*.c it
swept in the Ghidra-C INPUT cache (false exhaustion: 5,488 phantom attempts). Records the query that
actually answers 'is there fuel' and the structural point that high-reach fuel is CREATED by a
per-overlay Ghidra-C prefetch, not found.
- THE FREE TEST (cookbook §66): reverted func_801778A8's bank to its INCLUDE_ASM stub (stub state
rebuilds BYTE-IDENTICAL 7ca772be — a faithful revert proves itself; needs `make extract` first,
the R22 corollary) and re-banked it THROUGH recover_integration.py --commit --r22.
pass1 1/1 -> exact restore -> pass2 1/1 -> commit commit:0928 -> R22 140/140 -> report.json.
Bank confirmed from SOURCE (stub gone), never the report (§55b trap 4). EQUIVALENCE: git diff vs
the pre-revert commit = ONE blank line (mine) -> the driver reproduced SESSION-16's state exactly.
- DEFECT 1 (SAFETY, found by reading before firing): PROPAGATION is a fleet-tier write
(dedup_propagate --auto-from -> src/shared/engine_core.h + up to 138 overlay .c) that was both
UNDECLARED and the DEFAULT, so --max-tier binary still permitted the widest write in the toolchain.
assert_write_set cannot catch it (it runs before the gate; under --commit git status is clean).
FIXED up front: propagate now requires --max-tier fleet AND --r22, and is REFUSED after a
demacroize stage (those banks are x1 by construction; --auto-from would re-macroize and undo them).
Both refusals negative-control-tested, exit 1. The "standing hazard" is now a refusal.
- DEFECT 2 (METRIC): gate_stage scraped the fleet % via a progress.py label that no longer exists ->
fp=None -> 50 gate commits recorded "fleet None%". Now reads FLEET instr-weighted (legacy fallback
+ loud stderr warning if neither matches); parses 79.6.
- STALE DIGEST (R14): docs/progress.fleet.md at HEAD disagreed with HEAD's own source by 45 in the
dedup-shared column — generated during the §65g local_type trial whose edits were then reverted.
Regenerated (reproduced identically in-gate + standalone); headline %s unaffected.
- cookbook §66/§66a/§66b distilled in-session (R30); SETUP.md gains the missing recover_integration
row (R21 debt). tools-health OK: corpus 0/0, cdecl green, audit-binaries 140 citizens, lint OK,
dedup-check 1879/0. Fleet unchanged 79.6% instr / 67.7% distinct / 88.86% fn-count.
- 0 of 4 banked; reverted; make check BYTE-IDENTICAL; nothing landed.
- Ordering bug found+fixed: uniquifying the draft's type also renames it inside the draft's own
`extern <T> D_x;` decls, trading `redefinition of struct T` for `conflicting types for D_x`. With
uniquify moved BEFORE the reconcile one compiles -- and then DIFFs 48/53, because the data
reconcile's cast-at-use changes real codegen when the body depends on its own struct layout.
- func_8014C4AC: rtu MATCH but the gate returned a REAL final SHA != locked, i.e. the de-macroize edit
itself shifted a macro's OWN already-matched function. The §63 failure mode relocated somewhere the
per-binary gate catches it for free. MEASURED BOUNDARY: de-macroize is byte-neutral 14 of 15.
- Rule recorded: read the FINAL SHA, not the verified count -- `None` = no image (compile/link break),
a real hash != locked = the TU edit moved bytes. Different faults, different fixes.
- Two consecutive honest negatives (T8, T9): the EXISTING transforms stop at 14/36 (39%). §65f/§65g so
the next session does not re-buy this.
- func_8012F40C banked (the callee-conflict variant): relaxing demacroize from "the draft's own
function" to "any decl the DRAFT declares incompatibly" reaches macros that declare a CALLEE
differently than the draft does (RotTransPers/RotTransSV). 14 banks total, R22 140/140.
- THE ONE FAILURE, kept honest: func_8012F49C was rtu-MATCH but the whole-binary gate REJECTED it.
rtu_match is relocation-masked, so a wrong call TARGET is invisible to it -- and this was a callee
case, exactly where the mask hides the error. Trust rtu MATCH for self-decl corrections, distrust it
for callee ones (§65c). Reverted its edits and re-banked only the winner rather than leave
byte-neutral churn on matched code (§57a-4).
- DISTILLED IN-SESSION (R30/R16/R31/R21): cookbook §65 + §65a-§65e (blast-radius tiers; the
de-macroize escape and the §20 refutation; the rtu-vs-gate divergence; the existing-ladder baseline;
two-oracle practice); decision-log entry with the HONEST multiple (~2.3x, not the projected 3.7x,
and it lands on distinct-code not the display number); calibration.md measured table; SETUP.md rows
for blocker_probe + demacroize PLUS the three the inventory was missing (lift_types, uniquify_type,
fix_header_decl-as-retired).
- Carried and NAMED, not dropped: 10 match_one-MATCH drafts still blocked by stacked classes, and the
11 `near` drafts which are unfinished drafts, not recovery fuel.
Every real-TU rtu_match MATCH converted to a whole-binary bank: 13/13, 0 failed.
- BANKED (all BYTE-IDENTICAL, whole-binary gate, stub-gone confirmed by grep not by report):
func_8012CC88 func_80138DE0 func_80144B14 func_80146750 func_80147364 func_8014CF04
func_8014D12C func_8014D610 func_80161374 func_8016163C func_80161774 func_80161888 func_801778A8
- Mechanism: existing draft-side transforms (cast_call_sites + reconcile_tu) then tools/demacroize.py
expands the conflicting DEFINE_func_* instantiations in the overlay's OWN TU with the self-decl
corrected to the draft's byte-true signature. Writes confined to src/ov_SC07_006/**.
- R22 clean-fleet after the batch: 140 passed, 0 failed of 140. Write-set asserted T1 (3 TU files).
- METRICS, honest: distinct-code 64,860 -> 64,873 unique fns (+13) -- the FULL credit, since
progress.py marks an h_exact class matched if ANY instance is. instr-weighted 79.6% and fn-count
88.86% are ~flat, because a de-macroized bank is x1 and cannot propagate x138. That price was
stated before the work, not after it.
- dedup-check 1879 validated / 0 failed; 0 NON_MATCHING in any default build (G4).
The near-miss ledger (.run/backlog.jsonl) is append-only, so it filled with already-banked noise:
6,867 rows, ~98% banked. load_best()/render() already filtered on READ (docs/backlog.md was correct),
but the raw log drifted stale and every render re-scanned all 6,867 rows against the stub oracle.
- backlog.py: new `prune` subcommand — atomic rewrite (temp + os.replace) to load_best()'s output
(drop-now-matched P9 + best-per-addr collapse). Idempotent. 6,867 -> 1,704 open near-misses.
- Makefile: `backlog.py prune` wired into `make report` (BINARY=main block) so the ledger tracks
reality every cycle instead of drifting.
- Finding (Drew's question): crack waves DO log every non-byte-match to the backlog durably
(gate_stage copies best_draft -> .run/backlog_drafts/). BUT the `closeness` field is UNRELIABLE —
byte-correct drafts (match_one MATCH) are logged with closeness>0 (e.g. func_8012F49C logged 29,
actually MATCH). And a reach-N function's draft is overlay-SPECIFIC (per-location symbols), so the
backlog is a messy recovery source vs the fresh per-wave stranded drafts. Integration-recovery
should consume the fresh wave-dir strandeds, not re-derive from the backlog.
- 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.
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.
- 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.
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.
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).
Crack wave w9lidyi5b (24 fresh LIVE=138 families): 20 self-assessed MATCH, 3 near.
Banked x1 (R22 clean-fleet 140/140):
- 2 self-contained via plain harvest_verify: func_8012B4B8 (§52b-wall crack),
func_80169228.
- 5 via gate_stage's reconcile ladder (cast_call_sites in the draft's own TU):
func_80175308, func_8012E138, func_80130C08, func_8012A1BC, func_80137178.
Correction (decision-log follow-up): fix_header_decl v1/v2 is FRAGILE for shared
multi-caller decls — rewriting an engine_core.h decl breaks callers that use the
return differently (CC1-FAIL). func_8014CD80 was a lucky single-caller/ignored-return
case. gate_stage's call-site-cast is the right tool for multi-caller plumbing (banked
5 where fix_header_decl broke the build). Remaining ~13 near/deeper-plumbing drafts
staged in .run/drafts-sc07006-fresh/. Propagation x138 next.