Commit Graph

45 Commits

Author SHA1 Message Date
Drew T bdfb86dc4f feat(phase-15): T6 v2 — data-sig-aware harvest + struct-guarded propagate; fleet 31.22% -> 42.14%
- gen_harvest_targets.py: now also resolves canonical DATA-symbol declarations per target
  (scan the .s for D_XXXX refs -> `extern <type> D_XXXX;` from banked code) in addition to
  callee function sigs — the §14c(c) fix at the source, so agents declare both functions and
  data correctly and avoid the dominant remaining conflict class.
- v2 harvest (callee+data-sig-aware) on the 591 small still-stub call-heavy fns + a gap-fill
  agent for 6 targets dropped by a connection-closed-mid-response failure (the retry-wave
  misses truncated-non-null results). Gate: 306 verified (ov_SC01_077 1554 -> 1248 stubs).
- dedup_propagate.py: skip any struct/union-touching body — agents named structs with colliding
  generic names (`struct S`/`struct vec`) inline, so two macros' types redefine/conflict when
  instantiated in one overlay (ov_SC01_000 abort). 34 skip; struct-using shared fns stay banked
  in 077 (shared-types-header follow-up).
- 281 functions propagated fleet-wide (134 overlays each, every overlay byte-gated); dedup
  795 -> 1076 groups, dedup_integrate --check 1076 validated / 0 failed.
- fleet REAL substantive 105,764 -> 143,322; byte-identical 31.22% -> 42.14%.
- R22 clean rebuild: 136/136 byte-identical, 0 extract failures.
- cookbook §12: gap-fill is now a MANDATORY post-step for every multi-agent run (reconcile
  produced-vs-expected: missing + truncated drafts) before gating.
2026-06-17 11:59:33 -06:00
Drew T 1d94f9ec96 feat(phase-15): T6d — deterministic decl-canonicalization recovers 19 more shared fns; fleet -> 31.22%
- tools/canon_draft_decls.py: rewrites a quarantined harvest draft's extern/data
  declarations to the banked-consistent set (functions from engine_core.h DEFINE
  bodies / extern decls / inline defs; data from existing `extern <type> D_XXXX;`),
  so a draft whose BODY is byte-correct (passes match_one) but whose DECLARATION
  collided with already-banked code can re-gate cleanly. The whole-binary
  harvest_verify byte-gate stays the sole arbiter — a semantics-changing
  canonicalization just fails and reverts.
- recovered 19 of the 90 match_one-MATCH-but-conflicting quarantined failures
  (no API — immune to the rate limiting), propagated fleet-wide, all 134 overlays
  byte-identical; dedup 776 -> 795 groups, 0 failed.
- fleet byte-identical 30.48% -> 31.22%; ov_SC01_077 1574 -> 1535 stubs.
- R22 clean rebuild: 136/136 byte-identical, 0 extract failures.
- the remaining ~70 match_one-MATCH residual needs definition-widening (§14c(d),
  narrow-return) or true data-type resolution — queued for the next pass, with the
  un-started medium band (430) and the 54 genuine instruction-misses (permuter/§3a).
2026-06-17 00:30:45 -06:00
Drew T ef1cf9f05e feat(phase-15): T6 pass-1 — callee-sig-aware harvest of the call-heavy shared core; fleet 25.38% -> 30.48%
- tools/gen_harvest_targets.py: callee-signature-aware target manifest (the §14b
  extern-conflict wall-breaker). Pre-resolves each callee's EXACT signature from
  engine_core.h DEFINE bodies + extern declarations + inline defs, so drafts never
  emit a conflicting extern. Lifted call-heavy gate yield from the §14b-naive 16%
  to 60-67%.
- ov_SC01_077: 142 functions banked (1716 -> 1574 INCLUDE_ASM stubs) via the
  Ultracode parallel-draft + harvest_verify byte-gate loop (cookbook §12). The
  draft Workflow was throttled by server-side API rate limiting (stopped at
  ~246/616); the incremental gate -> dedup_propagate loop is deterministic and
  throttle-immune, so the wins banked steadily regardless.
- dedup_propagate --auto-from ov_SC01_077: ~132 functions propagated fleet-wide
  (134 overlays each), every round per-overlay byte-gated; dedup 644 -> 776 groups,
  dedup_integrate --check 776 validated / 0 failed.
- fleet REAL 85,651 -> 103,217; byte-identical 25.38% -> 30.48%.
- R22 clean rebuild: make clean + extract all 136 + check-all = 136/136 byte-
  identical, 0 extract failures.
- cookbook §14c: the wall-breaker + the 4 conflict flavors (defined / declared /
  DATA-symbol / narrow-return-widening) + the never-git-checkout-mid-harvest
  hazard + the rate-limit-resilient incremental loop. Residual = the data-symbol
  conflict class (structural canonical-decls fix queued for next pass) + the
  un-started medium band (430).
2026-06-17 00:12:23 -06:00
Drew T 9d5c087054 feat(phase-15): T5b pass-2 leaf-first harvest (+34 shared fns); fleet 25.38%
- leaf-first pass: 52 pure-LEAF unmatched-shared funcs (no jal/%hi/%lo -> match_one is an
  exact gate); 5-agent Ultracode Workflow -> 36/52 verified (69% yield, vs 16% mixed) ->
  34 propagated fleet-wide (644 groups, dedup-check 0 failed); R22 clean 136/136
- fleet REAL 81,093 -> 85,651; byte-identical 24.05% -> 25.38%
- pure leaves now ~exhausted; remaining shared core is call-heavy (extern-conflict wall)
- CURRENT_PHASE.md: RESUME HANDOFF for a fresh session (T6 callee-aware harvest, T7 giants
  + per-overlay unique, then T8 PhaseEnd) — no PhaseEnd this session (Drew)
- ghidra/ churn NOT staged (R23)
2026-06-16 22:18:06 -06:00
Drew T 2ac97878b2 feat(phase-15): T5b — Ultracode harvest pass 1 (+49 shared fns); fleet 24.05%
- 25-agent Workflow drafted + match_one-verified 300 small unmatched-shared functions;
  harvest_verify byte-gate in ov_SC01_077 verified 49 (byte-identical d19c9580);
  dedup_propagate spread them fleet-wide (610 groups, dedup-check 0 failed)
- fleet REAL 74,527 -> 81,093; byte-identical 22.14% -> 24.05%; R22 clean 136/136
- yield 16% = the call-heavy hard tail: match_one masks jal/HI16/LO16 (false MATCH on
  call-heavy fns); real misses are the extern-type-conflict wall (draft callee extern
  != the callee real macro signature). Leaf fns matched; call-heavy = open-ended tail.
- cookbook 14b documents the wall + the path forward (leaf-first, callee-signature-aware
  drafting, link-gated per-fn check)
