Commit Graph

1520 Commits

Author SHA1 Message Date
Drew T 61f3745193 feat(phase-31): S53 recovery — 10 more main functions banked (declaration reconciliation; EXE 143dbb89 byte-identical) 2026-08-16 22:38:47 -06:00
Drew T 1ebca23c87 feat(phase-31): gate_main hoists TU typedefs above the include block (§181 class 2); +3 recovered drafts banked 2026-08-16 22:20:56 -06:00
Drew T dc7e62c834 feat(decomp): worker gate — +21 fns x0 propagated (fleet 95.6%) 2026-08-16 20:16:34 -06:00
Drew T 486321996c feat(decomp): propagate func_801808C4 (gate lane) 2026-08-16 20:06:04 -06:00
Drew T d27ba537f8 feat(decomp): worker gate — +36 fns x0 propagated (fleet 95.6%) 2026-08-16 20:04:51 -06:00
Drew T e960382de7 feat(phase-31): wave R — 18 main functions banked (EXE 143dbb89 byte-identical) 2026-08-16 20:03:03 -06:00
Drew T 6bc8bb6894 feat(phase-31): wave Q — 40 main functions banked; + fragment_check.py and bisect_slate.py
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.
2026-08-16 17:21:10 -06:00
Drew T ec42c2116c feat(phase-31): worker gate — +8 fns x0 propagated (fleet 95.5%) 2026-08-15 21:56:44 -06:00
Drew T ad2aa6173f feat(phase-31): wave P — 32 main functions banked, main byte-identical (S52)
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).
2026-08-15 21:55:38 -06:00
Drew T 34a4d63d4e feat(phase-31): worker gate — +4 fns x0 propagated (fleet 95.5%) 2026-08-15 14:02:43 -06:00
Drew T 110570e3fc feat(phase-31): wave O — 46 main functions banked, main EXE byte-identical (S52)
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.
2026-08-15 14:01:19 -06:00
Drew T 1149feec2c feat(phase-31): propagate func_80186C44 (gate lane) 2026-08-15 09:49:54 -06:00
Drew T fa7204e531 feat(phase-31): worker gate — +1 fns x0 propagated (fleet 95.4%) 2026-08-15 09:46:12 -06:00
Drew T b9f2540aa7 feat(phase-31): propagate func_80181B4C (gate lane) 2026-08-15 08:08:34 -06:00
Drew T cb93147138 feat(phase-31): propagate func_80186764 (gate lane) 2026-08-15 08:08:24 -06:00
Drew T 6634db313d feat(phase-31): propagate func_80187738 (gate lane) 2026-08-15 08:08:14 -06:00
Drew T 0b838da46c feat(phase-31): propagate func_80187DB8 (gate lane) 2026-08-15 08:08:00 -06:00
Drew T f59b0fdc75 feat(phase-31): propagate func_801884FC (gate lane) 2026-08-15 08:07:50 -06:00
Drew T 308e59d995 feat(phase-31): propagate func_80186E6C (gate lane) 2026-08-15 08:07:40 -06:00
Drew T 1919009dc4 feat(phase-31): propagate func_80184A08 (gate lane) 2026-08-15 08:07:30 -06:00
Drew T 9f69581941 feat(phase-31): propagate func_80183754 (gate lane) 2026-08-15 08:07:17 -06:00
Drew T 3a708363b5 feat(phase-31): propagate func_801860E4 (gate lane) 2026-08-15 08:07:03 -06:00
Drew T 133e3c4e4c feat(phase-31): propagate func_80181934 (gate lane) 2026-08-15 08:06:54 -06:00
Drew T c2cf9f226c feat(phase-31): propagate func_80181820 (gate lane) 2026-08-15 08:06:40 -06:00
Drew T ccf48cf090 feat(phase-31): propagate func_80188790 (gate lane) 2026-08-15 08:06:22 -06:00
Drew T 3f31273793 feat(phase-31): propagate func_8018825C (gate lane) 2026-08-15 08:06:12 -06:00
Drew T 303e1ffc4b feat(phase-31): propagate func_8018512C (gate lane) 2026-08-15 08:05:58 -06:00
Drew T 62bda0dc38 feat(phase-31): propagate func_80183814 (gate lane) 2026-08-15 08:05:40 -06:00
Drew T 58b0547859 feat(phase-31): propagate func_80186424 (gate lane) 2026-08-15 08:05:26 -06:00
Drew T 3344015a12 feat(phase-31): propagate func_80188134 (gate lane) 2026-08-15 08:05:15 -06:00
Drew T 82744a4f85 feat(phase-31): propagate func_80188028 (gate lane) 2026-08-15 08:05:05 -06:00
Drew T 22878beeeb feat(phase-31): propagate func_801854CC (gate lane) 2026-08-15 08:04:52 -06:00
Drew T ec4c02b1d2 feat(phase-31): propagate func_80184250 (gate lane) 2026-08-15 08:04:42 -06:00
Drew T 90eb6204d6 feat(phase-31): propagate func_80186CE8 (gate lane) 2026-08-15 08:04:32 -06:00
Drew T 597a1a2f48 feat(phase-31): propagate func_80186D88 (gate lane) 2026-08-15 08:04:18 -06:00
Drew T 84753840a5 feat(phase-31): propagate func_801829F8 (gate lane) 2026-08-15 08:04:08 -06:00
Drew T 46cc75a5ce feat(phase-31): propagate func_80184B14 (gate lane) 2026-08-15 08:03:57 -06:00
Drew T 229c6fa8df feat(phase-31): propagate func_80182894 (gate lane) 2026-08-15 08:03:47 -06:00
Drew T 910950423a feat(phase-31): propagate func_801819F4 (gate lane) 2026-08-15 08:03:37 -06:00
Drew T 0e1aa40609 feat(phase-31): propagate func_80181C10 (gate lane) 2026-08-15 08:03:27 -06:00
Drew T dac6fd016e feat(phase-31): propagate func_8018419C (gate lane) 2026-08-15 08:03:16 -06:00
Drew T b5b3072d88 feat(phase-31): propagate func_80187F30 (gate lane) 2026-08-15 08:03:06 -06:00
Drew T c0c19b5c00 feat(phase-31): propagate func_80187354 (gate lane) 2026-08-15 08:02:56 -06:00
Drew T f55032ea56 feat(phase-31): worker gate — +42 fns x0 propagated (fleet 95.4%) 2026-08-15 08:02:45 -06:00
Drew T 8225ba9d8a feat(phase-31): propagate func_8018AD3C (gate lane) 2026-08-15 06:41:54 -06:00
Drew T 69b1ef8606 feat(phase-31): worker gate — +40 fns x0 propagated (fleet 95.4%) 2026-08-15 06:38:07 -06:00
Drew T a852982105 feat(phase-31): wave L — 42 MAIN functions banked, R22 213/213 (main 133 -> 175)
- 44 atlas mass cards -> 44/44 shape-verified, 42 banked (2 dropped: a duplicate SVECTOR
  typedef and a u8[] vs char[] decl conflict). main stubs 955 -> 913. fleet stubs -> 11,589.
