Chunk stopped at 8/50 (3 BANKED / 5 gate-fail) to read the real per-sibling error instead of
churning the ladder (§55b). Mid-flight ov_SC01_080 reverted clean.
Single-table carve jtbl_801D836C (27e, 4-mod-8 first-table = placement-only) into the _o0
subseg; draft spliced clean, no reconciles needed (its only blocker was the missing carve).
Whole-binary gate [ OK ] sha1 d19c9580 == check.
The full 138-overlay family (424 ins) is now banked: exemplar + 137 siblings, 0 failures across
all 3 chunks — the first jtbl giant family completed through the §8e pad-spec mechanism.
Logs .run/sweep_80131340_c{1,2,3}.log.
The 2 Task-3 cores banked x1 but skipped by dedup_propagate ("not self-contained: local types").
Lifted EntSC01077 (func_8014E284) + P_TAG_80137DD4 (func_80137DD4) into src/shared/engine_types.h
(fleet-included via engine_core.h), and inlined func_80137DD4's file-local `#define OTE` into the body
(byte-neutral macro expansion, re-evaluated per use to preserve codegen). Both now self-contained ->
dedup_propagate --recover = 138 overlays byte-identical, 0 stragglers, 2 new dedup groups.
~+32.7k ins (108+129 x138). R22 clean-fleet 140/140 byte-identical; tools-health OK; dedup 1846->1852;
C1 coverage 234205. §55c local-type propagation cap lifted for these 2.
SESSION-2 close: this session banked ~94k ins across 4 fns x~137 overlays (2 non-jtbl giants fully
propagated + this 2-core type-lift); fleet 71.4->72.1% instr (+0.7pp), 140/140 throughout. The 4 jtbl
giants remain deferred on the byte-proven 8-align jtbl-carve gap (root cause half-pinned: cc1+maspsx
both emit .align 2, so the +4B pad is a downstream as/ld_interleave artifact) -> teed up as the next task.
Task-4 giant-bank #2. func_8014F4C0 (141 ins) banked x1 in ov_SC01_077_after.c (its earlier
"gate reject" was pure §55b propagate-damage — gated clean on the healthy tree, no fleet change).
h_exact family -> dedup_propagate --addr 0x8014F4C0 --recover: ov_SC01_000 was a cross-overlay
straggler (all-or-nothing h_exact), --recover reconciled the conflicting caller externs and kept
it -> 134 overlays byte-identical after propagation, +1 dedup group in config/dedup.us.yaml.
R22 clean-fleet 140/140 byte-identical; tools-health OK; ~+19k ins.
GIANT TAXONOMY (session finding, cookbook §56 + CURRENT_PHASE): the 12 preserved giants split into
- NON-jtbl (func_8013FAF8, func_8014F4C0): bank clean on a healthy tree, propagate x137 via macro/h_seq.
- jtbl (func_80131340/func_80159C84/func_8013C414/func_8013F350): each needs a per-overlay jtbl carve
x137 AND hits an 8-align gap -> func_80131340 DEFERRED (byte-proven: gcc emits a non-first jump
table .align 3 while the original packs it 4-aligned -> +4B padding shifts the whole data island,
+5B/3077-diff image-wide %lo breakage). A jtbl_carve 8-align/isolation fix unlocks ~4 giants x137.
- targeted dedup_propagate --addr per core (NOT --auto-from), --recover for stragglers:
0x8014ADE0 -> 138 overlays byte-identical
0x801325B8 -> 134 (ov_SC07_011 byte-diverges -> auto-excluded, kept x1 — what --recover is for)
0x801387B8 -> 138 overlays byte-identical
= ~410 member-instances; 3 new dedup groups (1840 -> 1843), C1 coverage 233795/233795.
- 2 of the 5 banked cores (func_8014E284, func_80137DD4) stay ×1: "not self-contained (local types)"
-> blocked on the build_engine_types type-lift (the §19/§20 propagation cap). Carried.
- R22 clean-fleet 140/140 BYTE-IDENTICAL; audit-binaries OK; dedup 1843/0; 0 NON_MATCHING (G4).
Fleet instr 71.0 -> 71.4% / fn-count 86.30 -> 86.42% / distinct-code 53.3%.
- SELF-CORRECTION (R14/R35), now fixed in cookbook §55c + CURRENT_PHASE: my earlier claim that this
propagate "needs ~2h+" was WRONG. That timing was taken while the tree still carried the partial
damage of a killed --auto-from (90/140 overlays broken), so every member-gate was failing/retrying.
On a HEALTHY tree a targeted --addr propagate is ~233s/core (all 3 = ~27 min) — ~20x faster. Only
--auto-from is genuinely fleet-slow. A timing taken on a broken tree measures the breakage, not the
tool — recover the tree FIRST, then measure.
- cookbook §55: the wave's new byte-proven levers (§49-variant birthing-boost suppression via
reg_n_sets 1->2; sched1 birthing/LUID + "cc1 -dL" movable introspection; switch-tree vs jtbl
CASE_VALUES_THRESHOLD=5; block-scope-extern beats *(T*)&sym) + the GATE-ORCHESTRATION law
(--no-propagate per group then ONE targeted --addr; commit banks BEFORE propagating; a reverted src
needs a re-extract; gate_stage's default harvest_verified.txt accumulates -> phantom banks).
Completes T4 and corrects two defects I introduced, both landed in commit:0649.
- WIRED: 006 1543/1614 · 007 1544/1615 · 010 1544/1614 · 011 1543/1614 = 6174/6457 = 95.6%,
~0 agent tokens. Stubs/overlay ~2400 -> 831/984/898/825. Fleet instr 67.0 -> 68.9%,
fn-count 82.16 -> 83.94%. dedup-check 1840 validated / 0 failed; groups now read
"138 members [138 binaries]" (was 134); C1 coverage 227211 -> 233385 = exactly +6174.
R22 make clean && extract-all && check-all -> 140 passed, 0 failed of 140 at every stage.
- FIX#1 — I DESTROYED THE REGISTRY'S DOCUMENTATION, AND EVERY GATE CALLED IT GREEN (H5).
The first cut wrote config/dedup.us.yaml with yaml.safe_dump, round-tripping the whole file:
47 comment lines -> 0 (including the curated Phase-11 header explaining WHY the share is
source-level) and 1832 `vram: 0x80162FF4` -> `vram: 2148937716` (PyYAML parses YAML-1.1 hex to
int; dumps int as decimal). 25,948 lines rewritten. It passed dedup-check 1840/0 AND check-all
140/140 because _addr() accepts both forms: THE DATA WAS CORRECT AND THE DOCUMENT WAS RUINED.
Fixed forward (R6, no history rewrite): restored from commit:0649~1 and re-applied the 6174
memberships via a surgical text edit (add_members_surgical). Verified: 1545 insertions / 1545
deletions, 0 non-`binaries:` lines changed, 47 comments + 1908 hex fields intact, and the
rebuilt fleet is byte-identical to the destructive version (140/140).
THE LESSON: every oracle this project owns measures BYTES, so a formatting-destructive write is
invisible to all of them by construction. R34 says the byte-gate is a null COVERAGE oracle; this
is the same hole one layer out — it is a null DOCUMENT oracle too.
- FIX#2 — I MIS-REPORTED THE DIFFs, TWICE (R14).
(a) commit:0649 claims ov_SC07_006's 71 non-banks were "ALL PLUMBING, ZERO DIFF". FALSE — I read
head -6 of the classified file and generalized. It has the same 4 DIFFs as the others.
(b) I then built the jr guard assuming those 4 were the §53 jr class BECAUSE ov_SC01_077 hosts
them in _jr_8017A4AC.c / _jr_80182268.c. has_mid_jr is FALSE for all four (33-52 ins, no
jump table): they merely live in a carved jr-REGION split, which sweeps in every function in
its address range. HOSTING FILE != FUNCTION CLASS.
The guard is KEPT (preventive, §53-correct, currently skips 0 — no jr fn is in the extendable
set) with its docstring corrected to record what it is NOT. The 12 DIFFs (0.19%) are UNDIAGNOSED
and logged, correctly left as stubs by the gate — not dressed in a story.
- The 283 non-banks: 271 PLUMBING (the loose-typing conflict class + the whale, whose body lives
in src/shared/func_80144B9C.h so no DEFINE macro exists to expand) + 12 DIFF. Existing tools
cover the plumbing (cast_call_sites / canon_sig_reconcile / reconcile_tu).
The 4 SC07 overlays P27 onboarded were byte-clean but NOT citizens: their .c included only
common.h (never ../shared/engine_core.h), so no shared body could reach them, and they
appeared in ZERO dedup groups (1689 groups read "134 binaries", never 138). Each sat at ~80
matched / ~2400 stubs while its siblings were ~2150 matched.
- NEW tools/dedup_extend.py — the missing mode. dedup_propagate is built for CRACK -> AUTHOR
MACRO -> INSTANTIATE: --auto-from scans INLINE DEFS (planned only 11 here; the ~1600 shared
bodies are ALREADY DEFINE_func_* macros in engine_core.h) and --addr dies "no source overlay
has it matched" because no overlay holds an inline def. Extending an existing MACRO-BACKED
group to a newly-onboarded binary is a different operation and nothing implemented it.
- SAFETY (explicit — this feeds the byte-gate): h_exact is the SHA1 of RAW INSTRUCTION BYTES, so
two instances sharing one are identical INCLUDING their jal/lui/%lo reloc immediates — same
callees, same data addresses, same symbols. The body that compiles byte-identically at one
member does so at the other with NO remap. (Exactly why dup_report calls h_exact "guaranteed
byte-match" and h_norm "candidate-only".) A bug here can only FAIL TO BANK, never falsely bank.
- REUSE, DON'T REBUILD (R33): owns only the set computation + the registry edit. The splice and
the gate are harvest_verify verbatim (it already derives each stub's home TU from the corpus
oracle, chunks + bisects, reverts on failure). h_exact members are byte-identical by
construction -> the happy path is ~1 build per binary, not one per function.
- RESULT ov_SC07_006: 1543 / 1614 banked = 95.6%, ~0 agent tokens. Stubs 2374 -> 831.
The 71 non-banks are ALL PLUMBING, ZERO DIFF, in two named classes with existing tools:
* func_80144B9C "undefined reference" — the whale's body lives in src/shared/func_80144B9C.h
(the -O0 shared header), not engine_core.h, so no DEFINE macro exists to expand.
* "conflicting types for D_800A5E60 / func_8012C750 / func_8012C0EC" — the loose-typing
conflict class (cast_call_sites / canon_sig_reconcile / reconcile_tu already exist for it).
- GATES: R22 make clean && extract-all && check-all -> 140 passed, 0 failed of 140, 0 FAIL lines.
dedup-check 1840 validated / 0 failed; groups now read "135 members [135 binaries]" (was 134);
C1 coverage 227211 -> 228754 = exactly +1543. The second oracle accepts the extension.
- Mechanism had been proven by hand first (probe-before-investing): +include + ONE stub ->
DEFINE_func_80128158() -> ov_SC07_006 built 7ca772be BYTE-IDENTICAL, then reverted.
The family the roadmap recorded as 0/8 ("~0%, structural families do not template" — the
number that rewrote P29's arithmetic to "(cores cracked) x (reach)") banks at 88.7% when
swept with the carve its own exemplar required. ~0 agent tokens.
- SWEEP: jtbl_family_bank.py over the remaining 107 members ->
{'BANKED': 94, 'gate-fail': 7, 'remap-refuse': 6}. Family total 8 (T1) + 94 = 102/115.
R22: make clean && extract-all && check-all -> 140 passed, 0 failed of 140, 0 FAIL lines.
- FLEET (measured, make report): instr-weighted 67.0 -> 67.7% (+0.7pp, +97,104 ins);
distinct-code 47.8 -> 49.4% (+1.6pp); fn-count 82.16 -> 82.19%. 102 x 952 = 97,104 =
the exact measured instruction delta — the arithmetic reconciles to the byte.
- THE 13-MEMBER TAIL is the predicted shape, and both halves are data for T3:
* 6 remap-refuse = EXACTLY the family's 6 IMM members (cls_counts PURE 109 / IMM 6).
imm_map_tier1 REFUSED rather than guessed: "unresolved immediates: [(512,
'asm-ambiguous')]" — 512 also occurs at a non-differing position, so a blind swap could
corrupt it. This is the concrete shape of T3's IMM stratum.
* 7 gate-fail = genuine byte-DIFFs, correctly rejected. Verified to leave NO residue
(all 7: split_file=none, cfg_refs=0) — no false-bank risk.
- HYGIENE: the 7 "git checkout ... did not match any file" errors are benign (revert of a
never-tracked path). Verified 0 untracked splits belong to a non-banked member; 91 new
splits + 3 banked into existing splits = 94.
- SCOPE (P9, unchanged): still n=1 family, and jr is the rarest class (3/163 matched-exemplar
families). This demonstrates the mechanism at family scale; it does NOT give a rate for the
PURE/IMM mass (98% of the population). T3 measures the swing number.
The roadmap's decisive P28/P29 input (h_seq families bank at ~0%) is byte-refuted. Same
family, same era, through the carve path its own exemplar required: 8 of 8 BANKED.
- THE PROBE: jtbl_family_bank.py func_8017BEBC ov_SC01_000 0x8017bebc --raw
.run/phase26-cracks/func_8017BEBC.c over 8 of 115 members (4 same-address + 4
CROSS-address, exercising to_addr) -> {'BANKED': 8}.
R22: make clean && extract-all && check-all -> 140 passed, 0 failed of 140.
- ROOT CAUSE of the P27 0/8, byte-verified: 0x8017BEBC is a jr/switch core. §47 banked its
exemplar as "lazy isolation -> carve (9-piece interleave) -> splice -> BYTE-IDENTICAL" and
called the fix "×N template-safe". family_sweep.hseq_sweep stages C and gates -- it has NO
CARVE STEP -- so gcc's generated jump table is never placed at the sibling's address. The
entire residual is TWO WORDS: classify_member -> PURE, ndiff=2 @ idx 343/345 =
lui/lw %hi/%lo(jtbl_801EC44C). overlays.mk:112 carves ov_SC01_000_jr_8017BEBC.o for the
exemplar; :134 has no such entry for the member. tools/jtbl_family_bank.py exists to do
exactly this per sibling and had NEVER been run on this family.
- THREE COMPOUNDING FAILURES made the doctrine: (1) wrong tool for the class; (2) n=1 on the
LEAST representative family -- has_mid_jr is 3 of 163 matched-exemplar families (120 of
13,232 members) -- generalized to the whole frontier; (3) its corroborating Phase-26 probes
(tiny-IMM 0/241, PURE 0/134, pinned 0/133) ALL predate _carry_macros (P27 T5, commit:0637).
P27's decision-log calls its own re-probe "a FOURTH phantom exhaustion proof" -- naming the
mechanism that would have faked the first three, and never re-running them. The ~0% doctrine
has NO surviving post-fix evidence.
- SCOPE HONESTY (P9): this refutes the EVIDENCE for ~0%; it does NOT establish a general rate.
n=1, and jr is the rarest class by construction. T3 measures the rate over the population
that actually exists: 1418 matched-exemplar families / 21,889 members (PURE 78% / IMM 20% /
STRUCT 1.8% -- note the roadmap sizes its swing number on STRUCT = 1.8% of the input).
- TWO SELF-CORRECTIONS (R14), both mine: (a) the approved plan's "add jtbl_ to symbol_map" was
a WRONG FIX FROM A TRUE DIAGNOSIS -- a compiler-generated switch table is never named in C,
so there is no token to substitute; the fix is PLACEMENT. No symbol_map change was made and
T1 became a run, not a code change. (b) func_8017BEBC.md's header still says "close=2 of 952"
(pre-§47-slider); the .c was updated, the .md was not -- templating from the header's premise
would have produced zeros indistinguishable from a wall.
- DISTILLED IN-SESSION (R30/R16): cookbook §53 (sweep a family with the tool its exemplar
needed: the carve law, the --raw rule, the symbol_map-jtbl trap, and the "before a 0%
retires a lever" three-question test); calibration.md's decisive table REWRITTEN (the ~0%
row marked an artifact, not a rate; the addressable pool tabulated); decision-log R31.
- Carried: the family's remaining 107 members (~101,864 ins, ~0 agent tokens) -> T1b.
The whole-binary byte-gate is structurally blind to code nobody onboarded (R34): check-all is
green over the onboarded set no matter what code sits unbuilt on the disc. This reconciles the
onboarded set against every code-bearing PAC payload.
- new_overlay.sh: optional [ENTRY] arg (default 0.4) reaches a non-0.4.dec payload. Onboarded
ov_SC07_{006,007,010,011} from 1.4.dec (they put graphics at PAC entry 0, the code overlay at
entry 1 — invisible to the 0.4 hardcode for a month). Each byte-identical (7ca772be / b3b95547 /
d7b5875d / 9885af74). FLEET 136 -> 140; check-all 140/140 (T2's pass==N re-baselined cleanly).
difficulty.py NOT in the insertion set anymore (it derives, T6) -> only 3 tool dicts touched.
- tools/disc_code_sweep.py: decode every payload (reusing sig_image.make_insn) and gate code on
BOTH valid>=0.90 AND jr_$ra density>=0.01. The jr_$ra gate is decisive: isValid() alone flags
389 false hits (type-0/2 structured data decodes ~100% valid but has ZERO returns); jr_$ra
separates code (~2.9-3.4%) from data (0.000%), validated on positive+negative controls.
- FINDING (docs/disc-completeness.md): type-4 location overlays are COMPLETE (138/138). All other
types are data EXCEPT type-1 = 40 code payloads, 1 onboarded (the resident), 39 HIDDEN
resident-class modules (mostly MAIN.CD/FILE_XXX/1.1). They load at UNKNOWN addresses (not the
shared overlay slot), so they are NOT mechanically onboardable — byte-verifying a build binary
needs its load address (P9), knowable only by runtime RE (the Phase-3 method). Deferred with
evidence, NOT force-onboarded at a guess.
- CONSEQUENCE: game-code TRUE 100% now spans 140 onboarded binaries PLUS ~39 type-1 modules
pending load-address RE. The roadmap assumed 136 — this is a real re-baselining (the +4 overlays
also add ~2.45 MB to the denominator; every family propagation is now x138). Flows to T10/T11.
- SETUP §6.3 tool inventory updated (R21).
The A10 re-test payoff. func_8017A4AC (536 ins, reach-134) — "blocked on plumbing" since
session 8 — banks now that the audit repaired the recover path (A3d reconcile_tu / A3e gate).
jtbl_family_bank --raw swept all 133 siblings (per-sibling isolate → jtbl carve → remap_hseq +
canon_sig_reconcile → whole-binary gate): 133/133 BANKED, 0 failed. 0 still-stub overlays.
R22 CLEAN-FLEET (make clean + extract-all + check-all): 136 passed, 0 failed of 136.
dedup-check 1840/0 (jtbl sweep banks are per-overlay src, not registry).
DELTA:
instr-weighted 68.1% -> 68.6% (+0.5%, ~71,824 shipped .text instructions)
distinct-code 48.0% -> 49.2% (+1.2% — the siblings are per-location byte-variants)
The audit thesis, demonstrated: a giant "wall" that stood for many phases was our TOOLING (the
recover path could not resolve its struct/fn-ptr conflicts), not an intrinsic compiler residual.
Once the oracle was fixed, the wall dissolved and banked ×134.
The 536-ins reach-134 giant listed "blocked on plumbing" since session 8. Re-tested through
bank_exemplar after the audit's recover-path fixes (A3d reconcile_tu wiring / A3e gate): BANKED
at the `recovered` stage (fb.recover / reconcile_tu resolves the D_80126B58 struct + D_801DA75C
fn-ptr conflicts the raw/scoped stages hit). Lazy-isolated into its own jr subseg + jtbl carve.
HONEST ATTRIBUTION (R14): this bank is the payoff of the A3 recover path, NOT A9a — it banked at
`recovered`, before the `reconciled` (canon_sig_reconcile) stage was reached. A9a's fn-ptr
classifier fix is a correctness fix that did NOT independently unblock a bank in the 7-candidate
re-test (the reconciled stage failed on func_8015B950's func-conflicts; the rest hit K&R /
scalar-typedef / non-ov077 / non-contiguous-carve blockers) — the same null-immediate-banking
pattern as A3c/A3d/A3e; its value is protecting all future dispatch-table banking.
R22 clean-fleet: 136 passed, 0 failed of 136. Exemplar ×1 (+536 ins); the ×134 family sweep follows.
The standing-lead harvest (A3f/A3g continuation), measured precisely first (R14). Of the
~1,060 still-open byte-exact functions in the backlog:
- Bucket G (67 open in ov_SC01_077): re-gated through the A3e-fixed gate_stage
--no-propagate -> 0 banked. HONEST: A3f already took the bankable 33; the residual is
the known hard classes (jtbl-rodata / register-pins / struct-collision) + stale backlog
rows whose LATEST state is a WAVE mismatch. Correct G3/P9 rejection.
- Bucket P (88 matched in ov077, open in siblings): the clean lead. dedup_propagate --addr
(A3g primitive) skipped 70 as h_exact reach<2 (per-location byte VARIANTS -> family_sweep
territory, not plain propagation) and propagated the 14 genuine PURE fleet families:
5 top (func_80129C40/8012A6D0/80130A18/80131D68/80136DFC) + 9 more; 2 stragglers
dropped all-or-nothing (0x80173A60, 0x8014C568 -> --recover candidates).
Each propagated x~133 (dedup_propagate internal gate: 134 overlays byte-identical).
R22 CLEAN-FLEET (make clean + extract-all + check-all): 136 passed, 0 failed of 136.
dedup-check: 1826 -> 1840 validated, 0 failed | C1 227211/227211.
DELTA:
instr-weighted 66.8% -> 67.4% (+~1,862 member instantiations shipped from C)
distinct-code 46.8% -> 46.8% (flat: propagation adds MEMBERS, not new distinct code)
673 files (671 overlay .c instantiations + engine_core.h) + dedup.us.yaml + progress.fleet.md
Remaining standing lead: the ~72 variant Bucket-P + ~905 Bucket-X (absent from ov077) fns,
all latest-row closeness==0 -> route through family_sweep --hseq (per-sibling remap), next.
The 3 of A3f's 33 banks that are shared fleet-wide, stamped across all 134 overlays. Done the way
the earlier run should have been: TARGETED (--addr, not --auto-from), dry-run-sized first
(3 functions × 134 members = ~400 gates, not an unbounded fleet sweep), on a clean tree at HEAD.
func_80130650 (31 ins) · func_80149450 (13 ins) · func_80174684 (9 ins) — each ×134.
dedup_propagate internal gate : 134 overlays byte-identical, 3 groups registered
R22 CLEAN-FLEET (the real proof, not the tool's incremental check that lied during the crash):
make clean + extract-all + check-all -> 136 passed, 0 failed of 136
dedup-check: 1823 -> 1826 validated, 0 failed | C1 coverage 225335/225335
DELTA (reconciles exactly):
functions byte-identical 284,559 -> 284,958 (+399 = 3 fns × 133 other overlays)
instr-weighted 66.7% -> 66.8% (+13,167 shipped .text instructions)
distinct-code 46.8% -> 46.8% (flat: propagation adds MEMBERS, not new distinct
code — the 3 bodies were counted at A3f)
403 src files (3 ×134 instantiations + engine_core.h) + config/dedup.us.yaml
The other 30 of A3f's 33 are overlay-unique (×1) and need no propagation. The larger prize remains
the ~310 byte-exact stubs in the OTHER overlays (A3e), not yet attempted.
R22: check-all 136 PASSED / 0 FAILED. dedup-check 1823 validated / 0 failed (C1 coverage 224,933/224,933).
Fleet instr-weighted 66.5% -> 66.7%.
=== dedup_propagate: it was blind to HALF the corpus ===
overlay_files() used a hardcoded suffix allowlist ("_a","_o0","_o0b","_after") that predated the
Phase-26 jr carves -> 404 of the fleet's 811 overlay .c. The 407-file gap held 36,135 INCLUDE_ASM stubs
and ~32,000 inline defs, and overlay_files gates ALL of dedup_propagate (source_text / find_site /
apply_plan / struct_check / reconcile_caller_extern). Now a GLOB — never an allowlist, because the NEXT
split family would re-open it. The asm_subdir is always the file stem, an invariant the old four entries
already satisfied.
find_site's def-detector required the signature line to END in ')' and the next non-blank line to START
with '{'. It therefore silently dropped THREE shapes: K&R definitions (`s32 f(arg0)` / `s32 arg0;` / `{`),
multi-line signatures, and single-line bodies. K&R is the project's house style for exactly the biggest,
highest-reach functions — func_8015AE2C (562 ins), func_80166994, func_80133CD4, func_8015A3C8 — and they
live in the _jr_* files overlay_files could not even open. Fixing either alone would have been useless:
the glob exposes the files, and find_site would still drop their biggest prizes. Both fixed together.
* The signature's closing paren is now found by a real paren-walk, not line.count() or split(')')[-1]:
a single-line body containing a call (`void f(int a){ g(a); }`) has balanced parens of its own, so
both shortcuts land on the WRONG paren and then misread the body's ';' as a prototype terminator.
* AGREEMENT ASSERTION (the audit's): find_site vs family_remap.extract_unit -> 701 agree / 0 disagree.
Negative controls hold (a prototype+call is rejected; a 1-line body with a call is a def).
=== THE HARVEST (free work, byte-gated) ===
--auto-from ov_SC01_077 now nominates what it could never see: 20 planned, 17 propagated x134, 3 dropped
as cross-overlay stragglers. 134 overlays rebuilt BYTE-IDENTICAL; 17 new dedup groups.
Includes ALL FOUR functions A1 caught the registry lying about (func_80128ED8 / 8012C098 / 8012C0EC /
8012C750): 0 stubs remaining, real shared macros. THE LOOP CLOSES — A1 found the lie, and THIS is the
bug that had made it true (3 of the 4 are defined in ov_SC01_077_jr_8012ACE0.c, which the allowlist could
not open, so the propagation never ran and dedup_integrate greenlit the result).
=== family_remap: 96 PHANTOM exemplars -> 0 ===
extract_unit globbed only src/<ov>/<ov>*.c, so a function matched via a SHARED body had no source form
and read as NOT MATCHED. 93-96 of 218 h_seq "matched" exemplars were phantom, carrying 2,157 candidate
members of which 1,834 are still-stubbed, PURE/IMM-clean, symbol_map-clean and unpinned — staged and
gated today, dropped before the first build then. It is now TOTAL over BOTH shared-body mechanisms:
(1) the DEFINE_func_<ADDR>() macro — reconstructed as the exact INVERSE of dedup_propagate.make_macro
(derived from the generator, not re-guessed from the text);
(2) a DIRECT definition in a shared header, #included per overlay — the whale (func_80144B9C, 770 ins,
-O0), which the registry explicitly records as "NOT a DEFINE_ macro".
CENSUS: 216 matched exemplars, 216 real, 0 PHANTOM.
symbol_map named the symbol by HOW IT WAS LOADED, not by WHAT IT IS: reloc_targets labels every lui/%lo
pair "data", and a FUNCTION's address taken via lui/%lo (an address-taken callback) is exactly that shape
(splat's own .s: %lo(func_8017E1D4), 7 occurrences). The map got a D_<ADDR> key while the C writes
func_<ADDR>, so the word-bounded substitution matched NOTHING and silently no-op'd — the sibling kept the
EXEMPLAR's function pointer and the loss was booked as a BYTE failure, indistinguishable from a compiler
wall. Now emits both keys (addresses are unique; the pass is simultaneous, so the extra key is free).
gather_externs was line-oriented, so a WRAPPED comma extern was invisible in both directions (the first
line has no ';', the continuation has no `extern`). ov_SC01_077.c:271-272 declares NINE symbols that way,
and the exemplar referencing them (func_8013D178) is a 133-member family — every sibling was staged with
NO declaration, failed to compile, and bisect-stormed its whole gate group. Now statement-oriented, and
an unresolved symbol is REPORTED, never silently dropped.
=== family_sweep.stub_map / build_engine_types ===
stub_map: func_-only -> a curated-name stub read as "already matched" -> phantom exemplar. Now corpus-derived.
build_engine_types hard-exited on 1,070 of 1,470 type-bearing overlay .c (73%; the audit measured 573/709
= 81% on its narrower set) because 1,929 TAGGED-struct typedefs tripped a guard whose own comment asserts
"our source has only ANONYMOUS-struct typedefs" — true in Phase 20, false since the harvest agents started
writing tagged structs. inject_capped_externs routes every type-bearing body HERE as the type-heavy tail's
ONLY sanctioned unblocker, so the tail's unblocker could not run on the corpus the tail lives in.
A contained def (the typedef's span encloses the body) is liftable — it just must not be counted twice;
only a PARTIAL overlap is malformed. Verified on a file that used to hard-exit: 5 tagged typedefs folded +
forward-declared, 46 types written, exit 0.
** AND THE SHARPEST LESSON IN THE AUDIT: this one was never silent. It printed "[overlap] ... handle
manually" every single time. But the message reads like a rare edge case rather than a four-fifths
coverage failure, so nobody ever COUNTED it. A loud failure that nobody counts is exactly as
invisible as a silent one. R32 must be "assert your coverage", not merely "fail loud". **
R14 self-catches, recorded because I hit both while fixing them: my first shared-header scan read a macro
body's `extern void f(void); \` as a DEFINITION (the trailing continuation means the line does not end in
';', so the decl guard never fired) — the exact bug fixed at commit:0552, reintroduced by me and caught only
because the whale resolved from the WRONG file. Column-0 anchoring fixes it by construction. And my
phantom census returned 0/0 twice because I guessed the manifest schema instead of reading it.
R22 CLEAN-FLEET: make clean -> extract 136 -> build 136 -> check-all = 136 PASSED, 0 FAILED.
make audit-corpus: 0 PHANTOM + 0 TRUNCATED (was 193).
=== A4: a CORPUS defect the byte-gate could never have caught ===
config/symbols.us.txt:981 declared `listCdBuffer = 0x80180000` — a correct Phase-3 name for MAIN's
LIST.CD RAM buffer. But that address is OUTSIDE main's image and INSIDE the overlay slot, and every
overlay's splat config stacks symbols.us.txt. High RAM is REUSED: an address that is a buffer to main
is live CODE to an overlay. So splat saw a symbol boundary mid-code and, across 97 of 134 overlays:
* CUT 97 REAL FUNCTIONS IN HALF (a head ending on a `lui`, no return), and
* INVENTED 96 PHANTOM ONES (a tail beginning by reading the assembler temp $at).
193 slices NOBODY COULD EVER MATCH — not "hard", not "a compiler wall": unmatchable by construction.
They sat in the harvest queue as ordinary work, so agents would burn on them forever and the failures
would be filed as intrinsic compiler residuals.
The phantom listCdBuffer.s in ov_SC01_005 literally begins:
lw $ra, 0x10($sp) / addiu $sp, $sp, 0x18 / jr $ra
splat cut a function immediately before its EPILOGUE and called the epilogue a function.
AND IT HAD ALREADY CONTAMINATED REAL WORK: in ov_SC03_031 the cut landed where the epilogue was
exactly `jr $ra; nop`, so the Phase-26 x134 sweep innocently BANKED the phantom as
`void listCdBuffer(void) {}` — byte-correct, gate-green, entirely fictitious — while leaving
func_8017FFC4 permanently unmatchable. Removed.
WHY NO GATE CAUGHT IT, AND WHY THAT IS THE POINT: INCLUDE_ASM pastes the two .s halves back VERBATIM
in original order, so the image is byte-identical either way. The byte-gate was green the whole time
and always would have been. It is a perfect CORRECTNESS oracle and a NULL COVERAGE oracle. No
assertion added INSIDE it could ever have found this. What found it was a SECOND, INDEPENDENT oracle:
tools/sig_image.py derives boundaries from the ORIGINAL bytes without splat, and DISAGREED with the
corpus (58,524/58,621 agreement with spimdisasm; correct on all 97 disagreements).
=> When one oracle is structurally blind to a class of error, the answer is not a better assertion
inside it. It is a SECOND ORACLE THAT CAN DISAGREE WITH IT. (`make audit-corpus` is now that.)
THE RULE (the mirror of R13/R15, never written down): a symbol whose address falls inside ANOTHER
binary's vram window must never enter that binary's symbol stack.
FIX: config/symbols.us.ram.txt — main-scoped symbols outside main's image — stacked ONLY by
config/splat.us.exe.yaml. Main keeps the name it needs (10 %hi / 11 %lo refs; 143dbb89 byte-identical);
the overlays never see it. Exactly one symbol was in scope fleet-wide; the resident window was clean.
AND A REAL FUNCTION THE ACCIDENT WAS HIDING: in ov_SC01_084 / ov_SC02_041 / ov_SC03_094 / ov_SC06_008
there IS a genuine function at 0x80180000 (111 / 35 / 28 / 74 ins), reachable ONLY via a fn-pointer
table (.word func_80180000) and never by `jal` — so splat cannot find it and needs the boundary
DECLARED. listCdBuffer had been supplying it by luck. Now declared honestly, per-overlay, in
config/symbols.<ov>.txt — exactly where R13/R15 says an overlay-scoped symbol belongs.
=== A5: the closeness oracle every crack agent trusts was lying on 155 functions ===
masked_diff._reloc_kind() knew 26/HI16/LO16. An over-approximating sweep of every reloc objdump emits
across all 3,367 build objects found FOUR: R_MIPS_26, HI16, LO16 — and R_MIPS_PC16 (211). PC16 fell
through to a FULL-WORD compare, but the object holds an UNRESOLVED PLACEHOLDER in the branch
displacement, so that compare can NEVER succeed.
DECISIVE TEST (derived from the invariant, not from reading the regex): INCLUDE_ASM pastes the
ORIGINAL asm, so for every stub diff_object_s() MUST be 0. Measured, coverage-asserted:
2,741 functions scored — old mask: 150 LIES; PC16 masked: 4 LIES.
(The 4 survivors are the separate length-delta defect.) A phantom non-zero sends an agent to grind at
a wall that is not there, and the wasted attempt is then booked as a MATCHING failure, feeding
reserved_walls() and PERMANENTLY BLACKLISTING a function that was never broken.
=== NEW FINDING (found by cutting the R22 corner): a STALE OBJECT CAN PRODUCE A FALSE PASS ===
`.o <- .s` is not a dependency make can see: assembly arrives via INCLUDE_ASM, expanded to a `.include`
consumed by maspsx/as AFTER cpp, while -MMD tracks headers only. Re-extract, build incrementally, and
make links a STALE object. This is not merely slow — INCLUDE_ASM pastes the ORIGINAL bytes, so a stale
object still yields the original image: SHA1 GOES GREEN while the split just changed is never exercised.
A broken config change can be "verified" by an incremental build. Live proof: 8 of 136 binaries linked
stale objects here; they failed LOUDLY ONLY BY LUCK (the dead symbol was an undefined reference) — a
merely-different-but-valid split would have gone green on all 136.
R22/H3 already legislate this, and I broke them. But a rule that needs a human to remember it is not a
gate. FIX: `extract` now invalidates the objects that include what it just rewrote (main's are top-level,
so -maxdepth 1 — verified it cannot clobber the other 1,605 objects). Structural, not advisory.
R14 self-catch, recorded: my first A5 test passed `fn=` to diff_object_s(), which takes two args; the
TypeError was swallowed by my own `except Exception: continue` and it reported 0 scored / 0 lies. I
wrote the exact bug I was auditing, inside the test for it. Caught only because 0 looked wrong. The
test now asserts its own coverage.
The audit's priority #1: a fail-closed byte-honesty validator whose silent skips nothing
downstream can catch. Three false-green paths, all measured, all now fail-closed with
negative controls.
R33 FIRST (derive, don't re-derive). The registry makes two claims; the tool only ever
checked one, and mis-described that one:
C1 EQUIVALENCE ("these vrams hold the same code in the ORIGINAL") — checked against the
sigs, which sign the ORIGINAL bytes. KEPT. But the docstring claimed it also caught
SOURCE drift: it cannot. A sig is a property of the ROM, immutable w.r.t. src/. Source
drift is caught by the BUILD. Docstring corrected (P9).
C2 BANK ("matched once in the source header, instantiated at every member") — NEVER
CHECKED. Now DERIVED from the build invariant: INCLUDE_ASM pastes the ORIGINAL asm, so
a member NOT wrapped in it is byte-exact, and one that IS wrapped is not banked —
whatever the registry says. C2a: the group's macro token must occur in its source file.
C2b: no member may still be an INCLUDE_ASM stub.
THE THREE FALSE GREENS
1. 1808 groups claimed a DEFINE_func_* macro; only 1801 exist. The 7 ghosts printed [ OK ] —
hiding 532 member-instances / 22,344 instructions of REAL, UNBANKED work (4 fns matched in
ov_SC01_077, still INCLUDE_ASM in the other 133 overlays).
2. An absent .run/sig.<bin>.jsonl degraded to "0 validated, 0 failed" and EXIT 0. On a fresh
clone the gate validated NOTHING and passed. Now fails; --allow-unsigned is the escape.
3. The bank claim was never checked at all.
THE CAUSAL CHAIN (the audit's thesis in one example). 3 of the 4 hidden fns are defined in
ov_SC01_077_jr_8012ACE0.c — a _jr_* split file. dedup_propagate.overlay_files allowlists only
("_a","_o0","_o0b","_after"), so the propagator could not SEE them; the group was registered
anyway; dedup_integrate greenlit the lie. TWO silent-skip bugs compounding: one created the
hole, the other hid it. Harvest fuel -> .run/audit/a1_harvest_fuel.json, banked in A5.
BLAST RADIUS, MEASURED NOT PREDICTED (R14). Headline metrics UNCHANGED to the decimal
(instr-weighted 66.5%, distinct-code 46.8%) — weighted_metrics() derives from the invariant and
was structurally immune to the lying registry. FLEET REAL substantive unchanged (282,466):
progress.py had already been taught to distrust it (commit:0574). Only dedup_integrate still
believed it. A null result that CONFIRMS R33: the tool that refused to re-derive was the one
that was right.
- registry repaired: 1813 -> 1806 groups (7 ghosts removed; instances 223,725 -> 222,787)
- make report GREEN end-to-end: 1806 validated, 0 failed | C1 coverage 222,787/222,787 signed
- negative controls: stubbed member -> exit 1; missing sig -> exit 1; --allow-unsigned -> exit 0
- report-only tool: no compiled artifact depends on it, so no R22 clean-fleet is owed here
Residue of the same isolation-revert bug fixed for ov_SC01_000 in commit:0558: a failed bank left its
isolation's config in place, the retry re-isolated on top, and a duplicate
- [0x4b364, c, ov_SC01_077_jr_801734BC]
line rode into a commit. It is HARMLESS to splat (a zero-length subseg), so R22 stayed green and the
correctness gate never saw it — but it BLOCKED every subsequent isolation, which is what failed 5 of
the 9 crack-wave banks. Caught only by the fail-loud validation added in commit:0558 (a tool that refuses
to proceed on input it does not understand), never by the byte-gate. Fleet audit: ov_SC01_077 was the
ONLY affected config of 137. ov_SC01_077 rebuilds d19c9580 BYTE-IDENTICAL.
- BUG: gen_harvest_targets.SIG_IN_BODY_RE required `)\s*{` between a DEFINE_func_* macro's signature
and its opening brace. When the brace sits on its OWN continuation line there is a line-continuation
BACKSLASH between them:
s32 func_80148824(void *arg0) \
{ \
and `\s` does not match `\`. So the regex silently dropped every own-line-brace macro.
- BLAST RADIUS (measured): 186 of 1801 engine_core.h shared signatures — 10% of the oracle — were
MISSING from the canonical-callee map that cast_call_sites / sig_unify / gen_harvest_targets resolve
against. A draft calling one of them kept its own guessed signature, hit `conflicting types` against
the TU's real definition, and the recovery pass reported nothing to fix — the failure looked like a
hard wall. This is why the crack wave's byte-exact cores would not bank.
- FIX: `[\s\\]*` instead of `\s*`. Oracle 2122 -> 2308 entries.
- PROOF: func_8015A3C8 (493 ins, MATCH standalone) went from "28 conflicting types, unbankable" to
BANKED ×1 BYTE-IDENTICAL at the `recovered` stage, with zero hand edits. R22 clean-fleet 136/136.
- This is the phase's SIXTH silent-skip bug and the THIRD of the same brace-placement class (§19
find_site; scope_data_externs' own-line brace; now this). Cookbook §40's standing lesson applies:
a tool that silently no-ops on input it cannot parse is indistinguishable from one that had nothing
to do — prefer fail-loud on unparsed input.
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.
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.
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).
- 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.
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.
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).
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).
- 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)
- 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
- 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)