- ghidra/ churn NOT staged (R23)
2026-06-16 21:16:46 -06:00
Drew T aefe2eac18 feat(phase-15): T5a — bulk-propagate 553 shared functions fleet-wide (3.82% -> 22.14%)
- dedup_propagate --auto-from ov_SC01_077: propagated 553 already-matched, self-contained
  shared engine functions across all 134 overlays, each byte-gated. 9 functions skipped
  (use 077-local struct types -> not mechanically liftable; honest, P9). One R22 CLEAN
  rebuild: 136/136 byte-identical.
- fleet REAL 947 -> 74,527; byte-identical 13,132 -> 76,174 / 344,010 = 22.14%; 561 dedup
  groups, dedup-check 561 validated / 0 failed
- tool hardening for fleet scale: registry SHORTHAND (vram + binaries; dedup.us.yaml ~4k
  lines vs ~77k verbose); per-overlay apply (one read/write per file); gate-only-changed;
  skip already-registered (additive/resumable); compile pre-filter (body must build with
  common.h alone); group_members() reader (both forms) in dedup_integrate + progress;
  progress _DEDUP_CACHE (fleet 6m -> 7s)
- the first bulk attempt fail-closed-reverted on a local-typed body (byte-gate working) ->
  added the compile filter; cookbook 14a documents the 5 fleet-bulk lessons
- ghidra/ churn NOT staged (R23)
2026-06-16 20:35:39 -06:00
Drew T 87136a024e feat(phase-15): T3 — onboard the remaining 118 overlays; full fleet 136/136 byte-identical
- onboarded all 118 not-yet-onboarded overlays via tools/new_overlay.sh (0 failed)
  -> fleet = 134 location overlays + main + resident = 136 binaries
- R22 CLEAN rebuild (make clean -> extract all 136 -> make check-all):
  136 passed, 0 failed of 136 -- every overlay byte-identical at 100% INCLUDE_ASM
  from a fully clean tree, 0 extract failures
- per-overlay config (splat.ov_*.yaml / check.ov_*.sha / symbols.ov_*.txt) +
  config/overlays.mk var blocks + the 4 report/diff BINARIES dicts auto-registered
  (sentinel-anchored, idempotent); src/ov_*/ stub records committed (harvest_verify
  reverts via git checkout, so the records must be tracked before any harvest)
- ghidra/ churn NOT staged (R23); build/asm/assets/.run gitignored
- report-digest regen (fleet-wide duplicates.cross.md + progress.fleet.md) is T4
2026-06-16 19:41:37 -06:00
Drew T 0c7619231d feat(phase-15): T2 — dedup_propagate.py (match-once -> propagate-many) proven on wave
- tools/dedup_propagate.py: lift a matched body -> DEFINE_func_<ADDR>() macro in
  src/shared/engine_core.h -> instantiate in place at every onboarded overlay sharing
  that h_exact -> snapshot + per-overlay byte-gate (fail-closed revert) -> register in
  config/dedup.us.yaml. Keyed by addr-int (sig lowercase vs splat func_%08X).
- proof: 4 medium funcs propagated across all 16 onboarded overlays; clean check-all
  18/18 byte-identical; dedup_integrate 8 validated/0 failed; idempotent; negative test
  (corrupt shared body) -> make check FAILS then restores
- Makefile: header-dependency tracking (cpp -MMD -MP + -include ) so editing a
  shared header recompiles dependents — closes a stale-build/false-pass gap the negative
  test exposed; output-neutral (R22 clean 18/18)
- structural self-check: a leftover INCLUDE_ASM stub is byte-identical, so the byte-gate
  can't catch under-application -> assert DEFINE present + stub gone
- FINDING: 577 of ov_SC01_077's 785 matches are h_exact across all 134 overlays
  (2.19 MB collapsible, already matched) -> T5 = bulk-propagate these + harvest the rest
- cookbook §14 (the propagation runbook + gotchas), SETUP tool inventory
- ghidra/ churn NOT staged (R23); build/asm/.run gitignored
2026-06-16 19:24:08 -06:00
Drew T e5a2bd4083 feat(phase-15): T1 — onboard diverse wave-1 (12 overlays); fleet 18/18 byte-identical
- onboarded ov_{SC01_000,SC01_001,SC02_000,SC02_003,SC03_002,SC03_006,
  SC04_000,SC04_018,SC04_019,SC05_000,SC06_000,SC07_000} via tools/new_overlay.sh
  — spans all 7 SC areas + 2 full duplicate pairs (SC02_000≡003, SC04_018≡019)
- each byte-identical at 100% INCLUDE_ASM (non-4-aligned auto-handled); no
  position-lock anomalies — the cross-shape risk is retired before the full onboard
- make check-all = 18/18 passed (main + resident + 4 prior + 12 new)
- config/overlays.mk + 4 report dicts auto-registered (sentinel, idempotent)
- ghidra/ DB churn NOT staged (R23); asm/build/assets/.run gitignored
2026-06-16 19:02:14 -06:00
Drew T 7622ea7609 feat(phase-13): T7 — effort experiment (Max vs Ultracode yield = noise) + bank 14
Controlled: 80 fixed SC01/077 fns (nins 8-15), identical blind-draft Workflow,
only session effort varied. Arm A (Ultracode/xHigh) 13/80, Arm B (Max) 14/80;
A∩B=12. 13-vs-14 = noise -> per-agent depth does NOT change blind-draft harvest
yield; the 'pass 1 Max did better' observation was difficulty-confounded.
DECISION: prefer Ultracode for breadth harvests (same yield + orchestration),
Max for deep synthesis. Banked Arm B's 14 -> ov_SC01_077 REAL 704 (byte-identical).
(scriptPath re-invoke didn't forward args -> Arm B overwrote Arm A's drafts dir;
Arm A was already gated/recorded, so the comparison stands; 1 A-only fn unbanked.)
finding -> docs/effort-map.md (Evidence section)
2026-06-16 17:50:31 -06:00
Drew T eee4cb3196 feat(phase-13): T2 — dup-pair collapse SC01/005 ≡ 006 (one source, both green)
- src/shared/ov_setters.h: generic SETTER/RETCONST macro bodies (cookbook §11
  source-level share), instantiated IN PLACE (address order preserved) in both
  ov_SC01_005.c and ov_SC01_006.c via ../shared/ relative include
- config/dedup.us.yaml: D1/D2/D3 cross-overlay groups (members in BOTH 005 & 006)
- both make check BINARY=ov_SC01_005 AND =ov_SC01_006 -> 56760dbe BYTE-IDENTICAL
  from the one shared source; dedup_integrate --check: 4 validated, 0 failed;
  REAL=3 credited to both members
