mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-29 07:10:32 -04:00
6bc8bb6894
Wave Q (90 cards / 6,249 ins) was stopped mid-flight, then a repair-only pass recovered 12 of its
39 unfinished drafts (+579 ins, 51 -> 64 verified MATCH). Banking took two new tools, because the
gate failed three times on causes no C-level check can see.
tools/fragment_check.py (NEW) — the enclosing-function trap, both halves, in milliseconds:
* a draft whose [addr, addr+4*nins) SUBSUMES another symbol. splat labels addresses that are not
functions (a bare epilogue tail, a jump-only branch target, an interior label); convert the
enclosing function and a neighbour's `jal .L80050F24` loses its target.
* a draft that DEFINES another stub's symbol in inline asm. MoveImage's repair agent correctly
worked out that a trailing epilogue belongs to MoveImage (splat attributes those bytes to the
NEXT symbol) and emitted `.globl SYS_OBJ_8F4` itself -- right bytes, match_one passes, and the
assembler then sees the symbol defined twice because the fragment still has its own .s.
My first hypothesis was the subsumption case; the tool REFUTED it (clean) and the redefinition
case was the real one. Recording that order, because I built the tool before verifying the
premise -- R35 inverted.
tools/bisect_slate.py (NEW) — gate_main's built-in bisect ran THREE HOURS on a 45-draft slate and
printed nothing. Three defects: it never checked whether the BASELINE builds (if no subset can
pass, the search is doomed from step 1), it logs only when it isolates a single draft, and its
re-split rule degrades toward one rebuild per draft. The replacement runs the NULL CONTROL first
(the same control that refuted this phase's "main is link-blocked" misdiagnosis), logs every step,
and does a true binary search: it found the culprit (SYS_OBJ_1790) in 7 steps and 176 SECONDS.
Result: 40 banked, main stubs 1,803 -> 1,763.