Files
BFM-decomp/phase-ends/logs/Phase26.md
T
Drew T 1bbab78c65 feat(phase-26): close — family engine + the tooling-integrity audit + the §52 discovery-flywheel; mechanical harvest byte-proven exhausted; fleet 58.2->68.9% instr (v1.25.0)
- FAMILY ENGINE (Tasks 1-6): family_remap (extended reloc tracker + single-pass subst) +
  family_hseq (the h_seq reframe) + family_sweep (crack-one -> template-x134 -> byte-gate) +
  canon_sig_reconcile v3.2 + rtu_match. Sessions 6-8 cracked 13 cores (58.2->66.5% instr).
- 26-A TOOLING-INTEGRITY AUDIT (inserted half-phase, A0-A11): the tools WERE several of the
  walls. Fixed ~15; DELETED decaying scanners (R33); built corpus.py + cdecl.py (derived,
  coverage-asserted oracles) + make audit-corpus (a SECOND, disagreeing oracle, R34); the
  listCdBuffer 193-slice corpus defect -> 0; masked_diff 150 closeness-lies -> 4; the stale-
  object false-pass closed. Payoff 66.5->68.6% instr. docs/tooling-audit.md AUDIT-CLOSE LEDGER.
- 52 DISCOVERY-FLYWHEEL (Task 7): single Fable5 on func_80178004 = intrinsic 3-integer regalloc
  wall, BUT distilled the walker-family idiom (52); two cheap-Opus waves applied it -> 5 pin-free
  cores banked x134 = 670 instances (68.6->68.9%). 4 named wall classes; 52/52a/52b. pin-guard
  comment false-positive fixed; family_sweep --allow-pins.
- FINDING (R14/P9, 3 probes 0%): the matched-sib mechanical harvest is EXHAUSTED; the manifest's
  ~13k "templatable" members are an h_seq prediction the byte-gate refuses. Phase-26's templating
  thesis is spent -> close, open Phase 27 with byte-gate-honest re-scans.
- R22 clean-fleet 136/136 BYTE-IDENTICAL throughout; dedup 1840/0; 0 NON_MATCHING (G4).
- rules R32 (coverage assertion) / R33 (derive, don't re-derive) / R34 (a second, disagreeing
  oracle). worklog -> phase-ends/logs/Phase26.md (R19). bumps 1.24.0 -> 1.25.0.
2026-07-15 14:54:25 -06:00