2026-06-16 17:05:23 -06:00
Drew T 67592993ea feat(phase-13): T3+T4 — new_overlay.sh + dup-pair & free-roam onboarded byte-identical
- tools/new_overlay.sh: one-command overlay onboarding (template instantiate +
  @TRAILING@ carve + overlays.mk + 4-dict sentinel-insert + extract/build/check);
  idempotent (re-run = no-op, no dupe entries)
- T3: ov_SC03_001 (free-roam, 815,887 B) byte-identical f8fd92f5
- T2 (onboard): ov_SC01_005 + ov_SC01_006 (byte-identical pair) both 56760dbe
- template tokens unquoted (correct YAML int types); SETUP §2.8 MCP-reconnect note (R21)
- 6 binaries now build byte-identical (main, resident, 4 overlays)
2026-06-16 16:44:01 -06:00
Drew T ce07b72794 feat(phase-13): T1e harvest pass 5 — +106 ov_SC01_077 (REAL 690/2586 = 26.7%)
Paced blind draft + retry-wave (no throttle losses). Build d19c9580. Easy/medium
tier substantially harvested; the ~1815 remaining (large shared-engine fns +
compiler residuals) are the Phase-15 long-tail. SC01/077 end-to-end milestone met:
onboarded, byte-identical, 690 matched, Ghidra-imported.
2026-06-16 16:38:22 -06:00
Drew T 5ccdd2b225 feat(phase-13): T1e harvest pass 4 (rate-limited) — +52 ov_SC01_077 (REAL 584)
match_one iterate pass throttled by a transient server rate-limit (20/36 batches
lost); banked 52 from the 16 completed. Build d19c9580. Resume with paced blind
draft + retry-wave (§12 resilience).
2026-06-16 16:29:41 -06:00
Drew T b6a82b8c43 feat(phase-13): T1e harvest pass 3 — +217 ov_SC01_077 fns (REAL ~532; Ultracode §12)
34-agent draft + byte-gate: 217/400 verified, build d19c9580. 183 residuals
(harder/branchy + function families) -> pass 4 + match_one iterate.
2026-06-16 16:16:52 -06:00
Drew T fdc9e22a8c feat(phase-13): T1e harvest pass 2 — +205 ov_SC01_077 fns (REAL ~315; Ultracode §12)
22-agent parallel-draft + byte-gate: 205/260 verified, build d19c9580. 55
residuals -> pass 3 redraft+iterate.
2026-06-16 16:09:54 -06:00
Drew T 0278a902d3 feat(phase-13): T1e harvest pass 1 — 110 ov_SC01_077 fns matched (Ultracode §12)
Parallel-draft (12 agents) + harvest_verify byte-gate: 110/120 easiest fns
byte-identical, build stays d19c9580. 10 failures -> redraft pass 2.
2026-06-16 16:04:08 -06:00
Drew T 3b59354c7f feat(phase-13): T1c — commit ov_SC01_077 C record (2505 INCLUDE_ASM stubs)
splat carved 2505 functions cleanly (func_* names; the top cross-report group
func_80144B9C carved correctly at 770 ins). The C record is durable (splat
preserves it across re-extract); matches land here in T1d/T1e.
2026-06-16 15:42:43 -06:00
Drew T a480d83bee feat(phase-12): T3a — extern-conflict recovery, +20 (REAL 102->123, 85.6%)
The pass-4 functions that match_one matched standalone but the single-TU build rejected
on conflicting shared-symbol extern types are recovered by UNIFYING those types in
resident.c (widening definitions' return types where byte-identical — u16 f(){return
u16g} ≡ s32 f(){...} both lhu;jr; choosing asm-correct widths for globals; per-site
*(u16*)&g tricks where a neighbor pins the type). ~20 symbols reconciled
(func_800291B4/CFD68/D1714/D1078/801465C0/... + D_800AE6A8/80078E50/...).

