Commit Graph

2403 Commits

Author SHA1 Message Date
Drew T 059266afca feat(phase-32): T1c — md_MAIN_034: func_800CB00C (123 ins) BANKED byte-identical 46153c06 from the stored S72 body; its S68 "compiler wall" pin dropped
- the census's best_draft (.run/wave_g0c/shard30, 174 ins, 7 pins) was a DIFFERENT, wrong body under the bare
  name (R48); the journal (R38) named the real one — .run/O21/opus/func_800CB00C.c (88 lines, 7 BLOCK-scope
  callee externs: gcc-2.7.2 demotes the later-definition type conflict to a warning at block scope). rtu_match
  MATCH 123/123 in the real TU (the S75 redraft too); the S72 resolver had gated only the wrong file, 3x.
- raw splice into src/md_MAIN_034/md_MAIN_034.c; module island pads derived at build (§303); make build
  BINARY=md_MAIN_034 -j8 rc 0, sha 46153c06bca859dec05aff59fb1a77d3add3d02b == check (R53); verbatim strict ok
- config/wave_exclude.txt regenerated (exclude_audit --write): the md_MAIN_034 WALL pin labelled a wrong draft,
  not a wall — 8 -> 7 entries; docs/backlog.md re-rendered (matched rows drop)
- 0 drafting tokens; no Sonnet agent needed (plan T1c adjusted: no redraft)
2026-09-04 23:38:03 -06:00
Drew T c7f5b498ac feat(phase-32): T1b (3) — ov_SC02_017: func_80186C64 (209 ins) BANKED byte-identical c0253499 — the d=2 RELOC-ONLY twin of ov_SC02_016:func_801810C8 via family_remap + four TU spellings
- family_remap --addr 0x801810C8 --from ov_SC02_016 --to ov_SC02_017 --to-addr 0x80186C64 (23 per-overlay
  symbols remapped); rtu_match then named four §376 TU spellings (func_8012A828 (s32, void *); D_801E0F44 s32
  — address-only use; func_80131E00 (); func_80185F88 (s32) — calls already fn-ptr cast) + one TU-provided
  typedef to strip (Prim_8016E7C8, §491 gap 2) -> MATCH 209/209 in the old TU and in the new region TU
- jtbl_carve --func: jtbl_801EE414 clamped to its `sltiu 6` (6 entries) into
  [.rodata, ov_SC02_017_jr_80186C64] + tail19; JTBL_PADS 0,0; carve set 45 -> 46 pieces
- make extract + make build BINARY=ov_SC02_017 -j8 rc 0, sha c0253499eed71309d731862ffc76766d183d031e ==
  check (R53); pads_audit all ok; interleave_check ALIGNED n=46; verbatim_check --strict no drift
