Commit Graph

560 Commits

Author SHA1 Message Date
Drew T cc08601ae7 feat(phase-26): func_80178D40 swept ×134 — the heaviest core in the game, fleet-wide
- 132/132 siblings banked (0 failures) via jtbl_family_bank --raw + the lazy-isolation chain.
  Each sibling: isolate -> jtbl carve -> remap from the raw crack -> stage ladder
  (raw -> scoped §8d -> recovered -> reconciled) -> WHOLE-BINARY byte-gate.
- R22 clean-fleet 136/136 BYTE-IDENTICAL from `make clean`; 0 NON_MATCHING (G4).
- METRICS: instr-weighted 63.8 -> 64.7%; distinct-code 40.7 -> 42.8% (+2.1 points from ONE core —
  890 ins x 133 overlays = ~118K instructions of unique engine code); fn-count 82.43%.
- tools/bank_exemplar.py promoted from scratch: bank a cracked EXEMPLAR ×1 through the same stage
  ladder jtbl_family_bank uses for siblings (carve/lazy-isolate -> raw/scoped/recovered/reconciled
  -> whole-binary gate). The exemplar path was previously hand-run each time.
2026-07-14 00:02:26 -06:00
Drew T 07ebb5658d fix(phase-26): jr_isolate_all empty-region0 skip — cutting an already-isolated region's non-leader works
Cutting func_80178D40 out of ov_SC01_000_jr_801734BC adds the region's banked LEADER (0x801734BC)
as a cut too (the one-carve-per-object rule), making region 0 EMPTY (the object's first item IS the
first cut) — and region 1's derived name equals the object name, so emitting region 0 duplicated the
line exactly -> splat "segments out of order". Skip an empty region 0; region 1 rightly claims the
object's offset and name. First sibling then banks through the full chain (isolation validation
green -> carve -> --raw remap -> stage ladder -> whole-binary gate): ov_SC01_000 BANKED, included
here. The remaining 132 siblings sweep next.
2026-07-13 22:14:57 -06:00
Drew T 7e4165676d fix(phase-26): isolation-residue corruption chain — config cleanup + revert() restores config + fail-loud validation + --raw sweep mode
Three-layer fix for the func_80178D40 ×133 sweep failures:

- LAYER 1 (the residue): jtbl_family_bank.revert() restored carve pieces + src/ but NOT the
  isolation's CODE-subseg lines in the splat config. A failed bank attempt (BEBC's first try)
  left its isolation config in place; the successful retry re-isolated on top and a DUPLICATE
  `- [0x4b364, c, ov_SC01_000_jr_801734BC]` line rode into the commit (harmless to splat —
  zero-length — so R22 stayed green). revert() now also restores config/splat.<ov>.yaml.
  The committed duplicate is removed (ov_SC01_000 rebuilt BYTE-IDENTICAL 9052dc0e).

- LAYER 2 (the detonation): jr_isolate_all walked the duplicated object TWICE -> two
  replacements -> a reversed duplicate block -> splat "segments out of order". It now VALIDATES
  the generated config (code subsegs strictly ascending, names unique) and refuses to write on
  violation, naming the likely cause — a corrupt input dies at the tool, not three tools later.

- LAYER 3 (the sweep template): jtbl_family_bank gains --raw <crack.c> — template from the RAW
  crack via remap_hseq_body instead of the exemplar's banked source unit. REQUIRED when the
  exemplar banked at the `reconciled` stage: a reconciled body is TU-SPECIFIC (§41c — uniquified
  type names, TU-targeted casts), so extract_unit hands the sweep a polluted template and every
  sibling gate-fails (byte-proven: 178D40 banked reconciled -> sweep 0/4; 8015AE2C banked raw ->
  sweep 133/133). Same law as family_sweep --reconcile-raw.
2026-07-13 22:13:11 -06:00
Drew T 660aa9f215 feat(phase-26): func_80178D40 (890 ins, ×134 — the heaviest core) banked ×1 in ov_SC01_077
The §46 crack (MATCH 890/890, pin-free) banked through the whole-binary gate: lazy isolation ->
new region ov_SC01_077_jr_80178D40 + jtbl carve -> the FULL stage ladder (raw 36 conflicts ->
scoped -> recovered 5 -> RECONCILED banked; canon_sig_reconcile's type-name uniquification resolved
the SV3/Obj20/Blk typedef collisions) -> BYTE-IDENTICAL d19c9580. R22 clean-fleet 136/136.
The ×133 sibling sweep (PURE per-location, members staged) runs next.
2026-07-13 22:05:53 -06:00
Drew T 3a67dd609f feat(phase-26): func_8017BEBC (952 ins, ×113) CLOSED + banked ×1 — the §47 live-length slider
The largest unmatched core in the game, walled at close=2 for the permuter (25 min, no close) and
queued for a gdb-on-cc1 read. Closed WITHOUT gdb — the RTL dumps were the oracle:

- THE TIE, byte-measured (.lreg): &g.sz1 pseudo 228 refs 13 / live_length 783; &g.sz2 pseudo 230
  refs 13 / 782 -> pri = int(390000/L) = 498 == 498, an exact int-truncation tie in global.c:594
  allocno_compare. Tie-break = creation order -> allocation follows emission; the target needs them
  to DIFFER (allocation sz2-first, emission sz1-first). The shipped operand-permutation workaround
  could only pick one (close=2 vs close=10).
- THE FIX (§47): restore NATURAL operand order (emission correct) + ONE zero-byte
  `__asm__ volatile ("")` placed BETWEEN two existing GTE volatile asms (no new cse/sched barrier —
  one is already there) -> +1 static insn at global-alloc time -> L 784/783 -> pri 497 vs 498 ->
  the tie SPLITS toward the shorter-lived (later-created) pseudo, which is ALWAYS the direction
  "allocation != creation" requires. All 10 grants cascade; MATCH 952/952 first try; the slider
  emits only #APP/#NO_APP (zero bytes). PIN-FREE, ×113 template-safe.
- BANKED ×1 in ov_SC01_000 through the WHOLE-BINARY gate (jr fn — match_one is not the arbiter,
  §8a): lazy isolation -> new region ov_SC01_000_jr_8017BEBC + 9-piece jtbl interleave -> splice ->
  BYTE-IDENTICAL. One TU-visible decl reconcile en route (D_800B9A02: declare the TU's `short`,
  force the unsigned halfword at use `(*(u16*)&D_800B9A02)` — §8d sub-class (b)).
- R22 clean-fleet 136/136 BYTE-IDENTICAL; 0 NON_MATCHING (G4). The ×113 sibling sweep is IMM-class
  (scattered addresses) -> Task-8 mechanical work via the imm engine.
- cookbook §47 (the slider method + the placement rule + the direction law); decision-log (R31).
2026-07-13 22:02:46 -06:00
Drew T a0e7ff7f6f fix(phase-26): scope_data_externs ANSI-brace fix + wire §8d into family_sweep --hseq; 780-class diagnosed
- _body_open_brace only matched a `{` on its own line (the K&R shape), so fix() SILENTLY NO-OP'D on
  every ANSI draft — the same silent-skip disease as the four catalogued in §40/§8d, caught because
  the h_seq re-sweep banked 0/780. Now brace-scans forward from the signature (ANSI same-line,
  ANSI own-line, and K&R all work). Load-bearing for func_80178D40's upcoming ×134 bank.
- family_sweep --hseq now applies the §8d scoped stage at staging time.
- HONEST RESULT: still 0/780 — the substantial-band h_seq rejections are a DIFFERENT (sibling) class,
  now fully diagnosed against the bytes:
    gcc-2.7.2 decl-conflict semantics: a VISIBLE file-scope decl + a conflicting later decl (file OR
    block) is a HARD ERROR; a limbo-only block decl (scope closed) + a conflicting later decl is a
    warning. The h_seq drafts carry the EXEMPLAR TU's spellings; sibling TUs legitimately spell the
    same symbol differently (loose typing), and the visible decl is often MACRO-INJECTED — a
    DEFINE_func_* leading extern (§8c), invisible to any col-0 scan (e.g. D_80115158's `short` decl
    enters ov_SC01_000.c via DEFINE_func_8014168C() @4637; the draft carries ov077's
    `unsigned short` -> conflicting types at ANY scope).
  Sub-class (a) no-visible-decl -> §8d demotion (the jr class, proven x133). Sub-class (b) visible
  decl, different spelling -> needs reconcile-to-TU-VISIBLE (rewrite the draft decl to the TU-visible
  spelling + byte-neutral access cast; oracle = col-0 decls above the stub + engine_core.h macro
  externs for the DEFINE_ invocations above). Parked as a designed follow-up task; the 780 members
  are mechanical-recovery fodder once the tool exists.