20 of 21 recovered; func_800D00E4 stays an honest INCLUDE_ASM stub (its switch needs the
external jtbl_80113ED8 relocation, not a C-source fix — analysis preserved under #if 0).
REAL 102 -> 123 (85.62% byte-identical); resident 8e17e02f, main 143dbb89 (R22 clean).
22 stubs remain: ~20 documented compiler-internal residuals (permuter/§3a) + D00E4 + dedup.
2026-06-16 14:05:20 -06:00
Drew T 393d34604b feat(phase-12): T3 pass 4 — match_one iteration loop, +13 (REAL 89->102, 71.7%)
resident-harvest-iterate workflow: 13 agents iterated the 54 hard functions using
tools/match_one.py (per-function compile+diff loop), self-correcting against real
feedback. Agents reported 34 match_one-MATCHes; the whole-build byte-gate confirmed 13
(func_800D23D0 D1754 CEF5C CF584 D17B8 D2E6C D0588 D2CA8 CFC5C CF3B8 CF104 D20C0 D1BF8).
The ~21 standalone-MATCH-but-gate-FAIL are TU-level extern-type conflicts (a draft
declares a shared symbol's type to suit its own call site, conflicting with another
function's declaration) -> recoverable via a unified extern header (next).
Expert idioms found: struct-copy prologue, void-dispatcher-is-actually-s32-returning,
*10 -> 2x+8x decomposition, polarity flips. REAL 102 (71.72% byte-identical); both
binaries clean. 41 stubs remain (extern-conflict casualties + documented cross-jump/
regalloc residuals = decomp-permuter / cookbook §3a territory, honest P9 deferrals).
2026-06-16 13:15:50 -06:00
Drew T 4c7cf48ebf feat(phase-12): T3 — +2 (typedef-strip recovery) + per-function match tool (REAL 87->89)
- tools/match_one.py (new): compile ONE function's C standalone (pinned triple), mask
  relocations (jal/HI16/LO16 like psyq_identify), compare to the target bytes in its .s.
  Isolated temp dir -> parallelizable; a real per-function asm-differ loop for agents to
  iterate against without a shared build. Validated: a matched fn -> MATCH, residuals ->
  informative diffs.
- harvest_verify.py + match_one.py: strip inline scalar-typedef redefinitions (some drafts
  inlined `typedef unsigned char u8;` -> C89 redefinition error vs common.h = a COMPILE
  fail, not a byte mismatch). Re-gate recovered func_800CFBCC + func_800D1938.
- REAL 89 (62.76% byte-identical); resident 8e17e02f, main 143dbb89 (R22 clean).
- 54 stubs remain (scheduling/regalloc residuals + big GPU/dispatch fns) -> match_one-driven
  iteration pass next.
2026-06-16 12:43:59 -06:00
Drew T 8dbaa489f7 feat(phase-12): T3 batch 3b — +9 via retry-resilient redraft pass (REAL 78->87, 61.4%)
Pass 3 (resident-harvest-redraft3): retry-wave workflow re-drafted all 65 remaining
stubs seeded by BOTH prior failed drafts + a sharpened debugging checklist (callee
return-type-forces-andi, signed-vs-unsigned sltu, store order, QImode decrement, the
register-pointer far-load idiom). All 13 batches completed (retry waves defeated the
transient server rate-limiting). tools/harvest_verify.py byte-gated -> +9:
func_800D2F8C func_800D1F90 func_800D2DFC func_800D222C func_800D10C8 func_800CFBF8
func_800D3120 func_800D1B10 func_800D18DC.

Resident harvest this session: REAL 1 -> 87 (61.38% byte-identical), all hand-matched
engine C, via 3 parallel-draft workflow passes (79 fns) + a deterministic byte-gate that
makes a wrong match impossible (G3/P9). resident 8e17e02f, main 143dbb89 (R22 clean).
56 stubs remain (scheduling/regalloc residuals + the big GPU/dispatch fns) -> per-function
asm-differ/permuter loop + serial Ghidra next.
2026-06-16 12:35:21 -06:00
Drew T 69227e4f6a feat(phase-12): T3 batch 3 — +8 resident fns via redraft pass + byte-gate (REAL 70->78)
Second-pass workflow (resident-harvest-redraft): agents re-drafted the failed/undrafted
functions seeded by their prior draft + a debugging checklist (load width/sign, branch
polarity, arg count, store order). Transient server rate-limiting killed 10/14 agents, so
only ~25 re-drafts landed; tools/harvest_verify.py byte-gated them -> 8 more verified:
func_800D33B8 func_800D2EE8 func_800D0C74 func_800D0CA0 func_800D2DAC func_800CF5D4
func_800D2FEC func_800CFDE8. The recovered bugs: twin-fn u16-return (D2EE8 mirrors the
matched D319C), missing call arg (CF5D4), proven index idiom (CFDE8).
REAL 70 -> 78 (53.79%); resident 8e17e02f, main 143dbb89 (R22 clean).
Remaining: ~65 stubs (17 redraft-resisters + ~48 never-redrafted [rate-limited]) -> pass 3
+ serial asm-differ on the hard GPU/dispatch tail.
2026-06-16 12:15:27 -06:00
Drew T c37332fa19 feat(phase-12): T3 batch 2 — 62 resident functions matched via parallel-draft + byte-gate (REAL 8->70)
Ultracode harvest: a 16-agent workflow (resident-harvest-draft) drafted matching C for
the 135 unmatched resident functions (each agent: asm + cookbook + the 8 worked examples,
writing .run/drafts/<fn>.c, no builds/no Ghidra). Then tools/harvest_verify.py (new) byte-
gated every draft against 8e17e02f one at a time (chunk+bisect), keeping only the byte-
perfect ones and reverting the rest -- the build is the sole arbiter (G3/P9).

- 62 / 127 drafts verified byte-identical in one pass; 65 near/hard misses reverted to stubs.
- REAL 8 -> 70 (48.28%); byte-identical 49.66%. resident 8e17e02f, main 143dbb89 (R22 clean).
- cleaned 35 redundant '#include "common.h"' lines the drafts inlined (still byte-identical).
- remaining: 65 failed drafts (close-misses + the hard dispatch/GPU/big-fn tail) + 8 undrafted
  (2 agent batches hit transient API 500s) -> second-pass workflow + manual hard tail.
2026-06-16 11:59:02 -06:00
Drew T 6d1b0c051e feat(phase-12): T3 batch 1 — 6 trivial resident accessors matched (REAL 2->8)
Resident engine harvest underway (triple confirmed in T2). Batch 1, all byte-identical:
- func_800CF804 / func_800CF818 — set D_80127084 / D_80114E78 = 1 (s32)
- func_800CF82C / func_800CF840 — set D_800B9A0E = 1 / 2 (s16, sh)
- func_800D1714 — get D_80078E50 (u16; player-state region ~0x80078Exx)
- func_800D1724 — set D_800AE6B0 = arg (s32)

make report BINARY=resident: REAL 2 -> 8 (5.52%); byte-identical 10/145 (6.90%).
R22 clean rebuild green: resident 8e17e02f, main 143dbb89.
2026-06-16 11:17:54 -06:00
Drew T b8457a8636 feat(phase-12): T2 — resident compiler triple CONFIRMED = the EXE's (2 byte-exact matches)
- opt level: resident is -O2 (0x21f0a003 frame-ptr sig count = 0, vs the EXE's 54;
  the EXE's 800 game module is also -O2). No per-file override needed.
- triple (Makefile default, no override): gcc-2.7.2-psx -O2 -G0 -mips1 -mcpu=3000
  -mgas -msoft-float -fgnu-linker + maspsx --aspsx-version=2.56 --expand-div.
- 2 byte-exact resident matches confirm it across idiom classes:
  * func_800CF854 — lbu D_800AE6BF; sltu $zero (unsigned-!=0 accessor)
  * func_800CEE84 — 8-call init: branch-store (D_80127084=0; if(D_800B9A00) =1),
    delay-slot-filled func_80010AE0(0x3E0), early-scheduled load
- R22 clean rebuild: resident 8e17e02f, main 143dbb89 — both byte-identical.
  make report BINARY=resident: REAL 0 -> 2.
- R24: the "resident is 4.7" DetectPsyQ hit was a coincidental DsMix signature; the
  resident's actual game-code triple == the EXE's (byte-confirmed). No candidate
  ladder; the STOP-condition did not fire. Harvest (T3) de-risked.
2026-06-16 11:14:25 -06:00
Drew T a8ae190fa3 feat(phase-11): T3 — intra-binary collapse PROOF (one body, two addresses, byte-identical)
- src/shared/clearTbl40.h: CLEAR_TBL40 macro = the matched byte-clear loop body, authored ONCE;
  instantiated at both func_80037004 and func_80037334 in src/800.c (one source -> two vrams)
- matched first try; clean rebuild main -> 143dbb89 BYTE-IDENTICAL WITH the shared C AND WITHOUT
  it (INCLUDE_ASM stub fallback) -> dual invariant proven (R22 clean rebuilds, both states)
- config/dedup.us.yaml: I0_clearTbl40 group registered (h_exact a0744d60…); dedup_integrate
  --check validates it; negative tests (corrupt hash / wrong vram) fail-closed (exit 1)
- tools/progress.py: count dedup-shared members as REAL via the registry (the macro form isn't a
  parseable function def); REAL 52 -> 54, byte-identical 50.24% -> 50.33%; honest measurement (P9)
- tools/dedup_integrate.py: display vram in hex in diagnostics
- the machinery half of the Phase-11 milestone is proven on the byte-verified EXE
2026-06-16 00:56:35 -06:00
Drew T 03978ec4ba feat(phase-10): T4 — resident Ghidra program (2nd binary) + symbol seed + sig
- tools/ghidra_import_raw.sh (NEW): raw-blob importer (BinaryLoader + --loader-baseAddr +
  PSX:LE:32:default) — the Gen2 counterpart to ghidra_import.sh (PS-X-EXE only); reusable for
  Phase-13 location overlays. Imports the resident blob as program 'resident' @0x800CEDF8.
- tools/ghidra_scripts/DefineFunctions.java (NEW): seed splat's validated entry points
  (.run/<prog>_funcs.txt) — raw-binary auto-analysis finds only the reachable subset (23/143);
  this defines all 143 (created=120/existed=23/failed=0). R9-verified 143 funcs persisted.
- FINDING: DetectPsyQ reports the resident is PsyQ 4.7.0 (the EXE is 4.0.0); the lone in-range
  PsyQ-signature hit is DsMix (libsnd -> resident holds the sound driver). 4.7 .LIBs DEFERRED to
  Phase 11 start (Drew); carried to PhaseEnd Notes. Phase 10 needs nothing from 4.7.
- config/symbols.resident.txt: seed DsMix (R13 candidate, 4.0-sig vs 4.7 blob — confirm in Phase 11);
  stacked under symbols.us.txt, applied on re-extract -> resident still 8e17e02f BYTE-IDENTICAL (R22),
  main still 143dbb89 (no regression)
- Makefile: per-binary GHIDRA_PROG -> 'make sig-refresh BINARY=resident' (.run/sig.resident.jsonl)
- dup_report.resident now real (6 byte-identical intra-resident groups — Phase-11 dedup fodder)
- ghidra DB committed (R23, MCP stopped): new resident program 00000003.* (+ main db.15->16 no-op)
2026-06-15 23:25:00 -06:00
Drew T f06785bcf2 feat(phase-10): T2 — resident blob byte-identical (8e17e02f), the milestone
- mapped the blob vs bytes: word0 data header (0x36); clean code 0x4..0x4610 (145 funcs,
  zero embedded jump-tables/trap-ops); data tail 0x4610..EOF (pointer tables + 78.5KB zeros)
- split: [0x0, rodata, hdr] + [0x4, c, resident] + [0x4610, data, tail]
- fix 1: the leading data word sits BEFORE code, which fights section_order; emit it as
  rodata (no-dot) so section_order [.rodata,.text,.data,.bss] places it first @0x800CEDF8 —
  a 1-word analogue of main's rodata-island, no ld_interleave needed
- fix 2: build_path=build (not build/resident) so splat's .ld object paths match the
  Makefile's build/asm/** + build/src/** pattern rules (only elf/ld/output in build/resident/)
- MILESTONE: make build BINARY=resident -> 8e17e02ff8954d07c979449198f7e1645046b353
  BYTE-IDENTICAL (365,404 B, end vram 0x80128154); -G0 confirmed (0 gp refs);
  R22 clean-rebuild green; main still 143dbb89… (no regression)
- src/resident/resident.c (143 INCLUDE_ASM stubs) committed; asm/resident/** regenerated
2026-06-15 23:00:51 -06:00
Drew T 44586c885e feat(phase-8): game-code harvest (T13) — 9 trivial accessors, REAL 43 -> 52
- matched 9 game-code leaf getters/setters of D_* globals (byte-verified, asm-differ 0):
  func_8002AEF8 (D_800760C8=0), func_8002AF08 (return D_800760C8),
  func_8002AF60 (return D_80075A40), func_80037358 (D_8007623C=posInt),
  func_8002D4B8 (u8 return D_800A46BA), func_8002D7FC (D_800A4E7C=arg0),
  func_8002D834 (s16 D_8006A990=0), func_8002F648 (s16 return D_800A4EF0),
  func_80037CC8 (D_800BA0F8=0)  — all in src/800.c, extern-declared D_* (undefined_syms_auto)
- byte-identical (clean build); REAL 43 -> 52; byte-identical/matchable 50.24%
- GOTCHA: matching changes need `make clean` to verify — the incremental psyq_integrate
  .ld rewrite can leave a stale state (an incremental build falsely diffed in libmcrd;
  clean rebuild byte-identical). Canonical verify = make clean && extract && build
- bank, don't exhaust: stopped at 9 (more trivial leaves remain for later)
2026-06-15 19:07:59 -06:00
Drew T 11a9bdc032 feat(phase-8): link libapi+libcard combined 800c2 region (T7+T8) — 22 objs / +24 fns
- libapi (BIOS syscall trampolines) + libcard interleave in 0x61F38..0x62888; linked as
  one combined region (4 blocks apicard1..4) via tools/make_apicard_used.py (C112.o shared,
  byte-match dedup, 0 exclusions)
- subsegs via gen_lib_subsegs.py; integrate window 0x61F38..0x62888; region verified 22/22
- rm'd src/800c2.c (region starts with a lib block) -> splat regenerates apicard1..4 + frags
- dual byte-gate PASS: 143dbb89 with and without the apicard objects
- LINKED 935 -> 959 (+24); REAL still 43; byte-identical 49.81%
- libapi's ~22 objects in the 800c3 region DEFERRED (lowest value); SSGM + the scattered-.bss
  exclusions documented in docs/psyq-worklist.md

LIBRARY CEILING: 8 PsyQ libraries linked byte-identical (959 LINKED fns); byte-identical
coverage 20.31% (libcd+libgs only) -> 49.81%. Remaining = documented low-value deferrals.
2026-06-15 18:59:14 -06:00
Drew T 8bbf2e8e4d feat(phase-8): link libspu+libsnd combined sound region (T9+T10) — 60 objs / +225 fns
- libspu and libsnd interleave in 0x3A444..0x4239C (the 800-subseg tail), so they link
  as ONE combined region rather than two tangled passes
- NEW tools/make_snd_used.py: build the curated combined dir — merge both libs by vram,
  pick the byte-matching object per aliased address (link_object), exclude 4 addresses
  that don't reconcile in-region (kept as byte-identical stubs):
    0x3C438 S_R/S_W, 0x3D424 S_GRMDT/FB/T  — scattered-.bss commons, cross-object (§9.1)
    0x3D94C S_IH/UT_RON                      — false placement (inside libsnd SSSTART.o)
    0x3FA64 VM_F (237 ins)                   — scattered-.bss commons (the one real loss)
- subsegs via gen_lib_subsegs.py (9 snd blocks + 8 sgap game/excluded-stub gaps);
  integrate window 0x3A444..0x4239C; region byte-verified 60/60
- src/800.c trimmed at [0x3A444,0x4239C): kept 732 items < 0x3A444 (ALL matched C +
  game + the deferred SSGM stub preserved), 0 real-C moved
- dual byte-gate PASS: 143dbb89 with and without the sound objects
- LINKED 710 -> 935 (+225); REAL still 43; byte-identical 48.66% (nearly half the EXE)
- deferred: SSGM.o @0x1BD80 (isolated, matched-C region, 8 ins)
2026-06-15 18:54:21 -06:00
Drew T c4a627b22b feat(phase-8): link libgte byte-identical (T11, value-first) — 53/58 objs / +120 fns
- NEW tools/gen_lib_subsegs.py: generate splat subseg lines + integrate stub list for a
  multi-block library (section-size-correct block ends — bakes in the libc2/T6 boundary
  gotcha so it can't recur). Reused for libspu/libsnd next.
- libgte = GTE math, 53 objects in 22 blocks across the old 800b region (game code
  interleaved as 800b/800b_2..800b_7). Resegmented from the generator; integrate window
  0x4787C..0x51804 so it sees exactly the 22 in-region blocks
- 5 libgs-gap libgte objects (MTX_05/07/11/REG03/REG11) DEFERRED — gsgap1/2/4/5 stay
  stubs (gsgap2 != MTX_07 exactly, needs a sub-split); documented in worklist
- progress.py linked_subsegs() now resolves `$(VAR)` stub lists (LIBGTE_STUBS) — the long
  multi-block lists are passed via a make var
- region byte-verified 58/58 (clean, no scattered .bss); rm'd src/800b.c (region starts
  with a lib block) so splat regenerates the fragments; 22 src/libgteN.c + 6 game frags
- dual byte-gate PASS: 143dbb89 with and without the libgte objects
- LINKED 590 -> 710 (+120); REAL still 43; byte-identical 37.93%
- reordered remaining libs value-first (libspu/libsnd next; dense libcard/libapi last)
2026-06-15 18:43:27 -06:00
Drew T 9dbae2681e feat(phase-8): link libc2 byte-identical (T6) — 17 objs / +62 fns
- splat: libc2 C stdlib in 2 blocks — main 16-obj run libc2_1 (BZERO/MEMCPY/STRCMP/
  PRINTF/PRNT[jtbl ok]/.../SETJMP) split from 800c, + STRCAT.o libc2_2 split from
  800c2; new game-code fragments 800c3 + regenerated 800c2
- region byte-verified 17/17; PRNT.o printf-format jtbl resolves via NOLOAD .rodata
- BOUNDARY GOTCHA found + fixed: SETJMP.o .text is 0x80 B (8-align pad), not the
  0x78 psyq_identify reports (30 ins) -> the libc2_1/800c3 boundary was 8 B too low,
  overlapping SETJMP's padded tail; the relink inserted +8 padding and shifted the
  whole downstream image (56k diff bytes, +8 file len). Fix: boundary = last obj's
  readelf .text size (0x5CE18), not ins-count. Lesson recorded in docs/psyq-worklist.md
- when a library block sits at a subseg start, rm the old .c so splat regenerates it
- dual byte-gate PASS: 143dbb89 with and without the libc2 objects
- LINKED 528 -> 590; REAL still 43; byte-identical 32.25%
2026-06-15 18:32:48 -06:00
Drew T 0d6380c845 feat(phase-8): link libmcrd byte-identical (T5) — 2 objs / +104 fns
- splat: split 800c into [800c][libmcrd1][800c2][libmcrd2]; LIBMCRD.o (2186 ins,
  the 55 LIBMCRD_OBJ_* + _card_* memcard I/O) and USERFUNC.o (68 ins) are 2
  non-adjacent blocks split by game/libc2/libapi/libcard code (800c2)
- Makefile LIBMCRD_* + gated psyq_integrate libmcrd1,libmcrd2 + -T
- region byte-verified: 2/2 objects, 27 .bss commons all recovered (not scattered)
- src/800c.c trimmed (0 real-C moved); src/{libmcrd1,800c2,libmcrd2}.c committed
- dual byte-gate PASS: 143dbb89 with and without the libmcrd objects
- LINKED 424 -> 528; REAL still 43; byte-identical 29.29%
- NB: these are the libmcrd SDK objects; the game SaveLoadRoutine/Q#5 is Phase 12
2026-06-15 18:23:59 -06:00
Drew T ade73cce62 feat(phase-8): link libgpu EXT+PRIM byte-identical (T4); exclude SYS.o (scattered .bss)
- splat: split 800b2 into [800b2][libgpu][800c]; libgpu block = EXT.o+PRIM.o
  (vram 0x80058890-0x80059234, holds LoadClut/LoadClut2 + primitives)
- SYS.o (3109 ins) EXCLUDED — scattered-.bss commons (cookbook §9.1, the GS_001
  class): SYS references .bss by section+offset but the original linker scattered
  the commons across 0x80078xxx/0x800c5xxx, so no single NOLOAD base reproduces it.
  Stays a byte-identical INCLUDE_ASM stub in 800c; documented in docs/psyq-worklist.md
- curated dir .run/obj40/libgpu_used = {EXT,PRIM} (validates the _used mechanism for
  the later alias libraries); Makefile LIBGPU_* + gated psyq_integrate + -T
- src/800b2.c trimmed; src/libgpu.c + src/800c.c committed (stub records); the trim's
  9 "moved" items were all splat-auto empties (regenerated identically, 0 real lost)
- dual byte-gate PASS: 143dbb89 with libgpu objects AND without (stub fallback)
- LINKED 375 -> 424; REAL still 43; byte-identical 24.32%
2026-06-15 18:21:25 -06:00
Drew T 675872616d feat(phase-8): link libetc byte-identical (T3) — 5 objs / 35 fns
- splat: carve libetc subseg (vram 0x8004239C-0x80043088, VSYNC/INTR/INTR_VB/
  INTR_DMA/VMODE) out of the 800-subseg tail (ends exactly at libcd1); 5 objs,
  1 contiguous block, no placement window needed, no matched-C disturbed
- Makefile: LIBETC_ELF/OBJDIR/SYMS + gated psyq_integrate call + -T on the ld line
  (same conditional/stub-fallback model as libcd/libgs)
- src/800.c trimmed (split_src_region: dropped 35 libetc stubs, 0 real-C moved);
  src/libetc.c committed (35 INCLUDE_ASM stub records)
- pre-wire gate: psyq_link_lib 5/5 objects byte-identical (.text)
- dual byte-gate PASS: make check 143dbb89 WITH libetc objects AND without them
  (stub fallback) — both byte-identical
- progress.py LINKED 340 -> 375 (+35), stubs -> 1626, byte-identical 21.98%
  (metric auto-updated from the new Makefile psyq_integrate call)
2026-06-15 18:08:57 -06:00
Drew T 49db81d8ae feat(phase-7): Gen1 close-out — matching loop industrialized, PsyQ libs linked, LZSS matched (v1.7.0)
- reports (Task 3): tools/{progress,difficulty,dup_report}.py + make report/sig-refresh
  (deterministic digests); harvest to 43 REAL matches incl. LzssDecodeSector
- per-module -O0 split (Task 5.5): src/boot.c + Makefile per-file CC1FLAGS (cookbook §6)
- PsyQ SDK linking (sessions C-G): split/build/identify/link/integrate pipeline
  (tools/psyq_*.py, make_libgs.sh, ld_interleave.py, split_src_region.py) — libcd (18 obj)
  + FULL libgs (31 obj / 6 blocks) linked BYTE-IDENTICAL from real PsyQ 4.0 libs; byte-
  identical with or without the SDK objects (stub fallback); cookbook §7/§8/§9.1-9.5
- LZSS MATCHED byte-for-byte (session F): §5a cross-jump barrier + §10 regalloc/schedule
  idioms, ground-truthed against pinned gcc-2.7.2 source (the Gen1 LZSS gate)
- file-loader cluster: 6 matched + 5 NON_MATCHING-drafted (CdReadStateMachine,
  CdReadSectorReadyCB, StreamLoadStateMachine new this session, valid under -DNON_MATCHING);
  SaveLoadRoutine DEFERRED to Q#5 (save/memcard, documented stub)
- README Gen1-complete; worklog preserved -> phase-ends/logs/Phase7.md
- rules R17 (web-research compiler quirks), R18 (plain-English session summaries),
  R19 (preserve phase worklog out of load order)
- MILESTONE: Gen1 EXIT confirmed — byte-identical build, 43 matches incl LZSS, 7 zero-
  regression sessions, loader cluster matched/drafted, overlay map emulator-proven
- bumps project version 1.6.0 -> 1.7.0
2026-06-15 13:44:32 -06:00
Drew T f91a67a6fe feat(phase-7): libgs block 6 linked byte-identical (16 objs / 26 SDK funcs) — session F
- resegment 800b -> [800b pre][libgs6][800b2 post]; psyq_integrate the 16 contiguous
  block-6 libgs objects (GS_110/119/120/121/122/123/127/131/133/134/135/137, PRESET,
  PRESET3, OBJT, OBJT3) at vram 0x80053AF8-0x80057928; make check BYTE-IDENTICAL
- fix the resegment-triggered spimdisasm boundary instability: declare GsMulCoord2/3
  (real MATRIX.o funcs, verified via the PsyQ object, R15 Ghidra-mirror pending) +
  carve the s8 data descriptor table [0x53198,data,53198] (D_80062998 was shadowed by
  a mis-detected func_80062998); ld_interleave FRONT_DATA -> 53198.data.o
- psyq_integrate multi-library support: per-lib NOLOAD section namespacing (.nl_<tag>_*)
  so the 2nd integration's NOLOAD isn't skipped (was discarding OBJT3 .rdata/.bss);
  trial-link includes sibling *_externals.ld (kills the '31 UNRESOLVED' false alarm);
  global NOLOAD re-sort by vram (kills 'dot moved backwards')
- tools/make_libgs_block6.sh: reproducible curated-dir regen (disambiguated 16 objects)
- gated on [ -d .run/obj40/libgs_block6 ]: fresh-clone stub fallback verified byte-identical
- cookbook s9.4 (multi-library integration gotchas); CURRENT_PHASE updated
- next: full libgs integration (other 5 blocks), then Task 6 close-out + Task 7 PhaseEnd
2026-06-15 10:48:08 -06:00
Drew T c894dadb48 feat(phase-7): LZSS matched byte-for-byte (43 real) — gcc-2.7.2 regalloc tail closed — session F checkpoint
- LzssDecodeSector (0x80018730): asm-differ score 0, make check BYTE-IDENTICAL;
  NON_MATCHING guard dropped (C is the default build)
- closed the session-E ~4 regalloc/scheduling residuals via the §3a research tier
  (ground-truthed vs pinned gcc-2.7.2 reorg.c/jump.c/local-alloc.c) + a floor-free
  .text object metric (the permuter could not measure it: rodata/jtbl score floor)
- 5 LOAD-BEARING constructs documented in src/800.c + cookbook §10:
  (A) decoupled nh high-byte var + (code&0xFF)|(nh<<8) operand order [combine_regs]
  (B) result set in save predecessors [reorg fill_simple_delay_slots]
  (B/state-2) explicit register $2 local + early read-only input-asm pin [sched]
  (B3) no switch default -> state>=5 reuses the sltiu result
  (§5a) zero-byte cross-jump barrier (retained)
- cookbook §10 added (reusable regalloc/schedule-tail idioms + the .text metric),
  §5a cross-linked; CURRENT_PHASE task + green-log updated (Gen1-exit LZSS gate MET)
2026-06-15 10:10:26 -06:00
Drew T 038e7de532 feat(phase-7): LZSS cross-jump barrier breakthrough + libgs byte-verified — session E checkpoint
- LZSS: defeated gcc 2.7.2 -O2 cross-jump-merge of the twin state-save tails with a
  zero-byte __asm__ __volatile__("" ::: "memory") barrier (find_cross_jump bails on
  ASM_INPUT; ground-truthed vs gcc-2.7.2.3 jump.c by a web-research subagent).
  LzssDecodeSector now 122 instructions (correct structure); ~3 regalloc/scheduling
  swaps remain -> C kept under #ifdef NON_MATCHING, default build = stub = BYTE-IDENTICAL
- surgical rodata carve (lean LZSS path, no libgs needed): splat carves ONLY
  jtbl_80072A38 ([0x63238,.rodata,800] bounded by [0x6324C,data,6324C]); ld_interleave
  wired into `make extract` as the .data->.rodata->.data sandwich (TAIL_DATA=6324C.data.o)
- libgs: 31/32 used objects byte-verified IDENTICAL to real PsyQ libgs 4.0 (0 conflicts,
  69 externals); GS_001 deferred (psyq-obj-parser .bss-common scattering); 6-block
  resegmentation wiring pending. psyq_identify.py now skips data-only objects (GLOBAL.o)
- cookbook: §3a (web-research compiler internals — escalation tier above the permuter)
  + §5a (the cross-jump barrier idiom) — both reusable
- build BYTE-IDENTICAL (143dbb89f34491258bbc27810d0a12ec8b43a8dd) throughout
2026-06-15 01:47:18 -06:00
Drew T 3788a89b3c feat(phase-7): libcd linked into byte-identical build (58 SDK funcs) — session D checkpoint
The first real PsyQ library is sourced from real SDK objects in the byte-identical
build, replacing the libcd-region asm stubs. Tasks 2'.1/2'.2/2'.3 — the whole
PsyQ-library-into-build mechanism, proven on the simplest library (libcd).

- psyq_link.py: per-object byte-link engine — recovers externals from the EXE's
  resolved relocations (R_MIPS_26 / HI16+LO16); weakens psyq-obj-parser's
  mislabelled common-style .bss globals so a strong --defsym wins
- psyq_link_lib.py: whole-library verify — 18/18 libcd objects byte-identical
- psyq_link_region.py: region link via NOLOAD data placement (no carving) +
  weaken-all-.bss; gap-aware per-object placement
- psyq_integrate.py: build wiring — splat resegment swap + per-object .text at
  vram + NOLOAD data; external resolution (func_<addr> aliases, symbols.us.txt
  jump-table names, recovered St*/CD_* globals, all weakened .bss commons);
  idempotent; conditional on tools/psyq/ (fresh clone builds via stubs)
- split_src_region.py: H5-safe src/*.c split at vram boundaries (preserves
  matched C + NON_MATCHING blocks)
- splat.us.exe.yaml: 5-way text split [pre][libcd1][gap][libcd2][post]
- src/800.c trimmed to <0x80043088; src/{800b,gap,libcd1,libcd2}.c splat stubs
- Makefile: libcd integration in the $(OUT) recipe (conditional + idempotent)
- cookbook §9.1/9.2/9.3 (the reusable mechanism for libgs/Gen2); CURRENT_PHASE
  session-D log; ≥3-session green bar A/B/C/+D
- make clean && extract && build && check -> 143dbb89... BYTE-IDENTICAL
2026-06-14 23:13:39 -06:00
Drew T 8ffb7f0607 feat(phase-7): -O0 split + 4 matches (42 real) + libcd.h — session B checkpoint
- per-file -O0 mechanism: split text c-subseg into boot@-O0 (src/boot.c) + 800@-O2
  via splat resegmentation + Makefile target-specific CC1FLAGS; the boot/main/
  game-mode-dispatch module (0x80010000-0x800123F0) is -O0, not the pinned -O2
  (per-module compiler mixing, SETUP §5.5). Regression-gated byte-identical.
- 4 byte-matches (38->42 real, make check BYTE-IDENTICAL throughout): GameModeDispatch
  (-O0 register-ptr far member), DebugMenuHandler (-O0 reserved-slot local), CdQueueBusy
  (-O2 if/else order + branch polarity), CdReadRequest (-O2 early-return fall-through)
- PsyQ infra: include/psyq/libcd.h (CdlLOC/CdlFILE from the .gdt) + 4 named symbols
  (CdSearchFile/CdPosToInt/CdIntToPos/VSync) in symbols.us.txt; func_* stubs renamed
- loader cluster non-jtbl COMPLETE (6 matched + 2 drafted): NON_MATCHING drafts of
  LoaderInitFileTable + ResourceLoadStateMachine (logically faithful, residuals in-source)
- tooling: progress.py/difficulty.py fixed for the multi-file split (glob src/*.c, all
  asm dirs, skip forward-decls); deterministic; 42 real / 4 NM
- flywheel: matching-cookbook §6 (-O0 detection + idioms), §7 (PsyQ types/symbols), T4
- build byte-identical 143dbb89f34491258bbc27810d0a12ec8b43a8dd from a full clean cycle
2026-06-14 19:37:05 -06:00
Drew T 379185a799 feat(phase-7): matching reports + 24 matches (38 real) — session A checkpoint
Mid-phase checkpoint (Drew-directed; phase NOT closed — R8 exception).

- reports (Task 3): tools/{progress,difficulty,dup_report}.py + `make report`
  (deterministic) + `make sig-refresh`; authoritative baseline 38 real / 2050
  matchable; empties audit 42/42 genuine jr;nop; docs/{progress,difficulty,
  duplicates}.md digests
- matches (Tasks 4-5): +24 byte-identical (22 accessor leaves via the harvest
  pattern + ResourceGetCdLoc + LoaderResetReadState); make check BYTE-IDENTICAL
  throughout (143dbb89...)
- config/symbols.us.txt: declare func_80047CAC (R15) — fixes a latent
  non-reproducibility (spimdisasm 1.41.0 auto-detect of an 8B inter-fn blob was
  unstable across clean extracts; the committed Phase-6 baseline did not
  deterministically rebuild)
- Task 1 rodata-island foundation: investigated (migration co-locates jump
  tables + resolves refs, but byte-identity blocked by splat global-migration +
  contiguous linker placement vs BFM's monolithic segment) -> DEFERRED to Task 2'
  with a candidate fix; full findings in phase-ends/CURRENT_PHASE.md
- phase-ends/CURRENT_PHASE.md: reordered plan, loader-cluster triage, per-session
  green-check log (1 of >=3 needed for the Gen1-exit milestone)
2026-06-14 17:36:12 -06:00
Drew T 5f937bdda5 feat(phase-6): compiler pinned + matching loop proven (14 matches) — LZSS to Phase 7
- splat.us.exe.yaml: text subseg asm->c (INCLUDE_ASM scaffold); include/common.h
  (committed prelude); Makefile c-rule cpp->cc1->maspsx->as + -Map
- PIN (G8): gcc-2.7.2-psx -O2 -G0 -mips1 -mcpu=3000 -mgas -msoft-float -fgnu-linker
  + maspsx --aspsx-version=2.56 --expand-div; byte-exact on func_80018F20 +
  instruction-identical across 3 idiom classes; --expand-div REQUIRED for div/rem
  (SETUP.md §5.4 PINNED, Makefile MASPSX_FLAGS)
- harness: diff_settings.py (asm-differ mipsel object mode), tools/decompile.py
  (m2c wrapper), tools/permuter/ (decomp-permuter harness + objdump shim), expected/
- 14 real functions matched (asm-differ score 0): func_80018F20 + 13 accessors;
  +14 splat-auto empty no-ops; make check BYTE-IDENTICAL throughout
- 2 instruction-identical near-misses guarded NON_MATCHING (func_80015A74 scheduling,
  func_80016714 phantom frame) -> decomp-permuter candidates
- flywheel: docs/matching-cookbook.md, memory + CLAUDE.md step 5 (consult+evolve), R16
- requirements-python.txt: venv freeze (pycparser<3.0 pinned — permuter needs plyparser)
- LZSS spike: needs jump-table-in-rodata workflow (102 tables, mixed blob) -> Phase 7
- venv: asm-differ + permuter deps installed
- bumps project version 1.5.0 -> 1.6.0
2026-06-14 14:47:01 -06:00