- ROOT CAUSE (R14 — the session-7 diagnosis was half right): the isolated region builds [ OK ] WITHOUT the body, so §8b isolation was never implicated. `family_remap.gather_externs` prepends carried decls at FILE scope; D_801812A4 is a fn-ptr dispatch table the sibling declares FOUR incompatible ways at BLOCK scope inside its own later functions, so the carried file-scope decl ESTABLISHES A GLOBAL THE TU NEVER HAD and every later block-scope extern must now agree with it. Byte-proven asymmetry: BLOCK(int)->BLOCK(struct*)->FILE(void*) builds; FILE(void*)->BLOCK(int) errors. It was the ONLY hard error in the build — all 27 carried function externs were fine raw. - THE FIX (demote, don't reconcile): tools/scope_data_externs.py emits a carried D_ extern at BLOCK scope inside the function body when the TU has no file-scope decl of it above the insertion point. Byte-neutral (an extern emits no code; type + access opcodes unchanged) and never worse than raw, so it needs no oracle, no type comparator, no fn-ptr parser. Restores fidelity — the original declares these symbols at block scope in exactly this way. Wired into jtbl_family_bank as the `scoped` stage: raw -> scoped -> recovered -> reconciled (scoped is the base for the later stages). - reconcile_decls is the WRONG instrument for this class, twice: its oracle answers "what does the FLEET call this symbol" when the question is "what can THIS TU see", and its DATA_DECL_LINE_RE cannot parse `extern void (*D_x[])(void *);` — silently skipping the very symbols that were failing (the phase's third silent-skip bug, after find_site braces + overlay_files splits). - R17 TRIAGE RULE, first real test, held: `conflicting types` = the compiler REFUSED TO COMPILE = a C front-end diagnostic = our Python. Reading cse.c/global.c would have taught nothing. - RESULT: func_8015AE2C (562 ins, reach 134) swept 133/133 siblings, 0 failures. R22 clean-fleet 136/136 BYTE-IDENTICAL (534 changed src files); dedup-check 1813 validated / 0 failed; 0 NON_MATCHING (G4). instr-weighted 63.0 -> 63.6%; distinct-code 39.1 -> 40.5% (+256 unique fns / +79,957 ins) — one core, ~0 agent tokens. - knowledge captured during the producing session (R30/R31/R21): cookbook §8d, decision-log 2026-07-13 session 8, SETUP tool-inventory row; CURRENT_PHASE session-8 checkpoint.
64 KiB
CURRENT PHASE — Phase 26: The Family-Endgame (finish the decomp)
Status: ACTIVE · plan approved by Drew (gate 1) 2026-07-11 · Generation Gen2 (18th phase of the arc) Opening brief:
docs/family-endgame-megaplan.md(Phase-25 handoff). Fable5 window closes ~2026-07-13. Recovery note: a fresh session resumes from the ▶ CURRENT TASK below (P3 — autonomous between gates). Read the plan context here + the megaplan; per-task log at the bottom is the crash-recovery trail.
The plan in one paragraph
The Phase-25 h_seq reframe: the "unique tail" is really per-location families — crack ONE exemplar, template ×~120 siblings through the whole-binary byte-gate. Planning-session verification (2026-07-11) reproduced the survey from the sigs: 663 tail families; substantial (nins≥80) = 186 families / 1.85M ins (megaplan's "986" was a miscount). Design-stage discovery (byte-verified on specifics, V0 re-verifies — R14): the tail is ~90% a reloc-tracker blind spot — norm_stream/reloc_targets drop the pending lui-hi on any R-type write, but gcc-2.7.2's indexed-global idiom (lui; addu $idx; lw lo($at)) preserves it, so every D_x[i] access made its function "fleet-unique" and broke remap. Substantial-tail classes: PURE-same-addr 62 fams/1.55M ins · PURE-cross-addr 103/0.10M · IMM 8/0.10M. Free win: 63 families / 0.31M ins have a MATCHED exemplar and siblings that failed earlier sweeps only from the tracker bug → zero-crack banks once the ~40-LOC fix lands (= the validation corpus). Also found: remap() sequential substitution corrupts chained renames → must become single-pass simultaneous. Immediate substitution shrinks to an escalation tier (diff-driven, 3 tiers; probe only ambiguous values). Owner decisions: carried Fable5 queue (5 giants) deferred to END of phase (low priority); milestone = structural completion.
Task checklist (effort per R7 · one commit per completed task, Drew pushes — R6)
- Task 0 — Bootstrap
[xHigh]— this file + harness task list (R28). (completes with this commit) - Task 1 — Remap core: extended reloc tracker + single-pass substitution
[xHigh]—family_remap.py: hi propagates through add/addu index adds;symbol_map/remapgained backward-compatibleto_addr=None(cross-address) +imm_maphook; single-pass simultaneous substitution + self-rename. norm_stream/h_norm UNTOUCHED. Discovery → cookbook §40b (R30) + decision-log (R31). V0 PASS (.run/v0_reloc.py): 22/22 regression (func_80141100NEW==OLD), 15/15 fix (func_801407F4vs splat .s, recoversD_80187B88/90/B0), cross-addr symbol_map clean. V1 PASS (.run/v1_regression.py): 160 real h_norm pairs, 96 SAME, 0 lost, differences are strict indexed-reloc improvements. (committed) - Task 2 —
tools/family_hseq.py+ committed manifest[xHigh]— full-frontier survey; shared word-diff classifier added tofamily_remap.py(stream_words/reloc_indices/reg_fields/classify_member— PURE/IMM/STRUCT, register-drift aware). →.run/family_hseq.json+docs/family-hseq.md. VERIFIED: fleet 74.8/58.2/30.3 (= PhaseEnd_25 & progress.py to the decimal); tail cross-check 663 families / 186 substantial / 1.847M ins (exact); classification vs Plan-agent table PURE-same 62, IMM 8 exact, PURE-cross 114≈103; 890×134/562×134 PURE per-location + 952×113 #addr21 IMM confirmed; full frontier = 581 substantial families / 3.22M templatable ins, 345 matched-sibling PURE/IMM families / 1.14M ins = the V2/V3 zero-crack corpus. (committed) - Task 3 — Imm engine (T2a Tier 1) + cross-address delta (T2b)
[xHigh]—family_remap.imm_value/imm_map_tier1/remap_hseq: diff-driven Tier-1 value-replace (asm-side ambiguity guard defers ambiguous values; C-literal swap preserving sign/hex-case) + T2b self-rename via the Task-1to_addr. Tier 2 (probe) DEFERRED — build-if-needed per Task-5 measurement (byte-gate arbitrates; only ~8 low-weight IMM families). VERIFIED (.run/v3_imm.py, match_one reloc-masked): 0 DIFF on every compilable pair — 3 IMM + 2 cross-address MATCH; 4 remap-fails were correctly-deferred asm-ambiguous values; 45 compile-fail(isolation) → whole-TU gate in Task 5. (committed) - Task 4 —
family_sweep --hseqmode[xHigh]— additivehseq_sweep()(h_norm path byte-untouched): consumesfamily_hseq.json, templates matched-exemplar members viaremap_hseq(cross-address + imm), stages.run/sweep/<ov>/func_<TO_ADDR>.cgrouped by (overlay,split), gates viaharvest_verify(unique per-group verified-out — fixes a latent multi-split overwrite). Member pre-filter =remap_hseqrefusal (STRUCT/unresolved). Static pin guard (__asm__("$N"→ skip family; §42e — the ×1-only pinned cracks that cc1-crash sibling TUs).--band/--min-members/--stage-only/--only. VERIFIED: substantial → 29 families, 1507 clean members staged / 267 groups, 1643 correctly skipped as pinned (16/29 families pinned incl. the decision-log-namedfunc_8016DF5C/8013D9B0/80133AB0); h_norm path intact; drafts byte-correct by construction (V3), type-using → whole-TU gate (Task 5). (committed) - Task 5 — Zero-crack validation harvest (substantial band) — GO/NO-GO = GO
[xHigh]— ran the real byte-gate on the 29 substantial matched-exemplar families. Tooling fix discovered + applied (Task-5's "measure then fix"):remap_hseq.gather_externscarries file-scope externs for body-referenced symbols (extract_unitonly grabbed adjacent ones) — the decl class that depressed the first run. Result: 532 members banked (byte-gated); per-family: 3 tracker-miss PURE families (0x8015d5e8/0x8015f118/0x801407f4) bank 100% ×133 = 399 byte-perfect (the free win), 1 cross-addr family 50%; 9 zero-bank families are type-using (Work8016/Prim/…) → §41 reconcile follow-on (Task 8), 16 families pinned → Task 7. VERDICT: the h_seq machinery is 100% correct on clean families — GO. decision-log 2026-07-11 (R31). R22 clean-fleet 136/136 GREEN; metrics 30.3→30.9% distinct (+375 fns) / 58.2→58.5% instr. (committed) - Task 6 — Step-A triage of the 119 draftable substantial exemplars
[Ultracode]— Workflow (.run/wf_triage_full.js, 119 agents / 0 err / 5.3M tok): per-family m2c draft (+§8 jtbl) →match_onecloseness → class + §31/§45 lever + seed (.run/phase26-seeds/). 119 triaged → cheap 29 (325k ins, 23 closeness-0 isolation-MATCH) / permuter 29 (341k) / fable5 61 (1.71M). Curriculum →docs/phase26-triage.md. ⚠ Banking caveat (verified): the 23 closeness-0 seeds gate 0/23 into ov077 — genuine function matches but carry standalone types + Ghidra sigs conflicting with the TU (§41 def-side wall:redefinition of struct Obj/conflicting types); banking needs the Task-8--reconcile/canon_sig_reconcilepass. (committed) - Task 7 — Family-core crack waves (the Fable5 window)
[launch at Max — R27; agents model:fable, parallel-isolated, distill-between]— biggest byte-weight first (890/562/536/493…); §45-templated prompts (read.greg/.lregfirst; Lever-A merged-accumulator audit; 1-death in-out-asm; /s; gdb-on-cc1,tools/reference/gcc-2.7.2/); PIN-FREE (×134);harvest_verifyarbitrates; distill each crack → cookbook §46+ (R30); cheap-Opus applies banked idioms between waves; cheap/permuter lists run in parallel[UC]. ~375k tok/crack guide; documented wall + levers = valid outcome (P9). - Task 8 — Mechanical harvest waves
[Ultracode; continues post-window]— cracked exemplars → template ×members → gate → bank; h_norm draftable/matched-free retries with the new tracker (5.9 MB bucket); F-jumptable 4 (§8); M-linkwall 1; link-undef second pass. Batched commits; R22 clean-fleet before each commit batch (never while agents needasm/). - Task 9 — Mid-band + residue measurement
[xHigh]— <80-ins families (0.68M ins) through the engine; measure h_seq-miss → GO/NO-GO fuzzy pass (build only if ROI; else Phase 27). - Task 10 — Carried Fable5 queue (END of phase — Drew's call)
[Fable5 if window remains, else permuter/Opus + banked levers]— 801670E4 (diff-23), 80178004 (close-7), 801412A8 (close-29), 8016CBC0 (153/209), 8014D820 (LCS-226); specs.run/giants/*.opus.md+.run/t7b/close/. Crack ×134 or wall-document; post-window walls → Phase 27, accepted. - Task 11 — Step-D residue map
[xHigh]— true singletons (~0.27M ins) + 5 behemoths → Phase-27 input doc. NO execution. - Task 12 — PhaseEnd
[Max — Tier 1; R27 prompt]— P7 walk, milestone demo, gate 2,PhaseEnd_Phase26.md, worklog →logs/Phase26.md(R19), in-file recap (R25), decision-log current (R31).
▶ SESSION-8 CHECKPOINT (2026-07-13, cont.) — RESUME FROM HERE (fresh session)
THE ×133 SWEEP BLOCKER IS FIXED. func_8015AE2C (562 ins) BANKED ×134 — 133/133 siblings, 0 failures.
R22 clean-fleet 136/136 GREEN (from make clean, 534 changed src files). dedup-check 1813 validated / 0 failed.
Metrics: instr-weighted 63.0 → 63.6% · distinct-code 39.1 → 40.5% (+256 unique fns / +79,957 ins) · fn-count 82.31%.
One core × 133 siblings = +0.6% instr-weighted for ~0 agent tokens. Tree clean, all work committed.
The fix — §8d, tools/scope_data_externs.py (the session-7 diagnosis was HALF RIGHT — R14)
Session 7 blamed reconcile_decls' fleet-majority oracle and planned to teach it a TU-visible one. Reproducing
one sibling by hand (rather than trusting the handoff) gave a sharper picture and a smaller, safer fix:
- The isolated region builds
[ OK ]WITHOUT the body → §8b isolation was never implicated. The templated body is the sole cause. family_remap.gather_externsprepends carried decls at FILE scope.D_801812A4is a fn-ptr dispatch table the sibling declares four incompatible ways at BLOCK scope inside its own later functions. The carried file-scope decl establishes a global the TU never had → every later block-scopeexternmust now agree with it →conflicting types. Byte-proven asymmetry:BLOCK(int) → BLOCK(struct*) → FILE(void*)builds;FILE(void*) → BLOCK(int)errors.- It was the ONLY hard error in the build. All 27 carried function externs were fine raw —
cast_call_siteswas not needed at all (session 7 thought it was doing the heavy lifting). - FIX: demote, don't reconcile. Emit a carried
D_extern at block scope inside the function body when the TU has no file-scope decl of it above the insertion point. Byte-neutral (anexternemits no code; type + access opcodes unchanged), never worse than raw ⇒ needs no oracle, no type comparator, no fn-ptr parser. It also restores fidelity — the original declares these symbols at block scope in exactly this way. Wired as thescopedstage: raw → scoped → recovered → reconciled (andscopedis the base for the later recovery stages). Cookbook §8d + decision-log + SETUP row (R30/R31/R21). reconcile_declsis the wrong instrument for this class, twice: its oracle answers "what does the FLEET call this symbol" when the question is "what can THIS TU see"; and itsDATA_DECL_LINE_REcannot parseextern void (*D_x[])(void *);, so it silently skipped the very symbols that were failing. (This is the "reconcile fn-ptr-extern gap" logged 2026-07-12 — filed as a small separate lever, it was the blocker.)- The R17 triage rule (committed
commit:0550) paid off immediately:conflicting types= the compiler REFUSED TO COMPILE = a C front-end diagnostic = our Python. Readingcse.c/global.cwould have taught nothing. ("Wrong BYTES" → read gcc; "won't COMPILE" → read our tooling.) - Diagnostics gotcha: gcc-2.7.2 does not prefix errors with
error:— grepping a build log forerrorfinds only make'sError 33. Grep the diagnostic text (conflicting types/undeclared/parse error).
NEXT (priority order — byte-weight first; top-20 jr cores = 4.12M of the 5.53M templatable bytes)
func_80178D40(890 × 134 = 477K bytes — THE heaviest core). Crack in hand at.run/phase26-cracks/func_80178D40.c, close=39, ALL 39 inside ONE case body (0x5C); every other case is byte-exact. The 4 residuals are named in the file header (cross-jump merge ofD_801DAB2C = 3;$v0→$v1copy; loop2 keeping old q in$v1; gcc peeling loop3's first iteration where the original doesn't —loop.c). All §31-map classes ⇒ cheap-Opus + permuter, NO Fable5. Exemplar = ov_SC01_077, PURE per-location ⇒ straightjtbl_family_banksweep once closed.func_8017BEBC(952 × 113 = 430K bytes) — close=2. THE genuine R17/Fable5 target (R27: PROMPT DREW). Twoaddius TRANSPOSED in the loop preheader; registers already correct. Allocation order and preheader emission order are coupled (both follow creation/LUID order) but the target needs them to DIFFER: allocation (sz0, sz2, sz1) with emission (sz0, sz1, sz2). Permuter cannot reach it (not statement-permutable; ran 25 min, no close). Agent localized it toglobal.c's allocno-priority TIE and named the move: a §45-B gdb-on-cc1 read ofallocno_live_length(the original's length quantization plausibly split the tie), then hunt a byte-neutral L-shifter that survives cse. Full spec:.run/phase26-cracks/func_8017BEBC.md. ⚠ Exemplar isov_SC01_000(NOT ov077), class IMM, addr_tag scattered → its sweep runs from ov_SC01_000 through the immediate engine, not the plain PURE template path.- The rest of the 191 substantial jr cores (5.53M templatable bytes). Next by weight:
func_8017A4AC(536×134),func_8015A3C8(493×134),func_8013F350(490×134),func_801380E0(438×134) — all ov077 PURE per-location. Recipe = the session-7 five-step (unchanged) + the newscopedstage. - Re-check for cracked-but-unswept jr cores whose ×N sweeps never ran because of this blocker — use
family_remap.extract_unitas the definition oracle, not a hand-rolled regex (mine false-matchedexternlines — R14).
Banking a heavy jr core — the FULL recipe (unchanged from session 7, + the scoped stage)
jr_isolate_all --only <core>(also cuts every already-banked jr in the same object — one.rodatacarve per region). 2.jtbl_carve --func <core>(trims trailing.alignpad — §8a-pad). 3. If anengine_core.hthunk calls the core with zero args, the def must be K&R and the thunk's extern must drop(void)→(). 4. Gate stages: raw → scoped (§8d) → recovered (cast_call_sites+reconcile_decls) → reconciled. 5. Whole-binary gate →jtbl_family_bank×N → R22 → commit. Commit each family before sweeping the next (the per-sibling revert restores from HEAD).
▶ SESSION-7 CHECKPOINT (2026-07-13, cont.) — superseded by SESSION-8 above
Heavy-jr crack waves RUN (Drew approved top-3 + distill). 1 core BANKED, 2 cracks in hand. R22 136/136 GREEN, tree clean, all work committed. The §8b wall stayed broken throughout.
The three Fable5 cracks (all PIN-FREE, all independently re-verified against the bytes — R14)
| Core | Size × reach | Result | State |
|---|---|---|---|
func_8015AE2C |
562 × 134 | MATCH 562/562 | Exemplar BANKED (commit:0547, d19c9580, R22 green). ×133 sweep BLOCKED — see below |
func_80178D40 |
890 × 134 | close=39/890 — 851 exact; all 39 in ONE case body (0x5C) | crack at .run/phase26-cracks/func_80178D40.c; 4 named residuals in a 44-ins block, agent calls it permuter-tractable |
func_8017BEBC |
952 × 113 | close=2/952 — two addiu TRANSPOSED, same registers (pure emission order) |
crack at .run/phase26-cracks/func_8017BEBC.c; permuter ran 25 min, did NOT close it |
⛔ THE ONE BLOCKER — the func_8015AE2C ×133 sweep (precisely diagnosed, NOT yet fixed)
The remapped sibling body's DATA externs conflict with the sibling's §8b carried decl layer
(conflicting types for D_801812A4; the layer's decl is the "previous declaration"). reconcile_decls
resolves against a fleet-majority canonical oracle, not against the TU's actually-visible decl, so it
picks a type that still conflicts. Fix direction: reconcile the body's externs against the TU's carried
layer (which is authoritative — it reproduces the original TU's decl environment), or drop body externs the
layer already provides and cast at use. cast_call_sites already fixes the function-callee half (27
callees); only the ~4 DATA symbols remain. Everything else in the sweep works (isolate → carve → remap →
gate). Bank flow now has 3 stages: raw → recovered (per-sibling cast+reconcile) → reconciled.
Banking a heavy jr core — the FULL recipe (all byte-proven this session)
jr_isolate_all --only <core>— now also cuts every already-banked jr in the same object (a region may host at most ONE.rodatacarve; an object's.rodatais a single contiguous section).jtbl_carve --func <core>— now trims trailing.alignpad words (§8a-pad).- If an
engine_core.hthunk calls the core with zero args, the def must be K&R/unprototyped and the thunk's extern must drop(void)→()(byte-neutral fleet-wide; R22-verified for func_8015AE2C). - Recovery:
cast_call_sites(callees) +reconcile_decls(data) against the isolated region TU. - Whole-binary gate →
jtbl_family_bank×N → R22 → commit.
Six tool bugs found + fixed this session (each silently corrupts and each is committed)
canon_sig_reconcile void→s32 not byte-neutral (§41d) · extract_unit swallowing the §8b decl layer ·
jtbl_family_bank cross-address naming · jtbl_carve.func_subseg reading the stale asm tree ·
jtbl_carve/revert deleting the committed overlays.mk carve var · jr_isolate_all --only erasing the
banked set + carve-ownership read from a .s splat never emits for matched fns + one region hosting two
carves · p16_permute hide_asm eating GTE #defines (permuter silently no-op'd 0s on ALL renderer
drafts) + hardcoded to one overlay.
NEXT (in priority order) — with the R17 routing call (Drew asked, 2026-07-13)
Do NOT read the gcc-2.7.2 source for the sweep blocker. R17 (read the compiler internals) is for codegen residuals — regalloc / scheduling / cross-jump / CSE — i.e. things no C change reaches. The sweep blocker is a C FRONT-END diagnostic (
conflicting types: two incompatible file-scope decls of one identifier in one TU). gcc is correctly rejecting plain C89; the bug is in OUR Python (reconcile_declspicks a fleet-majority type instead of the type the TU can actually SEE). Readingcse.c/loop.c/global.cwould tell you nothing. Triage rule: "the compiler produced the wrong BYTES" → R17. "the compiler refused to COMPILE" → our tooling.
- Unblock the ×133 sweep (above) → banks 562×133 ≈ 75K templatable ins. Highest ROI, well-diagnosed. Python fix, NOT a gcc read.
func_8017BEBCclose=2 (×113) — THIS is where the gcc-source read belongs. The permuter failed (25 min, no close). The agent localized it toglobal.c's allocno-priority TIE and named the exact move: a §45-B gdb-on-cc1 read ofallocno_live_length(the original's length quantization plausibly split the tie). Two instructions from a 107K-ins bank — the best R17 target in the queue.func_80178D40close=39 (×134) — all 39 in case 0x5C; agent named 4 concrete residuals (incl. gcc peeling a loop iteration the original doesn't → likelyloop.c). Cheap-Opus/permuter first, R17 if it walls.- Then the rest of the 191 heavy jr cores. R27: prompt Drew before any further Fable5.
▶ SESSION-6 CHECKPOINT (2026-07-13) — superseded by SESSION-7 above
THE §8b SCOPING WALL IS BROKEN. Heavy-jr harvest is UNBLOCKED. Effort: Max.
Full 54-jr isolate-all on ov_SC01_077 → d19c9580 byte-identical; R22 clean-fleet 136/136.
All tools committed. Baseline clean (no config/src changes).
What session 6 delivered (committed):
- Declaration-environment reconstruction (
overlay_src_split.py+jr_isolate_all.py) — the fix. Session-5's "gcc block-scope-extern TU-persistence" diagnosis was WRONG (R14):DEFINE_func_*macros expand at FILE scope, so their leading externs are genuine file-scope decls that merely live inengine_core.h— invisible to any col-0 text scan. Four decl sources must be carried forward, and the byte-gate found three of them: (1) col-0 decls · (2) macro leading externs (1,377 macros / 3,929 lines / 1,462 syms) →D_80126B3E undeclared· (3) a definition is itself a declaration for everything below it →func_8012B2CC undeclared· (4) file-local typedefs used by a carried proto →parse error before '*'(Vec3s). Rejected the approved "global symbol→type map + shadow set" design — it would hoist loose-typing block-scope shadows to file scope and create the conflict the shadow-set then dodges. Faithful forward-carry is conflict-free by construction (see cookbook §8c + decision-log 2026-07-13). - LAZY per-core isolation wired (
jtbl_family_bank):jtbl_carveNON-CONTIGUOUS fail-loud →jr_isolate_all --only <core>→ re-extract → re-carve. Proven onfunc_80178D40(890×134, the heaviest core): carve blocked → isolated (byte-neutrald19c9580) → carve lands in its own subseg. - Two latent bugs fixed (both would have corrupted the heavy sweeps):
jtbl_carve.func_subsegderived the owning subseg from the asm tree, whichmake extractnever prunes → after an isolation it returned the STALE owner and silently re-created the collision (now derived from the config); and the sweep'srevert()deleted the sharedoverlays.mkcarve var unconditionally → would have destroyed a committed carve (all 134 overlays have one) on any failed sibling (now restored to its committed value).jtbl_family_bankalso now refuses to start on a dirtyconfig/+src/— commit each family before sweeping the next.
DE-RISK COMPLETE (Drew's call, session 6): func_80182268 cracked + banked ×3 (the whole family) through the
LAZY path — the composition is proven end-to-end. Cracked first try (31-ins jr: shared-tail fallthrough where
jtbl cases 3+7 enter case 4's tail, + the (s8)(*(u16*)(p+0x70) >> 8) sign-extend idiom). Its carve collided
with the committed func_801734BC carve → lazy isolation fired → carve into its own subseg → whole-binary gate
d19c9580. Siblings ov_SC02_000/ov_SC02_003 (cross-address, @0x8017FCB0) banked via jtbl_family_bank.
The de-risk paid for itself — it exposed 3 more bugs that would each have silently capped the heavy sweeps:
canon_sig_reconcile'svoid→s32return promotion is NOT byte-neutral (cookbook §41d, R14): for a void body with noreturnit costs ONE instruction. It turned a perfect 31-ins MATCH into 32 → the extra word made the isolated object's.text4 B long → every data symbol shifted +4 (~271k differing bytes).match_onesaid MATCH; only the whole-binary gate caught it. Fix (generalizes §19): every recovery pass is a FALLBACK —jtbl_family_banknow gates RAW first, reconciled only on failure.extract_unitswallowed the §8b carried decl layer (it walks backward absorbing extern/comment lines, and the layer sits above a region's first item) → the template dragged ~140 unrelated externs into every sibling → gate-fail. Fixed with an explicit end-marker + a stop inextract_unit(also guards the Phase-17 canon layer).jtbl_family_bankused the EXEMPLAR's name for the sibling's carve/isolate/stub → cross-address families never resolved. Now derived fromto_addr. (The first two banked jr families were same-address, so it hid.)
Backlogged: func_801549F8 (31-ins jr, reach ×134 — the other cheap ×134 target) is a genuine §31
loop-IV / strength-reduction residual: the target does NOT strength-reduce (recomputes script+(i<<2) each
iteration), but plain arr[i] with constant per-branch increments makes gcc build a pointer GIV. A variable-stride
step defeats biv recognition and gives the correct address shape (17/31, seed at
.run/backlog_drafts/func_801549F8.seed.c) but gcc then keeps step in a register instead of folding K into each
branch's addiu. Needs the C shape that keeps CONSTANT per-branch increments yet fails the giv worth-while test
(loop.md L1). Permuter/Fable5 class — do NOT hand-grind it.
NEXT (R27 BOUNDARY — prompt Drew before launching): Task 7 = the heavy-jr core crack waves. The 191 jr
family cores / 5.53M templatable ins are now bankable. Per core: Fable5 crack (whole-binary gate — NOT plain
rtu_match, jr false-match risk §8a) → lazy isolate → jtbl_carve → jtbl_family_bank ×134 → parallel R22 →
commit. Targets by byte-weight: func_80178D40 (890×134 = 477K ins, isolation already proven), func_8017BEBC
(952×113), func_8015AE2C (562×134), func_8017A4AC (536), func_8015A3C8 (493). Fable5 window now 7/19.
Optional cheap de-risk first: the 45 small jr families (~129K ins, no Fable5) to exercise the full lazy bank
end-to-end (isolate→carve→remap→reconcile→gate) on a cheap target — its composition is proven in parts but the
end-to-end bank with a cracked body gates at the first real core. Ghidra MCP NOT needed (matching uses cached asm).
▶ SESSION-5 CHECKPOINT (2026-07-13) — superseded by SESSION-6 above
Stage-2 isolation build — parser DONE + single-cut PROVEN; full isolate-all hit the gcc-2.7.2 scoping wall. Effort: Max. Drew's decision (2026-07-13, Fable5 window extended to 7/19 so no time pressure): BUILD declaration-completion + apply isolation LAZILY per-core (not upfront-×134 — avoids the ~7,200-file cost; same tool, isolate only cores that crack). Tools committed this session.
Built this session (baseline reverted + intact — ov_SC01_077 rebuilds d19c9580; only the 2 new tools are untracked, NOT yet committed):
tools/overlay_src_split.py— overlay-.c-aware partition (header = includes + Phase-17 canonical-sig layer; per-address items = preamble + body; robust def/decl/K&R/DEFINE_func/SETTER/RETCONSTclassification). VALIDATED fleet-wide: 404/404 overlay.c, 341,902 items — round-trip exact / 0 unresolved / 0 non-monotonic. This is solid, reusable, commit-worthy.tools/jr_isolate_all.py— multi-cut resegment (config split at every jr boundary, source repartition + INCLUDE_ASM path repoint, banked-jr carve repoint via config +overlays.mk --order, -O0-object skip, ambient file-scope decl carry). SINGLE-cut isolation BYTE-IDENTICAL (func_8013FFD8 inmain→ cleanmake build=d19c9580, R22). Full 54-jr isolation on the dense_afterobject hit the wall.
THE WALL (byte-verified, decision-log 2026-07-13): mechanical TU-splitting breaks gcc-2.7.2's block-scope-extern TU-persistence — func_801734BC uses D_80126B3E, declared extern s16 ONLY inside DEFINE_func macros in engine_core.h; the original _after.c compiles because an earlier macro's block-scope extern persists to file scope for the whole TU. Splitting separates the core from that macro → undeclared. (7 distinct C-scoping edge cases surfaced + fixed incrementally; this last one is the deep one — col-0 ambient-carry can't reach macro-injected decls.)
THE FIX TO BUILD (Drew-approved, fresh session): declaration-completion — build a global symbol→type map from engine_core.h macro externs (the DEFINE_func/SETTER/RETCONST bodies) + all overlay col-0 decls; then for each isolated region emit a file-scope extern <type> <sym>; for every D_/func_ symbol the region USES, EXCLUDING the type-shadowed set (symbols with inconsistent decls across the codebase, e.g. D_80115118 = unsigned short vs struct S115118 — kept block-scope in bodies). This makes every region self-contained regardless of where the original declared the symbol (col-0, block-scope body, or macro). Est. ~40–60 LOC on the proven overlay_src_split.py; the whole-binary byte-gate (G3/P9/R22) arbitrates. Wire it into jr_isolate_all._render_region REPLACING the col-0-only ambient carry (which can't reach macro-injected decls).
NEXT (fresh session): (1) build declaration-completion (above); (2) re-prove full isolate-all byte-identical on ov_SC01_077; (3) switch isolation to LAZY per-core — integrate a single-core isolate into the bank flow (jtbl_family_bank), isolating a heavy jr core only when banking it (fewer files than upfront-×134); (4) then the heavy-jr-core crack waves — Fable5 (window now to 7/19) → §8 carve + template ×134 → R22. Committed tools this session: tools/overlay_src_split.py, tools/jr_isolate_all.py. Ghidra MCP NOT needed (matching uses cached asm). R27 boundary: prompt Drew to re-confirm effort/Fable5 before the crack waves.
▶ SESSION-4 CHECKPOINT (2026-07-12 later) — superseded by SESSION-5 above
Stage 1 in progress — multi-jtbl --order BUILT + proven cross-subseg at fleet scale. Effort: Max (this session, Tier-1 tooling build).
What session 4 delivered so far (committed + R22 136/136)
ld_interleave.py --order— address-ordered N-piece multi-jtbl sandwich (text → [data|.rodata carves, address-ordered] → bss). Legacy--front/--tailpath byte-untouched (main + the 133 single-carve siblings unaffected). Empty code-object sections parked byte-neutrally with .text.jtbl_carve.pyrewritten additive/regenerate-from-config — parses the current tail data-region + existing.rodatacarves, adds the new fn's jtbl (splitting its containing data piece), re-emits the address-ordered pieces + the--orderinterleave arg. Same-subseg collision → fails loud (→ isolation). Idempotent.jtbl_family_bank.pyfix —bank()nowmake extracts BEFORE the carve (so the sibling asm matches the reverted committed config; the old error-string retry was fragile). Revert-on-carve-fail.- Family-1 banked:
func_801734BC(34-ins PURE jr, in ov_SC01_077_after) ×134 — matched in ov077 (shared-tail switch:case N: t=-N; break; default: goto after;), banked 133/133 siblings, R22 136/136 clean-fleet byte-identical. This is a CROSS-subseg multi-jtbl (func_8012ACE0 in_a+ func_801734BC in_after) — the checkpoint's primary Stage-1 goal, proven fleet-wide.
The same-subseg cases — TWO flavors (both surfaced this session; the de-risk paid off)
Two matched jr-fns in ONE code object emit their jtbls CONTIGUOUS (gcc source order). So:
- (a) CONTIGUOUS jtbls (adjacent in the island) → MERGE.
jtbl_carvenow merges adjacent same-subseg carves into one spanning.rodatapiece (+ a bound-fix: a new jtbl's end is bounded by the next raw dlabel OR the next existing carve start — an already-carved adjacent jtbl is gone from the data asm, so raw dlabels alone over-extend it → false "non-contiguous"). BUILT + config-proven (func_80171B4Cjtbl_801D8C48merges with func_801734BCjtbl_801D8C68→ one_aftercarve[0xb0af0..]). Byte-proof PENDING a matched adjacent pair — func_80171B4C is struct-heavy (m2c givesarg0->unkXX+ ratan2 + 8-case switch), a real match, not a quick de-risk. NO-OP for family-1/cross-subseg (single carve per subseg) — committed configs unaffected (verified by reasoning: R22 rebuilds static configs; jtbl_carve only runs on new carves). - (b) NON-CONTIGUOUS jtbls (unmatched jtbl between) → ISOLATE one fn into its own code subseg (whale
_o0bprecedent).tools/jr_isolate.pywritten (config split +func_subseg-derived carve, no rename bookkeeping; isolating F preserves carves BELOW F, so bank ascending). BLOCKED — the real finding:split_src_regioncan't partition the overlay.c— it has 922 non-address top-level items (the Phase-17 global canonical-sig extern layer + per-function callee-extern blocks +DEFINE_func_X()dedup macros +// @classannotations). Making it overlay-.c-aware (header = includes+global-extern-layer; attach leading externs to the following fn-block) is the Stage-2 build item.
⚠ Stage-2 unblock decision (Drew's call): isolation is a HARD Stage-2 prerequisite
Because func_801734BC is now committed in _after of every sibling, banking any heavy core (also _after, non-adjacent) hits case (b) → needs isolation. Options: (i) fix split_src_region for the overlay .c + finish jr_isolate (robust, needed regardless — Stage-2 has many _after cores → same-subseg even without func_801734BC); (ii) a one-time "isolate-ALL-jr-per-sibling" resegment (scalable: ~134 resegments then fast fills, vs per-fn ×134 splits) — likely the right Stage-2 architecture. Also open: byte-proof the MERGE with a matched adjacent pair.
NEXT: pivot to Stage 2 (this is an R27 effort/model boundary — prompt Drew to re-approve + toggle). Stage 2 = the heavy 191 jr cores (Fable5 crack-core → template ×134), which first requires the isolation build-out (option i/ii above). Cross-subseg multi-jtbl (the primary Stage-1 goal) is DONE + committed + R22 136/136.
▶ SESSION-3 CHECKPOINT (2026-07-12 late) — superseded by SESSION-4 above
Committed baseline = commit:0534, R22 136/136 (now ~50s, parallel). Session-3 commits: commit:0531 (tiny-band), commit:0532 (§8 PoC), commit:0533 (§8 ×134 automation), commit:0534 (R22 parallelization). Phase-26 total: distinct-code 30.3→39.1%, instr-weighted 58.2→63.0%.
What session 3 delivered (all committed, R22 136/136)
- Tiny-band harvest — 17,975 member-matches; distinct 35.2→39.1%.
- §8 jtbl-rodata tooling (the strategic unlock) — overlay switch (jr) functions can now bank as C for the first time.
tools/jtbl_carve.py(per-overlay jtbl-rodata carve) +ld_interleave.py --section+<bin>_JTBL_INTERLEAVEMakefile hook; cookbook §8a + SETUP. Reconcile-per-sibling +extract_unitnow carries single-line typedefs.tools/jtbl_family_bank.py= the sibling sweep driver. func_8012ACE0 banked ×133/133, 0 fail. - R22 parallelized —
make clean && make extract-all && make check-all= ~50s (was ~9m), 136/136 byte-identical.JOBS ?= 16.
⚠ THE STRATEGIC REFRAME (decision-log 2026-07-12, Drew's steer) — READ BEFORE PICKING THE NEXT TARGET
§8 did NOT just unblock a small mop-up — it unblocked the single heaviest byte-weight chunk of the game. Measured (.run/family_hseq.json): 9 of the 10 heaviest unmatched family cores are switch (jr) functions (func_80178D40 890×134 = 477K ins, func_8017BEBC 952×113, func_8015AE2C 562×134, func_8017A4AC 536, func_8015A3C8 493 …); jr substantial = 191 fams / 5.53M templatable ins; the 45 small jr families I first eyed = only 129K ins (a light-tail trap Drew caught). The endgame plan = heaviest-byte-weight-first via crack-core → template ×134; §8 is its key enabler.
▶ THE CORRECTED NEXT PLAY (fresh session) — small-jr-first as a DE-RISK PREAMBLE, then the heavy 191 (Drew's sequencing, 2026-07-12; agreed)
Stage 1 — the 45 small jr families (mid/tiny, 129K ins) FIRST, as a pipeline-hardening preamble (NOT for byte-weight — it's ~+1% instr; the point is de-risk). The decisive technical reason: jtbl_carve today only does the single-jtbl-per-overlay carve — but func_8012ACE0 is now matched in all 133 siblings, so the next jr family makes those overlays multi-jtbl → BUILD the ld_interleave --order (address-ordered) multi-jtbl carve HERE, on cheap targets, before a Fable5 giant depends on it. Also validates variety (IMM vs PURE, per-overlay jtbl positions, stubborn exemplars) where a bug costs a 30-ins fn, not a 890-ins core; and needs NO Fable5 (progress now, no session-limit burn). Pipeline: match each small exemplar (m2c + reconcile; func_8012ACE0 had a ready §41b draft — check which of the other 44 m2c cleanly) → jtbl_family_bank.py ×~120 → parallel R22. Do NOT let "45 done, feels productive" become grinding more light tail — pivot to Stage 2 once the pipeline is hardened + multi-jtbl proven.
Stage 2 — the heavy 191 jr family cores (5.53M ins — THE byte-weight objective). func_80178D40 (890×134 = 477K ins), func_8017BEBC (952×113), func_8015AE2C (562×134)… Needs Task 7 (Fable5) UN-PAUSED (§8 makes it worth it now — a jtbl core crack banks fleet-wide, not unbankable fuel). Per core: Fable5 crack (whole-binary-gate-verified, NOT plain rtu_match — jr false-match risk, §8a) → jtbl_carve (now multi-jtbl-capable from Stage 1) + jtbl_family_bank.py ×134 → parallel R22. Cheap-Opus applies banked §31/§45 idioms between Fable5 cracks. Non-jr substantial families (7.3M ins) — heavy too; mechanical ones via family_sweep, hard cores via Fable5.
Effort/model (fresh session): plan-mode Max for the Phase-Start re-plan; then prompt Drew to re-approve + /effort for Fable5 (Agent model:fable, parallel-isolated, whole-binary gate) on the heavy cores; Ultracode for the mechanical ×134 template waves; Max for synthesis. Ghidra MCP NOT needed (matching uses cached asm).
SESSION-2 CHECKPOINT (2026-07-12) — superseded by SESSION-3 above
Phase 26 status: Tasks 0–6 DONE + committed (the h_seq engine + triage). Task 7 (Fable5) + Task 8 (mechanical harvest) IN PROGRESS. Committed baseline = commit:0528, R22 136/136 confirmed. Commits this phase: commit:0518→commit:0528.
What's banked (all committed + R22-verified through commit:0528)
- 729 reconcile-class member-matches: 463 (
commit:0527) + 266 (commit:0528), from 6 no-jtbl reconcile-clean triage cracks templated ×~133 via--reconcile-raw. Metrics ≈ 31%+ distinct-code / 59%+ instr-weighted (was 30.3/58.2 at phase start). - MID-BAND HARVEST DONE + committed + R22 136/136: plain
--hseq --band midbanked 6,853 member-matches = 320 distinct functions (3,098 type-heavy tail / 1,743 pinned / 873 no-ov077-body — all expected). Metrics: distinct-code 31.1→35.2%, instr-weighted 58.9→60.9%. - TINY-BAND HARVEST DONE + R22 136/136 (session 3, 2026-07-12): plain
--hseq --band tinybanked 17,975 member-matches / 5,617 gate-rejected (h_seq-collision false-templates, correctly refused by the whole-binary gate — the collision-prone <16-ins band) across 266 overlay.cfiles (180 tiny families; skips 1,184 no-matched-unit / 148 unresolved-imm-Tier2 / 117 STRUCT / 39 pinned). R22 clean-fleet 136/136. Metrics: distinct-code 35.2→39.1%, instr-weighted 60.9→62.9%. Phase-26 total so far: distinct 30.3→39.1%, instr 58.2→62.9%. NEXT: the two harvest gaps — §8 jtbl-rodata tooling (Drew-approved) + the reconcile fn-ptr-extern fix — then re-measure/milestone.
The h_seq family engine (all committed, the durable tooling)
tools/family_hseq.py— the survey →.run/family_hseq.json(regen after every bank) +docs/family-hseq.md. Bands: substantial(≥80)/mid(16–79)/tiny(<16).tools/family_remap.py— extended reloc tracker (addu-hi §40b),classify_member(PURE/IMM/STRUCT),imm_map_tier1(T2a),remap_hseq(plain template),remap_hseq_body(remap a RAW crack body — for reconcile-raw),gather_externs.tools/family_sweep.py --hseq— templates matched-exemplar families;--reconcile-raw RAWDIR= §41c per-sibling reconcile (remap the RAW crack per sibling +canon_sig_reconcilevs that sibling's TU); static pin guard (__asm__("$N"→ skip).--band/--only/--stage-only/--min-members.- Cracked-seed dirs:
.run/crack_raw/(raw seeds, func_.c) +.run/phase26-seeds/(triage m2c seeds) +.run/phase26-cracks/(Fable5 crack bodies).
The TWO harvest gaps (the levers for the remaining crack families) — see decision-log 2026-07-12
- §8 jtbl-rodata (Drew APPROVED building it, 2026-07-12). Overlay jtbls live in the monolithic
data tail(asm/ov_*/data/tail.data.s, e.g.dlabel jtbl_801D8E24~line 92735 in ov077). Replacing a jr-function with C emits a duplicate jtbl → broken layout. FIX = carve each jtbl out of the data tail into a dotted.rodatasubseg co-located with its function's code object (ov077 configsection_order:[.rodata,.text,.data,.bss];ld_interleave.pyalready wired, Makefile:397). Per-overlay ×134 (each sibling's data tail). STAGE: prove on ONE jtbl fn in ov077 → automate ×134. Blocks all jr cracks incl. the top Fable5 cores (890/562/536…) and the 2 Fable5 crack bodies (.run/phase26-cracks/func_80159C84.c+func_8015444C.c— code-matched, jtbl-rodata unconfirmed; they bank once §8 exists). - reconcile fn-ptr-extern gap.
canon_sig_reconcile._reconcile_dataskips any extern containing((fn-ptr syntax), ANDvisible_above/tu_ambientdon't parsevoid (*D_x[])(…)→ fn-ptr dispatch tables (D_801891B8) conflict → blocks ~15 of the 21 no-jtbl triage cracks. FIX = parse fn-ptr-array externs in all 3 fns (additive, but touches proven paths → regression-test the h_norm sweep). Smaller lever than mid/tiny.
Fable5 findings (decision-log 2026-07-12) — Drew: NO more Fable5 agents until re-approval
- rtu_match ≠ whole-binary gate for jr-functions: rtu_match neutralizes INCLUDE_ASM (excludes the §8 jtbl rodata) + masks relocs → it MATCHES while the whole-binary gate FAILS. Batch-1 (
func_80159C84/8015444C/80176218) = 0 whole-binary-confirmed cracks (2 jtbl false-MATCH, 1 limit-cut). Fable5 crack prompts must require the whole-binary gate (or a jtbl-aware check), not plain rtu_match. New idioms found (distill to cookbook when banked): postincrement pending-queue(*(s32*)(p+K))++ >= N(func_80159C84); split-temps inverse-§45-A for cross-jumped tails (func_8015444C). - Usage/session limits repeatedly interrupt Fable5 (weekly + session limits, ~3:40am/5am resets).
Triage (Task 6, committed) — docs/phase26-triage.md + .run/phase26_triage.json
119 draftable substantial families: cheap 29 (23 closeness-0 isolation-cracks) / permuter 29 / fable5 61. Whole-binary reality: 6 cheap no-jtbl-reconcile-clean bank; ~15 no-jtbl need the fn-ptr fix; 2 jtbl + the fable5 cores need §8. .run/_rr_todo.txt = the 19 not-yet-banked cracks.
NEXT STEPS (priority order, all MECHANICAL — no Fable5)
mid-harvest → R22 → commitDONE (commit:0530). 2.tiny bandDONE (session 3, 17,975 banks, R22 136/136, distinct→39.1%). 3. §8 jtbl tooling (Drew-approved; ov077 PoC → automate) — the mechanical bands are now exhausted, so this + #4 are the remaining harvest levers. 4. reconcile fn-ptr fix → re-harvest the ~15 no-jtbl cracks (--hseq --band tiny.run/_rr19.shpattern). 5. Task-5 type-families (9 zero-bank substantial) via reconcile. 6. re-measure metrics; when gaps closed → milestone check.
Effort/model: Max set (this session). Fresh session: re-apply /effort max for §8 design (Tier-1 tooling) or /effort xhigh for mechanical harvest runs. Ghidra MCP NOT needed (matching uses cached asm; run /mcp only if RE work resumes — R29).
Milestone (gate 2 — structural completion, per Drew)
- h_seq engine committed, V0–V3 validated with a measured template success rate.
- Every substantial (nins≥80) family banked ×members OR classified with evidence.
- Fable5-necessary cores attempted before window close; every crack distilled (R30/R31).
- Carried 5-target queue resolved (cracked or wall-documented).
- 136/136 byte-identical from clean fleet rebuild (R22); 0 NON_MATCHING (G4).
- All three metrics reported + Step-D residue map.
Projections (targets, NOT gates): Task 5 ≈ +5.7% distinct-code; campaign → distinct 30.3%→~55–70%, instr-weighted 58.2%→~75–88%.
Effort/model toggle map (R26/R27 — prompt + WAIT at every boundary)
On approval → /model opus + /effort xHigh (Tasks 0–4; ALL Fable5 via Agent(model:fable)). Task 5/6/8 waves → /effort ultracode. Task 7 launches + between-wave synthesis → /effort max. Task 12 → Max. Non-obvious debugging → Max.
Blockers
(none)
Log
- 2026-07-13 (session 8, the ×133 sweep blocker FIXED —
func_8015AE2Cbanked ×134; Max): Reproduced ONE sibling by hand instead of trusting the session-7 handoff (R14) and the picture sharpened: the isolated region builds[ OK ]WITHOUT the body (so §8b isolation was never implicated), andconflicting types for D_801812A4was the only hard error in the whole build — all 27 carried function externs were fine raw, socast_call_siteswas doing nothing. Root cause:family_remap.gather_externsprepends carried decls at FILE scope;D_801812A4is a fn-ptr dispatch table the sibling declares four incompatible ways at BLOCK scope inside its own later functions, so the carried file-scope decl establishes a global the TU never had and every later block-scopeexternmust now agree with it. Byte-proven asymmetry:BLOCK(int) → BLOCK(struct*) → FILE(void*)builds;FILE(void*) → BLOCK(int)errors. Rejected the session-7 plan (teachreconcile_declsa TU-visible oracle — a big, risky change to a proven path) for a smaller one: don't disturb the TU's decl environment at all. Newtools/scope_data_externs.pydemotes a carriedD_extern to block scope inside the function body when the TU has no file-scope decl of it above the insertion point — byte-neutral (anexternemits no code), never worse than raw, so it needs no oracle, no type comparator, and no fn-ptr parser (reconcile_decls' regex cannot parseextern void (*D_x[])(void *);and was silently skipping exactly the failing symbols — the third silent-skip bug of the phase). Wired as thescopedstage (raw → scoped → recovered → reconciled). First sibling byte-identical first try; full sweep 133/133 BANKED, 0 failures; R22 clean-fleet 136/136 (534 changed src files); dedup 1813/0; instr-weighted 63.0→63.6%, distinct-code 39.1→40.5% (+256 unique fns / +79,957 ins) — one core, ~0 agent tokens. The R17 triage rule (committedcommit:0550at Drew's ask) paid off on its first test:conflicting types= the compiler refused to compile = a C front-end diagnostic = our Python; a gcc-source read would have taught nothing. Knowledge captured DURING the session (R30/R31): cookbook §8d, decision-log, SETUP tool row. NEXT:func_80178D40(890×134, close=39, all in case 0x5C — cheap-Opus/permuter, no Fable5), then the R27 prompt for Fable5 onfunc_8017BEBC(952×113, close=2 — the allocno-tie R17 target). - 2026-07-13 (session 6, the §8b scoping wall BROKEN — heavy-jr harvest unblocked; Max): Built the
declaration-environment reconstruction on the proven
overlay_src_split.pyparser. R14 correction: session-5's "gcc-2.7.2 block-scope-extern TU-persistence" root cause was wrong — there is no gcc quirk;DEFINE_func_*macros expand at FILE scope, so their leading externs are genuine file-scope decls that simply live inengine_core.hand are invisible to a col-0.cscan (census: 1,377 macros / 3,929 extern lines / 1,462 symbols). Rejected the approved "global symbol→type map + shadow set" design (X1/P5d — same goal, better mechanism): the engine is loosely typed (func_80173544is defineds32 f(void*)yet declaredextern void f(void);insidefunc_801734BC's body), so "declare every used symbol" hoists that block-scope shadow to file scope and CREATES the conflict a shadow-set heuristic then has to dodge. Instead: reconstruct the original TU's file-scope decl environment and carry it strictly forward — conflict-free by construction (every carried decl already coexisted with every definition in the one original TU; decl compatibility is order-symmetric; shadows stay in bodies). The byte-gate then found two more lost decl sources I had not predicted: a definition is itself a declaration for everything below it in its TU (func_8012B2CC undeclared) and file-local typedefs used by a carried prototype (parse error before '*',Vec3s). Full 54-jr isolate-all on ov_SC01_077 →d19c9580BYTE-IDENTICAL; R22 clean-fleet 136/136 (the exact configuration session 5 could not build). Parser selftest still 404/404. Then wired LAZY per-core isolation intojtbl_family_bank(Drew's call — upfront-×134 would add ~7,200 region files):jtbl_carveNON-CONTIGUOUS fail-loud →jr_isolate_all --only <core>→ re-extract → re-carve; proven onfunc_80178D40(890×134, the heaviest core) — carve blocked → isolated (byte-neutral) → carve lands in its own subseg. Two latent bugs found + fixed (both would have corrupted the heavy sweeps):func_subsegread the owning subseg from the asm tree, whichmake extractnever prunes, so after an isolation it returned the STALE owner and silently re-created the collision (→ derive from the config); and the sweep'srevert()deleted the sharedoverlays.mkcarve var unconditionally, which would have destroyed a committed carve (all 134 overlays have one) on any failed sibling (→ restore to its committed value). Added a dirty-tree preflight tojtbl_family_bank(an uncommitted prior family would be silently reverted). Knowledge captured DURING the session (R30/R31): cookbook §8b RESOLVED + new §8c ("splitting a TU means rebuilding its declaration environment, not moving text") + decision-log. Committed. NEXT: Task 7 heavy-jr crack waves — R27 boundary, prompt Drew for effort/Fable5 before launching. - 2026-07-13 (session 5, Stage-2 isolation build — parser DONE, single-cut PROVEN, full isolate-all hit the gcc-2.7.2 scoping wall; Max): Drew re-approved Stage 2 + set
/effort max; steer = scalable isolate-ALL-jr-per-sibling upfront resegment, then Fable5 on the heavy cores. Built + fleet-validatedtools/overlay_src_split.py(overlay-.c-aware partition; 404/404 overlay.c, 341,902 items, round-trip exact / 0 unresolved / 0 non-monotonic — fixed 5 parser edge cases: definition-vs-declaration by brace/;scan, K&R defs, comment/#-directive peeling,def_namefrom the signature not preamble,SETTER/RETCONSTmacro anchors, trailing-footer preservation). Builttools/jr_isolate_all.py(multi-cut resegment: config split at jr boundaries, source repartition + INCLUDE_ASM path repoint, banked-jr carve repoint, -O0 skip, ambient file-scope decl carry). SINGLE-cut isolation BYTE-IDENTICAL (func_8013FFD8 inmain, cleanmake buildd19c9580, R22) — Task 2 proven. Full 54-jr isolation FAILED on the dense_afterobject after fixing 7 C-scoping edge cases in sequence, on the deep one (byte-verified): gcc-2.7.2 block-scope-extern TU-persistence —func_801734BCusesD_80126B3Edeclaredextern s16only insideengine_core.hDEFINE_funcmacros; splitting the TU separates the core from the earlier macro expansion that declares it →undeclared. Root: mechanical TU-splitting rebuilds the decl ENVIRONMENT (semantics), not just text — col-0 ambient-carry can't reach macro-injected decls. Candidate fix (not built): declaration-completion from a globalengine_core.h+overlay symbol→type map (decision-log 2026-07-13, R31). Baseline reverted + intact; 2 tools untracked, NOT committed — surfaced the fork to Drew (P5a) before sinking more time. NEXT: Drew's steer (build declaration-completion vs pivot Stage-2), then commit the tools. - 2026-07-12 (session 4, multi-jtbl
--order+ family-1 — the Stage-1 de-risk build; Max): Recon proved the Stage-1 core risk is precise:jtbl_family_bank.revert()restores each sibling to committed = has func_8012ACE0's carve, so banking ANY 2nd jr family makes the overlay multi-jtbl. Builtld_interleave.py --order(address-ordered N-piece sandwich; legacy--front/--tailbyte-untouched → main + 133 single-carve siblings unaffected) + rewrotejtbl_carve.pyadditive/regenerate-from-config (parses tail data-region + existing carves, splits the containing data piece for the new jtbl, re-emits--order; same-subseg → fails loud). Fixedjtbl_family_bank.bank()tomake extractBEFORE the carve (asm must match the reverted config; the old error-string retry was fragile — 3 early siblings carve-failed). Family-1func_801734BC(34-ins PURE jr, ov_SC01_077_after) matched in ov077 (shared-tail switch idiomcase N: t=-N; break; default: goto after;) + banked 133/133 siblings — CROSS-subseg multi-jtbl (func_8012ACE0_a+ func_801734BC_after), the primary Stage-1 goal. R22 clean-fleet 136/136 byte-identical (~52s). Wrotetools/jr_isolate.py(same-subseg non-contiguous case — split a fn into its own subseg viasplit_src_region,jtbl_carvere-derives the carve subseg; ascending-order discipline avoids carve-renames) — not yet integrated/committed. §8a finding: the still-INCLUDE_ASM carve build fails (migrated rodata not emitted through INCLUDE_ASM) — OFF the banking critical path (bank swaps C before building). Committed (Drew pushes — R6). NEXT: prove isolation on a higher fn → integrate → pivot to Stage 2. - 2026-07-12 (session 3, R22 parallelization — Drew asked "why so slow, profile+optimize"): Profiled the clean-fleet R22 (
make clean+ extract-all + check-all). Phase split: extract-all ~6m11s (the BIGGER phase, 136 serialsplat splitruns) + check-all ~2m58s (136 serial builds; most overlays ~1.3s, ov077 slow — maspsx on its 15K-line.c) = ~9 min. Both phases were serial on a 32-core box (the old Makefile comment called cross-binary-j"racy"). Verified the only shared write is the 4 generatedinclude/*.incmacros at extract time (identical content); everything else is per-binary-disjoint andinclude/is read-only during a build → parallel is safe. AddedJOBS ?= 16+make extract-all(seedmainserial for the macros, then parallel-extract the rest) + parallelmake check-all(xargs -P$(JOBS)), correctness-gated. Result:make clean && make extract-all && make check-all= ~50s, 136/136 byte-identical — a ~10.5× speedup (9m→~50s). Committed the Makefile change (own commit). This compounds across the endgame (R22 runs every commit). - 2026-07-12 (session 3, §8 ×134 AUTOMATION — func_8012ACE0 banked fleet-wide): Built the jr-function ×134 harvest pipeline and proved it end-to-end.
tools/jtbl_carve.py= per-overlay §8 carve generator (finding: the same fn is at the same vram across siblings but its jtbl is at a DIFFERENT address in each — ov_SC01_000 jtbl_801A331C / ov_SC02_000 jtbl_801E587C — so the carve is recomputed per sibling; rewrites the config data-tail subsegs + sets<ov>_JTBL_INTERLEAVE).tools/jtbl_family_bank.py= the sibling sweep driver (per sibling: revert→carve→extract→remap_hseq+reconcile→whole-binary gate; idempotent, revert-on-fail). Propagation-cap fix:family_remap.extract_unitnow carries single-linetypedefs (jr-function bodies define localtypedef struct{} Foo_<addr>;that must template with the body, else the sibling seesFoo undeclared— additive, byte-gate-protected). func_8012ACE0 family: 133/133 siblings BANKED, 0 failures; R22 clean-fleet 136/136 byte-identical. Metrics: distinct-code 39.1% (50,698 unique fns), instr 63.0%. Opportunity map (has_mid_jrfamilies): 237 total (5,805 members / 5.68M ins) — 46 small mid/tiny (771 members, mechanical, same pipeline) + 191 substantial = the Fable5 cores (Task 7, paused). Committed. NEXT: (a) R22 profiling/parallelization (Drew asked — check-all builds 136 binaries serially on a 32-core box); (b) the other 45 small jr families. - 2026-07-12 (session 3, §8 jtbl-rodata tooling — PoC PROVEN): Built the overlay jtbl-rodata mechanism (cookbook §8a, the durable writeup). Findings: overlay jtbls form a contiguous
.rodataisland at the TAIL (between.dataglobals and a tiny remnant), not the EXE's central island. Mechanism (byte-identical, 2-step): (Step 1) carve a matched jr-function's jtbl out of[data,tail]into a dotted[.rodata, <code-subseg>]subseg (spimdisasm migrates it into the fn's.s) +[data, tail2]; parameterizedtools/ld_interleave.py --section .<binary>(derives the symbol prefix; default.main= EXE byte-identical, backward-compat proven) places text→data(pre)→rodata→data(post)→bss — build byte-identical with the fn still INCLUDE_ASM. (Step 2) swap in the C body → byte-identical — the C-emitted jtbl lands exact. Wired intomake extractvia<bin>_JTBL_INTERLEAVEinconfig/overlays.mk+ a$(strip)-guardedifneqbranch (gotcha caught: a trailing#commenton the:=left whitespace → the branch misfired on resident). PoC target:func_8012ACE0(25-ins single-jtbl jr-function, ov_SC01_077) — reconciled viacanon_sig_reconcile(raw draft hadconflicting types), banked byte-identicald19c9580, ov077 clean-rebuilds. Key P9 finding:func_80159C84/func_8015444C(the 2 carried Fable5 bodies) are rtu_match FALSE-MATCHes — their C jtbls are incomplete (52B vs 56B), so they never bank; rtu_match excludes the §8 rodata (confirms the checkpoint's "2 jtbl false-MATCH"). The maspsx "hang" scare was a truncated-experimental-file artifact — the real pipeline builds in ~1s. NEXT: full R22 (in flight) → commit the PoC + tooling; then the ×134 automation (generate the per-overlay carve + template the reconciled body per sibling). - 2026-07-12 (session 3, TINY-BAND mechanical harvest — Task 8 continuation): Regenerated the h_seq manifest from the mid-band-banked src (fleet 77.2% fn / 60.9% instr / 35.2% distinct — matches
commit:0530), then ranfamily_sweep.py --hseq --band tiny. Dry-run sized it: 180 tiny matched-exemplar families / 23,592 staged member-drafts across 267 (overlay,split) groups (skips 1,184 no-matched-unit / 148 unresolved-imm / 117 STRUCT / 39 pinned). Gated run: 17,975 member-matches BANKED / 5,617 gate-rejected (h_seq-collision false-templates — the whole-binary byte-gate G3/P9 refused every one; ~76% bank rate; per-group ~17/21 main + ~110–129/150_after). 266 overlay.cfiles touched. R22 clean-fleet (make clean+ extract-all-136 + check-all) → 136/136, 0 failed. dedup-check 1813 validated / 0 failed (registry untouched — hseq banks are per-overlay src, not ×134 registry). Metrics: distinct-code 35.2→39.1% (50,571/84,996 unique fns), instr-weighted 60.9→62.9%. The mechanical size-bands (substantial/mid/tiny) are now harvested; the remaining levers are the two harvest gaps (§8 jtbl-rodata, reconcile fn-ptr-extern). Committed (Drew pushes — R6). - 2026-07-12 (session 2b, Fable5 batch-1 whole-binary reality): P9 correction: the 2 Fable5 "cracks" (
func_80159C84/func_8015444C) rtu_match-MATCH but FAIL the whole-binary gate — both are jr-functions and rtu_match doesn't verify the §8 jtbl rodata (decision-log). Two harvest gaps found: §8 jtbl-rodata (blocks all jr cracks incl. the Fable5 cores) + reconcile data-extern (D_801891B8-class, blocks ~15/21 no-jtbl triage cracks). Real whole-binary result: 6 no-jtbl reconcile-clean cracks bank = 729 members (463 committed + 266 this commit, func_8015CD20/8015C128 ×133).func_80176218(no-jtbl) still cracking = the clean non-jtbl Fable5 test. R22 deferred until it releases asm/. - 2026-07-12 (session 2, resume after usage-limit interruption): R22 confirmed the committed 463 reconcile-class banks 136/136. Fable5 batch-1 results:
func_80159C84MATCHED (337-ins 2-jtbl giant, pin-free; new cookbook idiom = gcc-2.7.2 postincrement pending-queue(*(s32*)(p+0x238))++ >= K);func_8015444C(reached 29-mismatch) +func_80176218(early) were cut off by the weekly limit → re-launched (444C resumes from its 29-mismatch partial). The interrupted reconcile-raw-19 harvest (260/1565, partial src) was reverted (R22 discipline) and re-running clean folding in func_80159C84. All background; process on completion → R22 → commit. Fable5 batch-1 = the last batch until Drew re-approves (Drew, 2026-07-12). - 2026-07-11 (session 1, Task-8 validation slice — Drew-approved pre-window de-risk): Ran reconcile→gate→template on the triage cracks. Reconcile→bank WORKS: raw 0/23 (§41 wall) → via
canon_sig_reconcilev3.2 4/15 banked into ov077 (func_801506A4/8016A73C/80167540/80155800, byte-identical). Templating a reconciled body ×133 FAILS 0/4 — reconciled bodies are ov077-TU-specific (casts + collision-renames), need per-sibling re-reconcile (§41c). → Task-8 prerequisite: port the h_norm--reconcileM2 path intohseq_sweep. Kept the 4 ov077 banks. decision-log 2026-07-11 (R31). Paused before building the wiring per Drew. - 2026-07-11 (session 1, Task 6 — DONE + paused): Ultracode triage Workflow (119 agents, 0 err, 5.3M tok): m2c draft (+§8 jtbl) →
match_onecloseness → class + lever + seed. cheap 29 (23 closeness-0) / permuter 29 / fable5 61. Curriculum →docs/phase26-triage.md. Attempted to bank the 23 cracked "wins" into ov077 (Drew: "bank the wins but pause before task8") → 0/23 gate — the isolation-MATCHes carry standalone types/Ghidra-sigs that hit the §41 def-side wall in the real TU (redefinition of struct Obj/conflicting types); banking needs the Task-8--reconcilepass. Seeds preserved in.run/phase26-seeds/+.run/ov077_bank/. PAUSED before Task 8 per Drew. src pristine, ov077 green. - 2026-07-11 (session 1, Task 5 — GO/NO-GO = GO): Ran the real byte-gate on the substantial matched-exemplar band. Discovered + fixed the decl class (
remap_hseq.gather_externscarries file-scope externs). 532 members banked, R22 136/136 green, distinct 30.3→30.9% / instr 58.2→58.5%. Per-family: 3 tracker-miss PURE families bank 100% ×133 (399 byte-perfect free win); 9 type-using families → §41 reconcile (Task 8); 16 pinned → Task 7. Machinery byte-proven 100% correct on clean families → GO to scale. decision-log 2026-07-11 (R31). Committed. - 2026-07-11 (session 1, Task 4): Added
family_sweep --hseq(additivehseq_sweep(), h_norm path byte-untouched): manifest-driven templating viaremap_hseq, unique per-group verified-out, static__asm__("$N"pin guard (skips the ×1-only pinned cracks → Task 7). Dry-run (--stage-only): substantial band stages 1507 clean / 267 groups, 1643 correctly skipped as pinned (16/29 families pinned, incl. the decision-log-named ones). Drafts byte-correct by construction; whole-TU gate = Task 5. Committed. - 2026-07-11 (session 1, Task 3): Built the T2a imm engine (
imm_value/imm_map_tier1/remap_hseq) — diff-driven Tier-1 literal swap with an asm-side ambiguity guard — + wired T2b cross-address self-rename. Tier-2 probe deferred (build-if-needed; byte-gate arbitrates). V3 (.run/v3_imm.py): 0 DIFF on all compilable pairs (5 MATCH), ambiguity guard + cross-address self-rename confirmed; comprehensive whole-TU gate validation is Task 5. Committed. - 2026-07-11 (session 1, Task 2): Built
tools/family_hseq.py(full-frontier h_seq survey) + the shared word-diff classifier infamily_remap.py(PURE/IMM/STRUCT, register-drift aware). Reproduces the fleet metrics + the 663/186/1.85M tail cross-check exactly; classification matches the Plan-agent table; 581 substantial target families / 3.22M templatable ins, 345 matched-sibling families / 1.14M ins = the zero-crack corpus.docs/family-hseq.mdcommitted. Committed. - 2026-07-11 (session 1, Task 1): Extended
reloc_targetsfor the add/addu indexed-global idiom (the "reach-1 tail" was largely this tracker blind spot, not unique code — decision-log + cookbook §40b).symbol_map/remapgained backward-compatibleto_addr(cross-address T2b) +imm_maphook; sequential→single-pass substitution (fixes the latent chained-rename bug). norm_stream/h_norm untouched. V0 (22/22 regression, 15/15 fix vs splat .s) + V1 (160 pairs, 0 regressions) both green. Committed. - 2026-07-11 (session 1, planning): Phase Start (Tier 1, Fable5+Max+plan-mode). Megaplan analyzed; survey reproduced from sigs+src (R14) — fleet metrics match PhaseEnd_25 exactly; 186-not-986 substantial-family correction; #2 family is cross-address; 93 matched-sibling families found (0.51M ins). Tooling recon (Explore) + design pressure-test (Plan agent) → the reloc-tracker blind-spot discovery (addu-preserves-hi; 890×121 family is PURE reloc; 63-fam zero-crack corpus; sequential-substitution latent bug). Drew's gate-1 decisions: carried queue → end of phase; structural milestone. Plan approved; task list built (R28). Task 0 complete with this commit.