2026-07-13 21:49:22 -06:00
Drew T b8a525bb98 feat(phase-26): h_seq substantial-band re-sweep — 266 free member-matches (~0 agent tokens)
The extract_unit fix (commit:0552) revealed 82 families with a genuinely-matched exemplar and UNSWEPT
siblings (~2.03M templatable bytes) — mostly exemplars cracked AFTER the session-2/3 mechanical band
sweeps ran (the giant campaign + recent cores), so the sweep had simply never seen them.

- re-ran `family_sweep --hseq --band substantial` on a regenerated manifest: 29 matched-exemplar
  families, 1046 member drafts staged, 1643 correctly skipped as pinned-exemplar.
- BANKED 266 member-matches / 780 gate-rejected. The whole-binary byte-gate (G3/P9) arbitrated every
  one; R22 clean-fleet 136/136 BYTE-IDENTICAL from `make clean`.
- metrics: instr-weighted 63.6 -> 63.8%; distinct-code 40.5 -> 40.7%; fn-count 82.39%.

The 780 gate-rejections are the next lever: family_sweep's h_seq path does NOT yet carry the §8d
`scoped` stage (it prepends carried data externs at FILE scope, the exact class that blocked the jr
sweeps), so a large share are expected to be the same decl-environment conflict. Investigated next.
2026-07-13 21:29:45 -06:00
Drew T 7b970653ff docs(phase-26): cookbook §46 — func_80178D40 MATCH (890 ins ×134): four loop-structure levers
The heaviest core in the game (890 ins, reach 134 = 477 KB) closed from close=39 to MATCH 890/890,
PIN-FREE, by cheap-Opus reading loop.c/jump.c/cse.c. All 39 residuals were in ONE case body and every
one was STRUCTURAL — the permuter could not have reached any of them. Four new general levers:

- L1 PEEL: a loop's `break` must not land on the loop's own fall-through label — that leaves
  NOTE_INSN_LOOP_BEG + an unconditional jump, firing duplicate_loop_exit_test (jump.c:2131), which
  rotates the loop and peels iteration 1 (const-folding `i++` and dragging an extra address
  re-materialization block). Write `goto <label>;` — same destination, different construct.
- L2 SURVIVING COPY: a source-level `fp = q;` ALWAYS dies (cse canon_reg + qty_first_reg, then flow).
  To make it survive, split def and uses across extended basic blocks — cse resets its hash table at a
  label with >1 predecessor. Test the memory, assign inside the guard branch.
- L3 MERGED STORE: write the store INSIDE the branch that reaches the shared tail, so jump2 tail-merges
  it and reorg steals the `li` into the delay slot. An unconditional store before the `if` blocks it.
- L4 UN-COALESCED LOOP COPY = a non-replaceable giv, needing all three of: an index giv `&A[i]`; a use
  OUTSIDE the loop (record_giv, loop.c:4437 -> emit_insn_after at loop.c:3945); and the biv increment
  LAST, so the reduced giv's addiu lands in the loop-back delay slot (i++ at the top costs +1 insn).
