From 52a9f931fa005c6e802d464d8a5ba2f31f890acb Mon Sep 17 00:00:00 2001
From: Drew T <50529377+Druthulu@users.noreply.github.com>
Date: Mon, 24 Aug 2026 12:11:59 -0600
Subject: [PATCH] =?UTF-8?q?docs(S59):=20o0-path=20decision=20study=20?=
=?UTF-8?q?=E2=80=94=20per-population=20unlocks,=20first-compile=20-O0=20b?=
=?UTF-8?q?ank=20proof,=20cookbook=20=C2=A7261a=20reload=20grammar?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/cookbook-index.md | 10 +-
docs/matching-cookbook.md | 22 +++
docs/tool-designs/o0-path-s59.md | 288 +++++++++++++++++++++++++++++++
3 files changed, 316 insertions(+), 4 deletions(-)
create mode 100644 docs/tool-designs/o0-path-s59.md
diff --git a/docs/cookbook-index.md b/docs/cookbook-index.md
index 09ff735a3..73da9b005 100644
--- a/docs/cookbook-index.md
+++ b/docs/cookbook-index.md
@@ -2,7 +2,7 @@
> **Generated by `tools/cookbook_index.py` — do not hand-edit** (R33). Regenerate after adding a cookbook section.
>
-> `docs/matching-cookbook.md` is ~716 KB / 746 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
+> `docs/matching-cookbook.md` is ~716 KB / 747 sections. Grepping it blind is how three P30 wave-1 agents each "discovered" an idiom that was already written down. **Start here, then read the section.** A section appears under every symptom it addresses.
**How to use:** name what you SEE in the diff (a stolen delay slot, an extra `la`, a swapped register pair, a `conflicting types` error), find that symptom below, read those sections first. If nothing fits, THEN grind — and add a section when you win.
@@ -494,7 +494,7 @@
- **§256** — GOTOS IN THE TARGET'S BLOCK ORDER REPRODUCE SWITCH PLACEMENT WITHOUT SWITCH'S SIDE EFFECTS (P31 S58b) L24019
- **§222** — addendum (P31 S58b) — IF-CHAIN vs SWITCH: THREE MORE DISCRIMINATORS L24423
-### optimisation level (-O0/-O2) (14)
+### optimisation level (-O0/-O2) (15)
- **§6** — Per-module optimization mixing — the -O0 boot module (Phase 7) L246
- **Detecting** — the opt level (do this first) L254
@@ -510,6 +510,7 @@
- **§132** — The `JR-PAIR-IN-ONE-O0-OBJECT` "wall" was TWO instrument defects: a merged-double span the carve could not see, and a truncated object no rule deleted (P30 S29, `func_8013B83C` + `func_8013BD74`) L8570
- **§195-K** — At -O2 the §18 array-of-struct lever is a FRAME lever, not a length lever — but only when the N reads carry DISTINCT index expressions; with a SHARED index §18's +2-instruction residual is still alive at -O2 (the submitted "memory-loaded narrow index" precondition and unconditional length-neutrality are both falsified) L20234
- **§261** — THE -O0 ORACLE: DERIVE THE OPT LEVEL FROM THE TARGET, AND `$fp` IS NOT THE TELL (P31 S59) L24718
+- **§261a** — THE -O0 FRAME-RELOAD GRAMMAR: reload COUNT disambiguates the C spelling (P31 S59, byte-proven) L24744
### family propagation & sweeps (94)
@@ -1146,7 +1147,7 @@
- **§231** — addendum (P31 S58b) — FOUR MORE WAYS THE LISTING MISLEADS L24587
- **§232** — CROSS-CONFIRMED (P31 S58b) L24618
- **§260** — THE §154-A LEADING-ISLAND SPLIT: ONE CONFIG LINE, AND THE ISLAND PEELS FROM THE END (P31 S59, byte-proven) L24668
-- **§262** — A LANE'S YIELD IS ONLY A LANE FACT IF IT IS SIZE-MATCHED (P31 S59) L24744
+- **§262** — A LANE'S YIELD IS ONLY A LANE FACT IF IT IS SIZE-MATCHED (P31 S59) L24766
## All sections, in order
@@ -1896,4 +1897,5 @@
- **§259** — THE DISCARD LEDGER FOR THE aa–bg HARVEST (P31 S58b): WHAT WAS MINED AND REJECTED, AND WHY L24629
- **§260** — THE §154-A LEADING-ISLAND SPLIT: ONE CONFIG LINE, AND THE ISLAND PEELS FROM THE END (P31 S59, byte-proven) L24668
- **§261** — THE -O0 ORACLE: DERIVE THE OPT LEVEL FROM THE TARGET, AND `$fp` IS NOT THE TELL (P31 S59) L24718
-- **§262** — A LANE'S YIELD IS ONLY A LANE FACT IF IT IS SIZE-MATCHED (P31 S59) L24744
+- **§261a** — THE -O0 FRAME-RELOAD GRAMMAR: reload COUNT disambiguates the C spelling (P31 S59, byte-proven) L24744
+- **§262** — A LANE'S YIELD IS ONLY A LANE FACT IF IT IS SIZE-MATCHED (P31 S59) L24766
diff --git a/docs/matching-cookbook.md b/docs/matching-cookbook.md
index 900a533ae..b974f5d2e 100644
--- a/docs/matching-cookbook.md
+++ b/docs/matching-cookbook.md
@@ -24741,6 +24741,28 @@ perfect the body: the object's `CC1FLAGS` decide, and the Makefile's -O0 globs c
Of the 167, 51 are inside an -O0 object and **116 (14,148 ins) are stranded in -O2 subsegs**, so
`match_one` now says so on sight rather than letting an agent chase a body that can never land.
+### §261a — THE -O0 FRAME-RELOAD GRAMMAR: reload COUNT disambiguates the C spelling (P31 S59, byte-proven)
+
+`func_80184058` (131 ins, `ov_SC03_014_o0c`) banked on the FIRST compile — MATCH(131) then
+whole-binary BYTE-IDENTICAL — because at -O0 the number of frame reloads of a pointer is a
+fingerprint of the exact C spelling. Read it off the target before writing anything:
+
+* `p->f += k` (value unused) → **2** reloads of `p` (STORE base first, read base second), no copy.
+* `--p->f` / `++p->f` → **3** reloads (the FIRST is dead), an `addu rd,rs,$zero` copy after the
+ add, and — only when the value is used — `sll 16; sra 16` on the STORED register (no re-load).
+ So `if (--p->f == 0)` vs `p->f -= 1; if (p->f == 0)` (re-loads the field) vs `p->f -= 1;`
+ (2 reloads, no copy) are all distinguishable from the asm alone.
+* s16 fields: `lh` at a plain read, but `lhu` inside a read-modify-write.
+* Overlapping s32/s16 (a 16.16 accumulator at 0xE0 whose high half is read as the s16 at 0xE2):
+ spell the wide access through a SECOND struct view and cast the pointer —
+ `((Ent_fx *)p)->unkE0 += 0x5CCCC;` — the cast is free at -O0; no union needed.
+* §127a compounded: the decisive spellings (the call-arg marshaling, `++p->unk02`) were lifted
+ VERBATIM from banked siblings in the same `_o0*` TU. Read the TU's banked bodies first, always.
+
+With the §261 auto-oracle + this grammar, an -O0 function is STRICTLY easier than -O2 of the same
+size: no scheduling, no regalloc steering, no permuter — every miss is a spelling miss, and the
+spelling is enumerable from the reload count.
+
## §262 — A LANE'S YIELD IS ONLY A LANE FACT IF IT IS SIZE-MATCHED (P31 S59)
The `tells` lane was removed from the drafting rotation on four waves that gated 3–6 of ~56 drafts.
diff --git a/docs/tool-designs/o0-path-s59.md b/docs/tool-designs/o0-path-s59.md
new file mode 100644
index 000000000..718b00cb6
--- /dev/null
+++ b/docs/tool-designs/o0-path-s59.md
@@ -0,0 +1,288 @@
+# The -O0 path — per-population bankability, the byte-proven crack, and the ranked plan (P31 S59, 2026-08-24)
+
+**Provenance:** S59 subagent task over the S59 census (167 prologue-carrying functions; 51 covered /
+116 stranded / 14,148 stranded ins). Everything below is anchored to a file read or a command run
+this session; the one build allowance was spent on the gate that BANKED `func_80184058` (§3).
+
+**Headline results:**
+1. `func_80184058` (131 ins, `ov_SC03_014_o0c`) went **first-compile MATCH → whole-binary
+ BYTE-IDENTICAL → committed** (`commit:2659`). The -O0 idiom set exists, transfers from banked
+ siblings, and one-shots without iteration. Q3 is answered YES with bytes.
+2. **md_MAIN_011 needs NO carve at all.** Its entire code subseg (0x7C..0x4400 = 17,284 B =
+ 4,321 ins) is exactly the 21 stranded -O0 functions, and `src/md_MAIN_011/md_MAIN_011.c` is
+ INCLUDE_ASM-only. One boot-style Makefile line unlocks 31% of the stranded mass. The ox study's
+ "requires a ≥3-object re-carve" claim is wrong for this module.
+3. **47.6% of the stranded mass (6,730 ins / 58 fns) needs zero drafting** — the bodies already
+ exist (ov_SC01_077 cluster exemplars 16/16 matched; the whale shared header; the T85
+ `func_801457A4` exemplar). Those need only carve+remap mechanics.
+4. The §18-P29 wall is **sequencing-avoidable**: `match_one` iterates stranded functions against
+ their existing `.s` TODAY (proven in §3 — no carve needed to reach MATCH), so every carve can
+ land **populated** (no INCLUDE_ASM in the new -O0 object) — the exact shape the P30 ×137 `_o0c`
+ rollout used to beat the wall, vs the 1/4 record of the stub-carrying P29 carve.
+
+---
+
+## 1. The census, function-level (verify: `.run/s59_o0/census.py`)
+
+Denominators: 14,400 `.s` under `asm/`; 166 carry the -O0 prologue at `glabel`+8, +1 (`boot/start.s`,
+-O0 by subseg, no ordinary prologue) = 167. Covered = subseg is an -O0 object (`boot`, `*_o0*`):
+50 fns / 2,299 ins (+start). Stranded = 116 fns (my ins counter says 14,130 vs the census's 14,148 —
+a <0.2% counting-convention delta on the same file set; immaterial).
+
+Both md runs close arithmetically gap-free (every function's end == the next's start), so **neither
+contains a matched -O2 island**:
+
+* md_MAIN_011: one contiguous run 0x800CEE74..0x800D31F8 — and it is the WHOLE code subseg.
+* md_MAIN_003: one contiguous run 0x800D0100..0x800D1E18 (0x1308..0x3020 in-file), with genuine
+ -O2 stubs before (0xD8..0x1308, incl. the matched `func_800CEED0` dispatch) and after
+ (0x3020..0x477C). 29 stubs total in the TU, 16 of them -O0.
+* SC03_118/119's run 0x80183178..0x801838A4 is 10 contiguous fns inside `_jr_8017FB84`
+ (0x57A2C..0x5E274). **All 58 open stubs of that subseg are raw-word IDENTICAL between 118 and
+ 119** (relocation immediates included) — a byte-twin pair: draft once, bank twice, same symbols.
+
+## 2. Per-sub-population: why unbankable, and the minimum unlock (Q1)
+
+| population | fns / ins | why it cannot bank | minimum unlock | wall exposure |
+|---|---|---|---|---|
+| **md_MAIN_011** | 21 / 4,321 | object compiled -O2; no Makefile glob matches `src/md_*/` | **one Makefile line** (boot-style whole-object override — §6 shape, no splat change, no carve; byte-neutral on a stub-only object, gate it anyway) + the oracle-coupling fixes in §7.3 | **NONE** — nothing is re-disassembled |
+| **md_MAIN_003** | 16 / 1,862 | same, but the module mixes -O2 stubs + 1 matched fn around the run | `o0_subsplit md_MAIN_003 --lo 0x800D0100 --hi 0x800D1E18` (pre/-O0/post; K=0 islands inside) + an md Makefile glob + byte-neutral gate. **Sequence: draft all 16 to MATCH first** (works today), then carve POPULATED | dice-roll if carved with stubs (precedents §8); ~zero if populated |
+| **`*_jr_801380E0` ×3** (SC02_037, MAIN_012, SC03_107) | 48 / 3,867 | the 16-fn cluster (0x8013B568..0x8013C98C) never got the P30 `_o0c` carve in these 3 — it sits whole inside their `jr_801380E0` subseg (0xFF88..0x171F8) | o0_subsplit at [0x13410,0x14834) per overlay + **populate all 16 from the ov077 exemplars in the same commit** (`ov_SC01_077_o0.c` has 16/16 matched; per-overlay data addrs via the existing remap machinery; C0F8/C414 need the §132 `tables=+0x0,+0x70` spec like the 137) | avoided by populate-at-carve (the ×137 precedent) |
+| **`*_jr_8013F350` ×3** (same three) | 6 / 2,547 | the whale (770) + `func_801457A4` (79) sit inside `jr_8013F350`; these 3 never got `_o0b` | carve [0x1CA44,0x1D64C) as a **whale-shape** file (`#include "../shared/func_80144B9C.h"`, zero stubs) + append the T85 `func_801457A4` remap + stub-drop | **NONE** — the whale shape never hits it (§18-P29's own finding) |
+| **`*_jr_8017FB84` ×2** (SC03_118/119) | 20 / 918 | fresh -O0 region, no carve, no exemplars | draft the 10 distinct fns to MATCH (today, vs the stranded `.s`), then carve [0x5B020,0x5B74C) populated, both twins | ~zero once populated; twins share bytes so one carve spec serves both |
+| **`*_jr_801457A4` ×4** (SC07_006/007/010/011) | 4 / 316 | NOT a carve problem: each already has a whale-ending -O0 object at 0x1D64C (`_o0d` in 006/007/011, `_o0c` in 010) — `rollout_o0.py` just hardcodes the `_o0b` NAME and lists SC07 out-of-scope | **~15-line rollout_o0.py fix**: resolve the whale file by content (the shared-header include), drop `SC07_NO_O0B`; then the proven append+stub-drop (no splat change at all) | **NONE** |
+| **`main`/`800`** | 1 / 299 | `func_8002C410` is a lone -O0 island inside the EXE's `800` object (0x800123F0..0x8003A444) | draft to MATCH now (oracle works); banking needs a 3-way 800 carve (§18 mid-blob law; the EXE already tolerates subseg splits — `800b`..`800b_6` are precedent) + a rule for the new object | carve-with-0-stubs-in-the-o0-object if drafted first; still the crown-jewel binary — do it LAST, manually |
+
+Key asymmetry the table encodes: **the `md_*` rows are Makefile/carve problems; the `ov_*` rows are
+almost entirely REMAP problems** (bodies exist), except 118/119 which is a small drafting problem.
+
+## 3. Can we write -O0-matching C? YES — byte-proven this session (Q3)
+
+Target: `func_80184058` (131 ins, open in both `ov_SC03_014_o0c` and `ov_SC03_015_o0c`). Method:
+read the banked siblings in the same TU first (§127a), lift their proven spellings, draft, iterate
+with the fixed oracle. Result — **zero iterations needed**:
+
+```
+$ .venv/bin/python tools/match_one.py func_80184058 --c .run/s59_o0/func_80184058.c \
+ --asm-subdir asm/ov_SC03_014/nonmatchings/ov_SC03_014_o0c
+match_one: compiling at -O0 (frame-pointer prologue in the target; pass --no-auto-o0 to override)
+MATCH (131 ins) func_80184058
+```
+
+then spliced into the TU and gated under the binary's lock:
+
+```
+[ OK ] build/ov_SC03_014/ov_SC03_014
+ sha1 d84b01a2bd4c712e1127707f5cd2007d79f4afb0 == config/check.ov_SC03_014.sha (BYTE-IDENTICAL)
+```
+
+Committed as `commit:2659` (R42). The identical stub remains in `ov_SC03_015_o0c.c` — the same body
+banks it (byte-twin), one gate away; left for the campaign since the task's one-build allowance was
+spent.
+
+The C that matched (also at `.run/s59_o0/func_80184058.c`):
+
+```c
+typedef struct { /* 32-bit view: unkE0 is a 16.16 accumulator whose HIGH half */
+ s16 unk00, unk02; /* is the s16 unkE2 the rest of the function reads */
+ u8 pad04[0xD8];
+ s16 unkDC, unkDE;
+ s32 unkE0;
+} Ent58_fx;
+typedef struct {
+ s16 unk00, unk02;
+ u8 pad04[0xD8];
+ s16 unkDC, unkDE, unkE0, unkE2, unkE4, unkE6, unkE8, unkEA;
+} Ent_80184058;
+
+void func_80184058(Ent_80184058 *p) {
+ func_8017DF84(&D_801EAFD0, D_8018F858[p->unkE4], p->unkDC, p->unkE2);
+ func_80184354();
+ if (p->unkEA == 0) {
+ ((Ent58_fx *)p)->unkE0 += 0x5CCCC;
+ } else {
+ if (--p->unkEA == 0) func_8002D4C8(0x81E, 0);
+ }
+ if (--p->unkE8 == 0) {
+ func_8013C9C4(&D_8018BCC8);
+ p->unkE8 = (D_800B99DC & 7) + 3;
+ }
+ if (p->unkE2 >= 0x259) {
+ p->unkE2 = 0;
+ D_801270C8 = 2;
+ p->unkE4 = 0;
+ func_8013373C(1);
+ func_8002D4C8(4, 0x81E);
+ ++p->unk02;
+ }
+ p->unkDC += 8;
+}
+```
+
+**What made it one-shot — the -O0 frame-reload grammar** (read straight off the target and confirmed
+by the sibling's banked bytes; promoted to cookbook §261a):
+
+* `p->f += k` (value unused) → **2** frame reloads of `p` (store-base first, read-base second), no
+ register copy.
+* `--p->f` / `++p->f` → **3** reloads (the first one DEAD), an `addu rd,rs,$zero` copy after the
+ add, and — only if the value is used — `sll 16; sra 16` sign-extension of the STORED register (no
+ re-load). So `if (--p->f == 0)` is distinguishable from `p->f -= 1; if (p->f == 0)` (the latter
+ re-loads) and from `p->f -= 1;` (2 reloads, no copy) **by reload count alone**.
+* s16 fields load `lh` at plain reads but `lhu` inside read-modify-write.
+* An overlapping s32/s16 view (16.16 fixed point) is spelled with a second struct view and a free
+ pointer cast — no union needed, no extra code at -O0.
+* The verdict §127 predicted holds: plain C maps 1:1; no pins, no scheduling barriers, no permuter.
+ **-O0 is strictly easier than -O2 per instruction** — the entire difficulty is (a) knowing the
+ reload grammar and (b) being compiled at the right level, which is what the S59 oracle fix bought.
+
+Caveat quoted with its denominator: this is **n=1** at 131 ins with a same-TU sibling to crib from.
+The §127 P30 wave (15 targets, n=15) found agents independently re-deriving the idioms and still
+converging. The population's big tail (7 fns ≥ ~400 -O0-ins in md_MAIN_011/003) is untested — but
+-O0 ins are ~2× inflated, so 575 -O0-ins ≈ a ~280-ins -O2 function without the regalloc/schedule
+search space that makes 200+ collapse in §262's table.
+
+## 4. Are the 51 covered functions reachable? (Q2)
+
+The 51 = 48 boot fns (2,037 ins, incl. `main` at 509) + `func_80184058` ×2 (now ×1 — 014 banked
+today) + `start` (crt0, hand-asm, realistically permanent INCLUDE_ASM — honest denominator is **50
+draftable**).
+
+* **`rollout_o0.py` is NOT the vehicle** for these — it is a remap tool. Its full `--all-o0` dry run
+ today: **46 attempts, 0 reachable** — `{'no-o0b': 42}` (the ×3 group: no -O0 object exists yet =
+ needs the U3 carve) + `{'out-of-scope-sc07': 4}` (the U2 name-resolution fix). Both blockers are
+ exactly two items of the plan below; after U2+U3 it banks 46 members mechanically.
+* **The vehicle for the 50 is ordinary drafting with the fixed oracle.** Nothing draws them today
+ because the atlas excludes the `o0` LEVER from drafting lanes (`build_wave_atlas.py:38`) — a rule
+ from the era when the oracle compiled everything -O2. The new `_o0_unbankable` filter already
+ separates stranded from covered, so re-admitting the lever exposes only bankable targets.
+* **Boot's 48 are main-binary work**: draw with `--only-bins main` (a supported flow per the atlas's
+ own help text) and gate through `gate_main.py`. This week: one mini-wave (48 drafts vs the boot
+ stubs, sizes 8..509) + gate_main per bank; plus the one-gate 015 twin bank.
+
+## 5. Serial vs wave (Q4)
+
+**Recommendation: a 3-5 function serial warm-up, then wave the rest — but the real answer is that
+most of the mass should never see a drafting agent at all.**
+
+* 58 fns / 6,730 ins (47.6% of stranded) are remap-only → **tooling lane, zero drafts** (U2+U3).
+* 48 distinct fns / 6,941 distinct ins need drafts (md_011 21, md_003 16, 118-twins 10, main 1;
+ banked value 7,418 ins with the 119 twin).
+* Evidence for wave-readiness: my n=1 first-compile at 131 ins; §127a's sibling-transfer;
+ the grammar now being IN the cookbook (§261a) rather than re-derived per agent (§127's measured
+ failure mode: 12 of 15 agents paid to rediscover a source-comment lever).
+* Evidence for serial-first: the §127 wave predates §261a and the oracle fix, so no honest wave
+ yield number exists for the current toolchain; and md_MAIN_011's 7 fat functions (397-575
+ -O0-ins) are exactly the band where a wrong idiom costs the most iterations.
+* Cost shape (units are drafts and gates, not dollars — no calibrated $/draft for -O0 exists yet):
+ serial warm-up = 3-5 drafts (pick md_MAIN_011's 8-35-ins tail: `func_800D0430` 8,
+ `func_800D04C4` 12, `func_800D0828` 12, `func_800D03F8` 14, `func_800CEE74` 35) against
+ `match_one` only — **no build, no gate, no carve needed to learn the answer**. If ≥4/5 MATCH
+ within a few iterations each (my prior after today: likely), wave the remaining ~43 with the
+ subagent ladder on EFFECTIVE size (-O0 ins ÷ 2): Haiku ≲100 -O0-ins, Sonnet 100-240, Opus above.
+ If the warm-up stalls instead, the grammar has a hole — feed it to §261a and re-probe before
+ waving (the flywheel, not a bigger wave).
+
+## 6. Is it worth it at all? (Q5)
+
+**Yes — with U1-U3 unconditionally; U4-U5 as ordinary drafting work; U7 optional.** The numbers:
+
+* Total addressable: 14,148 stranded + 2,339 covered = **16,487 ins ≈ 3.3% of the ~499k-ins
+ frontier** — 2.5× the ox study's estimate (its census undercounted, 6,564).
+* Of that, **11,051 ins (67%) require zero or one-line infrastructure and zero drafting**
+ (md_MAIN_011's 4,321 behind one Makefile line + 6,730 remap-only) — the cheapest
+ instruction-per-effort mass currently identified anywhere on the frontier.
+* The wall's actual record, quoted with denominators: carve-with-stubs = 1/4 clean (P29
+ `rollout_o0_cluster`, SC07) but 2/2 clean (P30 `o0_subsplit`, SC03_014/015); carve-populated =
+ **137/137 clean** (the P30 fleet `_o0c` rollout — 136/137 twice only for the §132a jtbl
+ role-name bug, since fixed). Draft-first sequencing converts every remaining carve into the
+ 137/137 shape. The "documented image-corruption wall" is real but it is a *shape* to avoid, not
+ a barrier — and the failure mode is a refused gate + a yaml revert, never a corrupted commit.
+* Opportunity cost: the campaign's default lane banks ~44.6% of drafts at full band (§262). The -O0
+ drafting pool at 48 distinct fns is one wave's worth of cards; the remap pool competes with
+ nothing (different lane). This does not displace jtbl-lane-scale work; it retires a whole CLASS
+ (every future -O0 mis-draw, every "o0-in-an-O2-object" skip) plus two of the fleet's last
+ never-touched binaries.
+
+**Not worth doing:** re-opening the deferred ~1,233-member legacy harvest framing (it conflated this
+population with per-overlay re-derivation the remap machinery now does), and any md-module carve
+BEFORE its bodies are matched.
+
+## 7. The ranked plan, with wall risks named
+
+Order is by instructions-per-unit-risk; each step is independently gate-protected and revertible.
+
+1. **U1 — md_MAIN_011 Makefile rule** (unlocks 21 fns / 4,321 ins for drafting; zero risk).
+ Proposed diff (after the `O0_CLUSTER_OBJS` block, Makefile ~:726):
+ ```make
+ # S59: md_MAIN_011's entire code subseg is the 21-fn -O0 run 0x800CEE74..0x800D31F8 (census
+ # .run/s59_o0/): whole-object override, the boot precedent. Byte-neutral while stub-only (§6).
+ build/src/md_MAIN_011/md_MAIN_011.o: CC1FLAGS := -quiet -O0 -G0 -mips1 -mcpu=3000 -mgas -msoft-float -fgnu-linker
+ ```
+ Gate `md_MAIN_011` once to prove byte-neutrality (§6's verified precedent, but prove it).
+ `corpus.o0_sources()` parses explicit rules and picks this up automatically.
+2. **U2 — rollout_o0.py SC07 fix** (4 fns / 316 ins, zero drafting, zero splat change). Replace the
+ `o0b = .../_o0b.c` path + `SC07_NO_O0B` skip with content resolution:
+ ```python
+ def whale_file_of(ov):
+ """The overlay's -O0 object ending at 0x801457A4 = the file whose tail includes the
+ whale's shared header (letter drifts: _o0b fleet, _o0c SC07_010, _o0d SC07_006/007/011)."""
+ for p in sorted(glob.glob(os.path.join(REPO, f"src/{ov}/{ov}_o0*.c"))):
+ if 'shared/func_80144B9C.h' in open(p).read():
+ return p
+ return None
+ ```
+ and in `attempt()`: `o0b = whale_file_of(ov)` (delete the SC07 branch). The append+stub-drop
+ mechanics are unchanged (T85, 130/130).
+3. **U3 — the ×3 group carve+remap** (54 fns / 6,414 ins, zero drafting). Per overlay ×3:
+ `o0_subsplit --lo 0x8013B568 --hi 0x8013C98C` **plus, in the same commit, populate all 16
+ bodies** by remapping the ov077 exemplars (the machinery `rollout_o0`/`family_remap` already
+ keys these families — the dry run's 42 `no-o0b` rows ARE this list) with the §132
+ `tables=+0x0,+0x70` spec on the new `_o0X` rodata carve; then the whale: carve
+ [0x80144B9C,0x801457A4) whale-shape + U2's append for `func_801457A4`. Gate per overlay.
+ Risk: populate-at-carve = the 137/137 shape; pre/post jr stubs remain, ×137-precedented. If a
+ gate still refuses, revert the yaml (cheap), pin the drifted `D_*` in
+ `config/symbols..txt`, retry — the never-yet-tried surgical counter to §18-P29.
+4. **U4 — the 50 covered** (2,037+131 ins): re-admit the `o0` lever for covered targets in wave
+ draws; one `--only-bins main` mini-wave for boot's 48 through `gate_main`; one gate banks the
+ `ov_SC03_015` twin with today's body.
+5. **U5 — SC03_118/119** (20 fns / 918 ins): serial-or-wave draft the 10 distinct fns to MATCH
+ against the stranded `.s` (works today), then `o0_subsplit` both twins at
+ [0x80183178,0x801838A4) populated. One carve spec serves both (byte-twins).
+6. **U6 — md_MAIN_003** (16 fns / 1,862 ins): draft all 16 to MATCH first, then
+ `o0_subsplit md_MAIN_003 --lo 0x800D0100 --hi 0x800D1E18` populated + extend the md Makefile
+ coverage:
+ ```make
+ MD_O0_OBJS := $(patsubst src/%.c,build/src/%.o,$(wildcard src/md_*/md_*_o0*.c))
+ $(MD_O0_OBJS): CC1FLAGS := -quiet -O0 -G0 -mips1 -mcpu=3000 -mgas -msoft-float -fgnu-linker
+ ```
+ Pre-flight: verify `jr_isolate_all.plan()` on a jr-less md module (expected fine — it reads the
+ yaml generically — but assert before trusting; R43).
+7. **U7 — main/800 `func_8002C410`** (1 fn / 299 ins): draft to MATCH now and stage the body; carve
+ the `800` subseg 3-way only in a dedicated main-surgery window (the `800b_N` splits are
+ precedent, §18's mid-blob law was learned on this very object). Smallest payoff, biggest
+ binary — last, manual, or accept matched-unbanked indefinitely.
+
+**Oracle-coupling fixes to land WITH U1** (else the 21 stay invisible): three helpers key -O0-ness
+on the subseg NAME (`'_o0' in seg or seg == 'boot'`) — `match_one`'s subseg oracle,
+`build_wave_atlas._o0_unbankable`, `test_o0_detect.sub_is_o0`. U1's object keeps its plain name, so
+they must derive from `corpus.o0_sources()` (the Makefile ground truth) instead of the name. Until
+then the prologue oracle still auto-selects -O0 for all 21 (every one carries the tell), but the
+atlas would keep refusing to draw them and `match_one` would mis-warn "cannot bank".
+
+## 8. Appendix — the §18-P29 wall, restated precisely
+
+Mechanism (decision-log 2026-07-16, Arm A): 3-way splitting a code subseg and re-running `make
+extract` makes spimdisasm re-infer data auto-symbols inside the SPLIT subsegs; when INCLUDE_ASM
+stubs remain **in the new -O0 object**, some `%lo` refs re-bind to a different auto-symbol (+0x20),
+and the reassembled stubs shift 34% of the image. The discriminating variable across all recorded
+attempts is stubs-in-the-new-object:
+
+| attempt | shape | record |
+|---|---|---|
+| P29 `rollout_o0_cluster` SC07 ×4 | stubs left in `_o0` | 1/4 clean (010 only) |
+| P30 `o0_subsplit` SC03_014/015 `_o0c` | stubs left in `_o0c` | 2/2 clean (dice-roll won) |
+| P30 fleet `_o0c` rollout ×137 | **populated at carve** | 137/137 byte-neutral |
+| whale `_o0b` ×134 | populated (shared header) | never hit the wall |
+
+So: populate-at-carve when bodies exist (U3), draft-first to make bodies exist (U5/U6), and the
+untried surgical fallback (pin the drifted symbol in `config/symbols..txt`) if a roll is ever
+lost anyway. The wall gates nothing in this plan; it only orders it.