1107 lines
149 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CURRENT PHASE — Phase 26: The Family-Endgame (finish the decomp)
> **Status:** ACTIVE · plan approved by Drew (gate 1) 2026-07-11 · Generation Gen2 (18th phase of the arc)
> **Opening brief:** `docs/family-endgame-megaplan.md` (Phase-25 handoff). **Fable5 window closes ~2026-07-13.**
> **Recovery note:** a fresh session resumes from the ▶ CURRENT TASK below (P3 — autonomous between gates). Read the plan context here + the megaplan; per-task log at the bottom is the crash-recovery trail.
## The plan in one paragraph
The Phase-25 h_seq reframe: the "unique tail" is really per-location families — crack ONE exemplar, template ×~120 siblings through the whole-binary byte-gate. Planning-session verification (2026-07-11) reproduced the survey from the sigs: **663 tail families; substantial (nins≥80) = 186 families / 1.85M ins** (megaplan's "986" was a miscount). Design-stage discovery (byte-verified on specifics, V0 re-verifies — R14): **the tail is ~90% a reloc-tracker blind spot** — `norm_stream`/`reloc_targets` drop the pending `lui`-hi on any R-type write, but gcc-2.7.2's indexed-global idiom (`lui; addu $idx; lw lo($at)`) preserves it, so every `D_x[i]` access made its function "fleet-unique" and broke remap. Substantial-tail classes: PURE-same-addr 62 fams/1.55M ins · PURE-cross-addr 103/0.10M · IMM 8/0.10M. **Free win: 63 families / 0.31M ins have a MATCHED exemplar** and siblings that failed earlier sweeps only from the tracker bug → zero-crack banks once the ~40-LOC fix lands (= the validation corpus). Also found: `remap()` sequential substitution corrupts chained renames → must become single-pass simultaneous. Immediate substitution shrinks to an escalation tier (diff-driven, 3 tiers; probe only ambiguous values). **Owner decisions:** carried Fable5 queue (5 giants) deferred to END of phase (low priority); milestone = structural completion.
## Task checklist (effort per R7 · one commit per completed task, Drew pushes — R6)
- [x] **Task 0 — Bootstrap** `[xHigh]` — this file + harness task list (R28). *(completes with this commit)*
- [x] **Task 1 — Remap core: extended reloc tracker + single-pass substitution** `[xHigh]` — `family_remap.py`: hi propagates through add/addu index adds; `symbol_map`/`remap` gained backward-compatible `to_addr=None` (cross-address) + `imm_map` hook; single-pass simultaneous substitution + self-rename. norm_stream/h_norm UNTOUCHED. Discovery → cookbook §40b (R30) + decision-log (R31). **V0 PASS** (`.run/v0_reloc.py`): 22/22 regression (`func_80141100` NEW==OLD), 15/15 fix (`func_801407F4` vs splat .s, recovers `D_80187B88/90/B0`), cross-addr symbol_map clean. **V1 PASS** (`.run/v1_regression.py`): 160 real h_norm pairs, 96 SAME, **0 lost**, differences are strict indexed-reloc improvements. *(committed)*
- [x] **Task 2 — `tools/family_hseq.py` + committed manifest** `[xHigh]` — full-frontier survey; shared word-diff classifier added to `family_remap.py` (`stream_words`/`reloc_indices`/`reg_fields`/`classify_member` — PURE/IMM/STRUCT, register-drift aware). → `.run/family_hseq.json` + `docs/family-hseq.md`. **VERIFIED:** fleet 74.8/58.2/30.3 (= PhaseEnd_25 & progress.py to the decimal); tail cross-check **663 families / 186 substantial / 1.847M ins** (exact); classification vs Plan-agent table **PURE-same 62, IMM 8 exact, PURE-cross 114≈103**; 890×134/562×134 PURE per-location + 952×113 #addr21 IMM confirmed; full frontier = 581 substantial families / 3.22M templatable ins, **345 matched-sibling PURE/IMM families / 1.14M ins = the V2/V3 zero-crack corpus**. *(committed)*
- [x] **Task 3 — Imm engine (T2a Tier 1) + cross-address delta (T2b)** `[xHigh]` — `family_remap.imm_value`/`imm_map_tier1`/`remap_hseq`: diff-driven Tier-1 value-replace (asm-side ambiguity guard defers ambiguous values; C-literal swap preserving sign/hex-case) + T2b self-rename via the Task-1 `to_addr`. **Tier 2 (probe) DEFERRED** — build-if-needed per Task-5 measurement (byte-gate arbitrates; only ~8 low-weight IMM families). **VERIFIED** (`.run/v3_imm.py`, match_one reloc-masked): **0 DIFF** on every compilable pair — 3 IMM + 2 cross-address MATCH; 4 remap-fails were correctly-deferred asm-ambiguous values; 45 compile-fail(isolation) → whole-TU gate in Task 5. *(committed)*
- [x] **Task 4 — `family_sweep --hseq` mode** `[xHigh]` — additive `hseq_sweep()` (h_norm path byte-untouched): consumes `family_hseq.json`, templates matched-exemplar members via `remap_hseq` (cross-address + imm), stages `.run/sweep/<ov>/func_<TO_ADDR>.c` grouped by (overlay,split), gates via `harvest_verify` (unique per-group verified-out — fixes a latent multi-split overwrite). Member pre-filter = `remap_hseq` refusal (STRUCT/unresolved). **Static pin guard** (`__asm__("$N"` → skip family; §42e — the ×1-only pinned cracks that cc1-crash sibling TUs). `--band`/`--min-members`/`--stage-only`/`--only`. **VERIFIED:** substantial → 29 families, 1507 clean members staged / 267 groups, 1643 correctly skipped as pinned (16/29 families pinned incl. the decision-log-named `func_8016DF5C`/`8013D9B0`/`80133AB0`); h_norm path intact; drafts byte-correct by construction (V3), type-using → whole-TU gate (Task 5). *(committed)*
- [x] **Task 5 — Zero-crack validation harvest (substantial band) — GO/NO-GO = GO** `[xHigh]` — ran the real byte-gate on the 29 substantial matched-exemplar families. **Tooling fix discovered + applied (Task-5's "measure then fix"):** `remap_hseq.gather_externs` carries file-scope externs for body-referenced symbols (`extract_unit` only grabbed adjacent ones) — the decl class that depressed the first run. **Result: 532 members banked** (byte-gated); per-family: **3 tracker-miss PURE families (`0x8015d5e8`/`0x8015f118`/`0x801407f4`) bank 100% ×133 = 399 byte-perfect** (the free win), 1 cross-addr family 50%; **9 zero-bank families are type-using (`Work8016`/`Prim`/…) → §41 reconcile follow-on (Task 8)**, 16 families pinned → Task 7. **VERDICT: the h_seq machinery is 100% correct on clean families — GO.** decision-log 2026-07-11 (R31). **R22 clean-fleet 136/136 GREEN**; metrics 30.3→**30.9% distinct** (+375 fns) / 58.2→**58.5% instr**. *(committed)*
- [x] **Task 6 — Step-A triage of the 119 draftable substantial exemplars** `[Ultracode]` — Workflow (`.run/wf_triage_full.js`, 119 agents / 0 err / 5.3M tok): per-family m2c draft (+§8 jtbl) → `match_one` closeness → class + §31/§45 lever + seed (`.run/phase26-seeds/`). **119 triaged → cheap 29 (325k ins, 23 closeness-0 isolation-MATCH) / permuter 29 (341k) / fable5 61 (1.71M).** Curriculum → `docs/phase26-triage.md`. **⚠ Banking caveat (verified): the 23 closeness-0 seeds gate 0/23 into ov077** — genuine function matches but carry standalone types + Ghidra sigs conflicting with the TU (§41 def-side wall: `redefinition of struct Obj` / `conflicting types`); banking needs the Task-8 `--reconcile`/`canon_sig_reconcile` pass. *(committed)*
---
## 🔬 PHASE 26-A — TOOLING-INTEGRITY AUDIT (INSERTED HALF-PHASE) — ✅ COMPLETE (2026-07-15)
> **CLOSED.** A0–A11 done. Outcome + the fixed/remaining ledger: `docs/tooling-audit.md` (AUDIT-CLOSE LEDGER).
> Rules for P10 ratification at the Phase-26 PhaseEnd: **R32/R33/R34**. Payoff **66.5→68.6% instr** (banked by
> the fixes A3f/g/h + A9a/b). Final R22 **136/136 byte-identical**; `make report`/`audit-corpus`/`audit-cdecl`
> green. **Phase 26 RESUMES at Task 7** (fresh session — see the Log's A11 entry + the checklist below).
> *(The A0–A11 checklist below evolved its sub-numbering across sessions; the authoritative per-task trail is
> the `## Log` at the bottom. Do not re-derive from the checklist alone.)*
> **Drew's call, 2026-07-14 (gate-1 approved):** *"audit as an inserted half-phase in the current phase and
> then resume phase 26."* The Phase-3.5 precedent — a spike inserted mid-arc, not a new phase. Phase 26's
> Tasks 7–12 resume **unchanged** after A11. Effort: **Max** (Drew set it); the fan-out tasks (A9/A10) need an
> **Ultracode** toggle — R27: STOP, prompt, WAIT for the actual `/effort` command.
>
> **📄 THE PLAN IS `docs/tooling-audit.md`** — 40 measured findings, the method, the priority order, the 7
> already-fixed bugs, the 63 not-yet-audited tools. **Do not re-derive it.**
>
> **The case (the session's most important finding):** the whole-binary byte-gate is a *perfect correctness
> oracle and a null coverage oracle*. It has never accepted a wrong match — and it is blind **by construction**
> to work never attempted (green since Phase 5, when 0% was decompiled, because `INCLUDE_ASM` pastes the
> ORIGINAL asm: **a green byte-gate is compatible with any decomp %**). Seven silent-skip bugs in one session
> were not typos — they are one structural blind spot: *a scanner extracts N items from a corpus, the true
> count is M > N, and nobody ever compared N to M.* The cost is not wrong answers. It is **invisible work, and
> walls that aren't there** — one 10% hole in the callee oracle made **nine byte-exact functions look like an
> intrinsic compiler wall**.
>
> **R33 governs the order: apply it to each tool BEFORE R32.** *Why is this tool re-deriving something the
> build already guarantees?* **The best outcome is a DELETED SCANNER, not a fixed regex.**
> **⚠ ORDER CORRECTED (Drew, mid-session): the FULL AUDIT runs BEFORE the fix campaign.** My first
> ordering put the 18-tool audit near the *end* — which contradicts `docs/tooling-audit.md`, whose stated
> priority is `dedup_integrate` → `jtbl_family_bank` → the SELECTION tools → `masked_diff`/`match_one` →
> *then* the 40 measured findings. The reason is the one that matters: **a hole in a SELECTION tool makes
> work invisible to *planning* — the worst kind, because you never know to look.** Fixing on top of
> unaudited selection tooling means re-running the fixes when the audit later finds the hole. **A2 is now
> the full audit; A3–A9 (the fix campaign) are blocked on it.**
>
> **Tool coverage:** A1 (1) + A2 (18) + the fix campaign (~17 already-measured) ≈ **36 tools** — not 82.
> The filter (deliberate, from the audit doc): *does it PARSE something, and does it GATE or SELECT work?*
> The rest are dead LLM-tier scripts.
- [x] **A0 — Bootstrap** `[Max]` — this block + the harness task list (R28) + the phase-boundary decision → `docs/decision-log.md` (R31). *(committed `commit:0585`)*
- [x] **A1 — `dedup_integrate.py`: the false-green gate** `[Max]` — audit priority #1: a **fail-closed validator that can print a false green**, which nothing downstream can catch. **All three paths confirmed and closed** (`commit:0586`):
**(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**. **(2)** an absent `.run/sig.*.jsonl` degraded to *"0 validated, 0 failed"* and **exit 0** — on a fresh clone the gate validated **nothing** and passed. **(3)** the **bank claim was never checked at all**.
**R33 applied:** the bank claim is now *derived* from the build invariant (`INCLUDE_ASM` pastes the ORIGINAL asm ⇒ a member not wrapped in it is byte-exact) rather than trusted from the registry. The C1 sig check is kept but its docstring **corrected** (P9): a sig signs the ROM, so it is immutable w.r.t. `src/` and **cannot** detect source drift, which it claimed to.
**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 — and `dedup_propagate.overlay_files` allowlists only `("_a","_o0","_o0b","_after")`. 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.** Fuel → `.run/audit/a1_harvest_fuel.json`, banked in **A6**.
**Blast radius, MEASURED (R14):** headline metrics **unchanged to the decimal** (66.5% / 46.8%) — `weighted_metrics()` derives from the invariant and was *structurally immune*; `progress.py` had already been taught to distrust the registry (`commit:0574`). **A null result that CONFIRMS R33: the tool that refused to re-derive was the one that was right.** Registry 1813 → 1806 groups; `make report` green; negative controls all fail-closed.
- [x] **A2 — THE FULL AUDIT: the remaining 18 gate/select tools** `[Ultracode]` — **DONE. 38 agents · 2.24M tok · 0 err. 32 findings raised → 28 SURVIVED adversarial verification (4 REFUTED, 16 downgraded); 40 scanners measured CLEAN.** Full write-up appended to **`docs/tooling-audit.md` (ROUND 2)**.
**🔴 THE ROOT CAUSE — one bug, ~10 times:** *a hand-maintained model of the corpus layout (a file allowlist, a single-`.c` assumption, a `func_`-only regex, a `REGION_SUB` dict) sitting on top of a filesystem that already answers the question.* Every TU split silently widened it. **Decay proven:** `.run/fuel_manifest.json` (Jul 8) recorded **130** stubs; the same tool today returns **30** — the Phase-26 splits moved ~100 stubs out from under a dict literal last edited in Phase 22, and **nobody noticed, because an un-nominated target produces silence, not an error.**
**THE NUMBERS (measured, skeptic-confirmed):** **91.6% of ALL remaining project gain is invisible to target selection** (true 994,633 ins; the manifest sees 83,305) · **117 of 127 reach-134 functions never nominated** · `harvest_verify` cannot see **56,742 of 58,717 (96.6%)** open stubs · **`wave_targets` hands 78 of 87 targets an asm path that does not exist.**
**THE THREE THAT CHANGE WHAT WE BELIEVE:**
**(1) The Phase-22 verdict "the permuter's fuel is exhausted" is UNSAFE.** `grinder` banks through `harvest_verify`, which sees one TU — **1,290 of 1,298 (99%) of the grinder's own queue could never have banked**, however good the permuter's output was. "0 banks since Phase 21" is equally consistent with *the tool could not bank*. **Re-test before repeating it (A12).**
**(2) The Phase-25/26 endgame plan is majority-fiction.** `docs/family-manifest.md` advertises "2,758 multi-member families / 11.0 MB of hidden leverage." **1,071 of them / 6.80 MB are ALREADY FULLY MATCHED** — phantom targets, **62% of the advertised byte-weight** — because the matched-set oracle scans ONE overlay. The byte-weight *ranking*, the entire point of the file, is sorted mostly on dead work. True frontier: 1,475 families / 3.9 MB.
**(3) A corpus defect the byte-gate is structurally BLIND to.** `config/symbols.us.txt:981` declares `listCdBuffer = 0x80180000` (a main-EXE **data** symbol) and every overlay's splat config loads that file — but in overlay space 0x80180000 is **code**. splat cuts **97 real functions in half** and invents **96 phantom ones**: **193 slices that can never be matched by anyone**, in 97 of 134 overlays. They sit in the harvest queue as ordinary work, so agents burn on them forever and the failure reads as an intrinsic compiler wall — **and the build stays byte-identical and green throughout**, because the `.s` halves are pasted back verbatim. *A perfect correctness oracle and a null coverage oracle.* What saved us: **`sig_image` was RIGHT** (58,524/58,621 agreement with spimdisasm; correct on all 97 disagreements). **A second independent oracle is the only reason this was visible at all.**
- [~] **A3 — `tools/corpus.py`: ONE derived corpus oracle** `[Max]` — **IN PROGRESS. The oracle is built and 4 of ~10 scanners are deleted.**
**`tools/corpus.py` (`commit:0589`)** — derives from the FILESYSTEM (which `.c` files make up a binary; where a function's `.s` lives — the `INCLUDE_ASM` line is **self-describing**, its first argument *is* the asm subdir) and from the PROVEN INVARIANT (`matched` = `sig − stubs`, *derived*, never re-parsed from C text). Coverage-asserted (R32): every `INCLUDE_ASM` line must parse, every symbol must resolve (**any** C identifier — a `func_`-only regex silently misses the 100 curated `listCdBuffer` stubs), every stub must have a `.s`.
**The SECOND ORACLE (`make audit-corpus`)** — cross-checks splat's boundaries against `sig_image`'s independent ones. Reports **193** (96 PHANTOM + 97 TRUNCATED), **reproducing the A2 audit's number exactly from an independently-written tool** — a third confirmation. *RED by design until A4; then it becomes a gate.*
**R14 self-catch, recorded because the near-miss IS the lesson:** run naively over all 136 binaries the same check reports **914** slices — 4.7× the truth. `main`/`resident` are signed by the **Ghidra** dumper (shorter boundaries by design; never analysed the linked PsyQ subsegs), so the comparison measures *Ghidra's* limits, not splat's errors. Only the overlays are signed by `sig_image`. `sig_is_independent()` now encodes that domain. **A check applied outside its valid domain does not become more thorough — it becomes noise.**
**`build_fuel_manifest` + `wave_targets` (`commit:0590`)** — targets **30 → 263**; reach-134 targets **10 → 127** (the entire high-ROI band); remaining gain **83,305 → 994,633 ins** — *the audit's predicted figure to the unit* (a **fourth** independent confirmation). `wave_targets`' asm paths: **0 of 263 missing** (was 78 of 87 pointing at nothing, whose wasted attempts were booked as *matching* failures and fed `reserved_walls()` — a silent skip compounding into a **false wall**).
**`harvest_verify` + `gate_stage` (`commit:0591`) — the byte-gate itself.** It could only see ONE TU: **4.9% → 100%** of ov_SC01_077 reachable; **96.6%** of fleet stubs were unreachable. *Safety argued explicitly:* only the SPLICE LOCATION is derived — the verdict (`make build` + SHA1) is untouched, and since `INCLUDE_ASM` pastes the original asm, a bug can make it **fail to bank but never falsely bank**. Verified by an **identity known-answer test** across three different split TUs → `d19c9580` BYTE-IDENTICAL, tree clean.
**STILL TO DO in A3:** `family_manifest`/`family_hseq` (the matched-set oracle — **1,071 of 2,758 advertised families are already fully matched**, 62% of the endgame plan's byte-weight is phantom) · **DELETE `census_conflict_callees`** (R33 — `reconcile_tu` answers its question from the build) · `exemplar_miner`/`difficulty` (inherited holes) · `jr_isolate_all.jr_inventory` (reads its banked-roster from an **ephemeral gitignored scratch file**). `jtbl_family_bank` (3 bugs found by hand, never audited) · the SELECTION tools `family_hseq`/`family_manifest`/`wave_targets`/`exemplar_miner`/`worklist`/`build_fuel_manifest` · the closeness oracle `masked_diff`/`match_one` that every crack agent trusts · the bank/gate path `gate_stage`/`harvest_verify`/`bank_exemplar` · `dup_report`/`difficulty`/`sig_image`/`canon_draft_decls`/`derive_canonical_sigs`/`census_conflict_callees`. **METHOD (do NOT audit by reading regexes — that is the failure mode that WROTE these bugs):** build a deliberately **over-approximating** candidate detector, run both over the real corpus, compute `gap = candidates − parsed`, and **classify every item in the gap** as a real silent skip or a justified exclusion. Pair each auditor with an **adversarial skeptic** told to refute it (in the first audit several magnitudes were wrong in *both* directions and one whole class was refuted). **R33 before R32.**
- [x] **A3b — `tools/cdecl.py`: THE C-declaration oracle** `[Max]` — **DONE. `make audit-cdecl` GREEN; R22 clean-fleet 136/136.**
The audit prescribed a *shape-aware alternation* per tool (~15 coordinated regex edits). **Rejected (R33, decision-log 2026-07-14):** fifteen hand-maintained models are exactly what diverged — two tools in ONE pipeline already disagree about whether `extern s32 D_a, D_b;` is a declaration — and an alternation only ever covers the shapes somebody remembered. **The thing being scanned has a GRAMMAR.** C's declarator grammar is small, closed and **total**: it describes fn-ptr arrays, sized/2-D arrays, multi-declarators, fn-ptr params and K&R identifier-lists *without being told they exist*. ~250 lines of recursive descent — **less code than the fifteen regexes it deletes**, and exhaustive by construction rather than by memory.
**THREE ORACLES, whole corpus (a measurement, not a belief):** coverage **2,952,246 depth-0 statements → 2,731,521 declarators, 0 parser defects**; the **real cross-gcc** compiled each of **50,405 distinct declarations beside this parser's reconstruction of it — 0 rejected**; differential vs the incumbents — **0** symbols they see at file scope that cdecl misses, **26** in engine_core.h they cannot see, **6** they wrongly promote from *block* scope.
**Two design decisions (cookbook §51g, LAWS 4–8):** the **candidate set is DERIVED** — at file scope C admits nothing but declarations, so R32's over-approximating detector is *every depth-0 statement*, with no second model to rot; and **gcc adjudicates my own coverage gap** — a statement gcc *also* rejects is not C (my rejection is right, the input is corrupt), one it *accepts* and I don't is my defect. All 33 residual came back **NOT-C**, all in dead `.run/drafts*` scratch, **none in `src/`**.
**NEW findings (docs/tooling-audit.md):** `reconcile_decls.DATA_DECL_LINE_RE` finds **ZERO** decls in `engine_core.h` (line-anchored; every decl there ends in `\`) — its authoritative tier has **always been empty** · two scanners count **block-scope** externs as file-scope canonicals (the §8d wall) · `tu_ambient`'s func regex (`[^()]*` params) drops **any callee with a fn-ptr parameter** · an R14 near-miss: the 33 corrupt drafts were written by a *recovery tool* that prepended `extern` to an `if` statement — but the source bug was **already fixed in Phase 19** (today's oracle: 0 garbage / 300 sigs). *Mechanism confirmed, consequence nil.*
**Scope (deliberate): NO consumer changed** — so it cannot move a byte. The audit warns that making the parser see more **ARMS dormant transforms** (`reconcile_decls.data_access_subs` would mangle `D_1[i]()` the moment fn-ptr decls become visible to it). Migration is one tool at a time, each byte-gated.
- [x] **A4 — The `listCdBuffer` corpus defect: 193 unmatchable slices** `[Max]` — **DONE (`commit:0594`). R22 CLEAN-FLEET: `make clean` → extract 136 → build 136 → `check-all` = 136 PASSED, 0 FAILED. `make audit-corpus`: 0 PHANTOM + 0 TRUNCATED (was 193).**
`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 stacks that file. **High RAM is reused: an address that is a buffer to main is live CODE to an overlay.** splat therefore cut **97 real functions in half** and **invented 96 phantoms** — 193 slices **unmatchable by construction** (the phantom `listCdBuffer.s` 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).
**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 ×134 sweep **banked the phantom** as `void listCdBuffer(void) {}` — byte-correct, gate-green, and entirely fictitious — while leaving `func_8017FFC4` permanently unmatchable.
**And it was hiding a real function:** 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 and never by `jal` — so splat cannot find it and needs the boundary *declared*. `listCdBuffer` had supplied it **by luck**. Now declared honestly, per-overlay, exactly where R13/R15 says it belongs.
**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`, stacked **only** by main.
- [x] **A5 — The closeness oracle lied on 155 functions** `[Max]` — **DONE (`commit:0594`).** `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** — the missing one, **`R_MIPS_PC16`**, fell through to a **full-word compare** against an *unresolved placeholder*, which can never succeed. **Decisive test** (derived from the invariant, coverage-asserted): `INCLUDE_ASM` pastes the ORIGINAL asm, so every stub MUST score 0 — **2,741 scored: old mask 150 LIES, PC16 masked 4** (the 4 are the separate length-delta defect). A phantom non-zero sends an agent to grind at a wall that isn't there, and the wasted attempt is booked as a *matching* failure → `reserved_walls()` → **a function that was never broken is permanently blacklisted.**
- [x] **NEW (found by cutting the R22 corner): a STALE OBJECT CAN PRODUCE A FALSE PASS** `[Max]` — `.o ← .s` is **not** a dependency make can see (assembly arrives via `INCLUDE_ASM` → `.include` → maspsx/as, *after* cpp; `-MMD` tracks headers only). Re-extract + build incrementally ⇒ make links a **stale object** — and because `INCLUDE_ASM` pastes the ORIGINAL bytes, the stale object still yields the original image, **SHA1 goes GREEN**, and the split just changed is never exercised. **A broken config change can be "verified" by an incremental build.** Live proof: 8 of 136 linked stale objects here and failed **loudly only by luck**. R22/H3 already legislate this and I broke them — but *a rule that needs a human to remember it is not a gate*. `extract` now invalidates the objects that include what it rewrote. **Structural, not advisory.**
- [ ] **A6 — Wire `reconcile_tu.py`; retire the fleet-majority oracle** `[Max]` *(blocked on A2)* — `reconcile_decls.canonical_data_map` asks *"what does the FLEET call this symbol"* when C's constraint is **per-TU**: 36.8% of symbols carry ≥2 conflicting spellings, so one fleet-wide answer is **wrong for some TU by construction** — it returns an **actively WRONG** canon for **3,717** symbols and disagrees with the TU's own decl on **21.7%** of pairs (**every one of 678 TUs** has ≥1 broken answer). `reconcile_tu.py` is **written + validated + NOT WIRED** (`commit:0580`). Wire → `bank_exemplar` / `jtbl_family_bank` / `gate_stage`; byte-gate. Unblocks `func_8017A4AC` (287 KB), `func_8013F350`, `func_80131340`.
- [ ] **A5 — Family engine: 93 phantom exemplars, 1,834 free members** `[Max]` *(blocked on A2)* — `family_remap.extract_unit` globs only `src/<ov>/<ov>*.c`, so it **cannot read a `DEFINE_func_*` body out of `engine_core.h`** → **93 of 218 (43%)** "matched" exemplars are PHANTOM and **1,834** still-stubbed, PURE/IMM-clean, unpinned member templates are **never attempted**. Plus `symbol_map` naming an address-taken **function** `D_<addr>` (3 families × 37 members silently no-op, booked as *byte* failures), `gather_externs`' multi-line externs (9), `family_sweep.stub_map`'s curated-name stubs (3 phantom families). Fix, assert, **re-run the sweep, harvest.**
- [ ] **A6 — `dedup_propagate`: 407 invisible files** `[Max]` *(blocked on A2)* — a hardcoded suffix allowlist predating the jr splits sees **404 of 811** overlay `.c`; the gap holds **36,135 stubs + ~32,000 inline defs — half the corpus** — and it gates *all* of dedup_propagate. ≥266 free ×N banks cannot even be nominated. Fix = **glob, not allowlist** (the next split family would re-open it), landed **together with** `find_site`'s K&R blindness or the newly-visible half's biggest prizes (`func_8015AE2C`, `func_80166994` — both K&R) are still dropped. Re-run `--auto-from`, harvest.
- [ ] **A7 — `build_engine_types`: dead on 81% of its own corpus** `[Max]` *(blocked on A2)* — hard-exits on **573 of 709** type-bearing files (all 134 overlays) because 1,929 **tagged**-struct typedefs trip an overlap guard written when the source had only anonymous ones. `inject_capped_externs` routes every type-bearing body to this tool as the type-heavy tail's **only** sanctioned unblocker — and it cannot run on the corpus that tail lives in. **This is the "3,098 type-heavy tail" and the 9 zero-bank type-using families.** (Fail-LOUD, not silent — it went unfixed because the message read like an edge case rather than an 81% coverage failure.)
- [ ] **A8 — Split-infra: the silent byte-changers** `[Max]` *(blocked on A2)* — `jr_isolate_all._file_scope_decls` silently drops **4,040** decls, of which **683 are function PROTOTYPES**: in C89 an undeclared function is implicitly `int f()`, so the TU still **compiles** — with the wrong return type, and this project has **byte-proven that return type drives delay-slot fill**. A latent byte-changer armed for the next cut. (`uint`/`code_fn` are *defined in `engine_types.h`*, which every region includes; `volatile` is missing from a whitelist that has `const`; the comment ON `_SAFE_TYPE` documents the fix that was never applied.) Plus `jr_inventory`'s curated-name blindness — the tool's core invariant *"every jr gets its own region"* is **false in 4 overlays right now** — and `overlay_src_split`'s `force_decl` latch swallowing 2 real definitions **in the exemplar overlay** while its selftest passes green (a *serialisation* check masquerading as a *coverage* check).
- [ ] **A9 — `lint_symbol_refs`: a guard allowed to sit red does not exist** `[xHigh]` *(blocked on A2)* — currently **RED** (43 false positives) and **UNWIRED** (`make report` never calls it, though its docstring claims it does). No `__asm__("label")` model; unions two symbol files instead of using each binary's splat stack; globs `src/**/*.c` so **`src/shared/*.h` is never scanned** — yet `engine_core.h` (10,360 `func_`/`D_` tokens, ×134 overlays) is exactly where one dangling ref breaks every clean build at once. Fix → **green on HEAD** → **wire into `make report`**. It is the only detector for the R22 failure mode.
- [ ] **A10 — THE PAYOFF: re-test the walls** `[Ultracode/Max]` — *how many of the walls we "byte-proved" across 26 phases were **lookup misses wearing a wall's clothes**?* Re-test on the repaired oracles: the **def-side loose-typing wall** (§20/§41, "triple-confirmed" in Phase 23) · the **159 arity/narrow-param conflicts** (Phase-15 "documented dead-end") · the **3,098 type-heavy tail** · the **9 zero-bank type-using families** · the **780 h_seq rejections**. Phase 16 byte-proved that genuinely contradictory typings *do* exist, so the wall is real **in part** — but *"some of it was our tooling"* is now **the prior, not the long shot**. A re-confirmed wall is as valuable as a dissolved one (P9).
- [ ] **A11 — Distill + close the audit** `[Max]` — cookbook (the silent-skip class + the over-approximating-detector method) · **R32/R33** written for Drew's P10 ratification · decision-log (R31) · SETUP (R21) · `docs/tooling-audit.md` DIAGNOSIS → fixed/remaining ledger · final R22 clean-fleet 136/136 + `make report`. **Then resume Phase 26 at Task 7.**
---
## Phase 26 tasks — RESUME HERE after A11
- [ ] **Task 7 — Family-core crack waves (the Fable5 window)** `[launch at Max — R27; agents model:fable, parallel-isolated, distill-between]` — biggest byte-weight first (890/562/536/493…); §45-templated prompts (read `.greg`/`.lreg` first; Lever-A merged-accumulator audit; 1-death in-out-asm; /s; gdb-on-cc1, `tools/reference/gcc-2.7.2/`); PIN-FREE (×134); `harvest_verify` arbitrates; distill each crack → cookbook §46+ (R30); cheap-Opus applies banked idioms between waves; cheap/permuter lists run in parallel `[UC]`. ~375k tok/crack guide; documented wall + levers = valid outcome (P9). ⚠ **The Fable5 window (~2026-07-13) has almost certainly closed** — re-plan this task's model tier at A11.
- [ ] **Task 8 — Mechanical harvest waves** `[Ultracode; continues post-window]` — cracked exemplars → template ×members → gate → bank; h_norm draftable/matched-free retries with the new tracker (5.9 MB bucket); F-jumptable 4 (§8); M-linkwall 1; link-undef second pass. Batched commits; **R22 clean-fleet before each commit batch** (never while agents need `asm/`).
- [ ] **Task 9 — Mid-band + residue measurement** `[xHigh]` — <80-ins families (0.68M ins) through the engine; measure h_seq-miss → GO/NO-GO fuzzy pass (build only if ROI; else Phase 27).
- [ ] **Task 10 — Carried Fable5 queue (END of phase — Drew's call)** `[Fable5 if window remains, else permuter/Opus + banked levers]` — 801670E4 (diff-23), 80178004 (close-7), 801412A8 (close-29), 8016CBC0 (153/209), 8014D820 (LCS-226); specs `.run/giants/*.opus.md` + `.run/t7b/close/`. Crack ×134 or wall-document; post-window walls → Phase 27, accepted.
- [ ] **Task 11 — Step-D residue map** `[xHigh]` — true singletons (~0.27M ins) + 5 behemoths → Phase-27 input doc. NO execution.
- [ ] **Task 12 — PhaseEnd** `[Max — Tier 1; R27 prompt]` — P7 walk, milestone demo, gate 2, `PhaseEnd_Phase26.md`, worklog → `logs/Phase26.md` (R19), in-file recap (R25), decision-log current (R31).
## ⛳ SESSION-8 CLOSE (2026-07-14) — READ THIS FIRST
### ⚠ DREW'S DIRECTIVE (2026-07-14, binding): the TOOLING-INTEGRITY AUDIT comes BEFORE any further matching work
> *"I feel like we should do T14 now, before the rest of the work. but not in this phase."*
# 📄 THE AUDIT PHASE'S INPUT DOCUMENT IS **`docs/tooling-audit.md`** — READ IT FIRST, IT IS THE PLAN
> **40 MEASURED findings** (6 auditor agents + 6 adversarial skeptics, 1.2M tokens) with file:line evidence and
> candidate/parsed/skip counts per scanner — plus the METHOD, the priority order, the 7 bugs already fixed
> (do not redo), and the 63 tools not yet audited with the filter for which of them matter.
> **Almost nothing in it is fixed. It is diagnosis.** Everything below is a summary OF that document.
**✅ DECIDED (Drew, 2026-07-14, session 9): option (b) — the audit runs as an INSERTED HALF-PHASE inside
Phase 26** (the Phase-3.5 precedent), and Phase 26 then resumes at Task 7. Effort **Max** set. The plan is the
**🔬 PHASE 26-A** block in the task checklist above (A0–A11), built from `docs/tooling-audit.md`.
*(The alternative — close Phase 26 early on an unmet milestone and open the audit as Phase 27 — was declined:
Phase 26's structural-completion milestone is still live and the audit is a prerequisite to reaching it, not a
successor to it.)*
### WHY (the case for doing it first — this is the session's most important finding)
**Seven silent-skip tool bugs in one session**, and they were not typos — they are a *structural* blind spot:
> a scanner extracts N items from a corpus, the true count is M > N, and **nobody ever compared N to M**.
The whole-binary byte-gate is a perfect CORRECTNESS oracle (it never once accepted a wrong match) but it is
**blind by construction to work never attempted** — it has been green since Phase 5, when 0% was decompiled,
because `INCLUDE_ASM` pastes the ORIGINAL asm. A green byte-gate is compatible with ANY decomp %.
One hole (`SIG_IN_BODY_RE`, 10% of the callee oracle) made **nine byte-exact functions look like an intrinsic
compiler wall**. That is the cost of not auditing: not wrong answers — *invisible work*, and walls that aren't.
**AUDIT SCOPE SO FAR: 19 of 82 tools (23%), chosen by risk. NOT comprehensive.** The unaudited set includes the
most dangerous ones:
- **`dedup_integrate.py`** — the FAIL-CLOSED byte-honesty validator. A silent skip there prints
*"1813 validated, 0 failed"* — **a false green from a gate.** Audit this FIRST.
- **`jtbl_family_bank.py`** — three bugs found in it BY HAND this session; never formally audited.
- **`family_hseq.py` / `wave_targets.py` / `exemplar_miner.py`** — target SELECTION. A hole here makes work
**invisible to planning** — the worst kind, because you never know to look.
- **`masked_diff.py` / `match_one.py`** — the closeness oracle every agent trusts.
- (`harvest_verify.py` is the byte-gate but DERIVES from the build, so a parse hole makes it *conservative,
not wrong* — the good kind of tool. See R33 below.)
**Do NOT "audit all 82"** — many are dead LLM-tier scripts. The filter is: **does it PARSE something, and does it
GATE or SELECT work?** (~15 tools.) And per R33, for each one ask the better question first: *why is this tool
re-deriving something the build already guarantees?*
### 🔑 THE COOKBOOK LESSON THAT SUPERSEDES THE ONE WE STARTED WITH (R33 candidate)
> **A metric DERIVED FROM A PROVEN INVARIANT beats a metric that RE-PARSES THE WORLD.**
`progress.py` has two metrics answering the same question. `weighted_metrics()` derives from the invariant —
*"not wrapped in INCLUDE_ASM ⇒ byte-exact, because the build is byte-identical"* — and **inherits the byte-gate's
correctness for free**. `classify()` re-derives the same fact by parsing C, and inherited a bug instead (it read
a K&R definition as a forward declaration). Same question, two tools; **the one that refused to re-derive was the
one that was right.**
### 🔴 AND AN HONEST SELF-CORRECTION (P9/R14 — do not repeat it)
I told Drew our headline numbers had been under-reporting by ~190k instructions. **That was WRONG.**
`weighted_metrics()` never calls `classify()`, so it was structurally immune; **the published 65.6% / 44.9% were
CORRECT ALL ALONG** — only the secondary REAL/fn-count report was wrong. I had verified the DEFECT against the
bytes (R14) and still got the conclusion wrong because **I did not verify its BLAST RADIUS**. What caught it was a
**null result** (+376 instructions, not +190,000) against a strong prediction — trivially easy to wave off as noise.
*"This tool is broken" and "this number is wrong" are different claims needing different evidence.*
### RULE CANDIDATES FOR PHASEEND (P10 — Drew ratifies)
- **R32 — Coverage assertion.** A tool that scans the corpus must assert its own coverage (found vs. an
over-approximating candidate set) and **fail loud on unparsed input**. A silent skip is a DEFECT, not a no-op.
*(Drew: "agreed", 2026-07-14.)*
- **R33 — Derive, don't re-derive.** Where a proven invariant answers a question, derive the answer from it rather
than re-parsing the source. Before adding a coverage assertion to a scanner, first ask whether the scanner
should exist at all.
---
## 🔁 SESSION-9 CLOSE — HANDOFF (2026-07-14). Read this, then `docs/tooling-audit.md`.
**State: `check-all` 136/136 BYTE-IDENTICAL · `make audit-corpus` 0 unmatchable slices · dedup 1823/0 ·
fleet instr-weighted 66.5% → 66.7% · 0 NON_MATCHING. Tree clean, all work committed.**
### DONE (A0–A8 + two unplanned finds)
| | what | outcome |
|---|---|---|
| **A1** | `dedup_integrate` — a fail-closed gate that printed **false greens** | 3 paths closed w/ negative controls; 7 ghost groups purged |
| **A2** | THE FULL AUDIT (18 tools, 38 agents, 2.24M tok) | **32 raised → 28 survived**, 4 refuted, 40 scanners measured clean |
| **A3** | **`tools/corpus.py`** — ONE derived oracle + **`make audit-corpus`** (a *second oracle that can disagree*) | targets **30→263** · reach-134 **10→127** · gain **83k→994,633 ins** · byte-gate reach **4.9%→100%** |
| **A4** | the **`listCdBuffer`** corpus defect | **193 unmatchable slices → 0**; 4 real functions un-hidden; a **banked phantom** removed |
| **A5** | the closeness oracle (`masked_diff` PC16) | **150 lies → 4** (coverage-asserted over 2,741 fns) |
| **A6** | `dedup_propagate` (glob + K&R `find_site`) | **17 fns banked ×134 free**, incl. all 4 the registry lied about |
| **A7** | family engine (`extract_unit`/`symbol_map`/`gather_externs`/`stub_map`) | **96 phantom exemplars → 0** (216/216 real) |
| **A7** | `build_engine_types` | ran on **73–81%** of its corpus for the first time |
| **A8** | `jr_isolate_all._SAFE_TYPE` | **683 dropped prototypes** — a **latent BYTE-CHANGER** — fixed + coverage-asserted |
| ➕ | **stale objects can produce a FALSE PASS** | `extract` now invalidates them. **Structural, not advisory.** |
### REMAINING — all fully specified on disk; nothing lives only in a dead session's context
1. ~~**`tools/cdecl.py`** — the ONE coverage-asserting C-decl parser.~~ **DONE 2026-07-14** (A3b above; `make audit-cdecl` green, 0 parser defects over 2.95M statements, 50,405 declarations gcc-verified). **The 15 consumers are NOT yet migrated** — that is the next step, one tool at a time, each byte-gated. Migration order by measured harm: `reconcile_decls`/`canonical_data_map` (3,717 actively-WRONG canonicals; and see item 2 — `reconcile_tu` supersedes its oracle) → `gen_harvest_targets` (`DATA_DECL_RE`/`EXTERN_DECL_RE`/`tu_ambient`) → `sig_unify` → `canon_sig_reconcile` (its `_file_scope_statements` is CLEAN and should simply *delegate* to `cdecl.tu_statements`; only its classifier regexes are broken) → the rest. ⚠️ **`reconcile_decls.data_access_subs` must gain a `fnptr` kind IN THE SAME CHANGE** that lets it see fn-ptr decls, or it will mangle `D_1[i]()` → `((u8 *)D_1)[i]()` (audit, GROUP data-decls, CLEAN item 4 — a dormant transform that the fix ARMS).
2. **Wire `tools/reconcile_tu.py`** (written + validated at `commit:0580`, still **NOT WIRED**) into `bank_exemplar`/`jtbl_family_bank`/`gate_stage`; retire `reconcile_decls`' fleet-majority oracle (**3,717 actively-wrong decls**; 21.7% of (TU,symbol) pairs). Unblocks `func_8017A4AC` (287 KB), `func_8013F350`, `func_80131340`. **Then DELETE `census_conflict_callees`** (already marked; `reconcile_tu` answers its question from the build).
3. **`lint_symbol_refs`** — RED (43 false positives) and UNWIRED. Fix the 4 blind spots → green on HEAD → **wire into `make report`**. It is the only detector for the R22 rename-drift failure mode.
4. **`overlay_src_split.scan_construct`** `force_decl` latch (swallows 2 real defs **in the exemplar overlay**, while its selftest passes green — a *serialisation* check masquerading as a *coverage* check) + `jr_inventory`'s banked-roster read from an **ephemeral gitignored scratch file** (R33 violation).
5. **🏆 A10 — RE-TEST THE WALLS.** *This is the payoff and the reason the audit was gated ahead of matching.*
- **"The permuter's fuel is exhausted" (Phase 22) is UNSAFE.** `grinder` banks through `harvest_verify`, which could see ONE TU — **1,290 of its own 1,298 queued fns could never have banked.** "0 banks since Phase 21" is *equally consistent* with *the tool could not bank*. **Re-run it against the fixed gate before repeating that conclusion.**
- The def-side loose-typing wall (§20/§41, "triple-confirmed"); the 159 arity conflicts; the 3,098 type-heavy tail + 9 zero-bank type-using families (`build_engine_types` can now RUN); the **780 h_seq rejections** against the repaired callee oracle.
- Any wall whose closeness came from the **155 wrong scores**, or whose target was one of the **193 listCdBuffer slices** (unmatchable *by construction* — no C exists for them).
6. **A11 — distill + close**: `docs/tooling-audit.md` DIAGNOSIS→ledger (partly done), PhaseEnd, **then resume Phase 26 at Task 7**.
### RULE CANDIDATES for Drew's ratification (P10)
- **R32 — Assert your COVERAGE.** A tool that scans the corpus must compare what it found against an
over-approximating candidate set and fail on the gap.
> ⚠️ **This is a CORRECTION to the first draft** ("fail loud on unparsed input"). `build_engine_types`
> **failed loud every single time for four phases** while hard-exiting on 81% of its own corpus — and was
> still invisible, because the message read like an edge case and **nobody counted it**.
> **A loud failure that nobody counts is exactly as invisible as a silent one.**
- **R33 — Derive, don't re-derive.** Where a proven invariant answers the question, derive from it rather
than re-parse. **The best outcome is a DELETED SCANNER, not a fixed regex.** (28 findings → one derived
oracle + ~10 deleted scanners.)
- **R34 (new) — A second oracle, not a better assertion.** When an oracle is *structurally* blind to a class
of error, no assertion inside it can help. Add an independent oracle that can **disagree** with it, and
make them argue. (The byte-gate is a perfect correctness oracle and a **null coverage oracle**; `sig_image`
disagreeing with splat is what exposed the 193 slices. We had both all along and never compared them.)
**Reusable method + laws: `docs/matching-cookbook.md` §51.** Strategic why: `docs/decision-log.md`.
---
## ▶ SESSION-8 RESULTS (2026-07-13/14)
### 📊 SESSION-8 SCOREBOARD
**Fleet: instr-weighted 63.0 → 66.5% · distinct-code 39.1 → 46.8% · fn-count 82.61%** (all DEFENSIBLE — see the
self-correction below). **FINAL R22: `make clean` + extract-all + check-all → 136/136 BYTE-IDENTICAL, 0 coverage defects.**
**136/136 byte-identical after every single bank** (R22). dedup 1813/0. 0 NON_MATCHING (G4). ~25 commits.
**13 CORES CRACKED**, incl. the four heaviest functions in the game. The 12-agent Ultracode wave: **11/12 MATCH**
first pass, every one adversarially verified by a skeptic (re-run `match_one` + the §8a jump-table check).
| Core | size × reach | how it fell | banked |
|---|---|---|---|
| `func_8017BEBC` | 952 × 113 | **Fable5** + §47 live-length slider | ×1 |
| `func_80178D40` | 890 × 134 | **cheap-Opus** reading loop.c/jump.c/cse.c (§46) | **×134** |
| `func_8015AE2C` | 562 × 134 | §8d decl-scope fix unblocked the sweep | **×134** |
| `func_8017A4AC` | 536 × 134 | §49 **LUID dial** (sched.c) | blocked — see below |
| `func_8015A3C8` | 493 × 134 | §48-A1 sink-the-init | **×132** |
| `func_8015444C` · `func_8016AB6C` · `func_8013FFD8` · `func_801380E0` | | wave | **×134 / ×134 / ×129 / ×134** |
| `func_8013F350` · `func_80131340` · `func_8015B950` · `func_8015C32C` · `func_80159C84` | | wave (MATCH) | **blocked on plumbing** |
| `func_80135EB0` | 289 × 134 | 21→**6**, WALLED with a named mechanism (§50-F) | honest defer |
### 🧰 THE TOOLKIT CROSSED A LINE — three ZERO-BYTE DIALS now cover the three passes that make every residual
Each emits nothing; each steers a tie; each has a **diagnostic signature a cheap agent can recognise on sight**.
That is why 9/12 fell first-pass without Fable5. *Fable5 DISCOVERS a class; everyone else APPLIES it.*
| signature | pass | dial |
|---|---|---|
| registers rotated | `global.c` allocno priority | **§47** live-length slider · **§48-A** pricing dials |
| two insns swapped, **SAME registers** | `sched.c` `rank_for_schedule` LUID tiebreak | **§49** LUID dial |
| structure right, instruction COUNT wrong | loop peel / cross-jump | **§46** · **§48-D** |
New this session: **§46** (4 loop-structure levers) · **§47** (the slider) · **§48** (+A4 sink-the-consumer-call) ·
**§49** (the LUID dial) · **§50** (refinements that **BOUND** §47/§48 — read §50-B before using A1/A4: the
"cross_jump refunds the bytes" claim is FALSE for a 1-insn tail reached by two jumps, `jump.c:1993` minimum=2).
### THE HEADLINE — the three heaviest cores in the game are cracked, and the wave scaled
| Core | size × reach | how | state |
|---|---|---|---|
| `func_80178D40` | 890 × 134 (477 KB) | **cheap-Opus** reading loop.c/jump.c/cse.c → §46 | **BANKED ×134** |
| `func_8017BEBC` | 952 × 113 (430 KB) | **Fable5** + the §47 live-length slider | **BANKED ×1** (×113 sweep = IMM-class, Task 8) |
| `func_8015AE2C` | 562 × 134 (301 KB) | §8d decl-scope fix unblocked the sweep | **BANKED ×134** |
| **12-core Ultracode wave** | 2.29 MB | §31/§46/§47 in the prompt + adversarial verify | **9/12 MATCH**, 3 near (close=2/2/21) |
**Metrics: instr-weighted 63.0 → 64.7% · distinct-code 39.1 → 42.8% · fn-count 82.43%.** R22 136/136 after
every bank. dedup 1813/0. 0 NON_MATCHING. ~15 commits.
### THE LESSON OF THE SESSION — every wall was OUR TOOLING, and the R17 triage rule called it every time
**Six silent-skip bugs found and fixed**, THREE of them the same brace-placement class:
1. `scope_data_externs` (NEW, §8d) — carried DATA externs were emitted at FILE scope, establishing a global
the sibling TU never had → `conflicting types`. **Demote to block scope when the TU has no file-scope decl
above.** Byte-neutral, never worse than raw. Unblocked the ×133 jr sweeps.
2. `extract_unit` — `not ln.rstrip().endswith(";")` missed m2c's `...); /* extern */` form → a DECLARATION
was read as a DEFINITION and the brace-scan swallowed the NEXT function's body. **15 of 35** substantial
exemplars were phantom "matches"; 3 more templated garbage.
3. `scope_data_externs._body_open_brace` — matched only an own-line `{` → silently no-op'd on every ANSI draft.
4. **`gen_harvest_targets.SIG_IN_BODY_RE`** — required `)\s*{`, but an own-line brace has a `\` before it, so
**186 of 1801 (10%) of engine_core.h's shared signatures were MISSING from the canonical-callee oracle**
that `cast_call_sites`/`sig_unify` resolve against. This is why the wave's byte-exact cores would not bank:
the draft kept its guessed sig, hit `conflicting types`, and the "recovery" pass reported nothing to fix.
**Fixing it turned `func_8015A3C8` from 28-conflicts-unbankable into BANKED BYTE-IDENTICAL with zero hand
edits.** (`commit:0561`)
5. `jtbl_family_bank.revert()` didn't restore the splat config → an isolation's residue rode into a commit as
a DUPLICATE code-subseg line (harmless to splat, so R22 stayed green) → the NEXT isolation walked the
object twice → "segments out of order". Now reverts the config + `jr_isolate_all` FAILS LOUD on a
non-ascending/duplicate subseg list.
6. `jr_isolate_all` emitted an EMPTY region 0 when the object's first item IS the first cut (cutting a
non-leader out of an already-isolated region) → duplicate config line.
> **Standing rule (cookbook §40): a tool that silently no-ops on input it cannot parse is indistinguishable
> from a tool that had nothing to do. Prefer fail-loud on unparsed input, and regression-gate any change to a
> "proven" text scanner by snapshotting its output over the whole corpus before/after.**
### NEW TOOLING + KNOWLEDGE (all committed)
- `tools/scope_data_externs.py` (§8d) · `tools/bank_exemplar.py` (bank a cracked exemplar ×1 through the same
stage ladder) · `jtbl_family_bank --raw` (template from the RAW crack — REQUIRED when the exemplar banked at
the `reconciled` stage, since a reconciled body is TU-specific; byte-proven: D40 banked reconciled → sweep
0/4 until `--raw`, then 132/132).
- **Cookbook §46** (four LOOP-STRUCTURE levers: the PEEL rule — a `break` must never land on the loop's own
fall-through label; the surviving-copy EBB rule; the merged store; the non-replaceable giv).
**§47** (the LIVE-LENGTH SLIDER: measure `pri = int(floor_log2(n)·n/L·10000)` in the `.lreg`/`.greg` dumps;
a zero-byte `asm("")` between two existing volatile asms shifts L by +1 and splits an allocno tie — and the
split direction is FORCED toward the target). **§48** (the allocno-PRICING dials: sink-the-init-into-the-arms;
the local-alloc `$s0` occupant; per-case temps as a tie gate. The EBB rule generalized. The C type selects
the addressing mode. The cross-jump RATCHET.)
### ▶ NEXT — IN ORDER (Drew's directive: the AUDIT comes first)
**0. [FIRST — Drew's call] The Tier-1 phase-boundary decision** (see the top of this file), then the
**TOOLING-INTEGRITY AUDIT** in plan mode, Max.
**▶ Plan it FROM `docs/tooling-audit.md`** — 40 measured findings, the method, the priority order, the
already-fixed list, and the not-yet-audited list are all in there. Do not re-derive them.
Order: **`dedup_integrate.py` FIRST** (a fail-closed validator that can print a FALSE GREEN) →
`jtbl_family_bank` → the SELECTION tools (`family_hseq`/`wave_targets`/`exemplar_miner` — a hole there
makes work invisible to *planning*) → `masked_diff`/`match_one` → the 40 findings by severity.
**Apply R33 to each BEFORE R32:** *why is this tool re-deriving something the build already guarantees?*
The best outcome is a **deleted scanner**, not a fixed regex.
**Then re-test the walls diagnosed on top of the broken oracle** (the real prize): the def-side loose-typing
wall (§20/§41), the 159 arity/narrow-param conflicts, the 3,098 type-heavy tail, the 9 zero-bank type-using
families. Some of that "intrinsic wall" may have been lookup misses all along.
**1. [THEN — the cheapest matching work on the board] The CONSOLIDATED INTEGRATION FIX PASS.**
**Nine byte-exact cracks; six cannot bank — for PLUMBING, not matching (~1.2 MB sitting behind it).**
Four distinct fixes, all identified, one already built:
- **`tools/reconcile_tu.py` — WRITTEN + VALIDATED, NOT YET WIRED IN.** Replaces `reconcile_decls`' oracle.
That tool asks *"what does the FLEET call this symbol"*; the only question that matters is **"what can THIS
TU SEE"** — 34.4% of fleet symbols carry ≥2 mutually incompatible spellings, so one fleet-wide answer is
**provably wrong for some TU by construction** (and it returns ACTIVELY WRONG decls for 3,717 symbols).
`reconcile_tu` reconstructs the TU's visible file-scope environment from BOTH §8c sources (col-0 decls AND
`engine_core.h` macro-injected externs — 544 visible syms from 1801 macros) and parses the **fn-ptr forms
`reconcile_decls` is structurally blind to**. Validated on `func_8017A4AC`: resolves `D_801DA75C` (fn-ptr),
`D_80126B58` (struct), `D_801DA734` (ptr). **Wire into `bank_exemplar.py` + `jtbl_family_bank.py` as a
stage, byte-gate it.** Unblocks `func_8017A4AC` (287 KB), `func_8013F350`, `func_80131340`.
- **Strip scalar typedefs** from the draft before splicing (`match_one` does this via
`masked_diff.SCALAR_TYPEDEF_RE`; the BANK path does not) → `redefinition of 's16'`. Unblocks `func_8015C32C`.
- **`canon_sig_reconcile` is not K&R-aware** — raises `no definition found in draft`, so the def-side (§41)
conflict never gets a recovery attempt. Unblocks `func_8015B950`.
- **`func_80159C84`**: carve STILL non-contiguous after isolation (0xb09a4 / 0xb09c4) — a real edge case where
a region ends up hosting two carves with an unmatched jtbl between them.
⚠ **`func_8013F350` is NOT a plumbing bug — it is a real class.** Its `D_8011511C` must be **struct**-typed to
force `la`+offset (§48-C1): the type IS the code. The TU declares it `u16` at file scope, and **no cast fixes
it** (the cast folds back to `lui/%lo`). It needs an EBB-separated pointer re-crack (§48-B) or a fleet decl
migration.
**2. Re-run the 780 h_seq rejections against the REPAIRED callee oracle** (`commit:0561`) — large mechanical
recovery expected for ~0 agent tokens.
**3. The next crack wave** — 32 unmatched heavy-jr ov077 cores remain (`.run/wave_targets.json`, ranked, with
per-core asm subdirs). Plus **32 PINNED families (1.09 MB)** needing pin-free re-cracks — the toolkit is
pin-free by construction now. Recipe = the 12-core wave: §31/§46/§47/§48/§49 in the prompt + an adversarial
verifier + the mandatory §8a jump-table check.
**4. `func_8017BEBC`'s ×113 sweep** (IMM-class, scattered addrs → the immediate engine, not the PURE path).
**5. `func_80135EB0`** — the one documented wall (§50-F): needs a lever that injects a **reload-deleted no-op reg
copy** inside `[lhu 4($a2) … sh %lo(D_801152AC)]`. That is the entire remaining delta.
---
## ▶ SESSION-8 (earlier) — the ×133 sweep blocker
**THE ×133 SWEEP BLOCKER IS FIXED. `func_8015AE2C` (562 ins) BANKED ×134 — 133/133 siblings, 0 failures.**
**R22 clean-fleet 136/136 GREEN** (from `make clean`, 534 changed src files). dedup-check 1813 validated / 0 failed.
**Metrics: instr-weighted 63.0 → 63.6% · distinct-code 39.1 → 40.5% (+256 unique fns / +79,957 ins) · fn-count 82.31%.**
One core × 133 siblings = **+0.6% instr-weighted for ~0 agent tokens.** Tree clean, all work committed.
### The fix — §8d, `tools/scope_data_externs.py` (the session-7 diagnosis was HALF RIGHT — R14)
Session 7 blamed `reconcile_decls`' fleet-majority oracle and planned to teach it a TU-visible one. Reproducing
one sibling by hand (rather than trusting the handoff) gave a sharper picture and a **smaller, safer fix**:
- **The isolated region builds `[ OK ] ` WITHOUT the body** → §8b isolation was never implicated. The templated
body is the sole cause.
- `family_remap.gather_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**. The carried
file-scope decl **establishes a global the TU never had** → every later block-scope `extern` must now agree
with it → `conflicting types`. Byte-proven asymmetry:
`BLOCK(int) → BLOCK(struct*) → FILE(void*)` **builds**; `FILE(void*) → BLOCK(int)` **errors**.
- It was the **ONLY** hard error in the build. All 27 carried *function* externs were fine raw —
`cast_call_sites` was not needed at all (session 7 thought it was doing the heavy lifting).
- **FIX: demote, don't reconcile.** Emit a carried `D_` extern at **block scope inside the function body** when
the TU has no file-scope decl of it above the insertion point. Byte-neutral (an `extern` emits no code; type +
access opcodes unchanged), **never worse than raw** ⇒ needs no oracle, no type comparator, no fn-ptr parser.
It also *restores fidelity* — the original declares these symbols at block scope in exactly this way.
Wired as the `scoped` stage: **raw → scoped → recovered → reconciled** (and `scoped` is the base for the
later recovery stages). Cookbook **§8d** + decision-log + SETUP row (R30/R31/R21).
- **`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 *);`, so it silently skipped the very symbols that were failing. (This is the
"reconcile fn-ptr-extern gap" logged 2026-07-12 — filed as a small separate lever, it *was* the blocker.)
- **The R17 triage rule (committed `commit:0550`) paid off immediately:** `conflicting types` = the compiler
REFUSED TO COMPILE = a C front-end diagnostic = **our Python**. Reading `cse.c`/`global.c` would have taught
nothing. ("Wrong BYTES" → read gcc; "won't COMPILE" → read our tooling.)
- **Diagnostics gotcha:** gcc-2.7.2 does **not** prefix errors with `error:` — grepping a build log for `error`
finds only make's `Error 33`. Grep the diagnostic text (`conflicting types` / `undeclared` / `parse error`).
### NEXT (priority order — byte-weight first; top-20 jr cores = 4.12M of the 5.53M templatable bytes)
1. **`func_80178D40` (890 × 134 = 477K bytes — THE heaviest core).** Crack in hand at
`.run/phase26-cracks/func_80178D40.c`, **close=39, ALL 39 inside ONE case body (0x5C)**; every other case is
byte-exact. The 4 residuals are named in the file header (cross-jump merge of `D_801DAB2C = 3`; `$v0→$v1`
copy; loop2 keeping old q in `$v1`; gcc **peeling loop3's first iteration** where the original doesn't —
`loop.c`). All §31-map classes ⇒ **cheap-Opus + permuter, NO Fable5**. Exemplar = ov_SC01_077, PURE
per-location ⇒ straight `jtbl_family_bank` sweep once closed.
2. **`func_8017BEBC` (952 × 113 = 430K bytes) — close=2. THE genuine R17/Fable5 target (R27: PROMPT DREW).**
Two `addiu`s TRANSPOSED in the loop preheader; registers already correct. Allocation order and preheader
emission order are **coupled** (both follow creation/LUID order) but the target needs them to DIFFER:
allocation (sz0, sz2, sz1) with emission (sz0, sz1, sz2). Permuter cannot reach it (not statement-permutable;
ran 25 min, no close). Agent localized it to `global.c`'s allocno-priority **TIE** and named the move: a §45-B
**gdb-on-cc1 read of `allocno_live_length`** (the original's length quantization plausibly split the tie),
then hunt a byte-neutral L-shifter that survives cse. Full spec: `.run/phase26-cracks/func_8017BEBC.md`.
⚠ **Exemplar is `ov_SC01_000` (NOT ov077), class IMM, addr_tag scattered** → its sweep runs from ov_SC01_000
through the immediate engine, not the plain PURE template path.
3. **The rest of the 191 substantial jr cores** (5.53M templatable bytes). Next by weight: `func_8017A4AC`
(536×134), `func_8015A3C8` (493×134), `func_8013F350` (490×134), `func_801380E0` (438×134) — all ov077 PURE
per-location. Recipe = the session-7 five-step (unchanged) + the new `scoped` stage.
4. **Re-check for cracked-but-unswept jr cores** whose ×N sweeps never ran because of this blocker — use
`family_remap.extract_unit` as the definition oracle, **not** a hand-rolled regex (mine false-matched
`extern` lines — R14).
### Banking a heavy jr core — the FULL recipe (unchanged from session 7, + the `scoped` stage)
1. `jr_isolate_all --only <core>` (also cuts every already-banked jr in the same object — one `.rodata` carve
per region). 2. `jtbl_carve --func <core>` (trims trailing `.align` pad — §8a-pad). 3. If an `engine_core.h`
thunk calls the core with **zero args**, the def must be **K&R** and the thunk's extern must drop `(void)` →
`()`. 4. Gate stages: **raw → scoped (§8d) → recovered (`cast_call_sites`+`reconcile_decls`) → reconciled**.
5. Whole-binary gate → `jtbl_family_bank` ×N → R22 → commit. **Commit each family before sweeping the next**
(the per-sibling revert restores from HEAD).
---
## ▶ SESSION-7 CHECKPOINT (2026-07-13, cont.) — superseded by SESSION-8 above
**Heavy-jr crack waves RUN (Drew approved top-3 + distill). 1 core BANKED, 2 cracks in hand. R22 136/136 GREEN,
tree clean, all work committed.** The §8b wall stayed broken throughout.
### The three Fable5 cracks (all PIN-FREE, all independently re-verified against the bytes — R14)
| Core | Size × reach | Result | State |
|---|---|---|---|
| `func_8015AE2C` | 562 × **134** | **MATCH 562/562** | **Exemplar BANKED** (`commit:0547`, `d19c9580`, R22 green). ×133 sweep **BLOCKED** — see below |
| `func_80178D40` | 890 × **134** | **close=39/890** — 851 exact; **all 39 in ONE case body (0x5C)** | crack at `.run/phase26-cracks/func_80178D40.c`; 4 named residuals in a 44-ins block, agent calls it permuter-tractable |
| `func_8017BEBC` | 952 × **113** | **close=2/952** — two `addiu` TRANSPOSED, same registers (pure emission order) | crack at `.run/phase26-cracks/func_8017BEBC.c`; **permuter ran 25 min, did NOT close it** |
### ⛔ THE ONE BLOCKER — the `func_8015AE2C` ×133 sweep (precisely diagnosed, NOT yet fixed)
The remapped sibling body's **DATA externs conflict with the sibling's §8b carried decl layer**
(`conflicting types for D_801812A4`; the layer's decl is the "previous declaration"). `reconcile_decls`
resolves against a **fleet-majority canonical oracle**, not against the TU's *actually-visible* decl, so it
picks a type that still conflicts. **Fix direction:** reconcile the body's externs against the TU's carried
layer (which is authoritative — it reproduces the original TU's decl environment), or drop body externs the
layer already provides and cast at use. `cast_call_sites` already fixes the *function*-callee half (27
callees); only the ~4 DATA symbols remain. Everything else in the sweep works (isolate → carve → remap →
gate). **Bank flow now has 3 stages: raw → recovered (per-sibling cast+reconcile) → reconciled.**
### Banking a heavy jr core — the FULL recipe (all byte-proven this session)
1. `jr_isolate_all --only <core>` — now **also cuts every already-banked jr in the same object** (a region may
host at most ONE `.rodata` carve; an object's `.rodata` is a single contiguous section).
2. `jtbl_carve --func <core>` — now **trims trailing `.align` pad words** (§8a-pad).
3. If an `engine_core.h` thunk calls the core with **zero args**, the def must be **K&R/unprototyped** and the
thunk's extern must drop `(void)` → `()` (byte-neutral fleet-wide; R22-verified for func_8015AE2C).
4. Recovery: `cast_call_sites` (callees) + `reconcile_decls` (data) against the **isolated region TU**.
5. Whole-binary gate → `jtbl_family_bank` ×N → R22 → commit.
### Six tool bugs found + fixed this session (each silently corrupts and each is committed)
`canon_sig_reconcile` void→s32 not byte-neutral (§41d) · `extract_unit` swallowing the §8b decl layer ·
`jtbl_family_bank` cross-address naming · `jtbl_carve.func_subseg` reading the stale asm tree ·
`jtbl_carve/revert` deleting the committed `overlays.mk` carve var · `jr_isolate_all` `--only` erasing the
banked set + carve-ownership read from a `.s` splat never emits for matched fns + **one region hosting two
carves** · `p16_permute` `hide_asm` eating GTE `#define`s (permuter silently no-op'd `0s` on ALL renderer
drafts) + hardcoded to one overlay.
### NEXT (in priority order) — with the R17 routing call (Drew asked, 2026-07-13)
> **Do NOT read the gcc-2.7.2 source for the sweep blocker.** R17 (read the compiler internals) is for
> **codegen** residuals — regalloc / scheduling / cross-jump / CSE — i.e. things no C change reaches. The
> sweep blocker is a **C FRONT-END diagnostic** (`conflicting types`: two incompatible file-scope decls of one
> identifier in one TU). gcc is correctly rejecting plain C89; the bug is in OUR Python (`reconcile_decls`
> picks a fleet-majority type instead of the type the TU can actually SEE). Reading `cse.c`/`loop.c`/`global.c`
> would tell you nothing. **Triage rule: "the compiler produced the wrong BYTES" → R17. "the compiler refused
> to COMPILE" → our tooling.**
1. **Unblock the ×133 sweep** (above) → banks 562×133 ≈ 75K templatable ins. Highest ROI, well-diagnosed.
**Python fix, NOT a gcc read.**
2. **`func_8017BEBC` close=2** (×113) — **THIS is where the gcc-source read belongs.** The permuter failed
(25 min, no close). The agent localized it to `global.c`'s allocno-priority TIE and named the exact move: a
§45-B **gdb-on-cc1 read of `allocno_live_length`** (the original's length quantization plausibly split the
tie). Two instructions from a 107K-ins bank — the best R17 target in the queue.
3. **`func_80178D40` close=39** (×134) — all 39 in case 0x5C; agent named 4 concrete residuals (incl. gcc
peeling a loop iteration the original doesn't → likely `loop.c`). Cheap-Opus/permuter first, R17 if it walls.
4. Then the rest of the 191 heavy jr cores. **R27: prompt Drew before any further Fable5.**
---
## ▶ SESSION-6 CHECKPOINT (2026-07-13) — superseded by SESSION-7 above
**THE §8b SCOPING WALL IS BROKEN. Heavy-jr harvest is UNBLOCKED. Effort: Max.**
Full 54-jr isolate-all on ov_SC01_077 → `d19c9580` **byte-identical**; **R22 clean-fleet 136/136**.
All tools committed. Baseline clean (no config/src changes).
**What session 6 delivered (committed):**
1. **Declaration-environment reconstruction** (`overlay_src_split.py` + `jr_isolate_all.py`) — the fix. Session-5's
"gcc block-scope-extern TU-persistence" diagnosis was **WRONG (R14)**: `DEFINE_func_*` macros expand at FILE
scope, so their leading externs are genuine file-scope decls that merely live in `engine_core.h` — invisible to
any col-0 text scan. **Four** decl sources must be carried forward, and the byte-gate found three of them:
(1) col-0 decls · (2) macro leading externs (1,377 macros / 3,929 lines / 1,462 syms) → `D_80126B3E undeclared`
· (3) **a definition is itself a declaration** for everything below it → `func_8012B2CC undeclared`
· (4) file-local typedefs used by a carried proto → `parse error before '*'` (`Vec3s`).
**Rejected the approved "global symbol→type map + shadow set" design** — it would hoist loose-typing block-scope
shadows to file scope and *create* the conflict the shadow-set then dodges. Faithful forward-carry is
conflict-free by construction (see cookbook §8c + decision-log 2026-07-13).
2. **LAZY per-core isolation wired** (`jtbl_family_bank`): `jtbl_carve` NON-CONTIGUOUS fail-loud →
`jr_isolate_all --only <core>` → re-extract → re-carve. Proven on **`func_80178D40` (890×134, the heaviest
core)**: carve blocked → isolated (byte-neutral `d19c9580`) → carve lands in its own subseg.
3. **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 collision (now derived from the config); and the sweep's `revert()`
**deleted** the shared `overlays.mk` carve var unconditionally → would have destroyed a *committed* carve (all
134 overlays have one) on any failed sibling (now restored to its committed value). `jtbl_family_bank` also now
refuses to start on a dirty `config/`+`src/` — **commit each family before sweeping the next.**
**DE-RISK COMPLETE (Drew's call, session 6): `func_80182268` cracked + banked ×3 (the whole family) through the
LAZY path — the composition is proven end-to-end.** Cracked first try (31-ins jr: shared-tail fallthrough where
jtbl cases 3+7 enter case 4's tail, + the `(s8)(*(u16*)(p+0x70) >> 8)` sign-extend idiom). Its carve collided
with the committed `func_801734BC` carve → lazy isolation fired → carve into its own subseg → whole-binary gate
`d19c9580`. Siblings `ov_SC02_000`/`ov_SC02_003` (**cross-address**, @0x8017FCB0) banked via `jtbl_family_bank`.
**The de-risk paid for itself — it exposed 3 more bugs that would each have silently capped the heavy sweeps:**
1. **`canon_sig_reconcile`'s `void`→`s32` return promotion is NOT byte-neutral** (cookbook **§41d**, R14): for a
void body with no `return` it costs ONE instruction. It turned a perfect 31-ins MATCH into 32 → the extra word
made the isolated object's `.text` 4 B long → **every data symbol shifted +4** (~271k differing bytes).
`match_one` said MATCH; only the whole-binary gate caught it. **Fix (generalizes §19): every recovery pass is a
FALLBACK — `jtbl_family_bank` now gates RAW first, reconciled only on failure.**
2. **`extract_unit` swallowed the §8b carried decl layer** (it walks backward absorbing extern/comment lines, and
the layer sits above a region's first item) → the template dragged ~140 unrelated externs into every sibling →
gate-fail. Fixed with an explicit end-marker + a stop in `extract_unit` (also guards the Phase-17 canon layer).
3. **`jtbl_family_bank` used the EXEMPLAR's name for the sibling's carve/isolate/stub** → cross-address families
never resolved. Now derived from `to_addr`. (The first two banked jr families were same-address, so it hid.)
**Backlogged:** `func_801549F8` (31-ins jr, **reach ×134** — the other cheap ×134 target) is a genuine **§31
loop-IV / strength-reduction** residual: the target does NOT strength-reduce (recomputes `script+(i<<2)` each
iteration), but plain `arr[i]` with constant per-branch increments makes gcc build a pointer GIV. A variable-stride
`step` defeats biv recognition and gives the correct address shape (**17/31**, seed at
`.run/backlog_drafts/func_801549F8.seed.c`) but gcc then keeps `step` in a register instead of folding K into each
branch's `addiu`. Needs the C shape that keeps CONSTANT per-branch increments yet fails the giv worth-while test
(`loop.md` L1). Permuter/Fable5 class — do NOT hand-grind it.
**NEXT (R27 BOUNDARY — prompt Drew before launching):** Task 7 = the **heavy-jr core crack waves**. The 191 jr
family cores / 5.53M templatable ins are now bankable. Per core: Fable5 crack (**whole-binary gate — NOT plain
rtu_match**, jr false-match risk §8a) → lazy isolate → `jtbl_carve` → `jtbl_family_bank` ×134 → parallel R22 →
commit. Targets by byte-weight: `func_80178D40` (890×134 = 477K ins, isolation already proven), `func_8017BEBC`
(952×113), `func_8015AE2C` (562×134), `func_8017A4AC` (536), `func_8015A3C8` (493). Fable5 window now **7/19**.
Optional cheap de-risk first: the 45 small jr families (~129K ins, no Fable5) to exercise the full lazy bank
end-to-end (isolate→carve→remap→reconcile→**gate**) on a cheap target — its composition is proven in parts but the
end-to-end bank with a cracked body gates at the first real core. Ghidra MCP NOT needed (matching uses cached asm).
---
## ▶ SESSION-5 CHECKPOINT (2026-07-13) — superseded by SESSION-6 above
**Stage-2 isolation build — parser DONE + single-cut PROVEN; full isolate-all hit the gcc-2.7.2 scoping wall. Effort: Max. Drew's decision (2026-07-13, Fable5 window extended to 7/19 so no time pressure): BUILD declaration-completion + apply isolation LAZILY per-core (not upfront-×134 — avoids the ~7,200-file cost; same tool, isolate only cores that crack). Tools committed this session.**
Built this session (baseline reverted + intact — ov_SC01_077 rebuilds `d19c9580`; only the 2 new tools are untracked, NOT yet committed):
1. **`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). **VALIDATED fleet-wide: 404/404 overlay `.c`, 341,902 items — round-trip exact / 0 unresolved / 0 non-monotonic.** This is solid, reusable, commit-worthy.
2. **`tools/jr_isolate_all.py`** — multi-cut resegment (config split at every jr boundary, source repartition + INCLUDE_ASM path repoint, banked-jr carve repoint via config + `overlays.mk --order`, -O0-object skip, ambient file-scope decl carry). **SINGLE-cut isolation BYTE-IDENTICAL** (func_8013FFD8 in `main` → clean `make build` = `d19c9580`, R22). Full 54-jr isolation on the dense `_after` object hit the wall.
**THE WALL (byte-verified, decision-log 2026-07-13):** mechanical TU-splitting breaks gcc-2.7.2's **block-scope-extern TU-persistence** — `func_801734BC` uses `D_80126B3E`, declared `extern s16` ONLY inside `DEFINE_func` macros in `engine_core.h`; the original `_after.c` compiles because an earlier macro's block-scope `extern` persists to file scope for the whole TU. Splitting separates the core from that macro → `undeclared`. (7 distinct C-scoping edge cases surfaced + fixed incrementally; this last one is the deep one — col-0 ambient-carry can't reach macro-injected decls.)
**THE FIX TO BUILD (Drew-approved, fresh session):** **declaration-completion** — build a global symbol→type map from `engine_core.h` macro `extern`s (the `DEFINE_func`/`SETTER`/`RETCONST` bodies) + all overlay col-0 decls; then for each isolated region emit a file-scope `extern <type> <sym>;` for every `D_`/`func_` symbol the region USES, EXCLUDING the type-shadowed set (symbols with inconsistent decls across the codebase, e.g. `D_80115118` = `unsigned short` vs struct `S115118` — kept block-scope in bodies). This makes every region self-contained regardless of where the original declared the symbol (col-0, block-scope body, or macro). Est. ~40–60 LOC on the proven `overlay_src_split.py`; the whole-binary byte-gate (G3/P9/R22) arbitrates. Wire it into `jr_isolate_all._render_region` REPLACING the col-0-only ambient carry (which can't reach macro-injected decls).
**NEXT (fresh session):** (1) build declaration-completion (above); (2) re-prove full isolate-all byte-identical on ov_SC01_077; (3) switch isolation to LAZY per-core — integrate a single-core isolate into the bank flow (`jtbl_family_bank`), isolating a heavy jr core only when banking it (fewer files than upfront-×134); (4) then the heavy-jr-core crack waves — Fable5 (window now to 7/19) → §8 carve + template ×134 → R22. Committed tools this session: `tools/overlay_src_split.py`, `tools/jr_isolate_all.py`. Ghidra MCP NOT needed (matching uses cached asm). **R27 boundary: prompt Drew to re-confirm effort/Fable5 before the crack waves.**
---
## ▶ SESSION-4 CHECKPOINT (2026-07-12 later) — superseded by SESSION-5 above
**Stage 1 in progress — multi-jtbl `--order` BUILT + proven cross-subseg at fleet scale.** Effort: Max (this session, Tier-1 tooling build).
### What session 4 delivered so far (committed + R22 136/136)
1. **`ld_interleave.py --order`** — address-ordered N-piece multi-jtbl sandwich (text → [data|.rodata carves, address-ordered] → bss). Legacy `--front/--tail` path byte-untouched (main + the 133 single-carve siblings unaffected). Empty code-object sections parked byte-neutrally with .text.
2. **`jtbl_carve.py` rewritten additive/regenerate-from-config** — parses the current tail data-region + existing `.rodata` carves, adds the new fn's jtbl (splitting its containing data piece), re-emits the address-ordered pieces + the `--order` interleave arg. Same-subseg collision → fails loud (→ isolation). Idempotent.
3. **`jtbl_family_bank.py` fix** — `bank()` now `make extract`s BEFORE the carve (so the sibling asm matches the reverted committed config; the old error-string retry was fragile). Revert-on-carve-fail.
4. **Family-1 banked: `func_801734BC` (34-ins PURE jr, in ov_SC01_077_after) ×134** — matched in ov077 (shared-tail switch: `case N: t=-N; break; default: goto after;`), banked 133/133 siblings, **R22 136/136 clean-fleet byte-identical**. This is a CROSS-subseg multi-jtbl (func_8012ACE0 in `_a` + func_801734BC in `_after`) — the checkpoint's primary Stage-1 goal, proven fleet-wide.
### The same-subseg cases — TWO flavors (both surfaced this session; the de-risk paid off)
Two matched jr-fns in ONE code object emit their jtbls CONTIGUOUS (gcc source order). So:
- **(a) CONTIGUOUS jtbls (adjacent in the island) → MERGE.** `jtbl_carve` now merges adjacent same-subseg carves into one spanning `.rodata` piece (+ a **bound-fix**: a new jtbl's end is bounded by the next raw dlabel OR the next existing carve start — an already-carved adjacent jtbl is gone from the data asm, so raw dlabels alone over-extend it → false "non-contiguous"). **BUILT + config-proven** (func_80171B4C `jtbl_801D8C48` merges with func_801734BC `jtbl_801D8C68` → one `_after` carve `[0xb0af0..]`). **Byte-proof PENDING** a matched adjacent pair — func_80171B4C is struct-heavy (m2c gives `arg0->unkXX` + ratan2 + 8-case switch), a real match, not a quick de-risk. NO-OP for family-1/cross-subseg (single carve per subseg) — committed configs unaffected (verified by reasoning: R22 rebuilds static configs; jtbl_carve only runs on new carves).
- **(b) NON-CONTIGUOUS jtbls (unmatched jtbl between) → ISOLATE** one fn into its own code subseg (whale `_o0b` precedent). `tools/jr_isolate.py` written (config split + `func_subseg`-derived carve, no rename bookkeeping; isolating F preserves carves BELOW F, so bank ascending). **BLOCKED — the real finding:** `split_src_region` can't partition the overlay `.c` — it has 922 non-address top-level items (the Phase-17 global canonical-sig extern layer + per-function callee-extern blocks + `DEFINE_func_X()` dedup macros + `// @class` annotations). Making it overlay-`.c`-aware (header = includes+global-extern-layer; attach leading externs to the following fn-block) is the **Stage-2 build item**.
### ⚠ Stage-2 unblock decision (Drew's call): isolation is a HARD Stage-2 prerequisite
Because func_801734BC is now committed in `_after` of every sibling, banking any heavy core (also `_after`, non-adjacent) hits case (b) → needs isolation. Options: **(i)** fix `split_src_region` for the overlay `.c` + finish jr_isolate (robust, needed regardless — Stage-2 has many `_after` cores → same-subseg even without func_801734BC); **(ii)** a one-time "isolate-ALL-jr-per-sibling" resegment (scalable: ~134 resegments then fast fills, vs per-fn ×134 splits) — likely the right Stage-2 architecture. Also open: byte-proof the MERGE with a matched adjacent pair.
### NEXT: **pivot to Stage 2** (this is an R27 effort/model boundary — prompt Drew to re-approve + toggle). Stage 2 = the heavy 191 jr cores (Fable5 crack-core → template ×134), which first requires the isolation build-out (option i/ii above). Cross-subseg multi-jtbl (the primary Stage-1 goal) is DONE + committed + R22 136/136.
---
## ▶ SESSION-3 CHECKPOINT (2026-07-12 late) — superseded by SESSION-4 above
**Committed baseline = `commit:0534`, R22 136/136 (now ~50s, parallel).** Session-3 commits: `commit:0531` (tiny-band), `commit:0532` (§8 PoC), `commit:0533` (§8 ×134 automation), `commit:0534` (R22 parallelization). Phase-26 total: **distinct-code 30.3→39.1%, instr-weighted 58.2→63.0%.**
### What session 3 delivered (all committed, R22 136/136)
1. **Tiny-band harvest** — 17,975 member-matches; distinct 35.2→39.1%.
2. **§8 jtbl-rodata tooling (the strategic unlock)** — overlay switch (jr) functions can now bank as C for the first time. `tools/jtbl_carve.py` (per-overlay jtbl-rodata carve) + `ld_interleave.py --section` + `<bin>_JTBL_INTERLEAVE` Makefile hook; cookbook **§8a** + SETUP. Reconcile-per-sibling + `extract_unit` now carries single-line typedefs. `tools/jtbl_family_bank.py` = the sibling sweep driver. **func_8012ACE0 banked ×133/133, 0 fail.**
3. **R22 parallelized** — `make clean && make extract-all && make check-all` = ~50s (was ~9m), 136/136 byte-identical. `JOBS ?= 16`.
### ⚠ THE STRATEGIC REFRAME (decision-log 2026-07-12, Drew's steer) — READ BEFORE PICKING THE NEXT TARGET
§8 did NOT just unblock a small mop-up — it unblocked the **single heaviest byte-weight chunk of the game**. Measured (`.run/family_hseq.json`): **9 of the 10 heaviest unmatched family cores are switch (jr) functions** (`func_80178D40` 890×134 = 477K ins, `func_8017BEBC` 952×113, `func_8015AE2C` 562×134, `func_8017A4AC` 536, `func_8015A3C8` 493 …); **jr substantial = 191 fams / 5.53M templatable ins**; the 45 small jr families I first eyed = only 129K ins (a light-tail trap Drew caught). **The endgame plan = heaviest-byte-weight-first via crack-core → template ×134; §8 is its key enabler.**
### ▶ THE CORRECTED NEXT PLAY (fresh session) — small-jr-first as a DE-RISK PREAMBLE, then the heavy 191 (Drew's sequencing, 2026-07-12; agreed)
**Stage 1 — the 45 small jr families (mid/tiny, 129K ins) FIRST, as a pipeline-hardening preamble (NOT for byte-weight — it's ~+1% instr; the point is de-risk).** The decisive technical reason: `jtbl_carve` today only does the **single-jtbl-per-overlay** carve — but func_8012ACE0 is now matched in all 133 siblings, so the *next* jr family makes those overlays **multi-jtbl** → **BUILD the `ld_interleave --order` (address-ordered) multi-jtbl carve HERE**, on cheap targets, before a Fable5 giant depends on it. Also validates variety (IMM vs PURE, per-overlay jtbl positions, stubborn exemplars) where a bug costs a 30-ins fn, not a 890-ins core; and needs NO Fable5 (progress now, no session-limit burn). Pipeline: match each small exemplar (m2c + reconcile; func_8012ACE0 had a ready §41b draft — check which of the other 44 m2c cleanly) → `jtbl_family_bank.py` ×~120 → parallel R22. **Do NOT let "45 done, feels productive" become grinding more light tail — pivot to Stage 2 once the pipeline is hardened + multi-jtbl proven.**
**Stage 2 — the heavy 191 jr family cores (5.53M ins — THE byte-weight objective).** `func_80178D40` (890×134 = 477K ins), `func_8017BEBC` (952×113), `func_8015AE2C` (562×134)… **Needs Task 7 (Fable5) UN-PAUSED** (§8 makes it worth it now — a jtbl core crack banks fleet-wide, not unbankable fuel). Per core: Fable5 crack (whole-binary-gate-verified, NOT plain rtu_match — jr false-match risk, §8a) → `jtbl_carve` (now multi-jtbl-capable from Stage 1) + `jtbl_family_bank.py` ×134 → parallel R22. Cheap-Opus applies banked §31/§45 idioms between Fable5 cracks. Non-jr substantial families (7.3M ins) — heavy too; mechanical ones via `family_sweep`, hard cores via Fable5.
### Effort/model (fresh session): plan-mode Max for the Phase-Start re-plan; then **prompt Drew to re-approve + `/effort` for Fable5** (Agent model:fable, parallel-isolated, whole-binary gate) on the heavy cores; Ultracode for the mechanical ×134 template waves; Max for synthesis. Ghidra MCP NOT needed (matching uses cached asm).
---
## SESSION-2 CHECKPOINT (2026-07-12) — superseded by SESSION-3 above
**Phase 26 status:** Tasks 0–6 DONE + committed (the h_seq engine + triage). Task 7 (Fable5) + Task 8 (mechanical harvest) IN PROGRESS. **Committed baseline = `commit:0528`, R22 136/136 confirmed.** Commits this phase: `commit:0518`→`commit:0528`.
### What's banked (all committed + R22-verified through commit:0528)
- **729 reconcile-class member-matches**: 463 (`commit:0527`) + 266 (`commit:0528`), from **6 no-jtbl reconcile-clean triage cracks** templated ×~133 via `--reconcile-raw`. Metrics ≈ **31%+ distinct-code / 59%+ instr-weighted** (was 30.3/58.2 at phase start).
- **MID-BAND HARVEST DONE + committed + R22 136/136:** plain `--hseq --band mid` banked **6,853 member-matches = 320 distinct functions** (3,098 type-heavy tail / 1,743 pinned / 873 no-ov077-body — all expected). **Metrics: distinct-code 31.1→35.2%, instr-weighted 58.9→60.9%.**
- **TINY-BAND HARVEST DONE + R22 136/136 (session 3, 2026-07-12):** plain `--hseq --band tiny` banked **17,975 member-matches / 5,617 gate-rejected** (h_seq-collision false-templates, correctly refused by the whole-binary gate — the collision-prone <16-ins band) across **266 overlay `.c` files** (180 tiny families; skips 1,184 no-matched-unit / 148 unresolved-imm-Tier2 / 117 STRUCT / 39 pinned). R22 clean-fleet **136/136**. **Metrics: distinct-code 35.2→39.1%, instr-weighted 60.9→62.9%.** Phase-26 total so far: distinct 30.3→**39.1%**, instr 58.2→**62.9%**. **NEXT: the two harvest gaps** — §8 jtbl-rodata tooling (Drew-approved) + the reconcile fn-ptr-extern fix — then re-measure/milestone.
### The h_seq family engine (all committed, the durable tooling)
- `tools/family_hseq.py` — the survey → `.run/family_hseq.json` (regen after every bank) + `docs/family-hseq.md`. Bands: substantial(≥80)/mid(16–79)/tiny(<16).
- `tools/family_remap.py` — extended reloc tracker (addu-hi §40b), `classify_member` (PURE/IMM/STRUCT), `imm_map_tier1` (T2a), `remap_hseq` (plain template), **`remap_hseq_body`** (remap a RAW crack body — for reconcile-raw), `gather_externs`.
- `tools/family_sweep.py --hseq` — templates matched-exemplar families; `--reconcile-raw RAWDIR` = §41c per-sibling reconcile (remap the RAW crack per sibling + `canon_sig_reconcile` vs that sibling's TU); static pin guard (`__asm__("$N"` → skip). `--band`/`--only`/`--stage-only`/`--min-members`.
- Cracked-seed dirs: `.run/crack_raw/` (raw seeds, func_<ADDR>.c) + `.run/phase26-seeds/` (triage m2c seeds) + `.run/phase26-cracks/` (Fable5 crack bodies).
### The TWO harvest gaps (the levers for the remaining crack families) — see decision-log 2026-07-12
1. **§8 jtbl-rodata (Drew APPROVED building it, 2026-07-12).** Overlay jtbls live in the monolithic `data tail` (`asm/ov_*/data/tail.data.s`, e.g. `dlabel jtbl_801D8E24` ~line 92735 in ov077). Replacing a jr-function with C emits a duplicate jtbl → broken layout. FIX = carve each jtbl out of the data tail into a dotted `.rodata` subseg co-located with its function's code object (ov077 config `section_order:[.rodata,.text,.data,.bss]`; `ld_interleave.py` already wired, Makefile:397). **Per-overlay ×134** (each sibling's data tail). STAGE: prove on ONE jtbl fn in ov077 → automate ×134. Blocks all jr cracks incl. the top Fable5 cores (890/562/536…) and the 2 Fable5 crack bodies (`.run/phase26-cracks/func_80159C84.c`+`func_8015444C.c` — code-matched, jtbl-rodata unconfirmed; they bank once §8 exists).
2. **reconcile fn-ptr-extern gap.** `canon_sig_reconcile._reconcile_data` skips any extern containing `(` (fn-ptr syntax), AND `visible_above`/`tu_ambient` don't parse `void (*D_x[])(…)` → fn-ptr dispatch tables (D_801891B8) conflict → blocks ~15 of the 21 no-jtbl triage cracks. FIX = parse fn-ptr-array externs in all 3 fns (additive, but touches proven paths → regression-test the h_norm sweep). Smaller lever than mid/tiny.
### Fable5 findings (decision-log 2026-07-12) — Drew: NO more Fable5 agents until re-approval
- **rtu_match ≠ whole-binary gate for jr-functions:** rtu_match neutralizes INCLUDE_ASM (excludes the §8 jtbl rodata) + masks relocs → it MATCHES while the whole-binary gate FAILS. Batch-1 (`func_80159C84`/`8015444C`/`80176218`) = 0 whole-binary-confirmed cracks (2 jtbl false-MATCH, 1 limit-cut). **Fable5 crack prompts must require the whole-binary gate (or a jtbl-aware check), not plain rtu_match.** New idioms found (distill to cookbook when banked): postincrement pending-queue `(*(s32*)(p+K))++ >= N` (func_80159C84); split-temps inverse-§45-A for cross-jumped tails (func_8015444C).
- Usage/session limits repeatedly interrupt Fable5 (weekly + session limits, ~3:40am/5am resets).
### Triage (Task 6, committed) — `docs/phase26-triage.md` + `.run/phase26_triage.json`
119 draftable substantial families: cheap 29 (23 closeness-0 isolation-cracks) / permuter 29 / fable5 61. Whole-binary reality: 6 cheap no-jtbl-reconcile-clean bank; ~15 no-jtbl need the fn-ptr fix; 2 jtbl + the fable5 cores need §8. `.run/_rr_todo.txt` = the 19 not-yet-banked cracks.
### NEXT STEPS (priority order, all MECHANICAL — no Fable5)
1. ~~mid-harvest → R22 → commit~~ **DONE** (`commit:0530`). 2. ~~tiny band `--hseq --band tiny`~~ **DONE** (session 3, 17,975 banks, R22 136/136, distinct→39.1%). 3. **§8 jtbl tooling** (Drew-approved; ov077 PoC → automate) — the mechanical bands are now exhausted, so this + #4 are the remaining harvest levers. 4. **reconcile fn-ptr fix** → re-harvest the ~15 no-jtbl cracks (`.run/_rr19.sh` pattern). 5. **Task-5 type-families** (9 zero-bank substantial) via reconcile. 6. re-measure metrics; when gaps closed → milestone check.
### Effort/model: Max set (this session). Fresh session: re-apply `/effort max` for §8 design (Tier-1 tooling) or `/effort xhigh` for mechanical harvest runs. Ghidra MCP NOT needed (matching uses cached asm; run `/mcp` only if RE work resumes — R29).
## Milestone (gate 2 — structural completion, per Drew)
1. h_seq engine committed, V0–V3 validated with a measured template success rate.
2. Every substantial (nins≥80) family banked ×members OR classified with evidence.
3. Fable5-necessary cores attempted before window close; every crack distilled (R30/R31).
4. Carried 5-target queue resolved (cracked or wall-documented).
5. 136/136 byte-identical from clean fleet rebuild (R22); 0 NON_MATCHING (G4).
6. All three metrics reported + Step-D residue map.
Projections (targets, NOT gates): Task 5 ≈ +5.7% distinct-code; campaign → distinct 30.3%→~55–70%, instr-weighted 58.2%→~75–88%.
## Effort/model toggle map (R26/R27 — prompt + WAIT at every boundary)
On approval → `/model opus` + `/effort xHigh` (Tasks 0–4; ALL Fable5 via `Agent(model:fable)`). Task 5/6/8 waves → `/effort ultracode`. Task 7 launches + between-wave synthesis → `/effort max`. Task 12 → Max. Non-obvious debugging → Max.
## Blockers
*(none)*
## Log
- **2026-07-15 (session 13, A11 — DISTILL + CLOSE THE AUDIT (26-A COMPLETE); Max):** Closed the inserted
tool-hygiene half-phase. **Distillation (most captured live per R30/R21 during A1–A10; A11 synthesised the
close):** `docs/tooling-audit.md` transformed DIAGNOSIS → **AUDIT-CLOSE LEDGER** (A1–A10 outcomes table +
the payoff 66.5→68.6% instr + the remaining/handoff) and its "two rules" → **R32/R33/R34** written crisp for
P10 ratification at the Phase-26 PhaseEnd. `docs/decision-log.md` +A10 verdict (R31 — the broken tools WERE
the walls; the payoff was banked by the fixes; the closeness-0 residual is genuine; the real deliverable is
the 3 rules + the derived-oracle pattern). `docs/SETUP.md` +the A9d–A10 tool changes (R21). Cookbook **§51**
(silent-skip class + over-approximating-detector method + LAWS 1–8) verified complete; LAW 3 tagged **R34**.
**OBSERVABLES GREEN (P9):** final R22 clean-fleet `make clean`+extract-all+check-all = **136 passed, 0 failed
of 136 BYTE-IDENTICAL**; `make report` EXIT 0 — dedup **1840 validated / 0 failed**, C1 coverage
227211/227211 signed, `lint_symbol_refs` (A9c, now wired) passing; `make audit-corpus` 0 slices,
`make audit-cdecl` green. **This session (13) made ZERO src/config changes** — all tool/doc hygiene; the
A10 re-gate banked 0 (confirmed-real wall). Tree clean (only db.gbf R23 noise). **🔬 PHASE 26-A COMPLETE.**
**NEXT: resume Phase 26 at Task 7** (family-core crack waves) — a fresh session (Tier-1 R27 boundary:
Max/Ultracode + re-plan the Fable5 tier per the window). The handed-forward audit items (un-migrated cdecl
consumers; the #4 type-heavy harvest → Task 8) are recorded in the audit-close ledger.
- **2026-07-14 (session 13, A10 COMPLETE — the wall re-test verdict on all 5 walls; Ultracode/Max):**
**A10 SYNTHESIS — the audit's thesis is CONFIRMED, and the payoff was banked by the FIXES, not by re-gating
the residual.** Verdict per wall:
**① fuel/closeness-0 — CONFIRMED REAL.** Fleet-scale re-gate of all 958 closeness-0 backlog drafts = **0/958
bank** (135 binaries). Genuine whole-binary near-misses; `match_one closeness==0` overstates. The wall is real.
**② arity/narrow-param (Phase-15 "dead-end") — WAS TOOLING, dissolved.** A3c proved the `()` rule
order-dependent (cc1 doesn't enforce it); **13/18** Phase-15 arity fns already banked; 5 residual.
**③ def-side loose-typing (§20/§41, "triple-confirmed") — WAS PARTLY TOOLING, dissolved.** reconcile_tu (A3d,
retired the fleet-majority oracle) + A9a; **A9b banked func_8017A4AC ×134** — a many-phase "wall" that was our
oracle. Residual def-side conflicts are genuine (Phase-16 byte-proved real contradictions exist).
**④ type-heavy tail (3,098 + 9 zero-bank families) — the BLOCKING TOOL was broken (tooling); now UNBLOCKED,
harvest → Task 8.** A7 fixed `build_engine_types` (was dead on 81% of its corpus); confirmed it now RUNS +
is idempotent. But the 9 families' types (`Work8016`/`E4`/…) aren't lifted, and `family_sweep` doesn't wire
the type-lift (`remap_hseq` refuses STRUCT members) — so banking them (~1,200 members) is Task-8 INTEGRATION,
not a pure re-test. The wall's *cause* (tool couldn't run) is dissolved; the harvest is handed forward.
**⑤ 780 h_seq callee-oracle rejections — WAS TOOLING, dissolved.** A3h's post-fix `--hseq --band all` banked
**+2,675** members; the 16,049 residual failures are h_seq-collision false-templates the byte-gate correctly
refuses (real).
**BOTTOM LINE (P9):** the audit fixes dissolved the tooling-walls and BANKED the payoff (**A3f/g/h + A9a/b:
66.5→68.6% instr**); the re-tests CONFIRM the residual walls (closeness-0, genuine type contradictions) are
real; #4's type-harvest is unblocked and sequenced to Task 8. "A re-confirmed wall is as valuable as a
dissolved one" — A10 delivered both. **NEXT: A11 — distill + close the audit (R32/R33/R34 for ratification,
cookbook, decision-log, ledger, final R22), then resume Phase 26 at Task 7.**
- **2026-07-14 (session 13, A10 fan-out wave 1 — closeness-0 backlog re-test = WALL CONFIRMED REAL; Ultracode):**
Drew toggled `/effort ultracode`. **Definitive fleet-scale re-test of the "fuel exhausted"/closeness-0 wall
(#1):** re-gated all **958** open-stub backlog drafts with `closeness==0` (match_one says byte-exact,
gate-rejected before the A3e all-TU fix) through the FIXED `gate_stage --no-propagate` across **135 binaries**
in parallel (Pool-16, 63 min). **RESULT: banked=0, near=957, failed=71, 0 errors, tree clean (0 banks).**
**CONCLUSION (P9 — a re-confirmed wall is as valuable as a dissolved one):** the closeness-0 backlog is
**genuine whole-binary near-misses, NOT tooling misses.** `match_one closeness==0` (isolated, reloc-masked)
systematically OVERSTATES whole-binary bankability (A3h's Bucket-X finding, now confirmed fleet-wide at scale),
and the repaired gate recovers **none** of them. The audit's "some walls were tooling" thesis was ALREADY
validated by the *fixes'* banking (A3f/g/h + A9b, 66.5→68.6% instr); this residual is real codegen. Ran as a
deterministic parallel job (not agents — agents would be wasted running a shell gate); `backlog.py` gained an
env-gated `BACKLOG_NO_RENDER` (workers skip the render race; append is atomic) — a small backward-compatible
parallel-safety change. **NEXT: pivot the reasoning Workflow to the one UNTESTED wall — #4 the type-heavy tail
(9 zero-bank type-using families + ~73 type-suspect stubs + the 3,098 tail), which A7 fixed `build_engine_types`
to run but nothing has re-harvested since (A3h's h_seq sweep skipped STRUCT). Sample-test first, then scale.**
- **2026-07-14 (session 13, A10 Max-phase — wall re-test SCOPING + arity measurement; Max, fan-out pending R27):**
Began A10 (Drew: "begin at Max, prompt before the ultracode fan-out"). **Measured before claiming (R14).**
**KEY FRAMING:** the audit FIXES already dissolved the *easy* wall — A3f/g/h banked +2,675 h_seq re-harvest +
the byte-exact-stub backlog wins, A9b re-banked func_8017A4AC ×134 (a def-side wall) — driving 66.5→68.6%
instr. So A10 is the *systematic* re-test of what remains. **Scoping:** backlog = **2,218 open-stub drafts**
(deduped by fn) — **958 at closeness 0** (match_one says byte-exact, gate-rejected before the A3e all-TU fix),
429 @1-5, 543 @6-20, 288 @20+; fleet = 9,543 open stubs; h_seq = 16,049 residual failures (mostly
collision false-templates the byte-gate correctly refused — A3h already re-ran that sweep). **#2 arity
(targeted, measured):** of the 18 Phase-15 arity/narrow-param drafts, **13 are ALREADY banked** — the
"documented dead-end" wall largely fell (fix_arity_callers Phase-19 + later banking), 5 remain
(func_80156600/8015C030/80161208/8016191C/8016BF50); A3c already proved its premise false (the `()` rule is
order-dependent, cc1 doesn't enforce it). **#4 type-heavy:** build_engine_types now runs (A7) — the tail is
re-testable. **CONFIRMED the remaining re-test is BREADTH:** a serial `gate_stage` sample timed out (ov_SC01_077
rebuilds per draft; the reason the audit banked via ×134 family sweeps, not per-fn gating). Tree reverted clean
(HEAD commit:0618). **→ R27 BOUNDARY: prompting Drew for `/effort ultracode` before the fan-out** = re-gate the
2,218 open-stub drafts (958 closeness-0 first — the definitive "fuel exhausted" test) + the type-heavy tail
through the fixed oracles (reconcile_tu/cdecl-compat/build_engine_types), parallel-isolated, bank the
byte-gated wins, R22 before commit; a re-confirmed wall is as valuable as a dissolved one (P9).
- **2026-07-14 (session 13, A9g — jr_inventory: retire the ephemeral roster, derive banked from the image; Max):**
R33 applied to "the purest R33 case in the group" (audit). `jr_inventory`'s `banked` set was filtered by an
**EPHEMERAL, gitignored `.run/banked_func_*.json` roster** — `rm -rf .run`/a fresh clone would blind ALL
banked jr at once, cross-address siblings (roster named after the exemplar) were structurally invisible, and
non-leader banked jr were missed. **FIX (audit's exact prescription): deleted the roster glob + `cand`
filter; `banked` is now DERIVED FROM THE IMAGE** — a real-C def/define fn is a banked jr iff
`family_remap.reloc_targets` shows it references a committed `.rodata` carve offset (config + image, both
durable). **R32 assertion added:** every committed carve must resolve to EXACTLY ONE owner or the run
aborts (a stranded/duplicated carve = the §8b func_801734BC incident, never silent). **Also fixed** the
adjacent MEDIUM/LOW finding — the `asm_jr` scan's `func_`-fullmatch dropped the curated-name `listCdBuffer`
jr; now resolved via `oss.addr_of()` (the `--only` path's own fullmatch is left — it parses user input, not
the corpus). **Perf:** the image is read ONCE and passed to `reloc_targets(…, data=)` (new
backward-compatible param on family_remap; regression-verified 0/80 mismatch vs the re-read path). **VERIFIED:**
(1) reloc_targets `data`-param behavior-identical; (2) the R33 win — ov_SC02_000 now finds the cross-address
sibling `func_8017FCB0` the roster missed; the 3 non-leader overlays (ov_SC01_077/04_008/05_009) resolve;
(3) **full-fleet parallel run = 134/134 OK, 0 false aborts, 1336 banked jr == 1336 carves → 1:1 ownership
holds fleet-wide** (the R32 assertion is safe). **BYTE-SAFE:** jr_isolate_all is NOT in the make build/extract
path (R22-neutral); the change makes future isolations strictly MORE correct (finds carve owners the roster
missed → fewer stranded carves). tooling-audit ledger marked FIXED (3 jr_isolate_all findings). **NEXT: A10 —
re-test the walls (the audit payoff).**
- **2026-07-14 (session 13, A9f — overlay_src_split force_decl latch fixed + a coverage oracle; Max):**
The parser `jr_isolate_all` rewrites source from swallowed **2 real function definitions** on physical
lines of the form `extern A; extern B; void f(){...}`: `scan_construct`'s `force_decl` latched from the
FIRST token and returned at the first depth-0 `;`, so the def after it was never anchored — absorbed into
the next anchor's preamble. **The selftest was structurally blind** (round-trip = `"\n".join(item_texts)`
stays exact by construction when a miss lands in a preamble — a *serialisation* check, not *coverage*).
**FIX (byte-safe, R14-chosen):** rejected the audit's "split the line into 3 constructs" — round-trip
joins whole-line chunks with `\n`, so sub-line splitting would insert a newline where a space was and
BREAK round-trip. Instead: `force_decl` no longer survives a same-line `;` with trailing code (re-classify
+ keep scanning → the def anchors, its leading externs staying in its whole-line text); `def_name` now
names the LAST top-level header before `{` (the definition, not the first same-line extern; byte-identical
on every single-def construct). **R32 coverage oracle** `hidden_definitions()` wired into `selftest`
(independent detector of `func_XXXX(...){` bodies not anchored) — the selftest is now a coverage check.
**Audit line refs were STALE** (src rewritten by banking): real cases are `ov_SC01_077_after.c:2020`
(func_8014FDF4) + `ov_SC01_077_jr_8015444C.c:1495` (func_80155FF8), found via the new oracle (matched the
audit's count of 2). **VERIFIED:** 2 swallowed→0; full-fleet regression over **1738** overlay `.c` = 0
round-trip fails, 0 non-monotonic, **0 non-additive changes** (nothing removed/reordered, `def_name`
unchanged everywhere), exactly **+2** anchored defs. **BYTE-SAFE:** overlay_src_split is NOT in the
make build/extract path (R22 byte-neutral); ov_SC01_077 rebuilds `d19c9580` `[OK]`; neither def straddles
a committed subseg boundary (no cut in `(def, next]`) ⇒ a future re-isolation stays byte-identical.
tooling-audit ledger marked FIXED. **NEXT: A9g — jr_inventory ephemeral gitignored-scratch read (R33).**
- **2026-07-14 (session 13, A9e — reconcile_tu already wired into bank_exemplar; NULL RESULT; Max):**
P9/R14 — the session-12 handoff item "wire reconcile_tu into bank_exemplar" is a **stale carryover; it
was already done by A3d.** Traced the call chain rather than trusting the note: `bank_exemplar`'s
`recovered` stage (l.53) = `fb.recover(base, OV, cf, FUNC)` = `jtbl_family_bank.recover()`, which runs
`cast_call_sites` **then `reconcile_tu`** (l.94/96) — the reconcile_tu wiring entered there in **A3d
(`commit:0601`, "retire the fleet-majority oracle … on BOTH banking paths")**. So `reconcile_tu` reaches
`bank_exemplar` transitively via `recovered`, needing no bank_exemplar-specific rung. **Already
PROVEN**: A9b banked `func_8017A4AC` "at the recovered stage (reconcile_tu resolves its D_80126B58 struct
+ D_801DA75C fn-ptr conflicts)". Also confirmed **no live tool references the RETIRED `reconcile_decls`**
(only docstring mentions + the `make audit-cdecl` differential harness, which legitimately measures cdecl
against the old regexes). **NO code change warranted** — adding a redundant explicit reconcile_tu rung
would duplicate `recovered` and diverge from `jtbl_family_bank`'s pattern for zero benefit. One byte-neutral
hardening: documented the recovery-ladder composition inline in `bank_exemplar` (scoped/recovered/reconciled)
so a future session doesn't re-run this exact "is it wired?" investigation — the precise waste the audit
exists to eliminate. **NEXT: A9f — overlay_src_split force_decl latch.**
- **2026-07-14 (session 13, A9d — retire the dead Phase-17 canonical-sig chain; Max):** R33 applied to a
two-tool dead chain. **DELETED `tools/census_conflict_callees.py` + `tools/derive_canonical_sigs.py`.**
`census` was audit-CONFIRMED MARKED-FOR-DELETION (`commit:0593`; decision-log 836 "in its entirety gets
deleted"): it re-derives from C text the question — "for this TU, which callees are defined/declared/
stubbed/external?" — that `reconcile_tu` (Phase 26) answers FROM THE BUILD; a parse hole in `reconcile_tu`
is conservative, a parse hole here is WRONG in the unsafe direction (unknown→"conflict-free"). Its output
fed only `derive_canonical_sigs`, which the audit DOWNGRADED but which is genuinely **dead**: last touched
Phase-17 (`commit:0140`), output `.run/canonical_sigs.json` read by **nothing** (no Makefile target, no
workflow, no module import — all verified by grep), no-ops on the 2-byte `[]` input, and its asm-arity
heuristic is **36% wrong vs byte-exact banked C** (audit skeptic, ground-truth run). Its canonical-sig
purpose was itself retired in **A3d** (fleet-majority oracle → `reconcile_tu`'s per-TU oracle). So the
whole dead chain **ceases to exist** rather than leaving an orphaned, non-runnable, wrong-by-36% scanner
(R33: "the best outcome is a DELETED SCANNER"). **Byte-neutral BY CONSTRUCTION** — neither tool is in any
build/report path; verification = module-import smoke over the 13 importable harvest/bank/report/reconcile
tools (`corpus`/`cdecl`/`reconcile_tu`/`canon_sig_reconcile`/`gen_harvest_targets`/`gate_stage`/
`jtbl_family_bank`/`family_sweep`/`dedup_propagate`/`sig_unify`/`cast_call_sites`/`scope_data_externs`/
`family_remap`) = **all clean** (`bank_exemplar` is a run-only script that indexes `sys.argv` at module
scope → not importable by design, imports neither deleted module — a test-method false alarm, not
breakage). No `src/`/`config/` change ⇒ no byte can move ⇒ full R22 not warranted (P9-honest: a 136-binary
rebuild would prove only what the absence of a build-path edit already guarantees). **Doc-pointer hygiene**
(so nothing points at a nonexistent tool): `docs/hand-matching-process.md` §8a, `docs/matching-cookbook.md`
(canonical-sig-layer entry), and `docs/tooling-audit.md` (ledger row + the `derive_canonical_sigs` entry)
all annotated DELETED/historical. **NEXT: A9e — wire `reconcile_tu` into `bank_exemplar`** (its stage
ladder is `raw→scoped→recovered→reconciled`; `recovered`=`fb.recover`, `reconciled`=`canon_sig_reconcile`
— add a `reconcile_tu` stage, byte-gate); then A9f (overlay_src_split force_decl latch), A9g (jr_inventory
ephemeral read), A10 (wall re-test), A11 (distill + close → resume Phase 26 Task 7).
- **2026-07-14 (session 12, A9a+A9b — canon_sig_reconcile fn-ptr fix + wall re-test; Max):** Continued the
tool-hygiene audit. **A9a — `canon_sig_reconcile` sees fn-ptr dispatch tables (`commit:0609`).** The def-side-wall
recovery tool, live on the ×134 economic-engine paths (jtbl_family_bank, family_sweep --reconcile-raw,
bank_exemplar, t7_bank, scope_data_externs, family_remap). Its tu_ambient/visible_above classifiers +
`_reconcile_data`'s `_DATA_EXTERN_RE` have a type class `[\w \*]` that can't hold a `(` → 100% blind to
`extern void (*D_x[])(void);`, the per-overlay jump-table DISPATCH arrays. A fn-ptr symbol landed in NO bucket,
fell out of `visible`, and the tool block-moved the draft's extern into a guaranteed `conflicting types`.
**Fix = SUPPLEMENT, not wholesale-replace** (R14-driven): a full cdecl delegation of the funcs classification
was tried and REJECTED — cdecl normalizes funcs formatting (`void*`→`void *`, param names, a real return-ptr
hazard `u8*`→`u8`) → 728k value-changes rippling into the callee string-compare; the audit flagged fn-ptr
DATA, not funcs. So keep the proven regex byte-identical and supplement from `cdecl.tu_scope` ONLY the fn-ptr
symbols it drops (`_fnptr_data`); `_reconcile_data` gains a fn-ptr pre-pass (visible→STRIP, no cast — a
call-through `D_x[i]()` is decl-independent indirect codegen; casting would mangle it, the trap reconcile_tu
documents; not-visible→block-move) + the F2 comment-paren-bail fix + an R32 coverage assertion. **PROVEN
ADDITIVE:** classifier snapshot over 1683 TUs = **REGRESSIONS 0, ADDITIONS 69,798 (all data fn-ptr)**;
reconcile() OLD-vs-NEW over 434 real drafts = **0 regressions**; src/ UNTOUCHED (a tool change moves no bytes).
Harness in `.run/audit/a9a_*`. **A9a's immediate banking impact = NULL** (correctness fix, like A3c/A3d/A3e —
the historical tail fails on codegen/heterogeneous blockers, not the one fix); its value is protecting all
future dispatch-table banking.
**A9b — re-test the walls (`commit:0610`, `commit:0611`).** Re-ran 7 fn-ptr-referencing "blocked" cracks through
bank_exemplar. **HONEST (R14): A9a did NOT independently unblock any** — the `reconciled` stage failed on
func_8015B950's func-conflicts; the rest hit K&R / scalar-typedef / non-ov077 / non-contiguous-carve blockers.
**BUT the audit's recover path (A3d reconcile_tu / A3e gate) dissolved `func_8017A4AC` (536 ins × 134)** — a
giant "blocked on plumbing" since session 8. It banked at the `recovered` stage (reconcile_tu resolves its
D_80126B58 struct + D_801DA75C fn-ptr conflicts). Isolated + carved + jtbl_family_bank --raw swept **133/133
siblings, 0 failed**. **R22 clean-fleet 136/136** after each; **instr-weighted 68.1→68.6% (+0.5%), distinct
48.0→49.2% (+1.2%)**; dedup 1840/0. **The audit thesis demonstrated: a many-phase "wall" was our TOOLING, not
an intrinsic residual — fixed the oracle, the wall banked ×134.**
**A9c — `lint_symbol_refs` green + wired (`commit:0613`).** The ONLY detector for the R22 rename-drift failure
mode (a symbols rename leaves a func_<ADDR> ref dangling; a clean build fails, an incremental masks it —
undetected Phase 21→23). Was RED (262 FPs) + UNWIRED. All 3 audit blind spots fixed: #1 now scans
`src/shared/*.h` (engine_core.h's 10k+ tokens; negative-control-proven a shared-header ref IS flagged); #2
reads every REAL stacked symbol file, excludes R13 proto; #3 **all 262 FPs were the `__asm__("memcpy")` class**
(engine_core.h binds func_8005C324→memcpy via an asm label → resolves at link) — now modeled. Negative control
(inject a bare func_800d1bd8→DsMix in a shared header) FLAGS it then clears — detection intact. Wired
fail-closed into `make report`; no src/build change (report-time gate). **SESSION-12 net: instr 68.1→68.6%,
distinct 48.0→49.2%, 5 commits (`commit:0609`, `commit:0610`, `commit:0611`, `commit:0612`, `commit:0613`) + this log.**
**NEXT (tool-hygiene tail):** A9d (DELETE census_conflict_callees after confirming derive_canonical_sigs is
dead; wire reconcile_tu into bank_exemplar; overlay_src_split force_decl latch + jr_inventory ephemeral read);
then A10 (full wall re-test — the def-side loose-typing wall, 159 arity conflicts, 780 h_seq rejections, the
permuter-fuel "exhausted" claim) + A11 (distill + close, then resume Phase 26 Task 7).
- **2026-07-14 (session 11, A3h — the standing-lead harvest, measured then banked; xHigh):** Resumed the
A3f/A3g "310 byte-exact stubs" lead. **Measured it precisely first (R14) — and the "310 same class, same
fix" framing was optimistic.** Deduped the backlog's `closeness==0` rows (recovering `addr` from `name` for
the 1,492 null-addr LLM-tier rows — dropping them would have been the exact R32 silent-skip), cross-referenced
against `corpus.stubs()` over all 136 binaries: **1,024 still-open byte-exact functions**, in 3 buckets —
**G** (66 open in ov077), **P** (61 matched in ov077 + open in siblings), **X** (897 absent from ov077).
**Bucket G — re-gated the 66 through the A3e-fixed `gate_stage --no-propagate` → 0 banked, 64 near, 3 failed.**
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** (the `closeness==0` was an old
row). Correct G3/P9.
**Bucket P — `dedup_propagate --addr` (A3g primitive). It skipped 70 of 83 as h_exact reach<2** (their sibling
bytes DIFFER — per-location variants → `family_sweep` territory, not plain propagation) and **propagated the 14
genuine PURE fleet families ×~133** (2 stragglers all-or-nothing-dropped). R22 clean-fleet **136/136**;
**instr-weighted 66.8→67.4%** (distinct flat — propagation adds MEMBERS); dedup **1826→1840/0**. Committed
`commit:0606`.
**Variant families — regenerated `family_hseq.json` (the 14 banks refreshed it), then `family_sweep --hseq
--band all`** (the audit fixes A3–A8 + new exemplars unblocked it): staged 12,373 member drafts / 223 families,
**BANKED 2,675 / 9,698 failed** (22% — the hard residual; easy bands long-harvested), skipped 3,319 pinned +
212 imm + 137 STRUCT. R22 clean-fleet **136/136**; **instr 67.4→68.1%, distinct 46.8→48.0% (+1,435 unique
fns** — templated members are distinct byte-variants, so this moved BOTH). Committed `commit:0607`.
**Bucket X (897 absent-from-ov077) — DE-RISKED, then STOPPED (P9).** Gated ov_SC04_018's 35 X-drafts →
**0 banked, 35 near.** **THE FINDING (R14): `match_one closeness==0` (isolated, relocation-masked) ≠
whole-binary byte-exact.** In the real TU their fresh gate logs read `residual: 13/19/55… mismatch` — they were
never whole-binary-bankable; the backlog's isolated-proxy overstated them. Only ~5/35 are true match_one-MATCH
"declaration/TU plumbing" — and `reconcile_tu` is **already wired** into `gate_stage` (A3d, l.208), so those
need the **un-migrated cdecl recovery consumers** (`sig_unify` done A3e, but `canon_sig_reconcile`'s classifier
still on the old parser — session-9 handoff item 1), i.e. **the next tool-fixing task / A10**, not the current
pipeline. So the mechanically-clean lead is banked; the residual is gated behind hard classes + recovery holes.
**NET SESSION: instr-weighted 66.8→68.1% (+1.3%), distinct-code 46.8→48.0% (+1.2%, +1,435 fns).** 2 commits,
R22 136/136 after each. Tree clean (only db.gbf restart-noise, R23). Measurement + buckets in
`.run/audit/a3h_*`. **NEXT: the recovery-tooling task at Max** (migrate `canon_sig_reconcile` + the remaining
cdecl consumers → re-test Bucket-G/X plumbing-class + the A10 walls). — R27: prompt Drew, wait for `/effort max`.
- **2026-07-14 (session 10, A3f+A3g — the payoff of A3e, banked & propagated; Max):** With `gate_stage` no
longer pinned to the main `.c`, ran the 63 `ov_SC01_077` `closeness==0` backlog drafts (byte-exact bodies the
ledger called unrecoverable) through the fixed gate **`--no-propagate`**: **33 banked, 30 near, 0 failed.**
**Every one landed in a SPLIT TU** (7 of 8 files are `_jr_/_a/_after`; none in the main `.c`) — the diagnosis
proven by placement: not hard, **unreachable**. **A3f** committed the 33 (`commit:0603`), R22 clean-fleet
**136/136**, +1,531 ins, ×1 (fn-count 82.79→82.80%). Then **A3g** (`commit:0604`): the **3** of the 33 that are
fleet-wide, propagated ×134 — done RIGHT this time (targeted `--addr`, dry-run-sized to 3×134 first, on a clean
tree), after the earlier `--auto-from` disaster. **+399 members** (3×133), instr-weighted **66.7→66.8%**,
dedup **1823→1826/0 failed**, R22 clean-fleet **136/136**. The other 30 are overlay-unique (×1, no
propagation). **⚠ THE STANDING LEAD:** the backlog holds **373 still-open stubs with byte-exact bodies**; 63
were in ov_SC01_077 → 33 banked (52%). **310 remain across the OTHER overlays — same class, same fix,
untouched** — the single largest lead the audit produced. **Disk hygiene (Drew, mid-session):** retired the
dead 7B LLM tier (`.venv-train` 7.9G + HF Qwen cache 5.3G + pip CUDA-wheel cache 5.9G + ghidra installer zip)
→ ext4 33G→14G; the 112G `.vhdx` needs a Windows-side `wsl --shutdown` + compact to actually shrink (deferred
to Drew). 7B tier re-creatable from `docs/gen2-mips-matching-model.md`; nothing irreplaceable removed.
- **2026-07-14 (session 10, A3e — 🔴 THE BIG ONE: `gate_stage` pinned the byte-gate back to 4.9% — *of A3's own
fix*; Max):** Migrating `sig_unify` exposed a chain, and the last link is the worst defect in the whole audit.
**(1) `sig_unify` silently DROPPED 190 of 196 drafts (97%).** `cur_stubs` was read from the main `.c` (13
stubs of 263), so any draft whose stub lives in a `_jr_*` carve hit `if fn not in cur_stubs: continue` —
dropped **before the write**: never copied to `--out`, never gated, never logged. The summary printed *"drafts
unified: 6"* and read like success. **This is gate_stage's STAGE-2 RECOVERY** — the pass whose entire job is
to rescue stage-1 failures — **and it has been a no-op for almost every draft it was meant to save.** Fixed by
deriving the TU per draft (`corpus.stubs`) + the canon from `cdecl.tu_scope` (cpp, so macro-injected decls are
visible) + `_keep()` (only rewrite when cc1 would actually reject — the §19 "sig_unify regresses canonical
drafts" failure mode). Reach: **6 → 196 drafts; callee-externs rewritten 2 → 90; own def-sig 2 → 86.**
With all three consumers migrated the 196-draft failure profile went **near 5 → 116, failed 190 → 17**:
**173 of 190 "failures" were PLUMBING, not codegen** — now compiling and *scored* instead of invisible.
**(2) 🔴 `gate_stage.py:315`: `src=a.src or f"src/{b}/{b}.c"`.** `src` **RESTRICTS the byte-gate to ONE TU**,
and `_gate1` does `if src: cmd += ["--src", src]` — always truthy. **A3 had just taught `harvest_verify` to
derive each draft's home TU when `--src` is OMITTED (reach 4.9% → 100%), and `gate_stage` never omits it.**
The fix was neutralised **by its own caller's default**, leaving the *primary banking path* (every wave, the
grinder, the orchestrator, `bulk_harvest`) structurally unable to bank **250 of 263 stubs**.
**WHY IT SURVIVED 26 PHASES:** a draft whose stub isn't in the pointed-at TU simply never verifies → it is
logged `near`/`failed`, i.e. **as a MATCHING problem** → the wave reports a poor close-rate → the function
goes to the backlog as a compiler residual. **A tool that CANNOT bank a function is indistinguishable, in
every log this project keeps, from a function that CANNOT BE banked.** Proof, same draft/gate/second:
`gate_stage` rejected `func_80129C40`; **`harvest_verify` run directly (no `--src`) VERIFIED it
byte-identical and banked it.** **(3)** And a counting bug hid the hiding (`gate_stage:261`): `match_one`
MATCH + gate-reject logs `status="near"` and **never increments the counter** — a 63-draft run printed
`banked 0, near 0, failed 0`, *three zeros that do not sum to 63*, for phases, and **nobody added them up**.
**THE PRIZE, MEASURED:** the backlog holds **1,588** `closeness==0` entries (body byte-exact per `match_one`,
gate rejected). 1,215 were banked since by other paths; **373 are STILL OPEN STUBS whose bodies are already
byte-exact**, sitting in a ledger that calls them unrecoverable.
**⚠ THE HARVEST ATTEMPT FAILED AND WAS REVERTED (P9).** Gating the 63 ov_SC01_077 ones dragged
`dedup_propagate --auto-from --recover` behind it, which ran **>1 h and hit its timeout** — its first-ever run
over the FULL corpus (A6/A7 unblocked the 407 files it could never see). It **mutates the tree BEFORE it
gates**, so the kill left **859 files + engine_core.h (+544 lines) written and UN-GATED, and the registry
never updated**. R22 clean-fleet on it: **44 passed / 92 FAILED** → **`git checkout -- src/ config/`**, fleet
restored. **Nothing was lost (H4: the tree was clean, so the revert was one command) — but two real lessons:
`dedup_propagate` is NOT crash-safe and must never run under a timeout it can hit; and a 63-draft experiment
must not drag an unbounded fleet-wide propagation behind it (gate with `propagate=False`, then propagate as
its own bounded job).**
**Committed: the TOOL FIXES only. The harvest is NOT banked and is not claimed.** Knowledge captured live
(R30/R31): cookbook **§51g LAW 11** (*a fix is not landed until its caller stops overriding it* — after
fixing a scanner, grep every call site and ask whether a caller's default re-disables it), tooling-audit
**A3e**. **NEXT: re-run the 373-stub harvest with `propagate=False`, then propagate separately.**
- **2026-07-14 (session 10, A3d — RETIRE the fleet-majority oracle; both banking paths; Max):** R33 applied to
the audit's worst finding: **not fixed, RETIRED.** `reconcile_decls` asks *"what does the FLEET call this
symbol?"*; C asks *"what does THIS TU declare?"*. The engine is loosely typed, so one fleet-wide answer is
**wrong for some TU by construction** — and worse than a skip, because it writes an **actively wrong decl**
into the draft that then collides with the very TU it was meant to conform to. **Measured** across
ov_SC01_077's 12 TUs vs what cpp says each TU really declares: **agrees 2,883 · CONFLICTS 548 (16%, cc1
rejects the result) · absent 357.** And it was live on **both** banking paths — `gate_stage` (rewrote **60 of
196** drafts) and **`jtbl_family_bank`, i.e. EVERY SIBLING of the ×134 family sweep, the project's economic
engine**. A poisoned decl means that sibling silently doesn't bank and the sweep just reports a smaller
number. The irony is exact: that function's own docstring already knew the conflicting symbols are
**per-overlay** — which is precisely why a FLEET oracle could never have been right.
**`reconcile_tu.py`** (written in Phase 26, **never wired**) now supersedes it, rebuilt on cdecl: cpp for what
the TU declares (macro-injected externs included), **cc1** for whether the draft's decl can coexist, TU-derived
from `corpus.stubs()`, and it **handles the fn-ptr kind NATIVELY** — which is *why* it supersedes rather than
patches: teaching the old parser to see `extern void (*D_x[])(void);` would have **ARMED** its fn-ptr-blind
`data_access_subs` to rewrite a call-through `D_x[i]()` into `((u8 *)D_x)[i]()`. **Fixing the regex would have
detonated a dormant bug.**
**NULL RESULT AGAIN (P9/R14):** on the 196 never-banked drafts the new oracle banks **exactly as many as the
old — zero**; the two disagree on 45 of 196 and the outcome does not move. That tail fails on **codegen**, not
plumbing. This is a **correctness** fix (548 wrong decls removed from two live pipelines, protecting all future
drafts and every future family sweep), **not a banking win, and it is not being sold as one.** Three nulls in
one session. `reconcile_decls.py` kept as EVIDENCE, marked RETIRED, **no live caller**.
**R22 clean-fleet 136/136; src/ untouched; reconcile_tu 0 coverage defects over 196 drafts.**
⚠ **The family-sweep path gets its real exercise at Task 8 — watch the per-sibling bank rate.**
- **2026-07-14 (session 10, A3c — first consumer migration: `cast_call_sites` onto the cdecl oracle; Max):**
Added **`cdecl.compatible()`** — *"will cc1 accept these two declarations of one name?"*, the predicate four
tools each half-implement and get wrong (`norm_sig`/`_norm_type` collapse the int family, so a **signedness**
change reads as "already compatible" and gets no rewrite — while cc1 **rejects** that redeclaration). Wrote the
rules from the C standard; then let a compiler judge. **It contradicted me — and then the RIGHT compiler
contradicted the first one.** Modern `mipsel-linux-gnu-gcc`, gcc-2.7.2 `cc1`, and the standard give **three
different answers** (typedef redefinition: C89 error / C11 accepts / **cc1 ERRORS**; qualifier mismatch: modern
gcc errors / **cc1 ACCEPTS**; no-proto + narrow param: both error / **cc1 accepts in ONE direction**). So
`--compat` now adjudicates with **`tools/bin/gcc-2.7.2-psx/cc1`, the front end that actually arbitrates the
build** → **1,485/1,485 live corpus pairs agree, 0 disagree, 0 skipped.** 🏆 **THE PRIZE: the Phase-15
narrow-param wall rests on a false premise.** The `()` rule is **ORDER-DEPENDENT**: `void X(s16); void X();`
**compiles**; only the reverse fails. "The 159 arity/narrow-param conflicts — no clean deterministic fix" was
closed on a rule cc1 does not enforce. Four three-line probes, 90 s, zero tokens → **A10 re-test target**.
**THEN the migration itself: `cast_call_sites` was canonicalizing 95.1% of drafts against the WRONG TU.**
`--src-file` is an *optional hand-passed flag* defaulting to `src/<ov>/<ov>.c`, and no caller knows about the
Phase-26 `_jr_<ADDR>` carves — ov_SC01_077 has **263 open stubs across 12 TUs, only 13 in the main `.c`** —
while `harvest_verify` (A3) correctly splices into the real one. Now **DERIVED** from `corpus.stubs()` (the
`INCLUDE_ASM` line is self-describing) + the canonical map derived from `cdecl.tu_scope()` (cpp — so
macro-injected decls are finally visible). **Repair reach 8 → 58 of 196 drafts (7×).**
**THE NULL RESULT, REPORTED AS SUCH (P9/R14):** those 58 banked **ZERO**. The historical tail fails on
**codegen**, not plumbing — `func_801387B8`, which the audit blames on one unparsed `[4]`, is really **67/100
instructions off with a `$s0`/`$s1` swap** (that claim does not reproduce). The real gain is narrower and still
worth having: **52 drafts moved from "won't compile" to "compiles, N instructions off"** — from an *invisible
failure that reads as a compiler wall* into a *scored near-miss the permuter can act on*. **Three times in one
session a confirmed mechanism produced a null consequence.** I also mis-diagnosed the callee oracle as
"returning nothing" (my probe was buggy — it did have the sig) — corrected. **And my own new audit printed
"ALL ORACLES GREEN" while silently skipping 100% of its corpus** (a missing `-Isrc`): the exact bug class, in
the tool written to hunt it. Fixed — *an unadjudicable check is not a passed check.*
**R22 clean-fleet 136/136 BYTE-IDENTICAL; src/ untouched (0 changes); `make audit-cdecl` green.** Knowledge
captured live (R30/R31): cookbook **§51g LAWS 9–10**, decision-log, tooling-audit **A3c**.
**NEXT: `sig_unify` + `reconcile_decls` have the SAME wrong-TU bug** (same `--src-file` flag) — migrate them,
then `lint_symbol_refs`, then **A10 (re-test the walls)** with the narrow-param finding as the first target.
- **2026-07-14 (session 10, A3b — `tools/cdecl.py`, THE C-declaration oracle; Max):** Built the one parser
that lets fifteen die. **Rejected the audit's own prescription** (a shape-aware alternation per tool, ~15
coordinated regex edits) on R33 grounds: fifteen hand-maintained models are precisely what diverged, and an
alternation only ever covers the shapes someone remembered. The thing being scanned **has a grammar** —
C's declarator grammar is small, closed and total, and describes fn-ptr arrays / sized+2-D arrays /
multi-declarators / fn-ptr params / K&R identifier-lists *without being told they exist*. ~250 lines of
recursive descent, **less code than the regexes it deletes**. Two statement paths because the inputs
genuinely differ: a TU's file scope is derived from **`cpp`** (a decl inside a `DEFINE_func_*` macro body
declares nothing until invoked — §8c; 54 ms/TU, so the "too slow" objection is dead), while a draft gets a
**span-preserving** raw split (drafts are rewritten). **Proof, not belief — three oracles over the whole
corpus:** coverage **2,952,246 depth-0 statements → 2,731,521 declarators, 0 parser defects**; the **real
cross-gcc** compiled each of **50,405 distinct declarations beside my reconstruction of it → 0 rejected**;
differential vs the incumbents → **0** file-scope symbols they see that I miss, **26** in engine_core.h
they cannot see, **6** they wrongly promote from block scope. Two ideas worth keeping (cookbook §51g, LAWS
4–8): the **candidate set is DERIVED** (at file scope C admits nothing but declarations → R32's detector is
*every depth-0 statement*, no second model to rot), and **gcc adjudicates my own coverage gap** (a
statement gcc *also* rejects is not C; one it *accepts* and I don't is my defect — grading my own homework
is the habit that wrote the fifteen bugs). All 33 residual: **NOT-C**, all dead `.run/drafts*` scratch,
none in `src/`. **Bugs the oracles caught in ME, that I would otherwise have shipped:** `extern s32
(*D_801274D0)(s32);` parsed the *base type* as the name; a K&R declaration-list flushes as SEVERAL spans,
so the body attached to the wrong one and leaked `a0`/`arr` into file scope as fake globals. **New findings
→** `docs/tooling-audit.md`: `reconcile_decls.DATA_DECL_LINE_RE` finds **ZERO** decls in engine_core.h (its
authoritative tier has always been empty); two scanners treat **block-scope** externs as file-scope
canonicals (the §8d wall); `tu_ambient` drops any callee with a fn-ptr param. An honest R14 near-miss: the
33 corrupt drafts were written by a *recovery tool* prepending `extern` to an `if` — but the source bug was
**already fixed in Phase 19** (0 garbage / 300 sigs today), so *mechanism confirmed, consequence nil*.
**NO consumer changed** (deliberate — the audit warns the fix ARMS dormant transforms), so it cannot move a
byte: **R22 clean-fleet 136/136 BYTE-IDENTICAL**, `make audit-corpus` still 0 unmatchable slices. New gate
**`make audit-cdecl`** — standing, because a loud failure nobody counts is as invisible as a silent one.
Knowledge captured during the session (R30/R31): cookbook §51g, decision-log, SETUP inventory (+ the
`corpus.py` row, an R21 gap from session 9). **NEXT: migrate the consumers, one at a time, byte-gated** —
starting with `reconcile_decls`/`reconcile_tu` (3,717 actively-wrong canonicals).
- **2026-07-13 (session 8, the ×133 sweep blocker FIXED — `func_8015AE2C` banked ×134; Max):** Reproduced ONE
sibling by hand instead of trusting the session-7 handoff (R14) and the picture sharpened: **the isolated region
builds `[ OK ]` WITHOUT the body** (so §8b isolation was never implicated), and `conflicting types for
D_801812A4` was the **only** hard error in the whole build — all 27 carried *function* externs were fine raw, so
`cast_call_sites` was doing nothing. Root cause: `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. **Rejected the session-7 plan** (teach `reconcile_decls`
a TU-visible oracle — a big, risky change to a proven path) for a smaller one: **don't disturb the TU's decl
environment at all.** New `tools/scope_data_externs.py` demotes a carried `D_` extern to **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), *never worse than raw*, so it needs no oracle, no type comparator, and no fn-ptr parser
(`reconcile_decls`' regex **cannot parse** `extern void (*D_x[])(void *);` and was silently skipping exactly the
failing symbols — the third silent-skip bug of the phase). Wired as the `scoped` stage (raw → **scoped** →
recovered → reconciled). First sibling byte-identical first try; **full sweep 133/133 BANKED, 0 failures**;
**R22 clean-fleet 136/136** (534 changed src files); dedup 1813/0; **instr-weighted 63.0→63.6%, distinct-code
39.1→40.5% (+256 unique fns / +79,957 ins)** — one core, ~0 agent tokens. The **R17 triage rule** (committed
`commit:0550` at Drew's ask) paid off on its first test: `conflicting types` = the compiler *refused to compile* =
a C front-end diagnostic = **our Python**; a gcc-source read would have taught nothing. Knowledge captured
DURING the session (R30/R31): cookbook **§8d**, decision-log, SETUP tool row. **NEXT: `func_80178D40`**
(890×134, close=39, all in case 0x5C — cheap-Opus/permuter, no Fable5), then the R27 prompt for Fable5 on
**`func_8017BEBC`** (952×113, close=2 — the allocno-tie R17 target).
- **2026-07-13 (session 6, the §8b scoping wall BROKEN — heavy-jr harvest unblocked; Max):** Built the
**declaration-environment reconstruction** on the proven `overlay_src_split.py` parser. **R14 correction:**
session-5's "gcc-2.7.2 block-scope-extern TU-persistence" root cause was *wrong* — there is no gcc quirk;
`DEFINE_func_*` macros expand at FILE scope, so their leading externs are genuine file-scope decls that simply
live in `engine_core.h` and are invisible to a col-0 `.c` scan (census: 1,377 macros / 3,929 extern lines / 1,462
symbols). **Rejected the approved "global symbol→type map + shadow set" design** (X1/P5d — same goal, better
mechanism): the engine is loosely typed (`func_80173544` is *defined* `s32 f(void*)` yet declared
`extern void f(void);` inside `func_801734BC`'s body), so "declare every used symbol" hoists that block-scope
shadow to file scope and CREATES the conflict a shadow-set heuristic then has to dodge. Instead: **reconstruct the
original TU's file-scope decl environment and carry it strictly forward** — conflict-free by construction (every
carried decl already coexisted with every definition in the one original TU; decl compatibility is
order-symmetric; shadows stay in bodies). The byte-gate then found **two more** lost decl sources I had not
predicted: **a definition is itself a declaration** for everything below it in its TU (`func_8012B2CC undeclared`)
and **file-local typedefs** used by a carried prototype (`parse error before '*'`, `Vec3s`). **Full 54-jr
isolate-all on ov_SC01_077 → `d19c9580` BYTE-IDENTICAL; R22 clean-fleet 136/136** (the exact configuration
session 5 could not build). Parser selftest still 404/404. Then wired **LAZY per-core isolation** into
`jtbl_family_bank` (Drew's call — upfront-×134 would add ~7,200 region files): `jtbl_carve` NON-CONTIGUOUS
fail-loud → `jr_isolate_all --only <core>` → re-extract → re-carve; **proven on `func_80178D40` (890×134, the
heaviest core)** — carve blocked → isolated (byte-neutral) → carve lands in its own subseg. **Two latent bugs
found + fixed** (both would have corrupted the heavy sweeps): `func_subseg` read the owning subseg from the
*asm tree*, which `make extract` never prunes, so after an isolation it returned the STALE owner and silently
re-created the collision (→ derive from the config); and the sweep's `revert()` **deleted** the shared
`overlays.mk` carve var unconditionally, which would have destroyed a *committed* carve (all 134 overlays have
one) on any failed sibling (→ restore to its committed value). Added a dirty-tree preflight to
`jtbl_family_bank` (an uncommitted prior family would be silently reverted). Knowledge captured DURING the
session (R30/R31): cookbook **§8b RESOLVED + new §8c** ("splitting a TU means rebuilding its declaration
environment, not moving text") + decision-log. Committed. **NEXT: Task 7 heavy-jr crack waves — R27 boundary,
prompt Drew for effort/Fable5 before launching.**
- **2026-07-13 (session 5, Stage-2 isolation build — parser DONE, single-cut PROVEN, full isolate-all hit the gcc-2.7.2 scoping wall; Max):** Drew re-approved Stage 2 + set `/effort max`; steer = scalable isolate-ALL-jr-per-sibling upfront resegment, then Fable5 on the heavy cores. Built + fleet-validated **`tools/overlay_src_split.py`** (overlay-`.c`-aware partition; **404/404 overlay `.c`, 341,902 items, round-trip exact / 0 unresolved / 0 non-monotonic** — fixed 5 parser edge cases: definition-vs-declaration by brace/`;` scan, K&R defs, comment/`#`-directive peeling, `def_name` from the signature not preamble, `SETTER`/`RETCONST` macro anchors, trailing-footer preservation). Built **`tools/jr_isolate_all.py`** (multi-cut resegment: config split at jr boundaries, source repartition + INCLUDE_ASM path repoint, banked-jr carve repoint, -O0 skip, ambient file-scope decl carry). **SINGLE-cut isolation BYTE-IDENTICAL** (func_8013FFD8 in `main`, clean `make build` `d19c9580`, R22) — Task 2 proven. **Full 54-jr isolation FAILED on the dense `_after` object** after fixing 7 C-scoping edge cases in sequence, on the deep one (byte-verified): **gcc-2.7.2 block-scope-extern TU-persistence** — `func_801734BC` uses `D_80126B3E` declared `extern s16` only inside `engine_core.h` `DEFINE_func` macros; splitting the TU separates the core from the earlier macro expansion that declares it → `undeclared`. Root: mechanical TU-splitting rebuilds the decl ENVIRONMENT (semantics), not just text — col-0 ambient-carry can't reach macro-injected decls. **Candidate fix (not built): declaration-completion** from a global `engine_core.h`+overlay symbol→type map (decision-log 2026-07-13, R31). **Baseline reverted + intact; 2 tools untracked, NOT committed** — surfaced the fork to Drew (P5a) before sinking more time. NEXT: Drew's steer (build declaration-completion vs pivot Stage-2), then commit the tools.
- **2026-07-12 (session 4, multi-jtbl `--order` + family-1 — the Stage-1 de-risk build; Max):** Recon proved the Stage-1 core risk is precise: `jtbl_family_bank.revert()` restores each sibling to committed = has func_8012ACE0's carve, so banking ANY 2nd jr family makes the overlay multi-jtbl. Built `ld_interleave.py --order` (address-ordered N-piece sandwich; legacy `--front/--tail` byte-untouched → main + 133 single-carve siblings unaffected) + rewrote `jtbl_carve.py` additive/regenerate-from-config (parses tail data-region + existing carves, splits the containing data piece for the new jtbl, re-emits `--order`; same-subseg → fails loud). Fixed `jtbl_family_bank.bank()` to `make extract` BEFORE the carve (asm must match the reverted config; the old error-string retry was fragile — 3 early siblings carve-failed). **Family-1 `func_801734BC` (34-ins PURE jr, ov_SC01_077_after) matched in ov077 (shared-tail switch idiom `case N: t=-N; break; default: goto after;`) + banked 133/133 siblings — CROSS-subseg multi-jtbl (func_8012ACE0 `_a` + func_801734BC `_after`), the primary Stage-1 goal. R22 clean-fleet 136/136 byte-identical (~52s).** Wrote `tools/jr_isolate.py` (same-subseg non-contiguous case — split a fn into its own subseg via `split_src_region`, `jtbl_carve` re-derives the carve subseg; ascending-order discipline avoids carve-renames) — not yet integrated/committed. §8a finding: the still-INCLUDE_ASM carve build fails (migrated rodata not emitted through INCLUDE_ASM) — OFF the banking critical path (bank swaps C before building). Committed (Drew pushes — R6). NEXT: prove isolation on a higher fn → integrate → pivot to Stage 2.
- **2026-07-12 (session 3, R22 parallelization — Drew asked "why so slow, profile+optimize"):** Profiled the clean-fleet R22 (`make clean` + extract-all + check-all). **Phase split: extract-all ~6m11s (the BIGGER phase, 136 serial `splat split` runs) + check-all ~2m58s (136 serial builds; most overlays ~1.3s, ov077 slow — maspsx on its 15K-line `.c`) = ~9 min.** Both phases were serial on a 32-core box (the old Makefile comment called cross-binary `-j` "racy"). **Verified the only shared write is the 4 generated `include/*.inc` macros at extract time (identical content); everything else is per-binary-disjoint and `include/` is read-only during a build → parallel is safe.** Added `JOBS ?= 16` + **`make extract-all`** (seed `main` serial for the macros, then parallel-extract the rest) + **parallel `make check-all`** (`xargs -P$(JOBS)`), correctness-gated. **Result: `make clean && make extract-all && make check-all` = ~50s, 136/136 byte-identical — a ~10.5× speedup (9m→~50s).** Committed the Makefile change (own commit). This compounds across the endgame (R22 runs every commit).
- **2026-07-12 (session 3, §8 ×134 AUTOMATION — func_8012ACE0 banked fleet-wide):** Built the jr-function ×134 harvest pipeline and proved it end-to-end. `tools/jtbl_carve.py` = per-overlay §8 carve generator (finding: the same fn is at the same vram across siblings but its jtbl is at a DIFFERENT address in each — ov_SC01_000 jtbl_801A331C / ov_SC02_000 jtbl_801E587C — so the carve is recomputed per sibling; rewrites the config data-tail subsegs + sets `<ov>_JTBL_INTERLEAVE`). `tools/jtbl_family_bank.py` = the sibling sweep driver (per sibling: revert→carve→extract→remap_hseq+reconcile→whole-binary gate; idempotent, revert-on-fail). **Propagation-cap fix:** `family_remap.extract_unit` now carries single-line `typedef`s (jr-function bodies define local `typedef struct{} Foo_<addr>;` that must template with the body, else the sibling sees `Foo undeclared` — additive, byte-gate-protected). **func_8012ACE0 family: 133/133 siblings BANKED, 0 failures; R22 clean-fleet 136/136 byte-identical.** Metrics: distinct-code 39.1% (50,698 unique fns), instr 63.0%. **Opportunity map (`has_mid_jr` families):** 237 total (5,805 members / 5.68M ins) — 46 small mid/tiny (771 members, mechanical, same pipeline) + 191 substantial = the Fable5 cores (Task 7, paused). Committed. **NEXT: (a) R22 profiling/parallelization (Drew asked — check-all builds 136 binaries serially on a 32-core box); (b) the other 45 small jr families.**
- **2026-07-12 (session 3, §8 jtbl-rodata tooling — PoC PROVEN):** Built the overlay jtbl-rodata mechanism (cookbook §8a, the durable writeup). Findings: overlay jtbls form a contiguous `.rodata` island at the TAIL (between `.data` globals and a tiny remnant), not the EXE's central island. Mechanism (byte-identical, 2-step): (Step 1) carve a matched jr-function's jtbl out of `[data,tail]` into a dotted `[.rodata, <code-subseg>]` subseg (spimdisasm migrates it into the fn's `.s`) + `[data, tail2]`; parameterized **`tools/ld_interleave.py --section .<binary>`** (derives the symbol prefix; default `.main` = EXE byte-identical, backward-compat proven) places text→data(pre)→rodata→data(post)→bss — **build byte-identical with the fn still INCLUDE_ASM**. (Step 2) swap in the C body → **byte-identical** — the C-emitted jtbl lands exact. Wired into `make extract` via `<bin>_JTBL_INTERLEAVE` in `config/overlays.mk` + a `$(strip)`-guarded `ifneq` branch (gotcha caught: a trailing `#comment` on the `:=` left whitespace → the branch misfired on resident). **PoC target: `func_8012ACE0`** (25-ins single-jtbl jr-function, ov_SC01_077) — reconciled via `canon_sig_reconcile` (raw draft had `conflicting types`), banked **byte-identical `d19c9580`**, ov077 clean-rebuilds. Key P9 finding: **`func_80159C84`/`func_8015444C` (the 2 carried Fable5 bodies) are rtu_match FALSE-MATCHes** — their C jtbls are incomplete (52B vs 56B), so they never bank; rtu_match excludes the §8 rodata (confirms the checkpoint's "2 jtbl false-MATCH"). The maspsx "hang" scare was a truncated-experimental-file artifact — the real pipeline builds in ~1s. **NEXT: full R22 (in flight) → commit the PoC + tooling; then the ×134 automation** (generate the per-overlay carve + template the reconciled body per sibling).
- **2026-07-12 (session 3, TINY-BAND mechanical harvest — Task 8 continuation):** Regenerated the h_seq manifest from the mid-band-banked src (fleet 77.2% fn / 60.9% instr / 35.2% distinct — matches `commit:0530`), then ran `family_sweep.py --hseq --band tiny`. Dry-run sized it: 180 tiny matched-exemplar families / 23,592 staged member-drafts across 267 (overlay,split) groups (skips 1,184 no-matched-unit / 148 unresolved-imm / 117 STRUCT / 39 pinned). Gated run: **17,975 member-matches BANKED / 5,617 gate-rejected** (h_seq-collision false-templates — the whole-binary byte-gate G3/P9 refused every one; ~76% bank rate; per-group ~17/21 main + ~110–129/150 `_after`). 266 overlay `.c` files touched. **R22 clean-fleet (`make clean` + extract-all-136 + check-all) → 136/136, 0 failed.** dedup-check 1813 validated / 0 failed (registry untouched — hseq banks are per-overlay src, not ×134 registry). **Metrics: distinct-code 35.2→39.1% (50,571/84,996 unique fns), instr-weighted 60.9→62.9%.** The mechanical size-bands (substantial/mid/tiny) are now harvested; the remaining levers are the two harvest gaps (§8 jtbl-rodata, reconcile fn-ptr-extern). Committed (Drew pushes — R6).
- **2026-07-12 (session 2b, Fable5 batch-1 whole-binary reality):** **P9 correction:** the 2 Fable5 "cracks" (`func_80159C84`/`func_8015444C`) rtu_match-MATCH but FAIL the whole-binary gate — both are jr-functions and rtu_match doesn't verify the §8 jtbl rodata (decision-log). Two harvest gaps found: **§8 jtbl-rodata** (blocks all jr cracks incl. the Fable5 cores) + **reconcile data-extern** (D_801891B8-class, blocks ~15/21 no-jtbl triage cracks). Real whole-binary result: **6 no-jtbl reconcile-clean cracks bank = 729 members** (463 committed + **266 this commit**, func_8015CD20/8015C128 ×133). `func_80176218` (no-jtbl) still cracking = the clean non-jtbl Fable5 test. R22 deferred until it releases asm/.
- **2026-07-12 (session 2, resume after usage-limit interruption):** R22 confirmed the committed 463 reconcile-class banks **136/136**. Fable5 batch-1 results: **`func_80159C84` MATCHED** (337-ins 2-jtbl giant, pin-free; new cookbook idiom = gcc-2.7.2 postincrement pending-queue `(*(s32*)(p+0x238))++ >= K`); `func_8015444C` (reached 29-mismatch) + `func_80176218` (early) were cut off by the weekly limit → **re-launched** (444C resumes from its 29-mismatch partial). The interrupted reconcile-raw-19 harvest (260/1565, partial src) was **reverted (R22 discipline)** and **re-running clean** folding in func_80159C84. All background; process on completion → R22 → commit. **Fable5 batch-1 = the last batch until Drew re-approves (Drew, 2026-07-12).**
- **2026-07-11 (session 1, Task-8 validation slice — Drew-approved pre-window de-risk):** Ran reconcile→gate→template on the triage cracks. **Reconcile→bank WORKS:** raw 0/23 (§41 wall) → via `canon_sig_reconcile` v3.2 **4/15 banked into ov077** (`func_801506A4`/`8016A73C`/`80167540`/`80155800`, byte-identical). **Templating a reconciled body ×133 FAILS 0/4** — reconciled bodies are ov077-TU-specific (casts + collision-renames), need per-sibling re-reconcile (§41c). → **Task-8 prerequisite: port the h_norm `--reconcile` M2 path into `hseq_sweep`.** Kept the 4 ov077 banks. decision-log 2026-07-11 (R31). Paused before building the wiring per Drew.
- **2026-07-11 (session 1, Task 6 — DONE + paused):** Ultracode triage Workflow (119 agents, 0 err, 5.3M tok): m2c draft (+§8 jtbl) → `match_one` closeness → class + lever + seed. **cheap 29 (23 closeness-0) / permuter 29 / fable5 61.** Curriculum → `docs/phase26-triage.md`. Attempted to bank the 23 cracked "wins" into ov077 (Drew: "bank the wins but pause before task8") → **0/23 gate** — the isolation-MATCHes carry standalone types/Ghidra-sigs that hit the §41 def-side wall in the real TU (`redefinition of struct Obj` / `conflicting types`); banking needs the Task-8 `--reconcile` pass. Seeds preserved in `.run/phase26-seeds/` + `.run/ov077_bank/`. **PAUSED before Task 8 per Drew.** src pristine, ov077 green.
- **2026-07-11 (session 1, Task 5 — GO/NO-GO = GO):** Ran the real byte-gate on the substantial matched-exemplar band. Discovered + fixed the decl class (`remap_hseq.gather_externs` carries file-scope externs). **532 members banked**, R22 136/136 green, distinct 30.3→30.9% / instr 58.2→58.5%. Per-family: 3 tracker-miss PURE families bank 100% ×133 (399 byte-perfect free win); 9 type-using families → §41 reconcile (Task 8); 16 pinned → Task 7. Machinery byte-proven 100% correct on clean families → GO to scale. decision-log 2026-07-11 (R31). Committed.
- **2026-07-11 (session 1, Task 4):** Added `family_sweep --hseq` (additive `hseq_sweep()`, h_norm path byte-untouched): manifest-driven templating via `remap_hseq`, unique per-group verified-out, static `__asm__("$N"` pin guard (skips the ×1-only pinned cracks → Task 7). Dry-run (`--stage-only`): substantial band stages 1507 clean / 267 groups, 1643 correctly skipped as pinned (16/29 families pinned, incl. the decision-log-named ones). Drafts byte-correct by construction; whole-TU gate = Task 5. Committed.
- **2026-07-11 (session 1, Task 3):** Built the T2a imm engine (`imm_value`/`imm_map_tier1`/`remap_hseq`) — diff-driven Tier-1 literal swap with an asm-side ambiguity guard — + wired T2b cross-address self-rename. Tier-2 probe deferred (build-if-needed; byte-gate arbitrates). V3 (`.run/v3_imm.py`): 0 DIFF on all compilable pairs (5 MATCH), ambiguity guard + cross-address self-rename confirmed; comprehensive whole-TU gate validation is Task 5. Committed.
- **2026-07-11 (session 1, Task 2):** Built `tools/family_hseq.py` (full-frontier h_seq survey) + the shared word-diff classifier in `family_remap.py` (PURE/IMM/STRUCT, register-drift aware). Reproduces the fleet metrics + the 663/186/1.85M tail cross-check exactly; classification matches the Plan-agent table; 581 substantial target families / 3.22M templatable ins, 345 matched-sibling families / 1.14M ins = the zero-crack corpus. `docs/family-hseq.md` committed. Committed.
- **2026-07-11 (session 1, Task 1):** Extended `reloc_targets` for the add/addu indexed-global idiom (the "reach-1 tail" was largely this tracker blind spot, not unique code — decision-log + cookbook §40b). `symbol_map`/`remap` gained backward-compatible `to_addr` (cross-address T2b) + `imm_map` hook; sequential→single-pass substitution (fixes the latent chained-rename bug). norm_stream/h_norm untouched. V0 (22/22 regression, 15/15 fix vs splat .s) + V1 (160 pairs, 0 regressions) both green. Committed.
- **2026-07-11 (session 1, planning):** Phase Start (Tier 1, Fable5+Max+plan-mode). Megaplan analyzed; survey reproduced from sigs+src (R14) — fleet metrics match PhaseEnd_25 exactly; 186-not-986 substantial-family correction; #2 family is cross-address; 93 matched-sibling families found (0.51M ins). Tooling recon (Explore) + design pressure-test (Plan agent) → **the reloc-tracker blind-spot discovery** (addu-preserves-hi; 890×121 family is PURE reloc; 63-fam zero-crack corpus; sequential-substitution latent bug). Drew's gate-1 decisions: carried queue → end of phase; structural milestone. Plan approved; task list built (R28). Task 0 complete with this commit.