- L5 KEEP TAILS APART: two structurally identical loops must differ in a REGISTER or cross_jump merges
  their tails — give each its own pointer pseudo. (§8's cross-jump lever, inverted.)

Confirms the tier doctrine: cheap-Opus applying the documented §31 map cracked the game's heaviest core;
Fable5 was not needed. R17 held — "wrong BYTES" -> read the real gcc-2.7.2 passes.
2026-07-13 21:16:36 -06:00
Drew T cc6220eba4 fix(phase-26): extract_unit mistook m2c declarations for definitions (15 phantom exemplars)
- BUG: the guard `not ln.rstrip().endswith(";")` misses m2c's declaration form
  `M2C_UNK func_80178D40(s32, s32);   /* extern */` — the raw line ends in `*/`, not `;`, so a
  DECLARATION was accepted as a DEFINITION and the forward brace-scan swallowed the NEXT
  function's body, handing remap_hseq a garbage unit.

- BLAST RADIUS (measured): 15 of 35 substantial-family exemplars were phantom "matches" — all
  still INCLUDE_ASM stubs (incl. func_80178D40 and the carried-queue func_801670E4); 3 more
  anchored on the Phase-17 canonical-sig layer's `extern … /* match-first, arity N */` decls and
  templated garbage, leaving those families SILENTLY UNBANKABLE. The whole-binary byte-gate
  rejected every one — no wrong match was ever banked (G3/P9 held) — but the engine burned a
  build per sibling and every extract_unit-based readiness analysis was wrong.

- FIX: strip trailing comments before the `;` test.

- REGRESSION-GATED over the whole corpus (6,286 family exemplars, .run/_eu_before.json):
  15 phantom exemplars now correctly refused; 3 garbage units corrected to the REAL definition
  (found in the right region file); 0 real definitions lost; 0 unit contents otherwise changed.
  src/ and config/ untouched, so the committed build is unaffected.

- cookbook §40: the trap + the general lesson — this is the phase's FOURTH silent-skip bug
  (find_site braces, overlay_files splits, reconcile_decls fn-ptr regex, now this). A tool that
  silently no-ops on input it cannot parse is indistinguishable from one that had nothing to do.
2026-07-13 20:53:23 -06:00
Drew T 1ab9905368 feat(phase-26): §8d scope_data_externs — the ×133 sweep blocker fixed; func_8015AE2C banked ×134
- 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.
2026-07-13 20:45:15 -06:00
Drew T 12631df74a docs(phase-26): R17 triage rule — 'wrong bytes' -> read gcc; 'won't compile' -> read our Python
Drew asked whether the x133 sweep blocker warrants a gcc-2.7.2 source read. It does not,
and the distinction is worth pinning down because it routes every future residual:

- 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 reconcile_decls (fleet-majority oracle vs the TU's visible decl).
  Reading cse.c/loop.c/global.c would tell you nothing.
- func_8017BEBC (close=2) is the opposite: it compiles fine and emits the wrong bytes, and
  the cause is localized to global.c's allocno-priority tie. THAT is the R17/§45-B target
  (gdb-on-cc1 read of allocno_live_length) — 2 instructions from a 107K-ins bank.

Rule: 'wrong BYTES' -> read the compiler (R17). 'won't COMPILE' -> read our Python.
cookbook §31-triage + the CURRENT_PHASE NEXT block annotated with the routing.
2026-07-13 19:50:51 -06:00
Drew T 9bbfff9b8c docs(phase-26): session-7 checkpoint — heavy-jr waves run; 1 core banked x1, 2 cracks in hand, sweep blocker diagnosed 2026-07-13 18:35:38 -06:00
Drew T f206659dcf feat(phase-26): jtbl_family_bank recovery stage (per-sibling cast+reconcile) + tolerant stage loop
- NEW "recovered" stage between raw and reconciled: cast_call_sites + reconcile_decls run
  against THIS sibling's TU. The recovery must be redone per sibling because the conflicting
  symbols are largely PER-OVERLAY (D_801812A4 in ov_SC01_000 vs D_800D4F8C in ov_SC01_077),
  so the exemplar's recovered decls do not transfer through the remap.
- The stage loop no longer aborts a sibling when a stage cannot PRODUCE a candidate. It skips
  to the next one. canon_sig_reconcile raises on a K&R definition (it expects an ANSI
  signature), and a K&R def is MANDATORY whenever a zero-arg engine_core.h thunk calls the
  function (func_8015AE2C) — so that must not kill the bank.
- gate-fail now reports the last stage error instead of an empty string.

STATUS (P9): the func_8015AE2C x133 sweep is still BLOCKED and this commit does not close it.
Remaining blocker, precisely diagnosed: the remapped body's DATA externs conflict with the
sibling's §8b carried decl layer (which carries the macro externs of earlier regions and
faithfully reproduces the original TU's declaration environment). 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 (authoritative) — or drop body externs the layer already provides and cast
at use. The exemplar itself is banked and green.
2026-07-13 18:35:02 -06:00
Drew T 9b93c254c2 feat(phase-26): func_8015AE2C (562 ins, x134) banked — Fable5 MATCH + 3 isolation bugs fixed
Exemplar banked byte-identical (d19c9580); R22 clean-fleet 136/136.
Fable5 crack: MATCH 562/562, pin-free, jump table verified.

THREE REAL BUGS the bank exposed in jr_isolate_all (each byte-proven; each would have
silently corrupted every future heavy-core bank):

1. --only filtered `banked` as well as the cut set, so already-banked jr went untracked
   and their carves were never followed. --only selects what to CUT; it must not erase
   the record of what is already banked.
2. carve ownership was read from splat .s — but splat emits NO .s for a MATCHED function
   (its .c holds real C), so the lookup found nothing. Now resolved from the extracted
   IMAGE via family_remap.reloc_targets (byte-exact: func_801734BC -> 0x801d8c68 etc).
3. THE STRUCTURAL ONE: a region may host at most ONE .rodata carve, because an object's
   .rodata is a single CONTIGUOUS section. Cutting at func_8015AE2C (jtbl 0x801D8B54)
   left the banked func_801734BC (jtbl 0x801D8C68) inside the same region, so the object
   emitted a 0x34 .rodata spanning BOTH tables (image +33 B). Every already-banked jr in
   a cut object is now cut too -> exactly one carve per object. Cookbook 8b's "bank
   same-subseg families ASCENDING" note warned about this; it is now enforced by
   construction instead of left to discipline.

Also required (per the crack's own analysis, all byte-verified):
- engine_core.h: DEFINE_func_8015BEC4's zero-arg thunk returns func_8015AE2C(), so the
  extern must drop its (void) prototype and the def must stay K&R/unprototyped.
  Byte-neutral across all 136 (R22 green).
- recovery chain: cast_call_sites (27 callees) + reconcile_decls (3 data syms). The raw
  body declares callees with types that conflict with their real engine_core.h defs; the
  original never redeclares them, it CASTS at the call site (cookbook 20).

Layout now exact: .rodata 0x801d8b54/0x1c (7 entries, pad trimmed) + 0x801d8c68/0x14 +
0x801d92a0/0x20 — one table per object, each at its true address.
2026-07-13 18:26:32 -06:00
Drew T 754ac3428f fix(phase-26): permuter silently no-op'd on every GTE draft (+ --asm-subdir)
Second silent no-op of the §G class, found while permuting func_8017BEBC (close=2):

- hide_asm() is built for __asm__ STATEMENTS and `register __asm__("$sN")` pins inside a
  function body (it scans back to the previous ;{} and forward to the next top-level ;).
  A draft whose GTE ops are #defines CONTAINING __asm__ (the PsyQ inline_c.h convention,
  i.e. most renderer code) therefore had its macro DEFINITIONS chewed up, swallowing the
  function itself -> pycparser 'Function <fn> not found in base.c' -> decomp-permuter
  no-op'd in 0s. base.c contained ZERO occurrences of the target function.
  FIX: cpp_expand_macros() pre-expands with `cpp -P` so each GTE op becomes an inline
  __asm__ statement hide_asm can carry via the b64 pragma. Applied ONLY when a
  '#define ... __asm__' is present -> macro-free drafts byte-untouched.
- p16_permute was hardcoded to OV=ov_SC01_077's MAIN object, so no core in another overlay
  or split object could be permuted at all. Added --asm-subdir (threaded explicitly: a
  def-time default arg cannot see a mutated global).

LESSON (cookbook): permuter 'no match (0s)' is a TOOLING failure signature, never a real
search result. Verify workers actually ran.

Verified: base.c now holds the function; 16 workers searching on func_8017BEBC.
2026-07-13 16:50:38 -06:00
Drew T b0691f4bd9 fix(phase-26): jtbl_carve trims trailing .align pad words (§8a-pad)
A trailing `.word 0x00000000` under a jtbl dlabel is the ORIGINAL TU's intra-rdata
.align 3 padding, NOT a table entry (0x00000000 is not a jump target). The true entry
count is the fn's `sltiu <n>` bound: func_8015AE2C has sltiu 0x7 = 7 entries yet its
raw dlabel spans 8 words.

maspsx drops all .align, so a C-emitted jump table can never reproduce the pad. Carving
to the next dlabel would reserve 8 words while the compiled object supplies 7 ->
.rodata under-fills by 4 B -> every later symbol shifts +4 (the same image-corruption
class as §41d). jtbl_range now trims trailing zero words, leaving the pad in the raw
post-carve data piece.

Retroactively explains the §8a func_80159C84 '5 words vs the real 6' false-MATCH.
Existing carves are parsed from CONFIG, not re-derived, so committed banks are
unaffected (verified: the 3 carved jtbls are absent from the raw data asm). The build
never invokes jtbl_carve, so the fleet is inert to this change until the next bank.

Found by the Fable5 crack of func_8015AE2C (562 ins x134, MATCH, pin-free).
2026-07-13 15:23:59 -06:00
Drew T f89fd50afb docs(phase-26): session-6 checkpoint — de-risk complete, 3 gate-cap bugs fixed; §41d 2026-07-13 14:44:07 -06:00
Drew T 258f10c048 feat(phase-26): func_80182268 family banked x3 — the lazy jr pipeline proven end-to-end
Sibling sweep via jtbl_family_bank: ov_SC02_000 + ov_SC02_003 (cross-address, the
fn lives at 0x8017FCB0 in both) BANKED byte-identical. With the exemplar that is the
complete family (3/3).

This closes the de-risk: the lazy jr bank composition now runs end-to-end on a real
cracked core — lazy isolate -> jtbl_carve into the isolated subseg -> cross-address
remap -> raw-first two-stage gate -> whole-binary byte-gate -> x-members.

R22 clean-fleet 136/136 byte-identical; 0 NON_MATCHING (G4).
2026-07-13 14:43:36 -06:00
Drew T c66b530f71 fix(phase-26): bound the §8b carried decl layer + cross-address sibling naming
Two bugs the func_80182268 sibling sweep exposed (both would have silently capped
every future jr family bank):

- extract_unit walks BACKWARD from a definition absorbing preceding extern/comment
  lines as the fn's preamble. The §8b carried decl layer sits directly above the
  FIRST item of an isolated region, so the unit swallowed the whole layer -> the
  template dragged ~140 unrelated externs into each sibling (some naming types the
  sibling TU lacks) -> gate-fail. jr_isolate_all now emits an explicit end-marker and
  extract_unit stops at it (also guards the Phase-17 canonical-sig layer).
- jtbl_family_bank passed the EXEMPLAR's name to the sibling's carve/isolate/stub
  lookup. Cross-address families (same engine fn at a different vram per overlay)
  therefore never resolved: ov_SC01_077 @0x80182268 -> ov_SC02_000/003 @0x8017FCB0.
  The sibling's name is now derived from to_addr. The first two banked jr families
  were same-address, so this had never surfaced.

ov_SC01_077 d19c9580 byte-identical; R22 clean-fleet 136/136.
2026-07-13 14:41:53 -06:00
Drew T e79d030499 feat(phase-26): func_80182268 banked via the LAZY isolation path + the void->s32 gate-cap fix
End-to-end proof of the §8b lazy bank composition on a real cracked jr core:
lazy isolate -> jtbl_carve into the isolated subseg -> C body -> whole-binary gate
-> d19c9580 BYTE-IDENTICAL; R22 clean-fleet 136/136.

- func_80182268 (31-ins jr, ov_SC01_077_after) MATCHED first try: shared-tail
  fallthrough (jtbl cases 3+7 enter case 4's tail) + the u16-shift sign-extend idiom
  ((s8)(*(u16*)(p+0x70) >> 8) -> lhu/sll16/sra24). Carve collided with the committed
  func_801734BC carve -> lazy isolation fired exactly as designed.
- R14 FINDING (cookbook §41d): the Phase-17 canonical convention "void->s32 return is
  byte-neutral (§3a-1)" is FALSE for a void body with no `return` — it costs ONE extra
  instruction. canon_sig_reconcile applies it unconditionally, so it turned a perfect
  31-ins MATCH into 32 ins. That extra word made the isolated object's .text 4 B long,
  shifting EVERY data symbol +4 -> ~271k differing bytes, image +5 B. match_one said
  MATCH; only the whole-binary gate caught it (G3/P9).
- FIX (generalizes the §19 sig_unify lesson): every recovery pass is a FALLBACK, never
  unconditional. jtbl_family_bank now gates RAW first, reconciled only on failure.
- 136/136 byte-identical from a clean tree (R22); 0 NON_MATCHING (G4).
2026-07-13 14:34:04 -06:00
Drew T 38ac5659aa feat(phase-26): §8b scoping wall BROKEN — decl-environment reconstruction + lazy per-core isolation
The full 54-jr isolate-all on ov_SC01_077 now builds d19c9580 BYTE-IDENTICAL
(R22 clean-fleet 136/136) — the configuration session 5 could not build. The
heavy-jr harvest (191 cores / 5.53M templatable ins) is unblocked.

- 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 merely live in
  engine_core.h, invisible to any col-0 .c scan (1377 macros / 3929 lines / 1462 syms).
- REJECTED the approved "global symbol->type map + shadow set" design: the engine is
  loosely typed (func_80173544 is DEFINED `s32 f(void*)` yet declared `extern void
  f(void);` inside func_801734BC's body), so declaring every USED symbol hoists that
  block-scope shadow to file scope and CREATES the conflict a shadow-set then dodges.
  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; compatibility is
  order-symmetric; shadows stay in bodies and travel with their item).
- The byte-gate found two MORE lost decl sources, not predicted: (a) a definition is
  itself a declaration for everything below it in its TU (func_8012B2CC undeclared);
  (b) file-local typedefs used by a carried prototype (parse error, Vec3s). K&R defs
  must render `extern T f();` (unprototyped), never f(void).
- LAZY per-core isolation wired into jtbl_family_bank (Drew's call — upfront-x134 =
  ~7,200 region files): jtbl_carve NON-CONTIGUOUS fail-loud -> jr_isolate_all --only
  <core> -> re-extract -> re-carve. Proven on func_80178D40 (890x134, heaviest core):
  carve blocked -> isolated (byte-neutral d19c9580) -> carve in its own subseg.
- TWO LATENT BUGS fixed (both would have corrupted the heavy sweeps):
  * jtbl_carve.func_subseg derived the owning subseg from the ASM TREE, which `make
    extract` never prunes -> after an isolation it returned the STALE owner and
    silently re-created the very collision the isolation removed. Now config-derived.
  * jtbl_family_bank/jtbl_carve revert() DELETED the shared overlays.mk carve var
    unconditionally -> would destroy a COMMITTED carve (all 134 overlays have one) on
    any failed sibling. Now restored to its committed value; only region files created
    by this attempt are removed; dirty-tree preflight refuses to start a sweep.
- docs: cookbook §8b RESOLVED + new §8c "splitting a TU means rebuilding its
  DECLARATION ENVIRONMENT, not moving text"; decision-log 2026-07-13 (R30/R31).
- parser selftest 404/404; R22 clean-fleet 136/136; 0 NON_MATCHING (G4).
2026-07-13 13:25:39 -06:00
Drew T 234788dfc4 feat(phase-26): §8b overlay-src parser (404/404) + jr isolation tool + the gcc-scoping wall finding
- 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/RETCONST classification). Fleet-validated 404/404 overlay .c, 341,902 items —
  round-trip exact / 0 unresolved / 0 non-monotonic. The Stage-2 isolation unblock.
- tools/jr_isolate_all.py: multi-cut jr resegment (config split at jr boundaries, source
  repartition + INCLUDE_ASM path repoint, banked-jr carve repoint, -O0 skip, ambient decl
  carry). SINGLE-cut isolation byte-identical (func_8013FFD8 -> d19c9580, R22).
- FINDING (decision-log 2026-07-13): full 54-jr isolation of the dense _after object hits
  gcc-2.7.2 block-scope-extern TU-persistence (func_801734BC/D_80126B3E declared only in
  engine_core.h DEFINE_func macros); mechanical TU-split breaks it. Fix = declaration-
  completion from a global symbol->type map (Drew-approved next step; lazy per-core).
- baseline intact (ov_SC01_077 rebuilds d19c9580); no config/src/binary change committed.
  CURRENT_PHASE session-5 checkpoint + decision-log R31. db.*.gbf = R23 noise, not staged.
2026-07-13 12:00:26 -06:00
Drew T d1dd29d815 feat(phase-26): §8b multi-jtbl same-subseg — contiguous MERGE (built) + isolation scaffold
Session-4 same-subseg handling (the de-risk preamble's harder half; byte-proof of
the merged build + isolation deferred to Stage 2 with concrete cores):

- jtbl_carve.py: MERGE adjacent same-subseg carves into one spanning .rodata piece
  (a code object emits its jtbls contiguous, so two matched jr-fns in one subseg are
  byte-correct iff their jtbls abut). 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 -> raw dlabels over-extend it -> false "non-contiguous").
  Config-proven (func_80171B4C 801D8C48 merges with func_801734BC 801D8C68). NO-OP
  for family-1/cross-subseg (single carve per subseg) -> committed configs unaffected.
- jr_isolate.py (scaffold, NOT yet functional): the non-contiguous case — split a fn
  into its own code subseg (whale _o0b precedent) so its jtbl carves independently.
  BLOCKED on split_src_region, which can't partition the overlay .c (global canonical-
  sig extern layer + per-fn callee-externs + DEFINE_func macros + @class annotations,
  ~922 non-address items). Stage-2 build item (overlay-.c-aware source split).