- first wave carrying law 1c (match_one masks relocations => verifies SHAPE not SYMBOL
  IDENTITY; re-check every symbol against the target .s relocation lines after MATCH).
- the compile-error shortcut paid for itself: named 'SVECTOR at src/800.c:94' and the exact
  draft in seconds, where the old bisect path burned 28 minutes producing nothing.
- KNOWN NEXT IMPROVEMENT: gate_main should strip duplicate typedefs on substitution the way
  harvest_verify already does — src/800.c carries a local SVECTOR from a previously banked
  function, so any later draft defining its own collides. Mechanical, recurring, cheap.
2026-08-15 06:02:18 -06:00
Drew T cf36cf6f21 feat(phase-31): wave K — 41 MAIN functions banked, R22 213/213 (main 38 -> 79)
- 44 atlas mass cards on main -> 44/44 standalone, 41 banked after 3 in-TU decl-conflict drops.
  gate_main clean rebuild -> 143dbb89 BYTE-IDENTICAL, then full-fleet R22 213/213.
  main stubs 996 -> 955; main REAL 92 -> 133 (incl. propagated/dedup credit).
- took 5 attempts; each exposed a real defect, the last one substantive:
  * conflict checker too coarse (u8 D_x == u8 D_x[])            -> fixed + NC'd
  * my pkill pattern matched its own shell                       -> stop shell process-matching
  * FALSE PASS: sha() read a stale binary when the build failed  -> rm output + check returncode
  * bisect burned clean rebuilds; the compiler names the culprit -> read the error instead
  * THE REAL BUG: func_8002A234 stored to the WRONG GLOBALS (v1->D_80078EE8/0->D_80078EE4,
    target is the reverse). 2 bytes, both at %lo relocation offsets.