- 0 drafting tokens (the journal's S69/S70 lever drafts carried the same body; R38)
2026-09-04 23:36:52 -06:00
Drew T 599dba3ba0 feat(phase-32): T1b (2) — ov_SC02_017: func_80186C64 isolated into its own code subseg [0x5eb0c, c, ov_SC02_017_jr_80186C64] (byte-identical c0253499)
- jr_isolate_all ov_SC02_017 --only func_80186C64 (CLEAN after the §497 carrier fix — no source rename);
  2 region files; make extract + make build BINARY=ov_SC02_017 -j8 rc 0, sha
  c0253499eed71309d731862ffc76766d183d031e == check (R53). Carve state only; the bank is the next commit.
2026-09-04 23:35:19 -06:00
Drew T c513e1fbbd feat(phase-32): T1a (2) — resident: func_800D128C (243 ins) BANKED byte-identical 8e17e02f via the raw splice + a 5-piece carve; three instrument fixes (§498)
- BANK: the stored S71 closeness-0 draft spliced into src/resident/resident_jr_800D128C.c; jtbl_carve --func
  carved jtbl_80113FB8 (119 entries, 1 pad word trimmed) + jtbl_80114198 into [0x451c0, .rodata,
  resident_jr_800D128C] + [0x453c4, data, tail3]; JTBL_PADS 0,4; make extract + make build BINARY=resident -j8
  rc 0, sha 8e17e02ff8954d07c979449198f7e1645046b353 == check (R53). pads_audit ok/ok; interleave_check
  ALIGNED n=5; verbatim_check --strict 5==5. Resident stubs 2 -> 1 (func_800D06E8 remains).
- WHY THE GATE SAID DIFF (parallel_gate banked 0/DIFF on an rtu_match MATCH): jtbl_carve.set_overlays_var
  regenerated resident_JTBL_INTERLEAVE from the carve set and DROPPED the resident's `--pre hdr.rodata.o`
  (§8f leading-rodata sandwich); make extract refused (ld_interleave: hdr.rodata.o would be parked with
  .text), the build linked the STALE script (249,252 differing bytes from file offset 0x4), and
  harvest_verify._jtbl_prep_one never read the post-carve extract's exit code (R49/R61).
- FIXES (R35/R40/R57): jtbl_carve._merge_pre carries an existing --pre forward (idempotent; overlays
  unchanged, 4-shape unit control); harvest_verify refuses loudly on a failed post-carve extract and
  restores the snapshot (CARVE refusal, NOT a draft verdict); interleave_check's anchor accepts a leading
  --pre (was a false DRIFT n=0 on the resident; control ov_SC02_017 ALIGNED n=44 unchanged).
- cookbook §498 (+ the stale-asm-after-a-failed-extract sequencing law); SETUP rows for all three
2026-09-04 23:28:59 -06:00
Drew T 380ccdc843 feat(phase-32): T1a (1) — resident code subseg split (3 regions, byte-identical 8e17e02f) + jr_isolate_all include-derived provided types (§496)
- jr_isolate_all resident --only func_800D128C: [0x4 c resident] [0x12ec c resident_jr_800D00E4]
  [0x2494 c resident_jr_800D128C]; the banked jr func_800D00E4's .rodata carve + JTBL_PADS + --order
  repointed to resident_jr_800D00E4.o (config/overlays.mk resident block only, R60); make extract +
  make build BINARY=resident -j8 rc 0, sha 8e17e02ff8954d07c979449198f7e1645046b353 == check (R53)
- TOOL FIX (R43/R33): the carried-type test consulted _engine_types() (engine_types.h + common.h) for
  every TU, assuming each region includes engine_core.h; the resident includes only common.h, so its
  file-local `typedef struct {...} CdFileLoc;` (a name engine_types.h also defines) was silently NOT
  carried -> `parse error before cdFileLocTable` in both region TUs, build rc 2 while the stale binary
  on disk read green. Now _provided_types(header) derives the set from the TU's own #include lines
  (engine_core.h => engine_types.h + common.h, never engine_core's macro-internal typedefs; common.h
  => common.h) and _file_scope_decls(items, provided) uses it at both decision points. R39 controls:
  overlay header == legacy set (1,197 names); resident set lacks CdFileLoc. cookbook §496; SETUP row
- rtu_match func_800D128C --split resident_jr_800D128C: MATCH (243 ins) on the stored S71 draft;
  the gate is the next commit
2026-09-04 23:20:04 -06:00
Drew T 082ddc8590 feat(phase-31): S80 #10 (2) — ov_SC03_107: func_8017D878 (45 ins, the manifest's one GAME-C verbatim, "37 stored drafts") DECOMPILED: the stored best draft was byte-correct all along — it needed only its real return type (s32: the address of func_80172710 or 0) once the TU's extern void func_8017D878(void) was corrected (commit:3893) — a def-side declaration wall, not codegen; match_one 45/45, rtu_match MATCH, worktree gate banked (its merge step adopted 0 files — spliced in-tree instead) + in-tree byte-identical 87d02b57. ov_SC03_107 is now 100% C; the game's verbatim set is the five PERMANENT rows 2026-09-04 21:49:34 -06:00
Drew T b7f73e7187 feat(phase-31): S80 #10 (1) — md_MAIN_020: func_800CB17C (30 ins) DECOMPILED — the S79 #7 "raw splice" had banked its assembly as a verbatim __asm__ body (P9 correction: that was not a decompile, verbatim_check --strict caught it as a new verbatim); the C is seven straight calls (s0 = a0; func_8012A304(*(s16*)(s0+0xA), 0x80); func_801477E8(s0, 0xFFE80000); func_80154274(s0, D_800CB1F4); func_80147324(0x47A); func_8014C010(s0, 2); func_801483E8(s0); func_80019064(D_80062BD0)) as an s32 function with no return (the target sets no $v0); the TU's block-scope struct S decl needed a file-scope tag (commit:3894); match_one 30/30, rtu_match MATCH, worktree gate + in-tree byte-identical 0990e041 2026-09-04 21:49:33 -06:00
Drew T ec15509e68 chore(phase-31): S80 #10 — md_MAIN_020: a file-scope struct S; tag so the TU's block-scope extern s32 func_800CB17C(struct S *) no longer declares a block-local tag that no file-scope definition can match (conflicting types); byte-identical 0990e041 2026-09-04 21:46:55 -06:00
Drew T dd45617982 chore(phase-31): S80 #10 — verbatim end-state plumbing, byte-neutral: (1) ov_SC03_107:func_8017D878's file-scope __asm__ block (the manifest's one GAME-C row) converted back to an INCLUDE_ASM stub with tools/verbatim_to_stub.py --gate (87d02b57 byte-identical) and the TU's extern void func_8017D878(void) corrected to the real s32 (s32) signature (only its address is taken; ov_SC03_107 rebuilt byte-identical) — the void decl was the def-side wall that refused 37 drafts; (2) md_MAIN_020:func_800CB17C — S79 #7's "raw splice" had committed the function's ASSEMBLY as a verbatim __asm__ body (every stored 'draft' was the asm; verbatim_check --strict flagged it as a new verbatim) → converted back to a stub (0990e041 byte-identical): that bank was not a decompile (P9), the function is open again; (3) manifest _README: the five PERMANENT-VERBATIM rows RATIFIED 2026-09-04 21:45:31 -06:00
Drew T 402b7520c4 feat(phase-31): S79 #9 (10) — ov_SC02_027: func_80180B3C (297 ins, F-FAR) banked from an Opus agent's draft: recovered the S76 closeness-23 body and broke the 5-attempt plateau with four dials — tpg |= (y & 0x200) << 2; as its own accumulator statement, a register u32 c40 __asm__("$2") pin on the (w&0x40)>>6 term, the if (c) v -= 0x100 split into a second variable so sched1's birthing boost stops sinking the mask, and the inverted-arm if (!c) vv = v; else vv = v - 0x100; that keeps the &0xFFFF/-0x100 alive for the u8 store (the same arms un-inverted delete the andi); statement order INERT (792 permutations); real-TU MATCH after dropping the TU's duplicate Blk32_80180908 typedef; worktree gate + in-tree byte-identical 2026-09-04 20:50:13 -06:00
Drew T d04fe31882 feat(phase-31): S79 #9 (9) — main: func_8001EFE0 (468 ins, the largest G-UNKNOWN main body) banked from an Opus agent's draft: recovered the prior closeness-14 body from .run/match and closed all three [permuter]-filed clusters by reading the matched same-TU siblings func_8001DA34/func_8001EA14 — the addPrim tail's ot split so the sll lands between the two pinned luis, one zero-byte fence between the tpage sh and the q[7] RMW, a §419 density asm on (vh,vv2,vw) for the two-SVECTOR fill, and the shift split from its mask; rtu_match --tu src/800.c MATCH, gate_main --apply clean rebuild BYTE-IDENTICAL 143dbb89 2026-09-04 20:47:51 -06:00
Drew T 618e0907d4 feat(phase-31): S79 #9 (8) — ov_SC01_001: func_80181E04 (269 ins, the GAME-GTE 'uncertain' body) banked as compiler C by an Opus agent: sixteen D_801EDA?? globals as one 0x50-stride record array (§246-2/§200), a counted i<0x100 loop, the gte_stsz3 branch shape, and the OT insert as PsyQ's P_TAG addr:24 bitfield store (store_bit_field masks the value first); real-TU MATCH, worktree gate + in-tree byte-identical 2026-09-04 19:57:19 -06:00
Drew T 96c0fc02a7 feat(phase-31): S79 #9 (7) — ov_SC05_010: func_8017FFA8 (88 ins, 6-way jtbl switch) banked from a Sonnet agent's fresh draft (loop index s32 not s16 — §241 fused sign-extend; the D_801922B8 lookup into its own temp before the found/zero stores); tail jtbl carve at gate time; worktree gate + in-tree byte-identical 2026-09-04 19:45:16 -06:00
Drew T cdf50f96d7 feat(phase-31): S79 #9 (6) — ov_SC06_010: func_801809E4 (33 ins) banked by the Sonnet escalation (the Haiku plateau's missing 2 ins was an early return that should fall through into the shared mask/store tail; the -0x10 no-save frame is two s16 locals, §186b); real-TU MATCH, worktree gate + in-tree byte-identical 2026-09-04 19:43:50 -06:00
Drew T 1961a7bfb1 feat(phase-31): S79 #9 (5) — main: func_8002AC98 (114 ins) banked: the generic arm's val = r + b routed through a fresh s32 temp ({ s32 xt = r + b; val = xt; }, with b widened to s32) so expand_binop's target==op1 swap does not fire — the same lever as func_80015608; gate_main BYTE-IDENTICAL 143dbb89 2026-09-04 19:05:29 -06:00
Drew T a296bba0f3 feat(phase-31): S79 #9 (4) — md_MAIN_003: func_800D1D14 (65 ins, -O0 island) banked as genuine C (the S76 verbatim body retired): D_800D3630 read as *(s16*)&D_800D3630[i] so gcc materialises the base instead of folding %lo through $at; byte-identical dd1b32ec 2026-09-04 19:04:55 -06:00
Drew T 0833b418e6 feat(phase-31): S79 #9 (3) — ov_SC05_018: func_80180BE0 (65 ins) banked: the S74 recipe's memcpy(12) became a jal under the TU's extern memcpy; re-spelled as a 12-byte struct assign (the TU's own Blk8 idiom) — real-TU MATCH, worktree gate + in-tree byte-identical 2026-09-04 19:03:23 -06:00
Drew T ec786e0a46 feat(phase-31): S79 #9 (2) — main: func_80015608 (86 ins) banked: a Sonnet agent closed the permuter's last instruction by routing the accumulator add through a fresh temp ({ s32 xt = blockSize + x0; x0 = xt; } — expand_binop's target==op1 swap does not fire on a new pseudo); gate_main BYTE-IDENTICAL 143dbb89 2026-09-04 19:00:03 -06:00
Drew T 80eed5e9e9 feat(phase-31): S79 #9 (1) — md_MAIN_003: func_800D0174 (36 ins, -O0 island) banked from a Haiku agent's fresh C draft; byte-identical dd1b32ec 2026-09-04 18:57:35 -06:00
Drew T 06ee3c1234 feat(phase-31): S79 #8 (1) — main: func_80015760 (106 ins) banked from a permuter ILS score-0 winner (cycle 1) + plumbing: TU data spelling (u8 *D_800A5E60), the callee's TU prototype with a (u16) call-site cast for the target's andi, the permuter's typedef preamble stripped; gate_main BYTE-IDENTICAL 143dbb89 — the S76 journal had filed it as a 'genuine sched1 artifact' 2026-09-04 18:42:41 -06:00
Drew T 7129b6cac8 chore(phase-31): S79 #8 plumbing — main src/800.c: func_80015760's forward decl no-protoed + its 2 call sites cast (cast_self_callers --sync-decls); byte-neutral (143dbb89) 2026-09-04 18:39:40 -06:00
Drew T 42d432770d feat(phase-31): S79 #7 (2) — md_MAIN_020: func_800CB17C (30 ins) banked by a RAW splice, byte-identical 0990e041 — the 'match_one MATCH but the gate rejected — CAUSE NOT DETERMINED' verdict was gate_stage's transform ladder altering a correct body (it gates as NEAR); rtu_match MATCH + raw splice is the route 2026-09-04 18:24:21 -06:00
Drew T bf1b266e07 feat(phase-31): S79 #7 (1) — md_MAIN_003: func_800D06BC (33 ins) + func_800D0100 (29 ins) banked from their close-0 drafts; both are -O0-island bodies (the standalone checker needed --o0, the gate's Makefile wildcard already compiled the TU right); byte-identical dd1b32ec 2026-09-04 18:24:21 -06:00
Drew T 62475f7883 feat(phase-31): S79 #6 (3) — two twin banks: ov_SC04_018:func_80181CB8 (67 ins, tail jtbl carve, pads 0,0,0,0,4) and ov_SC05_005:func_80181828 (87 ins, exact clone of ov_SC05_003:func_80181720 via family_remap)
Both gated in parallel worktrees (parallel_gate, pinned at commit:3870) and rebuilt in-tree
byte-identical: ov_SC04_018 fe9b413f (after `make extract` — the merge changed the yaml carve
rows tail18-20 and the JTBL_PADS spec, and the main tree's split was stale until re-extracted),
ov_SC05_005 452897fc. The ov_SC05_005 remap needed two plumbing fixes: the TU's stale
`extern void` prototype (committed byte-neutral in commit:3870) and the draft's duplicate
Prim_8016E7C8 typedef (identical to the TU's, still a redeclaration for gcc 2.7.2).
2026-09-04 18:10:59 -06:00
Drew T 02e2cb265a chore(phase-31): S79 #6 plumbing — ov_SC05_005: func_80181828's extern returns s32 (its body is the twin of ov_SC05_003:func_80181720); callers ignore the value, byte-neutral (452897fc) 2026-09-04 18:08:23 -06:00
Drew T af1644c02b feat(phase-31): S79 #6 (2) — ov_SC04_018: func_80181804 banked from its ov_SC04_019 twin (77 ins, byte-identical fe9b413f); its jump table was already inside the TU's carve, only the JTBL_PADS spec had been trimmed to 3 tables (S62) — now 0,0,0,0 2026-09-04 18:08:03 -06:00
Drew T 0ab51c803c feat(phase-31): S79 #6 (1) — md_MAIN_003: D_800D3200 was a data word carried as a stub; emitted inside its asm island, byte-identical (dd1b32ec); the census's H-VIRGIN phantom is gone 2026-09-04 18:00:01 -06:00
Drew T 02f060f607 feat(phase-31): S79 #5 — the libpad 4.2.1 + libapi 4.2 band and the apicard region LINKED from real objects: 13 stubs + 4 TUs + the reorder island gone; main 16 stubs, fleet 38
800c3 (0x8005CE18-0x8005FC68, one contiguous run of 33 interleaved Sony objects) is now four
stub rows — libapi1 (21 BIOS trampolines + COUNTER), libpad1 (PADENTRY + PADMAIN 760), libapi2
(L02/L03), libpad2 (PADCMD PADIF PADPORTD PADSEQD WAITRC2) — fed by two WINDOWED psyq_integrate
calls from the raw .run/obj42/{libapi42,libpad421} dirs (integrate tiles each stub with one
library; every boundary checked against .text SECTION sizes). The apicard region's three
"game code" rows were libapi 4.2's C objects to the byte: 800c2 = FIRST.o (firstfile + the
"no jump table wall" stub func_80062144), 800c2_2 = PAD.o, 800c2_3 = PATCH.o + CHCLRPAD.o ->
apicard5/6/7; make_apicard_used.py sources libapi from 4.2 (the EXE's real libapi; libcard
stays 4.0) into .run/obj42/apicard_used, 26 objects / 7 blocks, no game code left in
0x80061F38-0x80062888. src/800c3.c (129 hand-matched "C", 62 verbatim bodies, 19 stubs incl.
the four §332 %lo-in-a-delay-slot "walls"), src/800c2.c, src/800c2_2.c, src/800c2_3.c removed;
REORDER_TUS is empty (mechanism kept). Cookbook §490.

Two stale instruments fixed: exclude_audit let a pinned WALL outrank LINKED (PopMatrix/
PushMatrix had sat as walls since S68 while living in libgte3, linked since Phase 8) — LINKED
dominates now, config/wave_exclude.txt 13 -> 3; frontier_classify carried a hard-coded 49-name
LINKED set (R51) and reported 337 "stubs" — derived from the Makefile now.

Verified: main 143dbb89f34491258bbc27810d0a12ec8b43a8dd WITH all SDK dirs and WITHOUT them from
a fresh extract; make tools-health OK; R22 fleet extract-all 212/212 + check-all 213/213.
Metrics: main REAL 839->773, LINKED 1,150->1,256, VERBATIM 29->3, stubs 29->16, byte-identical
2,075/2,091 = 99.2%; game-code weighted 93.3% (38,748/41,534), remainder 2,786 = the open-stub
sum; fleet stubs 51->38 (frontier_classify: 39 rows incl. the data word). Verbatim manifest
33 -> 6. Docs: worklist rows + "S79 task #5", SETUP (fresh-clone obj42 commands, Makefile
blocks, exclude_audit), decision-log "S79 addendum 2", accelerators "S79 (2)", CURRENT_PHASE
S79 FINAL refreshed (census, metrics, the task #6 brief).
2026-09-04 17:56:31 -06:00
Drew T 757bd82a0f feat(phase-31): S79 #4 — scattered-.bss split at link-prepare (psyq_bss_split): SYS.o→libgpu2, VM_F.o→snd12, GS_001.o→libgs8 LINKED; libgpu_used retired
The §9.1 "scattered .bss commons" exclusion class (Phase 8 → P31) is closed 3/3. New
tools/psyq_bss_split.py (own ELF32 REL reader/writer) cuts an object's packed .bss into
per-base NOBITS pieces: bases derived from the game bytes per HI16/LO16 pair, references
walked in offset order into single-base runs, cuts snapped to symbol starts (the linker
scattered SYMBOLS), symbols moved, a LOCAL section symbol per piece inserted, relocs
retargeted with the addend rewritten in the immediates, self-diffed. It runs inside the one
prepare step shared by psyq_link.link_object / psyq_link_region.build_region /
psyq_integrate.integrate (prepare_object before classify), re-derived every build.

GS_001.o was certified "5 interleaved bases, NOT splittable" by the S77 probe, which grouped
by BASE; by RUN it is six symbol-aligned pieces. All seven cuts across the three objects are
confirmed by the other objects' by-name recoveries (_que 0x800C5510, _svm_sreg_buf
0x800B9B58, PSDBASEX/CLIP2/PSDBASEY/POSITION/GsDRAWENV). R39 negative control: 235 placed
objects across 9 curated dirs, 0 refusals, exactly 3 splits (a libcd .bss+size end pointer
refused the first build → reference problems are fatal only when a split is needed).

Wiring: yaml 800c→libgpu2, sgap_6→sgap_6+snd12, gsgap3→libgs8 (comments rewritten);
LIBGPU_ELF := .run/obj40/libgpu (curated libgpu_used retired); libgs 34 objs/8 blocks
(make_libgs.sh +GS_001); snd 63/12 (make_snd_used.py exclusions 4→3). src/800c.c and
src/gsgap3.c removed (Sony code hand-matched as REAL/verbatim), sgap_6.c keeps only
func_8003FA54; splat-emitted libgpu2.c/libgs8.c/snd12.c stubs for the no-SDK fallback.

Verified: main 143dbb89f34491258bbc27810d0a12ec8b43a8dd WITH the SDK objects and WITHOUT
them from a fresh extract; make tools-health OK; R22 fleet clean extract-all 212/212 +
check-all 213/213. Metrics: main REAL 886→839, LINKED 1,040→1,150, VERBATIM 85→29, stubs 29
(unchanged); game-code weighted 91.1% (40,895/44,870) — both terms lost the 3,667 SDK ins;
the remainder is still exactly the 3,975-ins open-stub sum. Verbatim manifest --update
200→33 rows (subtractive). Docs: cookbook §489 (+index), psyq-worklist rows + "S78 task #4",
SETUP S79 R21 table, decision-log S79 addendum, accelerators S79, CURRENT_PHASE S79 FINAL 🛑.
2026-09-04 17:19:29 -06:00
Drew T a85733a487 feat(phase-31): S78 #3 — 13 "game code" subsegs were PsyQ objects: wired LINKED (libgte 70/30, libgs 33/7, snd 62/11); main's game-code metric corrected to 91.8%
- exact tiles, 0 tokens: libgte23-26 (MSC01/02/05/09, SMP_00, FGO_01-06, PATCHGTE), libgte9 re-derived
  as SMP_05 NormalClip (SMP_06 NormalClipS = nested sub-pattern; psyq_integrate now drops nested
  placements), libgte27-30 (the libgs-gap MTX_05/07/11, REG03+REG11), libgs7 (2D_BG0+2D_BG1), snd10
  (VM_NO1), snd11 (VM_NOWON carved off sgap_8). LINKED 959->1040, REAL 912->886 (SDK inline-asm wrappers
  re-provenanced), VERBATIM 146->85, 13 TUs deleted; splat re-emits the stub records.
- main 143dbb89 WITH and WITHOUT the SDK objects. The no-SDK fallback had been red since S7x
  (CdReadyCallback called by its SDK name while the libcd stub carried func_800435B4) — curated
  CdReadyCallback = 0x800435B4, refs unified. R22 clean fleet 213/213; tools-health OK.
- METRIC CORRECTION (R35): progress.py's "MAIN game-code weighted" sig never excluded the LINKED
  objects (its comment said it did) — ~31k linked-SDK ins sat in the denominator as unmatched game
  code. Exclusion now derived LIVE from the Makefile stub lists + yaml ranges: 91.8% (44,562/48,537),
  not 59.8%; the 3,975-ins remainder equals the open-stub sum exactly.
- VM_F.o probed SPLITTABLE at .bss 0x50c (SYS.o's class -> task #4). cookbook §488; worklist S78 #3;
  decision-log + accelerators; SETUP rows.
2026-09-04 16:26:12 -06:00
Drew T a7394f44dc feat(phase-31): S78 #12 — the 800c3 "wall" band is LIBPAD 4.2.1 + LIBAPI 4.2: 46 names applied; integrate wired by subseg range; renames via ApplySymbols
- provenance: the psx loader's per-version PsyQ signature sets place PADENTRY/PADCMD/PADPORTD/
  PADSEQD (4.2), WAITRC2 (4.3), COUNTER/C114/FIRST/PAD/PATCH/CHCLRPAD (libapi 4.2) byte-exact in
  0x8005CE48-0x8005FC68 / 800c2 -> 12 of main's 29 stubs incl. all four §332 walls are Sony's
  DualShock library in reorder mode. 46 names -> symbols.us.txt (count 1081), band TUs, verbatim
  manifest, wave_exclude; firstfile/firstfile2 (4.2 naming); CdGetToc @0x800430B8 (was the Phase-21
  xdedup mislabel DecDCToutCallback). SETUP §5.1 corrected; psyq-worklist S78; cookbook §487;
  decision-log + accelerators S78; CHECKSUMS +Psy-Q_46.zip +PSYQ_SDevTC_v4.5.zip.
- psyq_integrate: --yaml maps stub<->objects by SUBSEG RANGE with an exact-tiling check and PRINTS
  the located-but-unwired residue (libgte: 13 objs / 1,264 ins) — main's LINKED build had been RED
  at HEAD since the S77 psyq_identify fix (22 libgte blocks merged to 3; gate worktrees take the
  stub fallback so it never showed); a library object's exported symbol whose recovered address the
  curated file names differently is --redefine-sym'd (R15; A66 firstfile->firstfile2).
- Ghidra: 47 MCP renames did NOT persist through the sentinel stop (R9 caught it) -> NEW
  tools/ghidra_scripts/ApplySymbols.java + tools/ghidra_apply_symbols.sh mirror the curated file
  headless with a real save: 73 renamed, R9-verified x4. SETUP inventory rows (R21).
- lint_symbol_refs: scans verbatim __asm__ bodies (`.ent\tfunc_X` is invisible to \b and to the
  string-masked scan); negative-controlled (red on the pre-fix TUs, green on the passing tree).
- R22: clean extract-all 212/212 + check-all green on the final config; main rebuilt byte-identical
  143dbb89 after the last src-only fix -> 213/213; tools-health OK.
2026-09-04 15:57:06 -06:00
Drew T b31e499c9b fix(carve): repoint 800_b_2's INCLUDE_ASM paths to its own subseg
The 3-way split moved func_8002FDE8 and func_80032A74 into the 800_b_2 subseg,
but their INCLUDE_ASM directives still named "asm/nonmatchings/800_b". The
incremental build passed anyway because the OLD .s files were still on disk;
make clean removed them and splat now emits under 800_b_2, so a genuinely clean
rebuild died in jtbl_rodata_pads:

    FileNotFoundError: asm/nonmatchings/800_b/func_8002FDE8.s

This is exactly what R22 exists to catch, and it is the reason a byte check is
only trustworthy from a clean tree. asm/nonmatchings/800_b no longer exists at
all -- piece 1's three functions are all banked, so splat emits no directory
for it.

main rebuilds 143dbb89f34491258bbc27810d0a12ec8b43a8dd from a clean extract.
2026-09-03 22:26:10 -06:00
Drew T f4ff8267a5 feat(decomp): bank main:func_8002C410 (299 ins) — the first -O0 island in main
The body was MATCH 299/299 from the S77w wave and could not bank for want of an
-O0 object. With the 3-way carve in place it gated first try.

gate_main: BANKED 1, 143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL.
2026-09-03 22:21:24 -06:00
Drew T a13b2a5c38 carve(main): 3-way -O0 island split of 800_b for func_8002C410
func_8002C410 MATCHES 299/299 at -O0 and DIFFs 228-vs-299 at -O2 (verified
independently with match_one --o0 vs --no-auto-o0). gcc-2.7.2 has no
per-function optimize pragma, so opt level is per FILE, and the function needs
its own object. Main had no path to one: the Makefile's -O0 wildcard covered
src/ov_*/ and src/md_*/ but NOT top-level src/*.c, and o0_subsplit.py is
overlay-shaped -- it died on config/splat.main.yaml, which does not exist.

Measured the scope first (R37): the -O0 detector flags exactly TWO open main
stubs -- this one, and func_80011380, which already lives in -O0 boot.c and is
the proved floor. So this unblocks one function, not a class.

FIVE COUPLED PIECES, which is why the carve is worth recording:
  1. splat code rows: 800_b cut 3 ways -- 800_b / 800_b_o0a / 800_b_2
  2. splat .rodata: span B SPLIT, because the 3-way cut put its two jtbl owners
     in different objects -- func_8002B0B4 into 800_b, func_800335B8 into
     800_b_2 -- and one code object may contribute exactly ONE contiguous
     .rodata run. The boundary is DERIVED, not guessed: 800_b.o's compiled
     .rodata is 0xf8 bytes, so the front run ends at 0x80072E44+0xf8. The
     build's own jtbl_rodata_pads caught the missing piece.
  3. src/800_b.c split 3 ways -- 86-line prologue duplicated, 3 defs before the
     island, 97 after
  4. Makefile -O0 glob widened to top-level src/*_o0?.c
  5. ld_interleave --order: 800_b_2.o inserted after 800_b.o. Missing this
     floated the tail rodata and shifted every data symbol by exactly its size,
     +0x204, across 704 two-byte runs -- which is how it was found.

o0_subsplit.py now REFUSES main loudly instead of dying on a missing file
(R43/R61a) and names the manual procedure.

VERIFIED BYTE-NEUTRAL BEFORE ANY BANKING: main builds
143dbb89f34491258bbc27810d0a12ec8b43a8dd with the split in place and
func_8002C410 still an INCLUDE_ASM stub.
2026-09-03 22:20:57 -06:00
Drew T 335e1d677d feat(decomp): bank main:func_8001EA14 (371 ins) from close=89
Five new levers, all in the draft header. The headline one (L5): STATEMENT
ORDER IS THE ALIAS ORDER — a mem/s local matrix store can never be hoisted over
by a mem/s varying p-> load, because true_dependence's exemption needs one side
non-struct AND non-varying. Writing the matrix init in NATURAL OFFSET ORDER
closed the whole 45-instruction init block, and the same law one scope down
removed the +1 length drift.

Also: an inline-asm "r" operand that is a bare symbol_ref has NO pseudo and is
allocated by reload ($t0); assigning it to a local first makes it a pseudo and
local-alloc gives $v0 — worth 10 instructions.

A scripted 858-candidate sweep PROVED mode/rot/shift placement inert, which is
what redirected the hunt from LUID to DAG/allocation.

gate_main: BANKED 1, 143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL.
2026-09-03 20:43:01 -06:00
Drew T 8754b1a671 feat(decomp): bank main:func_800301C8 (170 ins), first-gate clean
18 -> 0 via three levers, all worth reading in the draft header: the sibling
func_8002FF0C's block-scope scalar spelling of D_800A46D2 (the array spelling
lets cse cache 'la $s1' across the call); splitting a $17 pin so only the
b*24 intermediate is pinned (expand_mult passes accum_target=target, and a HARD
target survives expand's generate-into-pseudos guard, so pinning the result
drags the whole chain); and pinning the DESTINATION for idx98, because
'addu $s0,$s1,$s0' is expand_binop swapping commutative operands to make
op0==target, not tree order.

Gated compatible on the first try — the agent had verified the spliced TU
compiles rc=0 with an instruction stream identical to the standalone compile.

gate_main: BANKED 1, 143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL.
2026-09-03 20:32:57 -06:00
Drew T 79006e5f4d feat(decomp): bank main:func_8006252C (§378 chain + the double re-tie)
Took three tools in order, and the first two were wrong:
  - scope_demote_drafts BROKE it (it aliased D_80078D08 through __asm__ and the
    build failed) — the clash was never a data extern
  - the real clash was func_8006252C ITSELF: TU void(void) vs draft s32(void),
    i.e. self_decl_tu -> cast_self_callers --sync-decls, 4 call sites
  - then sync_tu_decls closed func_800625DC and func_80062644

The BODY is the interesting part and is now cookbook §482: two INDEPENDENT asm
re-ties, ordered, because one barrier fixes one residual and re-creates the
other.
2026-09-03 20:31:27 -06:00
Drew T 6f5d1ecdca plumb(main): §378 self-caller casts for func_8006252C
TU declares it void(void), the draft returns s32 — the self_decl_tu class.
4 call sites cast; baseline green with NO draft substituted (143dbb89...).
2026-09-03 20:29:47 -06:00
Drew T 8e3e084f3b feat(decomp): bank main:func_8005D588 via the §8d scope-demote
gate_main has no scope-demote rung — only gate_stage's ladder calls
scope_demote_drafts, so a MAIN draft never saw §8d. Running it by hand demoted
7 file-scope data externs to block scope (D_80072960 among them, whose TU
spelling is void(*)(void) against the draft's void(*)(void*)) and the byte gate
then accepted the body.

gate_main: BANKED 1 of 3 after bisection, 143dbb89f34491258bbc27810d0a12ec8b43a8dd
BYTE-IDENTICAL. The other two are genuine rejects: func_8005FA94, and
func_8005D33C whose rejection shows the mass symbol shift its own agent
predicted from the jump-table rodata placement.
2026-09-03 20:24:44 -06:00
Drew T 1f2ae12b5d feat(decomp): bank main:func_8001FC08 (400 ins) and func_8002FF0C (166 ins)
Both bodies were already solved in S76 and had never banked. Neither needed a
codegen change — they needed the gate to stop applying a rule cc1 does not
(§481 / the _depth0 fix): func_8001FC08 renames its struct to MTX_8001FC08 and
declares D_80074818/D_80075018 at block scope, and func_8002FF0C shadows
D_800A46D2 with a block-scope scalar because the array spelling forces la and
costs 12 mismatches.

gate_main: BANKED, 143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL.
2026-09-03 20:21:22 -06:00
Drew T 5b8a0d0804 feat(decomp): bank main:func_8005D538 from the S77w wave
Plain C, no §265 verbatim needed — the pack's prior FAILED attempt had
over-thought it. Two levers: omit the forward decl for func_8005E188 so the
call is implicit K&R (fixing both an s0/s1 order swap and a spurious
sign-extend a visible prototype would insert), and close the 2 trailing pad
words with a file-scope __asm__ per the §295 class.

gate_main: BANKED 1, 143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL.
2026-09-03 20:19:20 -06:00
Drew T c35a21449e feat(decomp): bank func_8005E13C and func_8005EAE8 from the S77w wave
gate_main: BANKED 2, 143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL.

func_8005EAE8's agent resolved its own integration conflict — it adopted the
TU's declarations for func_8005DCA0 and D_80072974 and cast at the use site
rather than declaring its own incompatible externs.
func_8005E13C reproduces a trailing orphan pad nop (belonging to neither it nor
SysEnqIntRP) with a file-scope __asm__; the verbatim detector correctly does
NOT flag that as a §265 body.
2026-09-03 20:15:17 -06:00
Drew T a0c855648c feat(decomp): bank ov_SC01_084:func_80182A00 (§378 chain, 207 ins)
harvest_verify: verified 1 / failed 0, ef86fe1e403998a82ead42f4466ac4bc80f2c8d1
BYTE-IDENTICAL. The static probe had called this a `local_type' Blk16 conflict;
the real gate strips TU-provided typedefs and then named the true blocker.
2026-09-03 19:42:05 -06:00
Drew T 534979b4e7 plumb(ov_SC01_084): §378 self-caller casts for func_80182A00
harvest_verify named the step-2 signature exactly: `too few arguments to
function func_80182A00' at ov_SC01_084_jr_80182A00.c:534. 4 call sites cast.
Baseline green with NO draft substituted: ef86fe1e403998a82ead42f4466ac4bc80f2c8d1.
2026-09-03 19:41:45 -06:00
Drew T 337a040047 feat(decomp): bank main:func_80024054 via permuter ILS (DELAY-SLOT/2, 4 of 91)
Score 0 on cycle 1. gate_main: BANKED 1, 143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL.
2026-09-03 19:39:54 -06:00
Drew T a614d972c2 feat(decomp): bank main:func_80040DE8 via permuter ILS (REGALLOC-PERM/$t1>$v1, 2 of 347)
Score 0 on cycle 1. gate_main: BANKED 1, 143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL.
2026-09-03 19:28:55 -06:00
Drew T 94b528b54e feat(decomp): bank main:func_80021174 via permuter ILS (SCHEDULE-REORDER/2)
The residual was a two-instruction adjacent swap in the target's favour:

    idx 49  MINE lh   $a1, 0($sp)      TARGET sra $a2, $v1, 16
    idx 50  MINE sra  $a2, $v1, 16     TARGET lh  $a1, 0($sp)

Hand lever tried first and REFUTED by bytes: hoisting `a0 = a0 >> 16` above
the load is semantics-preserving (a0 is untouched in between) but scores
23 mismatched at 67/68 ins — it lets gcc fold an instruction away entirely.

permuter_ils --klass SCHEDULE reached score 0 on cycle 1. Its winning edit is
a clean C-level one: drop the `a1 = *(s16 *)sp;` temporary and inline the load
into both comparisons, which is what moves the sign-extend ahead of it.

gate_main: BANKED 1, 143dbb89f34491258bbc27810d0a12ec8b43a8dd BYTE-IDENTICAL.
2026-09-03 19:28:06 -06:00
Drew T c91c9dffee feat(decomp): parallel gate — 12 fns across 12 binaries (8 workers)
ov_SC03_111    func_80181344
  ov_SC01_006    func_8017FBCC
  ov_SC02_041    func_801832F8
  ov_SC03_124    func_8018095C
  ov_SC01_005    func_8017FBCC
  ov_SC04_002    func_80182CBC
  ov_SC03_105    func_8017F018
  ov_SC04_005    func_80185CEC
  ov_SC04_007    func_80182358
  ov_SC04_011    func_8018985C
  ov_SC05_018    func_80181294
  ov_SC05_003    func_80181720
2026-09-03 19:18:12 -06:00
Drew T 3c34f8f4a3 plumb(overlays): §378 self-caller casts + decl sync for 12 self_decl_tu drafts
The same class that produced four banks in main, applied across the overlay
fleet. `blocker_probe` over all 26 binaries holding a stranded S76 draft found
11 whose blocker is `self_decl_tu`; harvest_verify named a twelfth
(ov_SC03_111:func_80181344, `conflicting types for func_80181344').

    ov_SC01_005 func_8017FBCC     ov_SC04_005 func_80185CEC
    ov_SC01_006 func_8017FBCC     ov_SC04_007 func_80182358
    ov_SC02_041 func_801832F8     ov_SC04_011 func_8018985C
    ov_SC03_105 func_8017F018     ov_SC05_003 func_80181720
    ov_SC03_111 func_80181344     ov_SC05_018 func_80181294
    ov_SC03_124 func_8018095C     ov_SC04_002 func_80182CBC

35 edits, 0 refusals. cast_self_callers is binary-generic — only sync_tu_decls
is main-only — so the checkpoint's "extend it or drive recover_integration per
binary" needed neither.

Every one of the 12 binaries was baseline-checked with NO draft substituted and
all 12 build their locked SHA, so the casts move zero bytes fleet-wide, exactly
as they did in main.
2026-09-03 19:15:32 -06:00
Drew T 04d9d28bb6 feat(decomp): bank ov_SC06_032:func_8017D810
Verified in-tree by harvest_verify, final SHA af117efbe4c0142d204bd243e41fd53e6ea5e350
BYTE-IDENTICAL.

Notable because parallel_gate had just reported `banked 0` for this exact
binary and this exact draft dir, in a 106s worker run — see the follow-up
investigation. The in-tree gate is the one that agrees with the bytes.
2026-09-03 19:13:28 -06:00