- cookbook §8b (the --order sandwich + the two same-subseg cases + the blocker);
  CURRENT_PHASE session-4 checkpoint updated with the Stage-2 unblock decision.
2026-07-12 22:06:17 -06:00
Drew T ca50ee6978 feat(phase-26): §8 multi-jtbl --order carve + family-1 (func_801734BC ×134)
- ld_interleave.py --order: address-ordered N-piece data->rodata->data sandwich
  for overlays with 2+ matched jr-functions; legacy --front/--tail path is byte-
  untouched (main EXE + the 133 single-carve func_8012ACE0 siblings unaffected)
- jtbl_carve.py rewritten additive/regenerate-from-config: parse the tail data
  region + existing .rodata carves, split the containing data piece for the new
  jtbl, re-emit the address-ordered pieces + the --order arg; same-subseg carve
  collision fails loud (-> jr isolation); idempotent
- jtbl_family_bank.py: `make extract` BEFORE the carve (asm must match the reverted
  committed config; the old error-string retry was fragile) + revert-on-carve-fail
- family-1: func_801734BC (34-ins PURE jr, ov_SC01_077_after) matched in ov077
  (shared-tail switch idiom) + banked 133/133 siblings = x134 — CROSS-subseg
  multi-jtbl (func_8012ACE0 in _a + func_801734BC in _after)
- R22 clean-fleet 136/136 byte-identical (~52s); 0 NON_MATCHING (G4)
2026-07-12 21:51:27 -06:00
Drew T 79ca6b4975 docs(phase-26): refine session-3 checkpoint — small-jr-first as de-risk preamble, then heavy 191
- Drew's sequencing (agreed): do the 45 small jr families FIRST — not for byte-weight (~+1% instr,
  129K ins) but to de-risk + harden the §8 x134 pipeline before the heavy Fable5 cores bet on it.