- STANDING CAVEAT (write this into the wave prompt): match_one MASKS jal/HI16/LO16, so it
  verifies INSTRUCTION SHAPE, NOT SYMBOL IDENTITY. A draft that calls the wrong function or
  stores to the wrong global passes standalone every time. Only the whole-binary gate sees it
  — same class as the PsyQ symbol-name errors in waves F/G.
2026-08-15 05:35:59 -06:00
Drew T b8dbf6f6a7 feat(phase-31): wave J — 34 MAIN functions banked (main 4 -> 38), R22 213/213
- first full wave against the main EXE: 40 atlas mass cards -> 39/40 standalone (98%), ALL haiku.
  main drafts exactly like an overlay; the only special handling is the gate path.
- gated via the clean-rebuild batch path: substitute -> make extract BINARY=main -> make build
  BINARY=main -> 143dbb89 BYTE-IDENTICAL; then full-fleet R22 213/213. main stubs 1030 -> 996.
- NEW CLASS: in-TU cross-draft declaration conflicts. Batching N drafts into ONE .c means their
  externs must agree with EACH OTHER (D_800A4ED4 s16-vs-u16; func_8001C9D0 void/void*/s32).
  Resolved greedily (keep-in-order, drop incompatible) at a cost of 5 recoverable drafts.
- the recovery lever, proven on func_80037368: adopt the shared header's decl VERBATIM
  (extern u8 D_80076251;) and adapt at the USE site ((&D_80076251)[i]) instead of redeclaring.
- NOTE on my own tooling: my first conflict detector compared parameter NAMES and wrongly
  dropped 2 good drafts ((s32 *_) vs (s32 *)); comparing type signatures only recovered them.
  Second time tonight a refusal check of mine discarded good work (R39).
2026-08-15 03:57:50 -06:00
Drew T f22d4c7e51 feat(phase-31): wave I — 44/44 banked (perfect sweep), R22 213/213
- 44 atlas mass cards on ov_SC07_007 -> 44/44 standalone MATCH (independently re-verified),
  symfix clean on all 44, and the binary builds BYTE-IDENTICAL with every draft substituted.
- includes a fleet-shared engine_core.h arity fix (func_8017FD2C(u8*) -> ()), so this batch
  needed the full-fleet proof: make clean && extract-all && check-all -> 213/213.
- stubs 11,751 -> 11,706.
- TOOLING NOTE for next session: gate_lane SWALLOWS gate_stage's stderr. Two gate attempts
  reported 'banked 0, near 0, failed 0' -- an unreported crash that reads exactly like a
  legitimate 'nothing banked'. Running gate_stage directly surfaced the real cause at once
  (corpus.CorpusError naming 16 missing .s files, fallout from my own make clean). gate_lane
  should surface stderr / distinguish CRASH from NOTHING-BANKED.
2026-08-15 03:20:13 -06:00