docs(phase-30): SS131 the jtbl OVER-SPAN + checkpoint — #9 SOLVED, JTBL-CARVE-BREAKS-BYTES retired

SS131: `sltiu N` is ground truth in BOTH directions. jtbl_range already EXTENDS a span the
dlabel cut short and WARNS when a span is shorter than the bound, but had no clamp for a
span too LONG for a NON-ZERO reason — and the trailing trim only removes ZERO words, so
ordinary data that spimdisasm ran into the dlabel slipped through and under-filled the piece.

Records the reusable FINGERPRINT of an under-fill, because it does not look like codegen:
hundreds of 1-byte diffs spread over most of the overlay, ~95% at byte 0 (mod 4) = the low
byte of a 16-bit immediate, every one changing by exactly -4. Bucket differing bytes by
offset%4 and decode a few words; uniform small deltas in the immediate field mean LAYOUT,
not codegen. (Measured: 812 of 853 at pos 0 mod 4, all -4.)

The clamp's authorization matches the extension path exactly: unambiguous sltiu bound only,
and REFUSE LOUDLY if any surplus word is a plausible code address.

This was the single instrument failure that survived SS125's retraction round — the one case
where "the tool is broken" was actually true. Now fixed, with the 710-ins behemoth banked.
This commit is contained in:
Drew T
2026-07-31 20:05:44 -06:00
parent 0958120006
commit b58fd82068
6 changed files with 927 additions and 886 deletions
-1
View File
@@ -1275,7 +1275,6 @@
{"ts": "2026-07-21 13:34:42", "addr": null, "name": "func_8017EF1C", "reach": null, "klass": null, "nins": null, "status": "near", "closeness": 16, "where_stuck": "residual: 16 mismatch", "best_draft": ".run/backlog_drafts/func_8017EF1C.c", "binary": "ov_SC03_007", "source": "grinder", "residual": [[1, "afb00010 sw\ts0,16(sp)", "afbf0010 sw $ra, 0x10($sp)"], [2, "afbf0014 sw\tra,20(sp)", "0c00a46d jal func_800291B4"], [4, "00808021 move\ts0,a0", "304300ff andi $v1, $v0, 0xFF"], [5, "92020214 lbu\tv0,532(s0)", "2402000a addiu $v0, $zero, 0xA"], [6, "02002021 move\ta0,s0", "10620005 beq $v1, $v0, .L8017EF4C"], [7, "24420001 addiu\tv0,v0,1", "2402000c addiu $v0, $zero, 0xC"], [9, "a2020214 sb\tv0,532(s0)", "2402000b addiu $v0, $zero, 0xB"], [10, "8fbf0014 lw\tra,20(sp)", "14620003 bne $v1, $v0, .L8017EF54"], [11, "8fb00010 lw\ts0,16(sp)", "3862000d xori $v0, $v1, 0xD"], [12, "27bd0018 addiu\tsp,sp,24", "0805fbd6 j .L8017EF58"], [13, "03e00008 jr\tra", "24020001 addiu $v0, $zero, 0x1"], [14, "00000000 nop", "2c420001 sltiu $v0, $v0, 0x1"], [15, "--", "8fbf0010 lw $ra, 0x10($sp)"], [16, "--", "27bd0018 addiu $sp, $sp, 0x18"], [17, "--", "03e00008 jr $ra"], [18, "--", "00000000 nop"]], "passes_tried": null}
{"ts": "2026-07-21 13:37:27", "addr": null, "name": "func_8017E230", "reach": null, "klass": null, "nins": null, "status": "near", "closeness": 37, "where_stuck": "residual: 37 mismatch", "best_draft": ".run/backlog_drafts/func_8017E230.c", "binary": "ov_SC04_015", "source": "grinder", "residual": [[0, "27bdffe0 addiu\tsp,sp,-32", "27bdffe8 addiu $sp, $sp, -0x18"], [1, "afb00018 sw\ts0,24(sp)", "afb00010 sw $s0, 0x10($sp)"], [2, "00808021 move\ts0,a0", "afbf0014 sw $ra, 0x14($sp)"], [3, "afbf001c sw\tra,28(sp)", "0c04b06e jal func_8012C1B8"], [5, "260500a0 addiu\ta1,s0,160", "14400003 bnez $v0, .L8017E254"], [7, "02002021 move\ta0,s0", "0c04b2b9 jal func_8012CAE4"], [8, "8fbf001c lw\tra,28(sp)", "02002021 addu $a0, $s0, $zero"], [9, "8fb00018 lw\ts0,24(sp)", "8e040020 lw $a0, 0x20($s0)"], [10, "27bd0020 addiu\tsp,sp,32", "3c05801c lui $a1, %hi(D_801C30A4)"], [11, "03e00008 jr\tra", "24a530a4 addiu $a1, $a1, %lo(D_801C30A4)"], [12, "00000000 nop", "0c007085 jal func_8001C214"], [13, "--", "00000000 nop"], [14, "--", "0c0603ff jal func_80180FFC"], [15, "--", "02002021 addu $a0, $s0, $zero"], [16, "--", "02002021 addu $a0, $s0, $zero"], [17, "--", "3c058019 lui $a1, %hi(D_80188324)"], [18, "--", "24a58324 addiu $a1, $a1, %lo(D_80188324)"], [19, "--", "8e030068 lw $v1, 0x68($s0)"], [20, "--", "24020001 addiu $v0, $zero, 0x1"], [21, "--", "a6020002 sh $v0, 0x2($s0)"], [22, "--", "24027fff addiu $v0, $zero, 0x7FFF"], [23, "--", "a6000034 sh $zero, 0x34($s0)"], [24, "--", "0c04ba38 jal func_8012E8E0"], [25, "--", "a462000c sh $v0, 0xC($v1)"]], "passes_tried": null}
{"ts": "2026-07-21 19:42:42", "addr": "0x80135260", "name": "func_80135260", "reach": 1, "klass": "other", "nins": 136, "status": "near", "closeness": 5, "where_stuck": "none \u2014 MATCH", "best_draft": ".run/backlog_drafts/func_80135260.c", "binary": "ov_SC06_018", "source": "t5wave", "residual": [[76, "90840000 lbu\ta0,0(a0)", "8c843b68 lw $a0, %lo(D_80193B68)($a0)"], [78, "90c60000 lbu\ta2,0(a2)", "8cc63b64 lw $a2, %lo(D_80193B64)($a2)"], [82, "90a50000 lbu\ta1,0(a1)", "8ca53b70 lw $a1, %lo(D_80193B70)($a1)"], [102, "90840000 lbu\ta0,0(a0)", "8c843b64 lw $a0, %lo(D_80193B64)($a0)"], [104, "90c60000 lbu\ta2,0(a2)", "8cc63b68 lw $a2, %lo(D_80193B68)($a2)"]], "passes_tried": null}
{"ts": "2026-07-21 19:42:42", "addr": null, "name": "func_80191C50", "reach": null, "klass": "schedule", "nins": null, "status": "near", "closeness": 9, "where_stuck": "close=9 \u2014 only the case-7 sp20[] setup window (0x80192380..0x801923A4): gcc's list scheduler picks the D_80126B62 lui 2nd (its extra `addiu -0x38` gives that chain +1 priority) where the target picks D_80126B66 2nd (LUID/program order); everything else (710/710 ins, frame 0x40, $s0/$s1, jtbl, 3 entity loops, 8 sync blocks, cross-jumped L4AC tail) is byte-identical.", "best_draft": ".run/backlog_drafts/func_80191C50.c", "binary": "ov_SC06_018", "source": "t5wave", "residual": [[460, "3c030000 lui\tv1,0x0", "3c028012 lui $v0, %hi(D_80126B5E)"], [461, "94630000 lhu\tv1,0(v1)", "94426b5e lhu $v0, %lo(D_80126B5E)($v0)"], [462, "3c020000 lui\tv0,0x0", "3c038012 lui $v1, %hi(D_80126B66)"], [463, "94420000 lhu\tv0,0(v0)", "94636b66 lhu $v1, %lo(D_80126B66)($v1)"], [464, "3c040000 lui\ta0,0x0", "a7a20020 sh $v0, 0x20($sp)"], [465, "94840000 lhu\ta0,0(a0)", "3c028012 lui $v0, %hi(D_80126B62)"], [466, "2442ffc8 addiu\tv0,v0,-56", "94426b62 lhu $v0, %lo(D_80126B62)($v0)"], [467, "a7a30020 sh\tv1,32(sp)", "a7a30024 sh $v1, 0x24($sp)"], [468, "a7a40024 sh\ta0,36(sp)", "2442ffc8 addiu $v0, $v0, -0x38"]], "passes_tried": null}
{"ts": "2026-07-22 21:32:38", "addr": null, "name": "func_8018457C", "reach": null, "klass": "regalloc-order", "nins": null, "status": "failed", "closeness": null, "where_stuck": "none \u2014 MATCH (160 ins). case1-tail needed a $a0 pin on the state temp", "best_draft": ".run/backlog_drafts/func_8018457C.c", "binary": "ov_SC06_018", "source": "worker", "residual": null, "passes_tried": null}
{"ts": "2026-07-22 21:32:39", "addr": null, "name": "func_80187DD0", "reach": null, "klass": "regalloc-order", "nins": null, "status": "near", "closeness": 0, "where_stuck": "none \u2014 MATCH (174 ins). Levers: obj = *(*(b+0x20)+0x20) reads via b not a (store side uses a);", "best_draft": ".run/backlog_drafts/func_80187DD0.c", "binary": "ov_SC06_018", "source": "worker", "residual": null, "passes_tried": null}
{"ts": "2026-07-22 21:32:39", "addr": null, "name": "func_801886B0", "reach": null, "klass": "struct", "nins": null, "status": "near", "closeness": 0, "where_stuck": "none \u2014 MATCH (276 ins, relocation-masked)", "best_draft": ".run/backlog_drafts/func_801886B0.c", "binary": "ov_SC06_018", "source": "worker", "residual": null, "passes_tried": null}
+870 -871
View File
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -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 / 350 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 / 351 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.
@@ -219,7 +219,7 @@
- **§3-Do** — NOT "strip the duplicate typedef" — it breaks the extern that uses it <sub>L8030</sub>
- **§121** — Synthesise externs for macro-DEFINED callees from the macro's own definition head (Phase 29 T95) <sub>L8054</sub>
### jump tables & switches (22)
### jump tables & switches (23)
- **§8** — rodata island (compiler jump tables) — the `.data→.rodata→.data` sandwich (Phase 7) <sub>L320</sub>
- **§8a** — rodata island in a flat OVERLAY — the tail sandwich, per matched jr-function (Phase 26 — PoC PROVEN) <sub>L342</sub>
@@ -243,6 +243,7 @@
- **§129a** — the target instruction count is INFLATED after a carve <sub>L8434</sub>
- **§129b** — never commit a carve whose owner is still a stub (it strands the carve) <sub>L8455</sub>
- **§130** — An INCREMENTAL build can report BYTE-IDENTICAL for a change the CLEAN build cannot even LINK (P30 S28, the jr pair) <sub>L8479</sub>
- **§131** — The jtbl OVER-SPAN: `sltiu N` is ground truth in BOTH directions, and the zero-word rule only guards one (P30 S28, `func_80191C50`) <sub>L8526</sub>
### optimisation level (-O0/-O2) (11)
@@ -951,3 +952,4 @@
- **§3-The** — real blocker underneath, for the record <sub>L8470</sub>
- **§130** — An INCREMENTAL build can report BYTE-IDENTICAL for a change the CLEAN build cannot even LINK (P30 S28, the jr pair) <sub>L8479</sub>
- **§3-The** — diagnostic ladder that finally located it (reusable) <sub>L8516</sub>
- **§131** — The jtbl OVER-SPAN: `sltiu N` is ground truth in BOTH directions, and the zero-word rule only guards one (P30 S28, `func_80191C50`) <sub>L8526</sub>
+37
View File
@@ -8522,3 +8522,40 @@ The function-level tools all said MATCH, so the signal had to come from the imag
function emits a jump table", not "this function's code is wrong."
That size-and-location fingerprint distinguishes a codegen residual from an integration/layout effect
in one build, and it is what redirected the diagnosis away from three wrong guesses.
## §131 — The jtbl OVER-SPAN: `sltiu N` is ground truth in BOTH directions, and the zero-word rule only guards one (P30 S28, `func_80191C50`)
The carve had a symmetric blind spot. `jtbl_range` computes `end = the next data dlabel`, then:
* **extends** the span when the owning function's `sltiu N` demands more entries than the dlabel
supplies (§SPLIT-TABLE REPAIR — spimdisasm can cut one table in half);
* **trims** trailing words that are **zero**, on the axiom "`0x00000000` cannot be a jump target";
* **warns** when the span is shorter than an unambiguous `sltiu` bound.
Nothing handled a span that is **too LONG for a non-zero reason**. spimdisasm attributes to a dlabel
everything up to the *next* dlabel, and that remainder is not always zero — it can be ordinary data.
Then no trim fires, the carve reserves more words than the table has, the object supplies only the
real entries, and the `.rodata` piece **under-fills**.
**The fingerprint (this is the reusable part).** Under-fill does not look like a codegen bug:
```
image size: −4 (×N tables), often masked to −3 by the end-align TRIM
differing bytes: hundreds, in hundreds of 1-byte runs, spread over most of the overlay
position: ~95% at byte 0 (mod 4) — the LOW BYTE of a 16-bit immediate
value: every one changes by exactly −4
```
That is not "the function is wrong", it is **every `%lo` in the image pointing 4 bytes low** because a
data symbol moved. Bucket the differing bytes by `offset % 4` and decode a few words: if the deltas
are uniform and small and land in the immediate field, you are looking at a **layout/under-fill**
problem, not codegen. (Measured here: 812 of 853 at `pos 0 mod 4`, all `−4`.)
**The fix, and its authorization.** Clamp `end` down to `start + 4*N` when the `sltiu` bound is
**unambiguous** (exactly one — a multi-switch function cannot say which table owns which bound) AND
the surplus words are **not plausible code addresses**. If any surplus word is in the overlay's text
range, **REFUSE and say so**: it might be a real entry, and silently dropping one corrupts the image
in the opposite direction. Same standard as the extension path — act only on the program's own
statement, never on a guess.
**Why it mattered:** this was the single instrument failure that survived §125's retraction round —
the one case where "the tool is broken" was actually true. It blocked a 710-instruction behemoth and,
because a carve is per-overlay, it would have blocked every future jr family whose table happens to
be followed by non-zero data. One clamp, byte-identical, behemoth banked.
+7 -7
View File
@@ -4,16 +4,16 @@
# cross-binary collapsible-byte leverage: docs/duplicates.cross.md.
# THREE progress metrics (all matter — see the labels):
FLEET fn-count byte-ident: 329838 / 353720 = 93.25% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay)
FLEET instr-weighted : 11715810 / 13141652 = 89.2% (shipped .text across main + resident + 138 overlays; the decomp.dev-DISPLAY number)
FLEET distinct-code(uniq): 4533868 / 5634875 = 80.5% (72153/87459 unique fns; the DISTINCT-RE number)
FLEET fn-count byte-ident: 329839 / 353720 = 93.25% (REAL+LINKED+empties; FUNCTION-count, ×134-inflated — one crack counts per overlay)
FLEET instr-weighted : 11716520 / 13141652 = 89.2% (shipped .text across main + resident + 138 overlays; the decomp.dev-DISPLAY number)
FLEET distinct-code(uniq): 4534578 / 5634875 = 80.5% (72154/87459 unique fns; the DISTINCT-RE number)
MAIN game-code weighted : 436 / 60201 = 0.7% (INCLUDED in the fleet numbers above since 2026-07-22 — roadmap §1 metrics contract; LINKED-excluding Ghidra sig dated 2026-06-14; caveat is R34: no independent second oracle for a PS-X EXE, NOT drift)
(fleet EXCLUDING main, for continuity with pre-2026-07-22 readings: 11715374 / 13081451 = 89.6%)
(fleet EXCLUDING main, for continuity with pre-2026-07-22 readings: 11716084 / 13081451 = 89.6%)
FLEET REAL substantive : 327983 (of which dedup-shared 240422 via 1905 groups / 240496 instances)
FLEET REAL substantive : 327984 (of which dedup-shared 240422 via 1905 groups / 240496 instances)
FLEET LINKED PsyQ objs : 959
FLEET NON_MATCHING : 7 (0 in any default build — G4)
FLEET INCLUDE_ASM stubs : 23875
FLEET INCLUDE_ASM stubs : 23874
FLEET matchable : 353720
| binary | REAL | shared | LINKED | byte-ident | matchable | byte-ident % |
@@ -139,7 +139,7 @@ FLEET matchable : 353720
| ov_SC06_014 | 2354 | 1744 | 0 | 2356 | 2453 | 96.0% |
| ov_SC06_015 | 2352 | 1744 | 0 | 2352 | 2421 | 97.1% |
| ov_SC06_016 | 2369 | 1744 | 0 | 2371 | 2549 | 93.0% |
| ov_SC06_018 | 2396 | 1746 | 0 | 2403 | 2665 | 90.2% |
| ov_SC06_018 | 2397 | 1746 | 0 | 2404 | 2665 | 90.2% |
| ov_SC06_020 | 2364 | 1746 | 0 | 2365 | 2518 | 93.9% |
| ov_SC06_022 | 2389 | 1744 | 0 | 2397 | 2642 | 90.7% |
| ov_SC06_024 | 2400 | 1744 | 0 | 2406 | 2667 | 90.2% |
+9 -5
View File
@@ -110,14 +110,14 @@ stub on a named wall/behemoth/queue ledger** — 140/140 byte-identical througho
# 🛑 SESSION-28 CHECKPOINT (2026-07-31 08:1x) — FRESH SESSION SAFE HERE
> Supersedes SESSION-27 below. **Nothing is running. Tree lock FREE. Tree clean** but for the R23
> `db.*.gbf` churn (never stage). **HEAD `commit:1291`** (+ this doc commit).
> `db.*.gbf` churn (never stage). **HEAD `commit:1293`** (+ this doc commit).
> Effort: opened **xHigh** → **Max** for the jr re-measurement and the T2 probe ladder → back to
> **xHigh** for the driver + sweep. `make tools-health` RC=0 at session open.
> **R22 clean-fleet run THIRTEEN times this session, 140/140 every time** (one 139/140 and one
> 137-file false-pass, both MINE, both caught and reverted — see the honesty ledger).
## FLEET — R22 clean-fleet **140 passed / 0 failed** (verified THIRTEEN times this session)
**93.25% fn-count · 89.2% instr-weighted · 80.5% distinct-code** (72,153 / 87,459 unique fns) ·
**93.25% fn-count · 89.2% instr-weighted · 80.5% distinct-code** (72,154 / 87,459 unique fns) ·
dedup 1905/0 · C1 240496/240496 · 0 NON_MATCHING. Phase opened 92.00 / 87.5 / 78.0
⇒ **+1.25pp fn-count, +1.7pp instr, +2.5pp distinct this phase.**
@@ -148,9 +148,13 @@ code subseg so each object owns exactly one table.** Drafts preserved at `.run/s
(`.run/p30w4_pool.json`). ⚠️ **S28 ROI evidence: a 15-target wave cost 1.33M tokens for 12 banks
and +0.00pp headline.** Only worth resuming against HIGH-REACH targets; ×2-reach drafting is not
where the leverage is. Deal ACROSS binaries so the gate fans out.
3. **[Max] #9 — `jtbl_carve` diverges on ov_SC06_018** after a byte-neutral isolate (got `1b1667ea`,
want `cbbc4f44`, SHA-verified from a clean tree). The ONE confirmed instrument failure; blocks the
710-ins `func_80191C50`. Compare against `ov_SC05_010`, whose full chain succeeded S28.
3. ~~**[Max] #9 — `jtbl_carve` diverges on ov_SC06_018**~~ ✅ **SOLVED + BANKED (S28, `commit:1293`).**
Root cause: a jtbl **OVER-SPAN**. `sltiu 0xC` names 12 entries, the object emits 12 words, the carve
reserved 13 — the 13th being ordinary NON-ZERO data spimdisasm ran into the dlabel, which the
zero-word trim cannot see. The piece under-filled ⇒ every later symbol slid −4 ⇒ 812 `%lo`
immediates changed. Fixed with an `sltiu`-authorized clamp (refuses loudly if a surplus word looks
like a real entry). **`func_80191C50` (710 ins) BANKED**, R22 140/140. Cookbook **§131**.
⇒ the `JTBL-CARVE-BREAKS-BYTES` class is RETIRED — it was a real bug, now fixed.
4. **[Max, xHigh-able] `JR-PAIR-IN-ONE-O0-OBJECT`** — try §81 step 1 (isolate one of the pair into its
own code subseg) so each object owns exactly one table. Worth 2 × 138.
5. **[T5, Max] Phase close.** ⚠️ **Milestone reality: 89.2% instr vs a ≥95% bar.** The remaining