- decisive technical reason: jtbl_carve only built the single-jtbl carve; func_8012ACE0 is now
  matched in all 133 siblings, so family #2 forces the multi-jtbl address-ordered `ld_interleave
  --order` carve -> build & prove it on cheap 30-ins targets first. Also needs no Fable5.
- guardrail kept explicit: small tier = MEANS (harden pipeline + build multi-jtbl), NOT the
  objective; the 191 heavy jr families (5.53M ins) remain THE byte-weight target -> pivot after.
- CURRENT_PHASE.md SESSION-3 checkpoint updated to Stage 1 (small + build multi-jtbl) -> Stage 2
  (heavy 191, Fable5 un-paused). decision-log addendum with the forcing-function wiki lesson.
2026-07-12 20:24:21 -06:00
Drew T 4e17a7e77b docs(phase-26): session-3 checkpoint — heavy-byte-weight reframe (§8 unlocked the switch cores)
- decision-log (R31): §8 unblocked the SINGLE heaviest byte-weight chunk of the game — 9 of
  the 10 heaviest unmatched family cores are switch (jr) functions (func_80178D40 890x134 =
  477K ins alone); jr substantial = 191 fams / 5.53M templatable ins. My "45 small jr families"
  recommendation (129K ins) was a light-tail trap — Drew caught it against the endgame plan
  (heaviest-byte-weight-first). Corrected next play: Fable5 crack the heavy jr cores -> §8 x134
  bank -> parallel R22 verify; needs Task 7 (Fable5) un-paused (§8 makes that worth it now).
- CURRENT_PHASE.md: SESSION-3 checkpoint as the fresh-session resume point (4 commits this
  session: tiny-band commit:0531, §8 PoC commit:0532, §8 x134 commit:0533, R22 parallel commit:0534;
  distinct-code 30.3->39.1%, instr-weighted 58.2->63.0%, R22 now ~50s)
2026-07-12 19:20:58 -06:00
Drew T 6fb8d323bd perf(phase-26): parallelize R22 clean-fleet — ~9min -> ~50s (10.5x), 136/136 byte-identical
- profiled the clean-fleet R22: extract-all ~6m11s (136 serial `splat split`) + check-all
  ~2m58s (136 serial builds) = ~9 min, all serial on a 32-core box
- the only shared WRITE is the 4 generated include/*.inc macros at extract time (identical
  content per binary); everything else is per-binary-disjoint and include/ is read-only during
  a build -> concurrent builds/extracts don't race
- Makefile: JOBS ?= 16 + `make extract-all` (seed main serial for the macros, then parallel-
  extract the rest via xargs -P) + parallel `make check-all` (xargs -P), correctness-gated
- MEASURED: `make clean && make extract-all && make check-all` = ~50s, check-all 136/136
  BYTE-IDENTICAL (== the serial result) -> ~10.5x. Compounds across the endgame (R22 per commit)
- new R22 recipe: `make clean && make extract-all && make check-all` (was the serial for-loop)
2026-07-12 19:12:33 -06:00
Drew T 5a08180617 feat(phase-26): §8 ×134 automation — func_8012ACE0 banked fleet-wide (133/133, R22 136/136)
- the jr-function ×134 harvest pipeline, proven end-to-end: per family sibling,
  jtbl_carve (per-sibling jtbl-rodata carve, computed from THAT sibling's own jtbl
  address — the fn is at the same vram across overlays but its jtbl floats) -> make
  extract (auto ld_interleave) -> remap_hseq + canon_sig_reconcile -> whole-binary gate
- tools/jtbl_carve.py: per-overlay §8 carve generator (config data-tail split +
  <ov>_JTBL_INTERLEAVE var)
- tools/jtbl_family_bank.py: the sibling sweep driver (idempotent, revert-on-fail, byte-gated)
- tools/family_remap.py: extract_unit now carries single-line typedefs (jr-function bodies
  define local `typedef struct{} Foo_<addr>;` that must template with the body — the
  propagation cap for these; additive, byte-gate-protected)
- func_8012ACE0 family: 133/133 siblings BANKED, 0 failures; R22 clean-fleet 136/136
  byte-identical; 0 NON_MATCHING (G4)
- metrics: distinct-code 39.1% (50,698 unique fns), instr-weighted 63.0%
- opportunity (has_mid_jr families): 237 total (5,805 members) = 46 small mid/tiny
  (771 members, same mechanical pipeline) + 191 substantial (the Fable5 cores, Task 7 paused)
- NEXT: R22 profiling/parallelization; then the other 45 small jr families
2026-07-12 19:02:25 -06:00
Drew T 095a611e75 feat(phase-26): §8 jtbl-rodata tooling — overlay PoC proven (func_8012ACE0, R22 136/136)
- overlay jr-functions can now bank as C: gcc switch jump tables form a .rodata island at
  the overlay TAIL; carve a matched fn's jtbl into a dotted [.rodata, <code-subseg>] subseg
  + ld_interleave (data->rodata->data sandwich) places it byte-exact. cookbook §8a + SETUP.
- tools/ld_interleave.py: --section .<binary> param (derives the <binary>_TEXT/DATA/RODATA/
  DATA2/BSS symbol prefix); default .main = the EXE, byte-identical (backward-compat proven)
- Makefile + config/overlays.mk: <bin>_JTBL_INTERLEAVE hook + a $(strip)-guarded extract
  branch (gotcha caught: a trailing #comment on the := left whitespace -> non-empty -> the
  branch misfired on resident with the EXE defaults)
- PoC: func_8012ACE0 (25-ins jr-fn in ov_SC01_077) reconciled (canon_sig_reconcile) + banked
  BYTE-IDENTICAL d19c9580 -- the first overlay jr-function matched through the C pipeline
- R22 FULL-FLEET clean rebuild: 136 passed, 0 failed (main 143dbb89 unaffected by the
  ld_interleave change); 0 NON_MATCHING in any default build (G4)
- P9 findings: func_80159C84/func_8015444C (the 2 carried Fable5 jr bodies) are rtu_match
  FALSE-matches (incomplete jtbls: 52B vs 56B -> never bank); the maspsx "hang" scare was a
  truncated experimental-file artifact (real pipeline builds in ~1s)
- metrics: distinct-code 39.1% (50,572 unique fns), instr-weighted 62.9%
- NEXT: the ×134 automation (generate the per-overlay carve + template the reconciled body)
2026-07-12 16:37:37 -06:00
Drew T 025cc03f69 feat(phase-26): tiny-band mechanical harvest — 17,975 member-matches, R22 136/136
- family_sweep --hseq --band tiny: 180 tiny matched-exemplar families ->
  17,975 member-matches BANKED / 5,617 gate-rejected (h_seq-collision
  false-templates — the whole-binary byte-gate refused every one; G3/P9),
  266 overlay .c files touched (~76% bank rate)
- R22 clean-fleet (make clean + extract-all-136 + check-all) -> 136/136,
  0 failed; dedup-check 1813 validated / 0 failed; 0 NON_MATCHING in any
  default build (G4)
- metrics: distinct-code 35.2 -> 39.1% (50,571/84,996 unique fns),
  instr-weighted 60.9 -> 62.9%. mechanical size-bands (substantial/mid/tiny)
  now harvested; remaining levers = the two harvest gaps (§8 jtbl-rodata,
  reconcile fn-ptr-extern)
- regen docs/family-hseq.md + docs/progress.fleet.md; CURRENT_PHASE.md log
2026-07-12 15:38:40 -06:00
Drew T 3074ceb485 feat(phase-26): mid-band clean harvest — 6853 member-matches (320 distinct fns), R22 136/136
- plain --hseq --band mid: 6,853 whole-binary member-matches banked = 320 distinct engine functions
  templated across the overlays (matched-exemplar families, plain templating; the ×N leverage of the
  h_seq per-location reframe). 3,098 type-heavy tail + 1,743 pinned + 873 no-ov077-body skipped/failed
  (expected — the reconcile/§8/pin tail, not machinery failures).
- R22 clean-fleet: make clean + extract-all-136 + check-all = 136 passed, 0 failed. 0 NON_MATCHING.
- METRICS: distinct-code 31.1->35.2% (+6,437 byte-distinct classes), instr-weighted 58.9->60.9%.
  Phase-26 total: distinct 30.3->35.2%, instr 58.2->60.9%.
- session-2 checkpoint (CURRENT_PHASE 'SESSION-2 CHECKPOINT') current: next = tiny band, then the §8
  jtbl tooling (Drew-approved) + reconcile fn-ptr fix. Fable5 held until re-approval.
2026-07-12 11:28:48 -06:00
Drew T b94e417edf docs(phase-26): session-2 checkpoint — full resume context (mid-harvest in flight, §8 approved, 2 gaps)
Comprehensive CURRENT_PHASE handoff for a fresh session: committed baseline commit:0528 (729 banks, R22
136/136); the h_seq engine + reconcile-raw tooling map; the mid-band harvest in flight (~2477+ banked,
uncommitted -> R22 + commit next); the two harvest gaps (§8 jtbl-rodata [Drew-approved] + reconcile
fn-ptr-extern); the Fable5 rtu_match-vs-whole-binary finding (no more Fable5 until re-approval); and the
mechanical next-steps priority order. R30 knowledge capture before context handoff.
2026-07-12 10:22:31 -06:00
Drew T 62f9533024 feat(phase-26): +266 reconcile-class banks (2 no-jtbl cracks x133) + Fable5 batch-1 whole-binary findings
- +266 member-matches: func_8015CD20/func_8015C128 templated x133 via --reconcile-raw (each SHA-gated
  per-overlay vs config/check.<ov>.sha = byte-identical, G3). Full R22 deferred until func_80176218
  releases asm/ (established per-overlay-gate + deferred-R22 pattern, as the committed 463 which R22'd 136/136).
- family_sweep: --reconcile-raw now also covers draft-ov077 (unbanked) cracks (template from the RAW seed).
- P9 CORRECTION + decision-log 2026-07-12: the 2 Fable5 cracks rtu_match-MATCH but FAIL the whole-binary
  gate (both jr-functions; rtu_match masks relocs + excludes neutralized INCLUDE_ASM rodata, so it never
  verifies the §8 jtbl rodata). TWO harvest gaps: §8 jtbl-rodata (blocks all jr cracks) + reconcile
  data-extern (D_801891B8-class, blocks ~15/21 no-jtbl triage cracks). 6 no-jtbl reconcile-clean cracks
  bank whole-binary (729 members). rtu_match is NOT a sufficient arbiter for jr-functions.
2026-07-12 01:38:49 -06:00
Drew T 7ccf48f2f4 feat(phase-26): Task-8 reconcile wiring (§41c h_seq) + 463 reconcile-class banks
- BUILT the per-sibling reconcile: family_remap.remap_hseq_body (h_seq-remap a RAW crack draft: symbol +
  immediate + cross-address self-rename) + family_sweep.reconcile_remap_hseq + --reconcile-raw. Per sibling,
  remap the RAW crack then canon_sig_reconcile against that sibling's own TU (the h_seq port of the h_norm
  M2 path) — because a reconciled body is TU-specific and can't template plainly (validation: 0/4).
- HARVEST: the 4 triage isolation-cracks (func_80155800/80167540/801506A4/8016A73C) templated 463/0 x~133
  via --reconcile-raw (0 failures). Metrics: instr 58.5->58.9%, distinct 30.9->31.1%.
- each overlay SHA-gated by harvest_verify vs config/check.<ov>.sha (byte-identical = the match def, G3).
  FULL R22 clean-fleet DEFERRED until the concurrent Fable5 crack agents release asm/ (their m2c needs it);
  R22 fleet-confirm to follow post-window.
- cookbook §40c (the h_seq per-sibling reconcile technique, R30).
2026-07-12 00:03:47 -06:00
Drew T 8dbde10752 feat(phase-26): Task-8 validation slice — reconcile→bank proven (4 cracks into ov077, R22 136/136)
- pre-Fable5-window de-risk (Drew): validate reconcile→gate→template on the triage cracks before the window.
- reconcile→bank WORKS: raw 0/23 (§41 def-side wall) -> canon_sig_reconcile v3.2 -> 4/15 banked into ov077
  (func_801506A4/8016A73C/80167540/80155800), byte-identical, R22 clean-fleet 136/136.
- templating a RECONCILED body x133 FAILS 0/4: reconciled bodies are ov077-TU-specific (canonical-sig casts
  + collision-renames) -> need per-sibling re-reconcile (§41c). Task-8 prerequisite: port the h_norm
  --reconcile M2 path into hseq_sweep so the type-using families (triage cracks + the 61 Fable5 cores) can
  template x134. PURE families already template plainly (Task 5: 399 banked).
- decision-log 2026-07-11: the slice paid for itself — found the templating gap BEFORE spending the window.
  Paused before building the wiring per Drew.
2026-07-11 23:40:01 -06:00
Drew T 5f07d099e6 docs(phase-26): finalize Task-6 triage (119 agents) + banking caveat; pause before Task 8
- full triage complete: cheap 29 (23 closeness-0 isolation-MATCH) / permuter 29 / fable5 61 (1.71M ins).
- attempted to bank the 23 cracked wins into ov077 -> 0/23: the match_one isolation-MATCHes are genuine
  function matches but carry standalone struct/scalar typedefs + Ghidra-typed sigs that conflict with the
  real ov077 TU (redefinition of struct Obj / conflicting types) = the §41 def-side wall. Banking needs
  the Task-8 --reconcile / canon_sig_reconcile pass (not run — paused before Task 8 per Drew).
- docs/phase26-triage.md carries the crack curriculum + the caveat; seeds in .run/phase26-seeds/.
- src pristine, ov077 byte-identical.
2026-07-11 23:12:53 -06:00
Drew T 80536efbea feat(phase-26): task 6 — Ultracode triage of 119 draftable substantial families
- .run/wf_triage*.js Workflow: per-family m2c draft (+§8 jtbl handling) -> match_one reloc-masked
  closeness -> classify cheap/permuter/fable5 + §31/§45 lever + seed to .run/phase26-seeds/.
- 119 families triaged (2.38M templatable ins): cheap 22 (324k ins, 20 already isolation-MATCH) /
  permuter 23 (340k) / fable5 74 (1.72M). The cheap-Opus triage flywheel cracked 20 families to
  closeness-0 as a side effect (each templates x134) -> Task-8 gate+template candidates.
- docs/phase26-triage.md = the crack curriculum (already-cracked seeds + top-30 Fable5 targets +
  permuter band). Seeds in .run/phase26-seeds/. match_one closeness is an INDICATOR; the whole-binary
  byte-gate (Task 8) is the sole arbiter (G3/P9).
2026-07-11 23:00:26 -06:00
Drew T d05203b9a0 feat(phase-26): task 5 — h_seq zero-crack GO/NO-GO = GO; 532 members banked (R22 136/136)
- remap_hseq.gather_externs: carry file-scope externs for body-referenced symbols (extract_unit only
  grabbed adjacent ones) — the decl class that blocked per-location bodies indexing a global. func_8015F118
  gate-fail -> BYTE-IDENTICAL; the 3 tracker-miss PURE families then bank 133/133 each.
- ran the real whole-binary byte-gate on the 29 substantial matched-exemplar families:
  532 members BANKED (byte-gated). Per-family: 3 tracker-miss PURE (0x8015d5e8/0x8015f118/0x801407f4)
  bank 100% x133 = 399 byte-perfect (the tracker-fix free win); 1 cross-addr family 50%; 9 zero-bank
  families are type-using (Work8016/Prim/...) -> the existing --reconcile/type-lift follow-on (Task 8);
  16 families pinned -> Task 7 pin-free re-crack.
- VERDICT: the h_seq machinery (tracker + imm + cross-address + extern-carry) is byte-proven 100% correct
  on clean families. GO to scale.
- R22 clean-fleet: make clean + extract-all-136 + check-all = 136 passed, 0 failed. 0 NON_MATCHING (G4).
  Metrics: distinct-code 30.3->30.9% (+375 fns), instr-weighted 58.2->58.5%.
- decision-log 2026-07-11 (R31: stratify a mechanical-harvest rate by family/class before judging it).
2026-07-11 22:15:30 -06:00
Drew T 3ce81cbf56 feat(phase-26): task 4 — family_sweep --hseq mode (cross-address + imm templating)
- additive hseq_sweep(): consumes .run/family_hseq.json, templates each matched-exemplar family's
  still-stubbed members via remap_hseq (reloc remap + imm subst + cross-address self-rename), stages
  by (overlay,split), gates each group once via harvest_verify. h_norm path byte-UNTOUCHED (new --hseq
  branch routes before it). Unique per-group verified-out fixes a latent multi-split overwrite.
- member pre-filter = remap_hseq refusal (STRUCT regalloc-drift / unresolved immediates).
- static pin guard: skip families whose matched exemplar carries a hard-reg pin __asm__("$N") — the
  x1-only cracks (decision-log 2026-07-11: func_8016DF5C/8013D9B0/80133AB0) that cc1-crash sibling TUs;
  they route to Task 7 pin-free re-crack instead of bisection-storming the gate.
- flags: --hseq[=manifest] --band --min-members --stage-only --only.
- VERIFIED (--stage-only): substantial band 29 families -> 1507 clean members staged / 267 groups,
  1643 correctly skipped pinned (16/29 pinned); h_norm --only path intact; drafts byte-correct by
  construction (V3 0-DIFF), type-using -> whole-TU gate (Task 5).
2026-07-11 21:26:00 -06:00
Drew T 462734edb2 feat(phase-26): task 3 — T2a immediate engine (Tier 1) + T2b cross-address, 0-DIFF verified
- family_remap: imm_value (signed/unsigned field-aware) + imm_map_tier1 (diff-driven literal swap:
  asm-side ambiguity guard defers values that also appear at a non-differing position; C-literal
  swap preserves sign + hex-case) + remap_hseq (symbol remap + imm subst + cross-address self-rename
  in one pass; refuses STRUCT/unresolved members -> caller skips, byte-gate would reject anyway).
- Tier 2 (targeted probe) intentionally DEFERRED — build-if-needed per Task-5 measurement; only ~8
  low-weight IMM families, and the whole-binary byte-gate arbitrates (plan: simpler where gate arbitrates).
- VERIFIED (.run/v3_imm.py, match_one reloc-masked so immediates are checked exactly): 0 DIFF on every
  compilable derived draft — 3 IMM + 2 PURE cross-address MATCH; 4 remap-fails were correctly-deferred
  asm-ambiguous values (not wrong output); 45 compile-fail are match_one isolation limits -> whole-TU
  gate in Task 5. Cookbook §40b imm-engine forward-ref fixed.
2026-07-11 21:14:09 -06:00
Drew T faedd103e4 feat(phase-26): task 2 — tools/family_hseq.py full-frontier survey + shared word-diff classifier
- family_remap.py: shared classifier (stream_words / reloc_indices / reg_fields / classify_member)
  — per-instruction diff class RELOC/IMM/IMM_SA/STRUCT, register-drift aware (h_seq ignores registers,
  so regalloc-drift members are STRUCT-excluded, not templatable). Reused by T1/T2a/T3.
- tools/family_hseq.py: cluster ALL unmatched overlay instances by h_seq; per family classify every
  member vs exemplar (PURE/IMM/MIXED), tag per-location/cross-address/scattered, matched-sibling count,
  has_mid_jr (§8), exemplar pick (matched-ov077 > matched > draft-ov077 > modal), size band.
  -> .run/family_hseq.json + docs/family-hseq.md (committed digest).
- VERIFIED: fleet 74.8/58.2/30.3 (= PhaseEnd_25 + progress.py exact); tail cross-check 663 families /
  186 substantial / 1.847M ins (exact); classification vs Plan-agent PURE-same 62 & IMM 8 exact;
  890x134/562x134 PURE per-location + 952x113 #addr21 IMM confirmed. Full frontier: 581 substantial
  families / 3.22M templatable ins; 345 matched-sibling PURE/IMM families / 1.14M ins = V2/V3 corpus.
2026-07-11 21:05:29 -06:00
Drew T 5b7e366648 feat(phase-26): task 1 — extended reloc tracker (addu-hi) + single-pass remap; V0/V1 green
- reloc_targets: propagate lui-hi through add/addu index arithmetic (gcc-2.7.2 indexed-global
  idiom lui;addu $idx;lw %lo($at)). The pre-26 tracker dropped it -> D[i] functions mis-normalized
  per overlay (inflated the 'h_norm reach-1 tail') AND lost their indexed D_ symbols in remap.
  norm_stream/h_norm deliberately UNTOUCHED (fleet metrics + proven sweep depend on it).
- remap/symbol_map: backward-compatible to_addr=None (cross-address T2b sibling + self-rename) +
  imm_map hook (T2a); sequential re.sub -> single-pass simultaneous substitution (fixes latent
  chained-rename/value-permutation corruption). All 5 family_sweep call sites unchanged.
- V0 (.run/v0_reloc.py): func_80141100 22/22 NEW==OLD (zero regression); func_801407F4 15/15 vs
  splat .s (pre-fix 10), recovers indexed D_80187B88/90/B0; cross-addr symbol_map clean.
- V1 (.run/v1_regression.py): 160 real h_norm sibling pairs, 96 SAME, 0 lost — differences are
  strict indexed-reloc improvements only.
- docs: cookbook §40b (the technique, R30) + decision-log 2026-07-11 (the strategic why, R31).
2026-07-11 20:57:28 -06:00
Drew T 2226e565f5 feat(phase-26): open — family-endgame plan approved (gate 1); CURRENT_PHASE.md + task list
- Phase Start (Tier 1, Fable5+Max plan-mode) from docs/family-endgame-megaplan.md
- Survey reproduced from sigs+src (R14): 663 tail h_seq families; substantial = 186 fams / 1.85M ins
  (megaplan's '986' was a miscount); #2 family (952x105) is cross-address; 93 matched-sibling fams
- Design pressure-test discovery: the tail is ~90% a reloc-tracker blind spot (addu-preserves-hi
  indexed-global idiom dropped by norm_stream/reloc_targets); 890x121 flagship family = PURE reloc;
  63-fam / 0.31M-ins zero-crack validation corpus; remap() sequential-substitution latent bug
- Drew (gate 1): carried Fable5 queue deferred to END of phase; milestone = structural completion
- Tasks 0-12 planned with R7 effort annotations + R26/R27 toggle map; Task 0 complete
2026-07-11 20:45:33 -06:00
Drew T 4415fd9910 feat(phase-25): close — structural-family endgame + the giant endgame + the h_seq family reframe (v1.24.0)
- MECHANICAL FAMILY ENGINE: family_manifest/family_remap/family_sweep + canon_sig_reconcile v3.2 +
  rtu_match; ~20k+ member-matches banked for ~0 agent tokens (h_norm families are TEMPLATES, T3).
  Fleet 66.02% -> ~74.6% fn-count (58.2% instr-weighted / 30.3% distinct-code, progress.py --weighted).
- GIANT ENDGAME COMPLETE: every matchable region-a giant ×134 incl. the 399-ins flagship func_80133CD4
  (§45 Fable5 gdb-on-cc1 crack: merged-accumulator-variables + 1-death local-alloc in-out-asm + /s +
  goto-ret; the ~22-phase 'unsteerable' verdict retired). 3 flywheel giants + F-band permuter batch
  WALLED -> Fable5 (recon-done pin-free seeds + gdb specs).
- THE REFRAME (R14, byte-verified): the '36k unique / 87% distinct-code tail' is a strict-h_norm
  artifact; re-clustered by h_seq it collapses 90% into ~754 families (986 substantial / 1.88M ins,
  top-20=52%), templatability confirmed. Endgame = crack ~986 exemplars -> template ×120.
- cookbook §40-§45; docs/{phase25-t6-curriculum,phase25-frontier-map,family-endgame-megaplan}.md.
  136/136 byte-identical (R22), 0 NON_MATCHING (G4), dedup 1813/0. No new governance rules (techniques
  -> cookbook; the reframe -> the megaplan). worklog -> logs/Phase25.md (R19). bumps 1.23.0 -> 1.24.0.
2026-07-11 19:30:11 -06:00
Drew T b438ee1846 docs(phase-25): family-endgame megaplan + checkpoint — the 'unique tail' is ~986 templatable h_seq families
- FINDING (byte-verified): the '36k unique / 87% distinct-code tail' is a strict-h_norm artifact. Re-clustered
  by h_seq (mnemonic skeleton) it collapses 90% into ~754 families (986 substantial nins>=80 / 1.88M ins, top-20
  = 52%), all per-location-shaped; templatability CONFIRMED (identical nbytes/ncalls/calls across ~120 members;
  e.g. 0x80178d40 890ins x121, 0x8015ae2c 562 x121). Endgame = crack ~986 exemplars -> template x120, NOT 36k
  hand-decomps. (Drew's insight; makes 'finish this weekend' credible.)
- docs/family-endgame-megaplan.md: self-contained plan-mode/Fable5 input — Step A cheap map+triage -> Step B
  Fable5 hard family cores -> Step C family_remap immediate-substitution + mechanical x120 harvest -> Step D
  unique residue. Fable5 doctrine (family cores + 2 walls + 3 walled giants, NOT the unique behemoths; parallel-
  isolated, distill-between). Carried context: §45 flagship idiom, flywheel seeds, permuter-batch-walled.
- CURRENT_PHASE checkpoint: megaplan pivot; Fable5 batch #2 + F-band deferred into the megaplan; permuter batch
  ran this session + all walled (masked 22/31/2, 0 banks).
2026-07-11 16:52:46 -06:00
Drew T 8270e7692e feat(phase-25): task A giant #2 — flagship func_80133CD4 (399 ins) cracked ×134 via Fable5 §45; 3 flywheel giants Fable5-seeded
- FLAGSHIP func_80133CD4 (399 ins) CRACKED ×134 (Fable5 gdb-on-cc1 §34): whole-binary byte-gate
  BYTE-IDENTICAL (d19c9580); family_sweep 133/133 siblings, 0 failed; PIN-FREE (×134-clean).
  Retires the ~22-phase 'unsteerable whole-function register permutation'. Fleet instr-weighted
  57.7->58.2%, distinct-code 29.3->30.3% (+1.0% distinct from one giant).
- cookbook §45: merged-accumulator-variables permutation-breaker (K8 no-coalescing -> one reused
  C var) + 1-death local-alloc in-out-asm (flow.c:2511) + offset-0 /s + goto-shared-return.
- FLYWHEEL (3 cheap-Opus, §45 + the map): all 3 walled -> Fable5, each a pin-free ×134-safe seed
  + gdb-oracle spec (func_8014D820 LCS226, func_8016CBC0 c=153, func_801670E4 c=23). Downgraded
  §44-Lever-5 'i=0/p-hoist' (42->0, R14); merge-lever mirror split-law + input-anchor dial.
- R22 clean-fleet 136/136 byte-identical; 0 NON_MATCHING (G4).
2026-07-11 15:09:40 -06:00
Drew T 89162fd6b8 feat(phase-25): task A giant batch 1 — 2 more giants ×134 (func_80135480, func_80163EC8) + §44 levers; 4 Fable5 seeds
- cheap-Opus batch over the 6 frontier giants: 3 banked ×134 this session (func_80166994 §43
  committed earlier; + func_80135480 258-ins block-scoped-pointer-split; func_80163EC8 234-ins
  cross-jump-duplicated-tail, 1 benign $v0 pin). 266 siblings byte-identical, 0 failed
- R22 clean-fleet 136/136; instr-weighted 57.2->57.7%, distinct-code 28.2->29.3%, dedup 1813/0
- cookbook §44 — 5 reusable levers: §43-extension (K&R s16 also covers callee-stash sign-extend),
  pointer-var-decl (avoid &sym CSE-hoist), block-scoped-pointer-split, cross-jump-duplicated-tail
  (cracks a §31-D1/D2-"permuter-only" class), + the intrinsic-wall taxonomy (what cheap-Opus can't)
- R14: §43 does NOT universally transfer (only 1 of 6 giants was K&R-s16; each is its own class);
  giant #1's prior "MATCH" note was stale/false (verify vs bytes)
- 4 giants -> pin-free/structural Fable5+permuter SEEDS (func_80133CD4 flagship §37 allocno-tie,
  func_8014D820 RC-6 pin-free, func_801670E4 scheduling, func_8016CBC0 coalescing); escalation
  = permuter-first then Fable5 §34, queued in the CURRENT_PHASE resume block
- SESSION CHECKPOINT: phase 25 OPEN; fresh session resumes the giant-seed escalation round
2026-07-11 02:27:23 -06:00
Drew T c62fe7f7ea feat(phase-25): task A giant #1 — func_80166994 (369 ins) cracked ×134 via Fable5 + the K&R s16-param idiom (§43)
- Fable5 subagent cracked func_80166994 (trail/afterimage ring recorder, 369 ins) — FULLY
  STRUCTURAL, zero register pins -> swept ×134 CLEAN (exemplar + 133 siblings byte-identical).
  R22 clean-fleet 136/136; instr-weighted 56.8% -> 57.2%; distinct-code 27.3% -> 28.2%
- NEW IDIOM cookbook §43: a K&R s16-param DEFINITION dissolves the §17/§29 "narrow-param wall".
  On MIPS K&R promotes s16->int (ABI-identical to the canon-sig s32), body keeps the in-place
  sll aN,16 narrow/extend the (s16)cast form can't reproduce. void->s32 return-flip pair:
  split //@EDIT (self-fn, ov077-specific) + engine_core.h ec_edit ×5 (byte-neutral, callers discard)
- family_sweep --edit-remap: split-edits now OPTIONAL (apply where present, never skip; the
  whole-binary byte-gate is the sole arbiter, G3/P9) — a sibling lacking the ov077 canon-sig decl
  still banks via ec_edit + body. edit-absent tracked, not skipped
- R14: the prior wave's "@stuck: none — MATCH" note on func_80166994 was STALE/FALSE (re-ran DIFF
  366/369). Verify a MATCH claim vs the bytes, never a stale note
- structural cracks are the ×134-SAFE ones (contrast §42e pin-heavy families that cc1-SIGABRT in
  sibling TUs). Other 6 giants -> cheap-Opus applying §43+§31, Fable5 only on new-class evidence
2026-07-11 01:03:09 -06:00
Drew T c0379f0738 feat(phase-25): progress.py --weighted — byte/instruction-weighted metrics (the honest headline numbers)
- weighted_metrics() from .run/sig.*.jsonl + src stubs (executable code only, resident + 134
  overlays; main EXE excluded). Two framings: fleet instr-weighted (per-overlay, the decomp.dev
  -display number) + dedup distinct-code (each unique h_exact once, the distinct-RE number)
- --fleet now emits THREE labeled metrics into docs/progress.fleet.md: fn-count 74.48% (×134-
  inflated), instr-weighted 56.8% (shipped .text), distinct-code 27.3% (of 84,996 unique fns)
- --weighted prints the two weighted numbers standalone; degrades gracefully if sigs absent
- corrects the stale "~30-35% byte-weighted" estimate: the giant campaign since Phase 19 raised
  the fleet instr-weighted number to 56.8%; the distinct-code 27.3% is the unique-monster-tail truth
- SETUP §tooling row updated (R21)
2026-07-11 00:42:22 -06:00
Drew T 5fcb040dc3 feat(phase-25): task B — family_sweep --edit-remap; 2 array-decay families ×134 (+266 fns), 4 cc1-crash-walled
- family_sweep.py: new --edit-remap MANIFEST mode (§42e) — per family, symbol-remap the
  split-scope //@EDIT old||new per sibling + apply once-global engine_core.h ec_edits
  (byte-neutral), stage the family_remap body, gate via harvest_verify (the sole arbiter)
- BANKED 266/266 (0 failed): func_80136824 + func_80136334 (array-decay ptr-flip) ×133
  siblings each — full ×134. R22 clean-fleet 136/136, fleet 74.40% -> 74.48%, dedup 1813/0
- R14 FINDING (cookbook §42e addendum + decision-log): the other 4 byte-drift families
  (func_80133AB0 zero-reg pin, func_8016DF5C/8013D9B0 GTE-pin, func_80156044 trampoline)
  cc1-SIGABRT (Error 134) in the SIBLING TU — hand pins are ov077-TU-context-specific,
  NOT mechanically ×134-recoverable; backlogged as ×1/permuter fuel. rtu_match/match_one
  are blind here (neutralized/isolation compiles crash too); only make build is truth
- 0 NON_MATCHING in any default build (G4)
2026-07-11 00:03:39 -06:00