Found P31 S72; COULD have been found 2026-06-15 (Phase 7, commit:0025), which wrote the
island's contents by hand and named loadDestPtrTable as the divider. The signal needs no
matching progress — it is a property of the retail image.
The number that matters is the cost curve: at Phase 6 src/800.c had 13 externs and 0
typedefs and the split was a yaml edit; at S72 it had 2,378 externs and 175 typedefs and
cost 57 crossing declarations, a shared header and 4 stale consumers. Plus a session of
wrong conclusions (11 'PROVEN gate-rejects', 10 of which banked once the carve existed).
PREREQ recorded honestly: the binding constraint came from the OVERLAY work two phases
later, so this is knowledge that never got carried back to main — not carelessness.
General principle: segmentation is the exception to probe-before-investing. When a
decision is evidenced at t=0, cheap now, and strictly more expensive later, make it early
even though its payoff is unproven.
The split created two new TUs and a shared header; four consumers still described main's
game code as one file:
* tools/reconcile_slate.py — HARDCODED open('src/800.c'), so after the split it saw a
THIRD of main's typedefs while reporting success (silently-narrowed scope, R32).
Measured: 133 visible before the fix, 187 after, 0 lost. Now globs
corpus.src_files('main') + src/800_shared.h, so a future split is already handled.
* docs/wave-playbook.md 1c — still said spans B/C/D were NOT drawable and that drawing
one is an R45 violation. That is now false and would have STOPPED a future session
from drawing the very targets this work unlocked.
* cookbook §426 — its 'the remaining spans need src/800.c split' paragraph now records
that it was done the same session, and points at §431 for the method.
* config/dedup.us.yaml + src/shared/clearTbl40.h — both said dedup group I0 is
instantiated 'at both sites in src/800.c'; both sites are above 0x80035270 and are now
in src/800_c.c.
Byte-neutral: dedup.us.yaml parses, gate_main --assert-baseline BYTE-IDENTICAL.
SETUP.md gains a row describing the layout and the rule it implies: never hardcode
src/800.c, glob corpus.src_files('main').
I wrote the rule for declaration edits and then lost two byte-proven banks to the same
mechanism an hour later. gate_main's opening 'git checkout -- src/*.c' destroys anything
uncommitted in src/, banks included. R42 is 'commit before the next command that can
touch src/', not 'commit at a good stopping point' — and count banks from the SOURCE,
which is the only oracle that caught it.
Both banked byte-identical earlier this session ('BANKED 2 of 3'), then sat UNCOMMITTED
while my very next action was another gate. gate_main.try_batch's first step is
`git checkout -- src/*.c`, which reverted them; the following commit captured only the
third function. I reported 14 banks; the source said 12.
Caught by counting banks from the SOURCE (the INCLUDE_ASM stub's absence) rather than
from my own account of what I had done — the oracle the project already mandates.
I had written this exact hazard into cookbook §431 an hour earlier, for DECLARATION
edits, and did not apply the same reasoning to BANKS. R42 is not 'commit at a good
stopping point', it is 'commit before the next command that can touch src/'.
Quoted '2,318 scattered externs' as measured-not-guessed. It was measured, and it
measured the wrong quantity: what a split costs is declarations used OUTSIDE their
region (57 of 1,247), not the total. R41's denominator discipline applied to an EFFORT
estimate. Also records the correction to the '1998' premise: the spans prove at least
three TU boundaries, not that the devs' files were exactly these three.
Where to split: the jtbl spans (tables pack tight within a TU, separated across TUs), and
that is also the MINIMUM — a TU with no switch emits no table and is invisible, so what
you recover is a lower bound on the original structure, not the structure.
What crosses: ask the compiler. 2,318 externs is the scary number and the wrong one; only
57 of 1,247 declared names cross a boundary, 19 of them typedefs with one definition each
and zero shape conflicts. Fix TYPES first — a missing typedef cascades into dozens of
parse errors that all evaporate at once.
Plus the general defect it exposed (a typedef stripper must read the destination's
includes) and the operational rule it cost twice (gate_main reverts src/*.c first, so
commit alignment edits before gating).
Its blocker was an extern the DRAFT carried for a different symbol
(func_8004355C declared (s32, void*) against the TU's (s32, u8*)). Adopting the TU's
spelling verbatim — the documented §376 recovery — banked it byte-identical in 10s.
Only func_800316F8 of the eleven remains, and it is a TABLE REJECT: .text
byte-identical, 18 bytes wrong in its own jump table (§405-A).
func_800316F8's .text was BYTE-IDENTICAL and all 18 differing bytes were its own jump
table; the tool called it a PLUMBING REJECT and routed it to the §376 declaration chain,
advice that would never have fixed it. classify() now separates a .rodata-only
divergence and names it §405-A: match_one compares .text ONLY, so a draft sits at
closeness 0 while emitting a wrong table — gcc emits case BODIES in source order while
entry i points at case i, so case value and case order are independent and only the
order is pinned by .text.
Attribution reads one symbol LOW for a cc1-emitted table (once the function is C its
table is a $L label, not a jtbl_ data symbol, so the bytes land in the PRECEDING table's
extent) — the OBJECT name is what identifies it, not the symbol name. Shared by
gate_main so both report the same four verdicts.
Controls: self-test PASS, green build IDENTICAL, and the known func_800316F8 case now
classifies TABLE REJECT.
Byte-identical. 13 main functions banked this session.
func_800316F8 rejected with a precise, new-class verdict: its .text is BYTE-IDENTICAL
and all 18 differing bytes are its own jump table at 0x800730C4 (attributed to the
preceding jtbl_800730AC because the table is now a cc1 $L label, not a data symbol).
That is §405-A in the flesh — match_one compares .text ONLY, so a draft can sit at
closeness 0 while emitting a wrong table. Not a body reject and not plumbing either.
Each of these five had a TU forward declaration that contradicted the real signature,
which is what made gate_main drop their byte-correct drafts:
func_800316F8 void f(void*) -> void f(s32) + cast at the one call
func_8003602C void f(void) -> void f(s32) (use is address-taken)
func_80036260 void f(void) -> int f(void) (use is address-taken)
func_80038FFC void f(u8**) -> s32 f(s32*) + cast at the one call
func_80039C70 void f(void*,s16,u8) -> void f(u8*,s16,s16)
Verified byte-identical with NO draft substituted, so any later gate failure is
attributable to the draft and not to this edit.
OPERATIONAL NOTE: gate_main's first action is , so an
UNCOMMITTED declaration edit is silently discarded and the gate then judges the drafts
against the old declarations. Commit alignment work before gating (R42's shape, seen
from the tool's side).
func_8002EED8 · func_8002F248 · func_80031988 — byte-identical, the first banks that
span B's carve made possible.
gate_main defect the split exposed: defs_above scans the destination .c ALONE, so a
typedef the TU gets through #include is invisible to strip_dup_typedefs and every draft
carrying its own copy dies with 'redefinition of X'. Latent until src/800.c's split moved
19 shared typedefs into src/800_shared.h, at which point func_80031988 — byte-correct,
and one of the eleven — failed to compile for that reason alone. header_defs() now walks
the destination file's quoted includes transitively and seeds defs_above with what they
provide, so an identical copy is stripped and a different shape is renamed, exactly as
for in-file definitions.
func_80031988 had TWO stacked blockers: this one, and the struct-tag false conflict in
typesig fixed earlier today. Neither was a property of the function.
BYTE-IDENTICAL with NO function banked (gate_main --assert-baseline, clean rebuild),
which is the whole point: the structure lands first and proves neutral, then drafts bank
against it.
One code object contributes exactly ONE contiguous .rodata run, and 800.o's is span A,
so spans B and C each needed their own object:
800 vram 0x800123F0-0x8002B0B4 -> .rodata span A (0x80072A38-0x80072C70)
800_b vram 0x8002B0B4-0x80035270 -> .rodata span B (0x80072E44-0x80073140)
800_c vram 0x80035270-0x8003A444 -> .rodata span C (0x800732A0-0x8007344C)
The span owners' address ranges are disjoint and ordered — tables pack tight WITHIN a
TU and are separated by other data ACROSS TUs — so these are (at least some of) the
original translation-unit boundaries. Splitting here is both the fix and the minimum;
any extra split would be speculation.
main's island is now a 7-piece data->rodata sandwich, so ld_interleave moves from
--front/--tail to --order.
THE SPLIT WAS CHEAP, AND MY FIRST ESTIMATE WAS WRONG. I costed it at '2,318 scattered
extern lines' — that is the TOTAL; what matters is how many CROSS a boundary, and that
is 57 of 1,247 declared names (4.6%), of which 19 are typedefs with exactly one
definition each and zero shape conflicts. Zero file-local statics. src/800_shared.h
carries exactly those, derived from the COMPILER's own errors rather than a regex model
of C (R33), and each typedef was MOVED, never copied.
Unlocks 17 functions / 4,471 instructions = 39% of what is left in main, incl.
SaveLoadRoutine (1139) and func_8003388C (663).
The 11 'PROVEN gate-rejects' were one missing rodata carve, not bad bodies. Next
session starts at the span B/C carve: 18 jtbl functions left in main's frontier holding
most of its remaining instruction mass, blocked on splitting src/800.c at 0x8002B0B4
and 0x80035270 — the original TU boundaries the jtbl spans reveal.
Counterweight to §3-B, with a precise discriminator. When two arms converge on a shared
block, that block is usually a late cross_jump merge of per-arm DUPLICATED statements
(§298). Spelling it as a real goto is not equivalent when the label sits INSIDE a loop:
the goto becomes a jump into the loop body, jump.c's mark_loop_jump marks it
loop_invalid, cc1 -dL prints 'Loop at N ignored due to multiple entry points', and
loop.c silently drops invariant hoisting — measured: the 1/0x80 constant hoist into
$a0/$a1 vanished, 2 insns plus a spurious andi.
Discriminator: shared tail outside every loop -> fold it (§3-B, and you may free a hard
ABI register). Shared tail inside a loop body -> duplicate per arm and let cross_jump
merge. A -dL line is a free oracle for this.
Also records CdReadSectorReadyCB's three remaining residual clusters as pack fuel so the
next attempt starts from the draft, not from the .s.
CdReadStateMachine (385 ins) · func_80024448 (362) · func_80026D64 (189) ·
func_8001B0D4 (86). One clean rebuild, 10.8 s, 4 of 4 accepted.
Wave shape: 5 targets, one agent per workflow, 5 concurrent. 4 MATCH / 1 NEAR.
Every agent verified its jump table and reloc stream past match_one's .text-only blind
spot (§405-A) because the packs carried the §426 carve note.
Three new laws banked from their notes: §428 (zero-byte cross-jump barrier), §429
(every held pointer needs its own local), §428a (two residuals moving in opposite
directions share one starved resource — which refuted my own prediction).
func_80024448 was recovered from disk after its Fable agent was killed by a rate limit
and the workflow reported NO-DRAFT; match_one on that file: closeness 0 (playbook §5b).
I predicted §428's UID barrier would resolve func_8001B0D4's fence<->over-merge
coupling, reasoning that it changes no liveness. The escalation that tested it did not
use §428 at all. §3-B did it: seven in-block 'return 0;' -> 'goto L_ret0;' to one shared
tail removed the priority-1 hard-$v0 sets, freeing $v0 for the D_800747E4 reload and
$v1 for CdQueueBusy's result, AND fired all three cross-jumps (92->86). One edit, both
residuals.
The real law is the opposite of my framing: two residuals moving in opposite directions
under every lever are usually not in tension — they are two symptoms of ONE starved
resource, and every lever so far was paying for one with the other. Ask what they are
both competing for, and inventory the hard register sets the source forces. A repeated
'return <const>;' in switch arms is the commonest way to pin $v0 many times over.
The wrong prediction is kept in the section as the refutation (R14).
From main/CdReadStateMachine (MATCH 385/385, opus). One root: gcc-2.7.2 canonicalises
(mem (reg)) back to a symbol when the pseudo has a single reachable set, so reusing a
pointer local changes the addressing mode downstream. p[-0x10] re-folds to
lui %hi(sym-0x10) unless the offset pointer gets its own single-set local; and a
multi-set pseudo defeats the canonicalisation for every use, costing a load-delay nop.
Same mechanism as §421 read from the source side.
Also confirms the §333 frame dial and the merged-tail label pin (gcc's cross_jump picks
the other end of a merge than you expect) as the cheap alternative to a §5a fence.
A volatile __asm__ barrier is a scheduling AND allocation event, so on a function whose
residual is allocation-shaped every fence that kills the double-hop re-enables a
cross-jump over-merge. Two residuals in tension, which is why ~20 variants across two
attempts never converged. §428's UID-based barrier is the predicted resolution because
it changes no liveness; the escalation now running is the test.
Flagged explicitly as one agent's report, not a byte-proof (R14).
Sharpens §5a/§336, supplies the missing precondition to §162. Writing the cursor
advance inside each switch arm instead of a shared temp makes the converging addu a
label CREATED by cross_jump (get_label_before), so its INSN_UID >= max_uid and
jump.c:1988's guard stops the minimum=2 jump-to-jump search from ever running — only
minimum=1 survives, which is exactly the target's single merge. Killed a -23
LENGTH-DRIFT (5 spurious tail merges) in one edit, with no volatile asm.
Found by the S72 main wave on func_80026D64 (MATCH in 2 compiles). The agent also
verified the .rodata table against jtbl_80072BFC past match_one's .text-only blind
spot — because the pack carried the §426 carve note telling it to.
A wave verdict is a claim about what the AGENTS returned, not what is on disk.
claude_wave_draft.js has no filesystem access, so its .catch() reports NO-DRAFT for
any agent that dies — including one that already wrote a finished body.
S72: a Fable agent on main/func_80024448 spent 133k tokens / 17 tool calls / 10 min,
wrote its draft, then died on 'You've reached your Fable limit'. The workflow returned
NO-DRAFT with an empty draft_path; match_one on that same file returns
{status: match, closeness: 0, nins: 362}. A complete byte-perfect body reported as no
work at all.
typesig() keeps only tokens in TYPES, which DISCARDS every typedef name — so
'Ent30D80 *' and 'Rec14 *' both reduce to '*' and the model has always been blind to
what a pointer points at. But 'struct' was in TYPES, so 'struct Ent30D80 *' reduced to
'struct*' and conflicted with 'Ent30D80 *', its own typedef.
src/800.c declares func_80031988 BOTH ways and compiles today — gcc, the arbiter,
agrees they are one type — yet the checker DROPPED the byte-verified draft, and S71
recorded it among the eleven 'PROVEN gate-rejects'. Dropping struct/union/enum from
the param token set loosens nothing the typedef path had not already loosened.
R39 control over the already-succeeded population (gate_main.typesig is imported by
pregate_check and four other tools, so this reaches overlay slates too): 452 drafts
across 54 binaries, 178 drops before / 177 after — ZERO new refusals, exactly one
removed: main:func_80031988.
§426 — main's switch functions were never a codegen wall: one .rodata carve had been
missing since Phase 7, so a drafted switch double-emitted its jump table (+28/+52/+76/+84
image growth, 238 symbols shifted, first mover jtbl_80072A4C every time). Includes the
derived name-address overlay that names a layout shift with no reference build, the span
table, and why spans B-D need src/800.c split at the original TU boundaries the spans reveal.
§427 — a hash is a correctness oracle with zero diagnostic content; preserve the red
artifact before anything rebuilds over it, attribute per byte, and negative-control the
localizer in both directions.
playbook 1c — which main jtbl functions are drawable (R45), and the gate note: main is not
in the parallel lane, read the BODY/PLUMBING/MIXED verdict before recording a main reject.
The idempotency check was 'heading present -> skip', and claude_wave_packs.py calls
this tool at pack-build time, so EVERY pack that had any history was sealed against
evidence recorded later. Measured on wave S72m_1: 4 of 5 targets took a
freshly-recorded carve finding and the fifth silently did not, because it alone
carried a prior note. Now idempotent by REPLACEMENT — the generated block is always
the tail of the file, so truncate at the heading and re-render the current row set.
Re-running is byte-identical (verified) and never duplicates the heading.
Also records the S72 main carve unlock in .run/journal_notes_local.jsonl so it
reaches every future main switch-function pack through the same one code path.
main's gate could only ever say "got X want Y". S71 read 7 such verdicts as body
rejects and recorded 11 functions as "PROVEN gate-rejects, §376 in its purest form".
They are not: all 11 are switch functions, and the blocker is that main has had
exactly ONE rodata carve since Phase 7 (LZSS's jtbl_80072A38). Every other main jump
table stayed raw in the tail data, so a drafted switch DOUBLE-EMITTED its table, the
image grew (+28/+52/+76/+84 measured), and all 238 symbols above 0x80072A4C shifted.
* tools/main_diff_locate.py (NEW) — turns a red image into a named list of divergent
symbols via the linker map; per-byte attribution, self-test flips a byte at a known
address and asserts the containing symbol (plus the identical-pair direction).
* gate_main.py — PRESERVES the red image + map before the R40 baseline control
rebuilds over it, and auto-localizes: BODY REJECT vs PLUMBING REJECT vs MIXED. Also
-j on the build (was single-threaded) and the §376 drop list written to
.run/gate_main_dropped.json with the reconciliation chain.
* splat.us.exe.yaml — the .rodata carve extends from the LZSS table alone to the whole
contiguous game-jtbl span 0x80072A38-0x80072C70 (12 tables, one 800.o run).
Byte-neutral with no drafts substituted (probed first).
* jtbl_rodata_pads.py — --derive now works for main: one file-0-vram expression makes
both address->bytes and yaml-piece->address correct for the EXE's 0x800 header and
leaves flat overlays unchanged. Makefile arms it for BINARY=main.
Banked byte-identical: func_8001A114, func_8001AAD0, func_8001AF34 — three of the
eleven. 25 of main's 59 frontier functions (6,215 of 12,912 instructions) are in this
class; the remaining spans need src/800.c split at the TU boundaries the spans reveal.
Audit found real gaps rather than assumed coverage:
* SETUP.md (R21) had NONE of the five tools written this session. Added a table for
journal_notes / launch_check / gate_triage / restage_matching / weave_sweep, each with
when you need it, plus the two gating rules now enforced in code (parallel_gate refuses
main; gate_main refuses a no-op draft and counts banks from the source).
* wave-playbook: launch_check as step 4c (payloads go stale while gates run - 3 of 27
wave-2 targets were already banked) and gate_triage as step 6b with the measured
blocker census.
* decision-log (R31) held only the §406 pivot. Added the two strategic entries this
session actually turned on: gating main with a tool documented as unable to gate it
(false PASS, caught only by R22), and the drafting pool running dry while the lever
was an exclude list nobody re-probed after a tool fix.
* CURRENT_PHASE: the per-gate ledger for all 14 cycles plus the carve/rebase/main gates.
* Two memories: gate-main-only-with-gate-main, reprobe-exclude-lists-after-tool-fixes.
Four byte-verified findings from md_MAIN_003/func_800CF3E8 (467/469 ins), read off
-dS/-dR/-dl/-dr:
1. sched.c true_dependence guards on GET_MODE(mem) != QImode, so a `sb` store aliases
scalar global loads while sh/sw struct stores are exempt - that is what pins the
colour lbu after `sb 0xb` and gives it a mandatory filler slot. A property of the
store's MODE, not of what it points at.
2. An OT-index re-read must be a MEM_IN_STRUCT_P FIXED-address lhu to depend on its
store; expand's memory_address() forces the constant into a reg (la+lhu 0(reg))
unless you copy the whole struct into a 2-byte register local. This was the 468/469
wall for every prior attempt.
3. A `la` above an idx*24 chain needs a single-set base pseudo emitted before the
multiply: block-scope `{ Sprt24 *b_ = ARR; p = &b_[idx]; }`.
4. Recorded as NOT reachable from C: $v1-vs-$a0 for the last prim pointer is
local-alloc's pointer-vs-temp priority tie. Permuter or a §419 density manoeuvre.
Byte-proven on ov_SC07_006/func_801890FC (387 ins). For two stores at equal priority,
sched1's LUID tie picks the LAST statement's store first; regalloc then gives the other
load $v0, where it sits behind its own $v0 predecessors, and sched2 pins that chain last.
Each equal-priority pair therefore appears reversed: source FE;E-=0x40;A-=0xEE;88;8A;8C
emits as E,88,A,8C,8A.
This is why "statement order is inert" is such a common wrong conclusion here - the
mapping is not identity, so trying orders at random explores the wrong space. Compute the
intended emission order, then invert each equal-priority pair.
Companion (§193-E): the prior draft left no different-address store between `sh 0xA` and
its re-read, so cse forwarded it as `andi 0xffff`. A store to a different address between
the two re-seeds cse - §416's "re-read the store" seen from the failure side.
A §332 delay-slot wall the pinned triple cannot emit from C; banked the verbatim-asm way,
verified by one clean rebuild at 143dbb89f34491258bbc27810d0a12ec8b43a8dd. Bank confirmed
from the source (stub gone), not from the tool's own count.
Substituting such a draft puts the stub straight back: nothing changes, the clean build
is trivially byte-identical, and the function is reported banked while its stub is still
in src/. That is how func_8002B0B4 was counted in this morning's "BANKED 5 of 6" when
only 4 had applied.
Refused at slate load so it fires in every mode including dry run. Negative-controlled
both directions: the no-op slate is refused by name, a real verbatim draft still passes.
Scope measured before generalising: 5 of 2,749 stored drafts, all one of two functions -
rare, but silent, which is why it is a refusal and not a warning.
len(good) is "what we decided to keep", not "what was substituted". A draft whose stub
pattern does not match is a SILENT NO-OP: nothing changes, the build is trivially
byte-identical, the batch passes, and the function is reported banked while its
INCLUDE_ASM is still in src/.
Measured here: the bisect printed "BANKED 5 of 6" and func_8002B0B4's stub was still in
src/800.c - four real banks. The stub's absence is the bank oracle everywhere else in
this project; gate_main now uses it too, and names any accepted draft that never applied
instead of counting it.
The main lane, run the ONLY way main can be gated (§414): substitute the whole slate ->
make extract -> make build -> compare SHA1, with a bisect when the batch fails.
Baseline asserted green first (143dbb89...), batch of 6 failed, bisect isolated
func_8002C410 in 7 rebuilds, and the remaining 5 banked BYTE-IDENTICAL.
Four of the five are §265 verbatim-asm bodies for functions on the §332/§188 toolchain
wall list - the accepted route for a function the pinned triple cannot emit from C, the
same way func_800D0B1C banked overnight. Candidates came from scoring every stored draft
for main's 53 non-rejected open functions with match_one: 6 of 53 at closeness 0.
Drew, 2026-09-02: "use opus mainly and only escalate the difficult ones to fable".
The S69 table that set the old 150 line actually puts opus's cliff at ~350:
m1 opus 191-347 ins 10/15 MATCH 1,291 tok/matched-ins <-- best measured
m2 opus 347-670 ins 1/9 MATCH 7,158 <-- the cliff
So 150 was handing opus's STRONGEST band to Fable. Fable is now reserved for >340
instructions and for arm_from_history's compiler-internal residual signal (§413) at any
size. On the current pool that moves three functions back to opus while two stay on
Fable because their history names a scheduling/regalloc residual - escalation by
difficulty rather than length, which is the point.
Retries default back to opus: one failure is not evidence of a wall, and the history
signal lifts a target on its own if the notes justify it.
§422 (resident/func_800D06E8, 344 ins): mips.h has no PROMOTE_MODE, so a u8 local is
really QImode - `(u8)(c-3) < 2` gives widen_operand a paradoxical subreg (raw $a0) and
combine.c:9246 drops the truncation before the sltiu, while `(u32)(c-3)` re-widens and
loses it. And `s1 = (cmp) ^ 1` puts the comparison in the destination pseudo; the flag
needs its own temp.
§423 (ov_SC03_092/func_8017FA74): match_one closeness 0 + gate reject + "cause not
determined" has a checkable cause. harvest_verify splices the draft where the
INCLUDE_ASM stub was; a file-scope typedef the TU also defines (five lines below, here)
makes gcc-2.7.2 exit 33 on a C89 redefinition, the TU fails, the gate reverts, and
nothing names the typedef. Fix is block scope, proven with a three-way control. Mirror
of §409 law 2 - together they cover collisions above and below the splice point.
Tool trap: a scratch TU copy needs -Isrc/<overlay> or cpp exits 1 on the relative
engine_core.h include and EVERY variant passes identically.
Byte-proven on md_SC07_003/func_801A293C (313 ins, 6 -> 0 in 23 compiles). $t0 there is
reload's scratch (regalloc.md L80: first wholly-unused call-clobbered reg), not an
allocation: a launder output goes to $v0 via local-alloc, and any $8 pin evicts every
mfhi/reload to $t1 (measured 3x). The reach is §385's single-instruction non-volatile
asm with the bare symbol as an INPUT.
Also: spelling an addPrim RMW as a libgpu P_TAG 24-bit addr bitfield makes
store_fixed_bit_field mask the value first, hoisting 0xFFFFFF before 0xFF000000 and
closing both the lui/ori and lw-swap clusters at once (6 -> 3); and an in-place `and $s0`
needs `s0 = s0 & 0xFFFFFF` written out, not the compound form.
The law: before spending iterations on a register you cannot get, ask whether it belongs
to regalloc at all - reload runs after every dial C gives you.
aprop_symfix deduped its slate by BARE FUNCTION NAME, so a four-row slate for
func_8016AB6C across ov_SC03_107/ov_SC07_007/010/011 reported "1 drafts audited" - and
the three dropped rows each needed a DIFFERENT rebase, because each overlay has its own
target symbols. Same root as reloc_filter's binof and gate_lane's homonym staging: three
tools, one R48/§238 defect.
With all four visible, the structure is two uniform delta clusters of two, identical in
shape across all four overlays - one seed body's two data clusters each moving as a
block. STALE-DELTA only admits ONE cluster, so it refused all four as AMBIGUOUS. §420
records the safe generalisation (runs of constant delta, every run >= 2 members, D_
symbols only) and the verification step.
Rebased by hand under that rule, all four still MATCH at closeness 0, and the gate
banked 4/4 in 57 seconds with no drafting (commit:3629). Frontier 165, 45 banked.
Wave 3 drew 1 target - 0 left in pool. Of 174 open: 64 main, and of 110 non-main, 41
drafted this session, 68 excluded, 2 walls, ZERO undrawn. Re-probing the 68 with
jtbl_carve --probe found 17 now reporting `tail`, because tonight's jr_isolate_all
fixes changed their overlays. All 17 already had drafts; 10 scored closeness 0 with no
drafting. The gate banked 5, and they are exactly the five overlays jr-isolated tonight.
An exclude list is a snapshot of what the TOOLING could not do and goes stale the moment
the tooling improves - re-probe it after every tool fix.