§176i — WHAT A STATIC PRE-GATE CHECK CAN AND CANNOT PROVE. pregate_check validated wave Q's slate
as clean in 0.7s (the first slate all session to reach the gate pre-validated) and the build then
failed twice, both times outside what any text-only check can see:
1. LINK-time undefined reference: `.L80050F24` lives INSIDE gfx2D_BG0_OBJ_698 and another
function's .s branches to it -- converting a function to C deletes the local labels its
neighbours jump to. Statically checkable, but from the .s files, not the .c: scan every other
.s for label references landing inside a candidate's address range. Worth building.
2. BYTE mismatch: with the link fixed the binary BUILT and the SHA differed -- the §174 law 1c
class, which reloc_identity had already named six suspects for.
The division of labour to rely on: text checker for SHAPE, reloc oracle for IDENTITY, gate for
TRUTH. A clean pre-gate is a licence to build, not a prediction of success -- and when the binary
builds but the hash differs, BISECT, because it costs wall-clock and zero tokens.
§176j — STOPPING A WAVE MID-FLIGHT COSTS THE IN-FLIGHT TAIL. Wave Q stopped early: 51/90 verified
(3,631 of 6,249 ins) versus the 96-97% the same pipeline yields when allowed to finish. The loss is
SUSPENDED, not destroyed -- every draft persists on disk, 15 of the 39 unfinished sit at closeness
<=10. Do NOT resume the workflow to recover it (resume re-runs unfinished agents from scratch at
full cost); use a REPAIR-ONLY pass over the <=30 band instead. Decision rule: before killing a long
agent run, price the tail -- stopping converts near-matches into "needs a cheaper second pass",
which is a deferral, not a saving.
The 68%->95% lever from §176h.C2, mechanized. Reconciliation belongs INSIDE the wave: a banked
draft's declarations become the TU's, so a sibling clash hardens into a file clash and post-bank
recovery is measurably worse (18 parked drafts still MATCH, only 1 survived after their wave banked
vs 5 before).
AUTO-FIXES, each re-verified with match_one and REVERTED if a byte moves (a declaration change is
a codegen change, §176f):
* COSMETIC-TYPEDEF two names for a structurally identical struct -> adopt the other. Compared by
BODY, never by name (OtBlk_80015498 == OtBlk_80016450; Elem12 != B12). This body comparison is
also the answer to §176h.C's spelled-name limit.
* SIGNEDNESS / ALIAS / ARRAY-VS-SCALAR -> adopt the TU's spelling, fixing the use site.
* DEFPARAMS (NEW LEVER) -> adopt the TU's parameter types on the DEFINITION and re-narrow with a
shadowing local: `void f(s32 a0_p) { s16 a0 = (s16)a0_p; <body unchanged> }`. One textual
insertion instead of rewriting every use site, and the cast emits the same sll/sra pair.
Byte-identical on both cases tried.
REFUSES, with named reasons, because these are decisions and not edits: DIFFERENT-STRUCT (two real
layouts for one symbol), IMMOVABLE-TU-DECL (gate_main reverts src/, so it needs its own commit +
rebuild + R22), DEF-SIDE-RETURN (adopting the TU's return type usually costs the match -- measured
on func_8001ABBC), and BROKE-MATCH for anything its own verification rejects.
Measured on wave P's leftover slate: 6 -> 9 compatible, 3 auto-reconciled, 2 repairs reverted by
the tool's own byte check, 7 named for a human.
build_wave_atlas: --rank mass (main's gate cost is per SLATE, so ranking groups by member count
silently collapses a wide band to the smallest functions -- measured 60 cards/2,604 ins where 46
cards/4,829 ins were available), and the selector no longer counts ITS OWN OUTPUT as already-waved
(re-running with identical filters had been shrinking the pool 60 -> 46).
MEASURED, and it inverts the obvious plan. "Bank the clean drafts now, recover the conflicted ones
later" is backwards: of 18 wave-O/P drafts parked and re-verified still MATCH, only 1 survived
resolve_conflicts once their wave had banked -- versus 5 before it.
The mechanism: a banked draft's declarations BECOME the TU's, so every parked draft that merely
disagreed with a SIBLING now disagrees with the FILE, which is the stricter arbiter (a sibling
clash can be settled by editing either side; a file clash only by editing the draft, and some
cannot be settled at all because gate_main reverts src/ before every build). Worse, the auto-rename
that reconciles a cosmetic clash pre-bank becomes a DUPLICATE TYPEDEF post-bank, because the name
it renames to is now defined in the file.
So iterate the dry run to `N -> N compatible, 0 dropped` BEFORE spending the first rebuild, and
budget reconciliation into the wave rather than after it.
pregate_check: DUPLICATE-TYPEDEF now fires on ANY redefinition, not only differing bodies. C89 has
no compatible-redefinition allowance for typedefs, and my first version missed exactly the case the
tool exists for -- two identical `OtBlk_80016450` definitions, which the compiler rejected on the
next rebuild. Measured, not reasoned.
Also banks the auto-reconciler's rule: tell a COSMETIC clash from a REAL one by comparing struct
BODIES, not names. OtBlk_80015498 vs OtBlk_80016450 are the same {s32 a; s32 b[4];} and rename
byte-identically (both re-verified MATCH); Elem12 vs B12 genuinely differ and were refused.
Wave P drafted at 97% and cost A DOZEN clean rebuilds to bank, and not one of those rebuilds
failed on a matching problem -- every one failed on a TEXTUAL property of the substituted file
that a grep could have reported instantly. This is that grep.
gate_main's resolve_conflicts cannot answer it, and not from carelessness: it inspects the DRAFTS
while the compiler sees the FILE THEY LAND IN -- after typedef stripping and renaming, at each
draft's own insertion offset, interleaved with declarations the file already had. Those
transformations run AFTER the conflict check passes. So substitute() gained write=False and this
tool checks the artifact itself.
Five checks, each earned by a rebuild lost this session (§176h): typedef used above its
definition; type never defined anywhere; duplicate typedef with different bodies; one symbol
declared two incompatible ways; definition contradicting a visible prototype.
CALIBRATED AGAINST THE COMPILER, NOT AGAINST C89 PEDANTRY -- and this mattered. The first version
reported 4 hard FAILUREs on the slate that had just built BYTE-IDENTICAL:
- it ignored SCOPE, but the project deliberately uses block-scope extern blocks, and a declaration
inside one function cannot conflict with a definition elsewhere. Now brace-depth aware.
- it split `void f()` from `void f(void)`, which gcc-2.7.2 accepts. Normalized.
- it called every def-vs-decl mismatch fatal, but gcc-2.7.2 accepted `void f(void*,s32)` against a
`void f(s8*,s32)` definition and even `G3P *f(...)` against `G4P *f(...)`. What it REJECTED was
a void/non-void RETURN split (func_8001ABBC). That split alone is FAIL; the rest are WARN.
Comments are masked via cdecl before any use-site scan (an unmasked scan reported 7 phantom hits).
R39 controls: the slate that banked is FAIL-free (exit 0, 3 informative warnings); four synthetic
defects each reported at FAIL; a clean text reports nothing; a block-scope extern does not
conflict; `short` vs `s16` does not conflict; array-vs-scalar does.
Wave P drafted at 97% and then cost a dozen clean rebuilds to bank, and not one of those rebuilds
failed on a matching problem. Banks the whole failure surface:
A. The SEVEN under-reporting holes in gate_main, all the same shape (R32): the checker never read
the destination TU, shared headers, a draft's own definition, lines with trailing comments,
typedef aliases, the build's own error text, or file order. Law: audit a batch-integration tool
for what it DOESN'T look at -- its verdicts can be correct on the inputs it reads and still be
worthless, because the compiler reads more.
B. Typedef handling, with the two wrong strategies that both look right: blanket STRIP (assumes
the surviving definition sits above the insertion point -- src/800.c defines Rec14 at 7336
while stubs wanting it sit at 7272), blanket RENAME (breaks drafts sharing an identical
typedef, because their externs stop agreeing -- my regression, three drafts at once), and the
rescan loop that deletes the definition it just renamed. The survivor is body-aware +
position-aware in a single pass over a snapshot.
C. The remaining limit: conflict detection compares spelled type NAMES, so three drafts each
defining their own Slot54 with different layouts all declare func_80032A74(Slot54*) and compare
equal. Comparing struct LAYOUTS is the real fix.
D. The measured cost shape -- drafting cheap and solved, integration expensive -- and therefore the
next lever: a STATIC pre-gate check over the substituted text, no make at all. Plus the R39
lesson that negative controls apply to the tool you are FIXING, not just the one you ship.
Wave P was the first full run of the 6k-ins doctrine: 60 cards / 6,589 ins in 2 gate groups,
59/60 claimed and 58/60 independently re-verified MATCH (6,372 ins), reloc_identity 58/58 AGREE
with ZERO symbol errors -- the second consecutive clean wave on symbol identity.
Banking cost a dozen rebuilds and exposed four more gate_main defects plus three regressions of
my own. The tool fixes, all NC'd:
- resolve_conflicts never read a draft's OWN DEFINITION, so the DEF-side wall (a draft defining
s32 func_X against a TU prototyping void func_X) reached the compiler. Now definition-aware:
it caught 13 conflicts up front where the build had been finding them one rebuild at a time.
- DECL and both typedef patterns anchored on end-of-line, so a TRAILING COMMENT hid a declaration
or typedef entirely -- and agents comment nearly everything they declare. Seventh instance of
one root cause: a scanner that looks green while reading less than it claims (R32).
- typedef handling is now BODY-AWARE and POSITION-AWARE, in a single pass:
* identical definition visible ABOVE the insertion point -> strip and reuse;
* same name, different shape -> rename (private to the draft);
* definition below the insertion point -> never reuse (it is not in scope there).
Three wrong strategies preceded this, each costing a rebuild: blanket strip (the file's copy can
sit BELOW the draft -> implicit-int, then a collision), blanket rename (breaks drafts that share
an IDENTICAL typedef, because their externs stop agreeing -- my regression, three drafts at
once), and a rescan loop that found the definition it had just renamed and stripped it as a
self-duplicate -> 'parse error before *'.
KNOWN LIMIT, recorded not fixed: the conflict check compares spelled type NAMES, so three drafts
each defining their own Slot54 with different layouts all declared func_80032A74(Slot54*) and
looked compatible. Comparing struct LAYOUTS for locally-defined types is the real fix.
13 + 4 verified-correct drafts are parked in two named buckets (competing local type models;
immovable TU declarations that gate_main reverts before every build).
A wave is now sized by INSTRUCTION MASS, not card count. The metric is instruction-weighted, so a
wave is worth what its instructions are worth: the 12-42-ins card lanes carried ~1,400 ins/wave
(~0.011pp, ~440 waves to finish) while wave O carried 6,266 ins at the same gate cost and the same
draft rate.
build_wave_atlas --target-ins draws cards until the instruction budget is met (still capped by n)
and refuses to under-fill silently. Standard recipe: --target-ins 6500 --min-ins 60 --max-ins 200
--max-bins 4, levers now including UNKNOWN.
THE MEASUREMENT BEHIND IT: draft rate barely decays with size -- wave M 98% at avg 51 ins, wave N
92% at avg 65, wave O 96% at avg 128. Mass is nearly free.
THE UNKNOWN UNLOCK: UNKNOWN is not a difficulty label, it means the atlas could not name a lever,
and it had been routed as needing its own bespoke lane. Wave O's 22-card R37 probe drafted it like
any other lane -- reclassifying ~138k ins (a quarter of everything open) as ordinary wave fuel.
With UNKNOWN in, 9,224 fns / 417,325 ins = 70% of all open instructions are agent-draftable; the
60-200-ins mass band alone is 164,357 ins ~= 27 waves, and is the band to work first.
Also banks the five-step PRE-GATE PROTOCOL (independent re-verify -> reloc_identity -> dry-run to
0-dropped -> reconcile declarations toward the form the match needs -> gate), cookbook §176g.
36 fresh wave-O cracks + 10 recovered wave-J/K/L drafts, verified in ONE clean rebuild:
143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL. main stubs 1881 -> 1835.
Wave O was a 3-arm 49-card wave (6,266 ins): main head-crack, main UNKNOWN, overlay UNKNOWN.
47/49 standalone MATCH, independently re-verified by me (R14) at 47/49 -- exact agreement --
and reloc_identity reported 46 AGREE / 0 MISMATCH, the first wave of the campaign with zero
symbol errors. THE UNKNOWN LEVER DRAFTS LIKE ANY OTHER LANE, which matters strategically: it is
~138k ins fleet-wide (a quarter of everything open) and was routed as "needs its own lane".
FOUR gate_main defects fixed here, each of which had been silently costing prior waves drafts:
- typedef stripping walked drafts in SLATE order while substitution happens at ADDRESS order, so
the surviving typedef could land BELOW a draft using it -> "syntax error before D_800A651C".
Verified the two orders genuinely diverge for both destination files in this slate.
- a BUILD failure (sha None) fell through to a silent bisect -- a full clean rebuild per step to
rediscover what the compiler had already printed and discarded. Now the error lines are shown
and the offending drafts named for undefined-reference/redefinition/conflicting-types.
(My first version of that printer TAILED a stderr+stdout concatenation and faithfully showed 25
lines of make progress chatter instead of the error -- selecting by position, not by content.)
- typesig treated "short" and "s16" as different types (R39 over-refusal). Aliases now normalize;
11/11 NC cases pass, with signedness, volatile and array-vs-scalar still conflicting correctly.
- conflict detection ignored shared headers: engine_core.h's DEFINE_ macros declare symbols in
their own bodies, so a draft's file-scope array decl of D_800A651C was illegal. Block-scoping
the draft's extern fixes it byte-identically.
DECLARATION RECONCILIATION took the slate from 5 dropped to 0, and three of the four conflicts
were load-bearing CODEGEN, not style: the array form of D_80078D88 blocks a sched1 hoist (scalar
users adopt [0] for free); "volatile" on D_800B9A02 is required by one draft and fatal to two
others (plain u16 loses 1 bank, volatile loses 2); D_800A651C needs block scope. Cookbook §176f.
Wave O: six drafts in one TU referenced D_80078D88, three declaring it scalar and three as an
array. One draft's own comment explained why the array form is load-bearing: with a scalar decl the
global load is a plain symbol_ref and sched1 HOISTS the lui/lw above a store; declaring it as an
array makes gcc-2.7.2 alias.c treat the access as possibly-aliasing and the hoist stops.
So §176b/§176d's 'pick one form and cast at the use site' is wrong for a scalar/array clash. Array
is the STRONGER form -- scalar users adopt it for free by indexing [0] (byte-verified on all three)
-- while forcing an array user to scalar can re-enable the hoist and break the match. Reconciling
toward the array form took the slate from 42 -> 37 compatible (5 dropped) to 42/42, every converted
draft re-verified MATCH. Waves J/K/L each lost 5-10 drafts to the greedy keep-first rule.
R37 probe: 20 shape-verified AND symbol-verified stored drafts, 5 gate groups -> 1 banked (5%),
statistically the same as the project's A10 stored-verdict law (~0-8%; T1 measured 0/23 on the same
kind of pile earlier this phase). The null is the finding: a stored draft's rejection is almost
never symbol identity, it is TU plumbing (§176d) or staleness. reloc_identity's real home is a
PRE-GATE check on FRESH drafts, not a backlog resurrection tool. The remaining 30 groups are not
worth 30 rebuilds -- lane closed rather than pursued because the tooling was new and interesting.
Also names the SYMBOL-COLLAPSE class in the fixer's refusal (one draft extern standing in for N
distinct globals; a textual rename moves every occurrence together, so it needs one extern per
site) and records the R38 self-note: the 0/23 prior was already in the phase log.
§174 law 1c recorded match_one's relocation blindness as a caution to the reader ('check every
symbol by hand after MATCH'). It is a computation, not a human's job. Banks the arithmetic, the two
failure shapes it separates (uniform-delta stale seed symbols vs wrong field offset), the four
traps that bit me building it (splat-derived names absent from the symbol files; MIPS o32 REL keeps
the addend in the instruction; index alignment is a precondition; a nearest-symbol label needs a
tight window), and the honest limit measured the same session: symbol-verified + shape-verified is
still NOT sufficient for a bank -- the first re-gate group of five such drafts banked 0/5, because
what remains is TU plumbing (§176d), not identity.
--fix rewrites only unambiguously-wrong symbols (every mismatch naming a symbol must imply the SAME
corrected base) and refuses otherwise: 10 of 12 repaired, 2 correctly refused.
match_one masks relocations (26-bit jal field, HI16/LO16 immediates), so it verifies instruction
SHAPE and is structurally blind to WHICH symbol each relocation names: a draft calling the wrong
function or touching the wrong global reports a clean MATCH (§174 law 1c; wave K burned 5 gate
attempts on two swapped globals). Until now only the whole-binary gate caught it, and it reports a
hash, not a cause.
But the target .s comment column carries the FINAL LINKED WORD, so the true address behind every
masked field is recoverable arithmetically, and config/symbols*.txt maps it back to a name. This
tool resolves what the DRAFT names, computes what the TARGET references, and compares -- /bin/bash, no
rebuild, and it names the fix instead of reporting a mismatch.
match_one --emit-streams additionally carries mine_relocs (kind/operand per index); existing
consumers read mine/tgt only.
THREE INSTRUMENT BUGS FOUND BY ITS OWN NEGATIVE CONTROLS, each fixed before any verdict was
believed (R35/R39):
- splat-derived func_/D_/jtbl_ names are not in the symbol FILES (their address IS their name), so
the first run checked ZERO relocations on a draft whose every callee was correct -- a checker
that looks clean while checking nothing (R32).
- the nearest-symbol fallback used a 0x4000 window and labelled func_8001C9D0 as 'SsGetMute+0xC50';
a wrong label is worse than none. Tightened to 0x200 with an explicit splat-derived fallback.
- MIPS o32 uses REL relocations: THE ADDEND IS IN THE INSTRUCTION, not the reloc entry. Reading it
off the operand string reported 0 for every struct-field/array access and fabricated mismatches
(the +1/+2/+3 signature on func_801F0734 was a byte-array walk, not three symbol errors).
Also refuses to answer confidently when the streams are not index-aligned (shape differs), since a
single inserted instruction shifts every later index -- my own NC produced exactly that phantom.
NC: known-good drafts AGREE (3 and 5 relocs actually checked); a synthetic callee 4 bytes off is
caught while match_one still says MATCH; a misaligned mutant is downgraded to advisory.
The wave-J/K/L draft recovery (S52) showed §176b was under-scoped: it made batched drafts agree
with each other and forgot the file they land in. Banks (a) TU-seeded conflict detection and its
iterative behaviour, (b) per-destination-file keying, and (c) the new recovery variant for a callee
the TU prototypes as (void) while your call must pass an argument. All 11 recovered drafts
re-verified MATCH after repair; none needed a codegen change.
resolve_conflicts() had two defects, both found by the wave-J/K/L draft recovery:
(a) THE SYMBOL TABLE STARTED EMPTY -- only draft-vs-draft was compared, so a draft contradicting
a declaration ALREADY IN the .c reached the rebuild and surfaced only as a compile error and
a bisect. src/800.c carries 'extern void func_8001C9D0(void);' (from banked func_8001C2C4)
while three wave-J drafts declared it (s32)/(void *). The TU now seeds the table, and the
drop report names whether the clash is with the TU itself or an earlier draft.
(b) ONE NAMESPACE FOR ALL FILES -- 'seen' was global across the slate, so two drafts landing in
DIFFERENT .c files could not legally disagree about a symbol. Separate TUs are separate
namespaces; the table is now keyed per destination file (R39: over-refusal discards good work).
On the 11 recovered drafts the new check named 7 real TU conflicts that the old one missed
entirely. All 7 were repaired by adopting the TU's declaration verbatim and casting at the use
site -- including a NEW variant: when the TU's prototype takes no argument and the call must pass
one, cast through a function pointer, ((void (*)(s32))func_8001C9D0)(a0). All 11 re-verified
MATCH afterwards, so the cast is byte-identical in every case.
R39 NC: a synthetic draft re-contradicting the TU is still dropped; the repaired slate is 11/11.
build_wave_atlas.py:
- taken-set was a hardcoded 'abcdefghijkl' wave-letter literal -> glob('.run/wave_*_cards.json')
(R33 derive, don't re-derive). NC: 634 -> 726 taken, strict superset, +92 cards from waves m/n
that the literal would have silently re-issued.
- --exclude-bins defaulted to 'main' on the REFUTED link-defect rationale; default now empty and
the help states the real reason (main cannot be gated incrementally; use tools/gate_main.py).
- new --only-bins allow-list: main waves need it, since gate_main rebuilds once per SLATE.
gate_lane.py: an unhandled gate_stage exception produced no JSON line -> v={} -> '0 banked',
indistinguishable from an honest empty gate (cost 2 cycles in P31). Now a non-zero rc or a missing
JSON line is labelled CRASH with the stderr tail, recorded in the results JSON, listed in the
summary as NEVER GATED, and exits non-zero. R39 NC both directions.
Harvested by a 15-agent workflow over every wave's journal.jsonl (where the long analyses live —
notifications truncate them), each cross-checked against the existing cookbook + gcc-2.7.2-map
before being called novel, then synthesized by residual CLASS rather than by function.
- §176-A STATEMENT ORDER AROUND A CALL is the first thing to check for any schedule/delay-slot/
±1-length residual. fill_simple_delay_slots backward-scans and never hoists an instruction
emitted AFTER a call into that call's slot. The arg-register tell: a delay-slot store whose
address goes through that call's own arg reg PROVES the statement sits before the call.
func_80186764 7/92-off + pins -> MATCH 92/92 by moving one statement (no pin needed);
func_80188528 41/102-off, filed 'irreducible tie-break, permuter fuel' -> MATCH 102/102.
- §176-B a small REGALLOC-PERM is usually NOT allocation. B1: a narrow global that is really
wide_sym+2 must be expressed through the wide object (asm-label alias) or the disambiguator
sees no dependency; func_80185548 MATCH 77, verified with a full HI16/LO16+R_MIPS_26 resolve
oracle. B2: pin the short-lived INTERLOPER out of the way, not the contested value;
func_8018CA74 MATCH 63/63 with a register-choice sweep confirming the mechanism.
- §176-C 🔴 WALL REFUTATION, and I verified the source myself: gcc-2.7.2 sched.c:1704 tests
call_used_regs[i] where every neighbouring line uses regno+i, so for any 1-word register the
test is always call_used_regs[0] (, call-used on MIPS). EVERY hard-reg SET in a block
therefore gets a REG_DEP_ANTI on the last call, while the pseudo arm (sched.c:1732) is guarded
by reg_n_calls_crossed. A PIN CANNOT SCHEDULE AROUND A CALL — sometimes the correct move is to
UNPIN. Refutes the universality of sched.md S11 step 1 and the 'always try pins' reflex.
- plus §176-D (CSE levers in reverse), §176-E (two cc1-probed spellings), §176-F (four residual
verdicts that were lying).
- the section ends with an explicit 'What is NOT banked here' listing 7 mined items judged too
thin — including two whose functions are still INCLUDE_ASM (lever unverifiable) and one whose
narrative CONTRADICTS the banked C. Recorded so they are not silently lost.
Banking the PROCESS idioms this session produced, which were sitting only in commit messages,
tool docstrings and the wave prompt — none of which a future session reads.
- §176a VERIFICATION-LAYER LAWS: match_one verifies SHAPE not SYMBOL IDENTITY (masks
jal/HI16/LO16 — a wrong callee or wrong global reports MATCH; func_8002A234 cost 5 gate
attempts); a detector is ADVISORY and the gate is the ARBITER (3 wave-G drafts withheld on
symfix flags all banked unchanged); a verifier that can pass WITHOUT BUILDING is worse than
none (stale-binary false pass); an all-zeros gate result is a NULL not a finding; and the
general rule — before believing a measurement, run the control that would make it FAIL.
- §176b BATCH-GATING MECHANICS: gate cost scales with (binary,TU) GROUPS not drafts; batched
drafts must agree with EACH OTHER (type conflicts, duplicate typedefs); compatibility compares
TYPE SIGNATURES ONLY but the declarator suffix matters (too-strict and too-coarse both bit me);
conflict-dropped drafts are recoverable via cast-at-use; a COMPILE error names its own culprit
so only a BYTE mismatch needs bisection.
- §176c MAIN CANNOT BE GATED INCREMENTALLY — psyq_integrate/ld_interleave rewrite the .ld;
byte-proven both ways including with NO draft substituted. Use tools/gate_main.py.
Agent-discovered matching idioms are being mined from all 14 wave journals in parallel and land
next as §176.
- 48 atlas mass cards on ov_SC02_000 with --min-ins 40: 45/48 shape-verified, 42 banked,
ONE gate group. stubs 11,549 -> 11,477. distinct-code 90.4%.
- the band question is answered: 94% draft at avg 65 ins (up to 119), after 98% at avg 51 in
wave M. The mass lane is NOT size-limited in the band the instruction-weighted metric tracks.
- 2 NEARs enqueued with unusually deep analyses, both reusable beyond their own functions:
* func_80189C6C (close=2): magic 0x66666667 + mfhi-shift 5 DECODES to a plain /80 — write
'(x<<12)/80' and let gcc synthesize its own magic multiply. Residual root-caused against
REAL cc1 -da RTL dumps to loop.c move_movables desirability (threshold 29 vs measured
insn_count 24-26). Matches the func_80015A74 hard-tail class.
* func_80185840 (close=3): 'register u32 zr __asm__("$0"); c = val + zr;' reproduces the
non-coalescing addu-zero copy that cookbook §52a had classified as a WALL; plus 'r = K;'
before a SINGLE-armed if is what lets reorg's backward scan steal the li into the delay
slot (any two-arm spelling needs the eager target-thread steal, which never fires).