Commit Graph

101 Commits

Author SHA1 Message Date
Drew T 324ad1c3a6 docs(phase-15): T0 — defer Phase 14 to Gen3+; Phase 15 is the active phase
- gen2-roadmap: mark Phase 14 (public flip) DEFERRED to Gen3+ (Drew 2026-06-16)
  across header rev, phase table, Phase-14 detail, EXIT criteria (crit 5 parked),
  critical-path, and Phase-15 (now ACTIVE) detail/deps — additive, text preserved (H5)
- CURRENT_PHASE.md: Phase 15 kickoff log (approved plan, verified ground truth,
  task list T0-T8, milestone, strategy: match-once -> propagate-many)
- ghidra/ DB churn deliberately NOT staged (R23 noise; Ghidra-free phase)
2026-06-16 18:57:06 -06:00
Drew T a0865e78ca docs(phase-13): PhaseEnd — representative overlays complete; 6 binaries byte-identical (v1.13.0)
Milestone confirmed (gate 2): make check-all 6/6 from clean (R22); ov_SC01_077
704 matched, dup-pair collapse, free-roam, new_overlay.sh + build-all/check-all.
Rules R27 (effort-transition discipline), R28 (task-list-after-plan), R29 (MCP
reconnect). CURRENT_PHASE.md archived -> phase-ends/logs/Phase13.md (R19).
2026-06-16 18:00:25 -06:00
Drew T 52514b5f45 docs(phase-13): T6 docs — cookbook §13 overlay runbook + SETUP/gen2-roadmap + digests
- cookbook §13: the canonical add-an-overlay runbook (new_overlay.sh, the flat-blob
  config, the non-4-aligned bin-carve/asset/trim gotcha, A->B->C workflow, dedup-credit
  two shapes, build-all/check-all) — the Phase-15 fleet recipe
- SETUP tooling inventory: tools/new_overlay.sh (R21)
- gen2-roadmap Phase-13 milestone: ACHIEVED amendment (6 binaries byte-identical,
  704 harvested, dup-pair collapse, T7 effort finding)
- regenerated per-overlay progress/difficulty/duplicates digests + cross report
2026-06-16 17:56:38 -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 b2773874d0 docs(effort-map): per-task effort mapping + pause-at-every-transition discipline (Drew) 2026-06-16 17:23:07 -06:00
Drew T eaff101c3f docs(phase-13): T0-T5 complete — milestone met; T7 experiment + T6 PhaseEnd remain 2026-06-16 17:09:23 -06:00
Drew T e2200e17db feat(phase-13): T5 — make build-all / check-all (fleet PASS/FAIL)
Recursive $(MAKE) BINARY=<b> over $(BINARIES) (correct per-binary OBJS prune,
not foreach), aggregated to one PASS/FAIL + per-binary .run/check.<b>.log.
check-all: 6/6 [OK] exit 0; negative control (corrupt sha) -> [FAIL] + nonzero.
2026-06-16 17:07:57 -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 3262cbca39 docs(phase-13): T1c done — C record + Ghidra import (2661 fns, 0 failed); harvest next 2026-06-16 15:51:44 -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 144839f24b feat(phase-13): T1a/T1b — SC01/077 onboarded + all-asm byte-match (d19c9580)
- ov_SC01_077 scaffolded: config/overlays.mk (OVERLAY_BINARIES + var block),
  config/splat.ov_SC01_077.yaml (from template), check.sha, empty symbols, +
  ov_SC01_077 entry & sentinel anchor in the 4 Python BINARIES dicts
- GATE T1b: make check BINARY=ov_SC01_077 -> d19c9580 BYTE-IDENTICAL @ 100%
  INCLUDE_ASM; clean rebuild leaves main 143dbb89 + resident 8e17e02f unregressed
- reusable non-word-aligned-overlay handling (~75% of fleet) added to the
  template + Makefile: (1) [word_floor, bin, trailing] carve for the final 1-3
  bytes spimdisasm drops; (2) build/assets/%.o incbin rule (+ .data align=1) for
  splat bin assets (asset_path scoped per-alias); (3) objcopy end-align TRIM
  (shrink-only, <=3 B) removing the .ld's segment-end ALIGN(.,4) pad
- .gitignore /assets/ (regenerable splat output); clean removes assets/
2026-06-16 15:39:52 -06:00
Drew T 50c5c9ea33 feat(phase-13): T0 — overlay splat template + overlays.mk indirection
- config/splat.us.overlay.template.yaml: reusable flat-blob splat template for
  location overlays (@TOKEN@ placeholders), modeled on splat.resident.yaml; code
  at file 0x0 (no leading-rodata trick), stacks symbols.resident.txt (overlays
  call the engine), vram 0x80128158
- Makefile: -include config/overlays.mk + BINARIES := main resident
  $(OVERLAY_BINARIES); the generated overlays.mk keeps new_overlay.sh out of the
  hand-maintained Makefile body; silent when absent (fresh-clone-safe)
- GATE T0: clean rebuild main 143dbb89 + resident 8e17e02f BYTE-IDENTICAL
  (indirection proven a no-op)
- phase-ends/CURRENT_PHASE.md: Phase-13 task log (plan approved gate 1)
2026-06-16 15:19:49 -06:00
Drew T b7b34f007e docs(phase-12): PhaseEnd — key engine systems complete; resident 1.4%->85.6% (v1.12.0)
Phase 12 close (milestone confirmed by Drew, gate 2):
- resident engine REAL 1 -> 123/146 = 85.62% byte-identical, 0 NON_MATCHING; both binaries
  byte-identical from a clean rebuild (resident 8e17e02f, main 143dbb89)
- pivots (byte-driven, Drew-approved): T1 the resident has NO PsyQ library footprint (all
  custom engine code, REAL not LINKED); T4 NO bytecode VM (script/event = compiled-MIPS
  fn-ptr-table dispatch, byte-backed); T5 save format documented, deep data + SaveLoadRoutine
  code-match honestly deferred (Gen3/P9)
- method: Ultracode harvest = swarm parallel-draft + incorruptible byte-gate (5 passes) +
  match_one iteration loop + extern-conflict recovery; tools harvest_verify.py + match_one.py
  (-> Phase 13). cookbook §12, R26 (prompt for ultracode on breadth)
- gen2-roadmap milestone + EXIT criterion #2 AMENDED (script/event resolved; save documented)
- PhaseEnd_Phase12.md; CURRENT_PHASE.md archived -> logs/Phase12.md (R19); README status
- rule R26; bumps project version 1.11.0 -> 1.12.0
2026-06-16 14:42:52 -06:00
Drew T 373418dc8d docs(phase-12): T5 — save trace findings (memcard path + directory confirmed; deep data deferred)
Live save-to-slot-1 trace via the PCSX-Redux web API confirmed the memcard path
bu00:BASLUS-00726MUSASHI (libmcrd) + the directory/title-frame staging in low RAM. The
save-DATA serialization couldn't be isolated from a live before/after diff (running-game
churn; the one big changed region @0x8007CD28 is an unrelated UI list). Clean route = the
.mcd file / a paused capture -> deferred as Gen3-repack territory, NOT needed for the
SaveLoadRoutine byte-match (code-level). SaveLoadRoutine stays the documented hard-defer
(1139-ins multi-entry, Gen1 precedent, P9).
2026-06-16 14:33:54 -06:00
Drew T d443cdf433 docs(phase-12): T5 (static start) — save/memcard format: saveHeaderTemplate + handler table (Q#5)
formats.md §6: SaveLoadRoutine @0x8002B154 = multi-entry save/load blob driving the linked
PsyQ libmcrd primitives; saveHeaderTemplate @0x80072DF0 decoded — memcard filename
"BASLUS-00726MUSASHI", SJIS title "BRAVE FENCER MUSASHI", and a @+0x54 handler DISPATCH
TABLE of 0x8002Bxxx pointers (the "multi-entry blob" IS this table of save/load sub-handlers).
Static layout VERIFIED. TBD (needs Ghidra-on-EXE + a Drew-operated PCSX-Redux save trace +
PsyQ-memcard CRC research): the save-DATA serialization (player/progress state 0x80078Exx +
checksum) + matching the tractable handlers. ram_savescreen.bin holds the live header.
2026-06-16 14:18:47 -06:00
Drew T 9a70f7179c docs(phase-12): T4 — script/event system + SQV driver determinations (byte-backed)
- memory-map.md: RESOLVE the "Script VM instruction set" open question — BFM has NO bytecode
  VM. "Scripting" is compiled-MIPS state machines dispatched via function-pointer tables
  indexed by game-state vars, proven by the matched resident dispatchers (D_800D3430[
  D_800B99F0](), D_800D3480/3488/3490[state](), the func_800D2Fxx cluster) mirroring the EXE's
  GameModeDispatch[gameMode](). Overlays = compiled MIPS that call the resident, not bytecode.
  Basis for the gen2-roadmap criterion #2 amendment (T6).
- formats.md §5: SQV driver = semi-custom — thin Square wrappers/glue over stock PsyQ libsnd;
  DsMix @0x800D1BD8 is a custom 2-line wrapper (NOT stock libsnd; the 4.7 sig was coincidental,
  T1). Bytes matched in the harvest; deep playback semantics deferred (Gen3, not needed for the
  byte-match).
2026-06-16 14:14:57 -06:00
Drew T 0821ba22da docs(phase-12): T3 substantively complete — REAL 123/146 (85.6%); T3b reassessed/deferred
T3a recovery landed REAL 102->123 (85.62% byte-identical). T3b reassessed under Max:
intra-resident dedup collapse has no recovery value left (all 6 h_exact + 9 h_norm group
members are individually matched byte-identical) -> deferred as optional source-DRY elegance
(the §11 share mechanism is proven; real leverage is the Phase-13 overlays). The ~21
remaining stubs are documented compiler-internal residuals (cross-jump/regalloc) -> honest
P9 deferrals (decomp-permuter is deliberate per-function work, not a blind sweep). T3 done
at the "substantial not exhaustive" bar. Both binaries byte-identical.
2026-06-16 14:12:46 -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 e3d86e6077 docs(phase-12): cookbook §12 (ultracode harvest pattern) + effort-map ultracode-prompting (R16/R21)
- matching-cookbook.md §12: the parallel-draft + deterministic byte-gate + match_one
  iteration loop that took the resident 1.4%->71.7% in one session. The pipeline (Workflow
  draft -> harvest_verify.py gate -> redraft passes -> match_one.py iterate), retry-wave
  resilience, the two TU gotchas (inline-typedef strip; standalone-MATCH-but-build-FAIL =
  extern-type conflict -> unify types), and the idioms the swarm surfaced (void-dispatcher-
  is-s32, struct-copy prologue, *10->2x+8x, masked-andi-range, callee-return-type-forces-cast).
- effort-map.md: standing instruction to PROACTIVELY prompt Drew to enable /effort ultracode
  on breadth-shaped stretches during a Max session (with the Phase-12 evidence), keeping the
  deep single-thread tasks at Max. Memories: ultracode-harvest-pattern, effort-prompt-
  ultracode-on-breadth.
2026-06-16 13:28:46 -06:00
Drew T f5209b6ef3 docs(phase-12): T3 harvest checkpoint — REAL 102/145 (71.7%); recovery path recorded
Resident engine harvest this session: REAL 1 -> 102 (71.72% byte-identical) via 5 ultracode
workflow passes + a deterministic byte-gate. 41 stubs remain in two classes recorded in
CURRENT_PHASE.md: (a) ~21 extern-type-conflict casualties (match_one matched them standalone;
the single-TU whole build conflicts on ~25 shared symbols -> unify extern types in resident.c,
widening definitions where byte-identical), (b) ~20 documented compiler-internal residuals
(cross-jump/regalloc -> decomp-permuter + cookbook §3a). Both binaries byte-identical.
2026-06-16 13:20:21 -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 ce79096547 feat(phase-12): T1 — resident PsyQ footprint survey = NIL (resident is custom engine code)
- psyq_identify over 4.7 (conv47, already ELF) AND 4.0 libs vs the resident
  (MAIN.CD/FILE_010/1.1, --vram-base 0x800CEDF8), code window + whole file:
  NIL footprint — 4.7 libsnd 1/226 (4-ins coincidence), libspu 0/134, libgte
  0/509, libgpu 0/61; 4.0 libsnd 2/163 (VM_DON/VM_DOFF 4-5 ins), libspu/gte 0.
  All hits are the §9.5 short-object coincidental class (<=8 ins).
- tool sanity: 4.0 libsnd vs the EXE snd region = 35/163 (works, version-sensitive)
- Ghidra corroboration: DsMix = {FUN_800d1bf8(); return 1;} custom wrapper (NOT
  stock libsnd; R13 tag refuted); resident makes 61 distinct EXE-range jal calls
  vs 37 internal — it CALLS the EXE's SDK, doesn't embed it
- => the resident is ~143 funcs of custom engine code; nothing to link. The
  DetectPsyQ 4.7 was one coincidental signature. Phase-12 plan revised
  (Drew-approved): drop the library-integration tasks; full substantial harvest
  of the resident engine by hand (REAL, not LINKED). Resident unchanged 8e17e02f.
- docs/psyq-worklist.md: corrected resident section with the byte-evidence +
  regen command; phase-ends/CURRENT_PHASE.md: revised task plan
2026-06-16 11:05:22 -06:00
Drew T 0cd9656f25 docs(phase-11): close-out — PhaseEnd_Phase11 + worklog archive (v1.11.0)
- PhaseEnd_Phase11.md: cross-binary dedup pipeline complete; milestone proven (clean
  dual-binary rebuild main 143dbb89 / resident 8e17e02f; cross-report 9366 h_exact groups
  across 136 binaries / 28.5 MB collapsible; one shared body byte-gated in both states)
- deviations D1 (source-level share, not object-swap) + D2 (self-consistent h_norm) recorded;
  no new rules (captured as cookbook §11 techniques)
- CURRENT_PHASE.md archived -> phase-ends/logs/Phase11.md (R19)
- bumps project version 1.10.0 -> 1.11.0
- Next: Phase 12 — key engine systems, opening with the resident's PsyQ 4.7 linking (R24)
2026-06-16 09:45:49 -06:00
Drew T 190afe10f0 docs(phase-11): T7 close-out — 4.7 sha-record, cookbook §11, SETUP §6.8, README/worklist
- tools/psyq/CHECKSUMS.sha256: integrity record for psyq-4.7-converted.zip (R20) + Phase-12
  provenance (the resident is 4.7 -> link from conv47/, not the EXE's 4.0 libs; R24)
- cookbook §11: the cross-binary dedup & code-share workflow — source-level macro share (NOT an
  object swap; game fns are interior to one object/binary, D1), the byte-gate, sig_image notes
  (h_exact workhorse / self-consistent h_norm D2 / linear-partition+code-end overlay boundaries),
  the cross-report as the Phase-12/13 work queue, per-binary SDK provenance (R24)
- SETUP §6.8 + tooling inventory: sig_image.py, dedup_integrate.py, dup_report --cross,
  make sig-overlays, config/dedup.us.yaml + src/shared/ (R21)
- docs/psyq-worklist.md: resident PsyQ is 4.7 (Phase-12 linking note)
- README: Gen2 status — resident is the 2nd byte-identical binary; cross-binary dedup live
  (~9000 cross-binary groups / ~28 MB collapsible; one engine fn byte-identical in all 134 overlays)
2026-06-16 01:31:50 -06:00
Drew T f672c709c1 feat(phase-11): T6 — sign the 134 overlays; cross-report spans 136 binaries (milestone report half)
- sig_image overlay discovery: linear partition (split contiguous code at jr+delay boundaries) +
  detect_code_end (first run of invalid instrs = the code->data transition; overlay code decodes
  ~100% valid, data drops to 43-95%). BFS dead-ended — overlays dispatch via function-pointer
  tables, not jal — so call-graph BFS found ~2 fns; linear partition recovers the whole code prefix
- Makefile: sig-overlays: signed 134 overlays -> .run/sig.ov_*.jsonl signs all 134 SCxx 0.4.dec @ 0x80128158 -> .run/sig.ov_*.jsonl (27s)
- dup_report --cross: ingest the overlay sigs (sig.ov_* convention) + main/resident; condensed
  source header (overlay set-sha for reproducibility); cap top-200 per subsection + state totals;
  compact member sample + #bin column
- RESULT (docs/duplicates.cross.md): h_exact 9366 cross-binary groups / 28.5 MB collapsible; h_norm
  8957 / 38.3 MB. Top group = a 770-instruction function BYTE-IDENTICAL in all 134 overlays (one
  match credits the whole fleet) — 'one match unlocks many' quantified; the Phase-12/13 work queue
- dedup-check green; committed per-binary digests byte-stable; report deterministic (sorted glob,
  no Date/random); the EXE<->resident pair still shares nothing (overlay<->overlay dominates)
2026-06-16 01:26:49 -06:00
Drew T 81e33c7a1e feat(phase-11): T5 — sig_image self-consistent h_norm + h_seq (scope-guard D2)
- norm_stream(): mask address-sensitive fields so structurally-identical functions at different
  addresses normalize equal — j/jal 26-bit targets, lui highs, and hi/lo-paired I-type address-los
  (a consistent lui->reg pending-hi tracker); KEEP registers, true constants, PC-relative branch
  offsets. h_seq = mnemonic sequence. Self-consistent within sig_image (the overlay fleet).
- validated on the resident vs the Ghidra oracle: h_exact equivalence classes 6/6 == Ghidra;
  h_norm reproduces 7/9 Ghidra structural groups — the 2 disagreements are BENIGN (differ only in
  masked address-low / jump targets; Ghidra's own reference analysis is inconsistent there). Any
  h_norm candidate is byte-gated (its sole acceptance, per the roadmap).
- DEVIATION D2: self-consistent h_norm, NOT a Ghidra-byte-exact normToken replica. Byte-reality
  makes cross-tool structural matching low-value (EXE<->resident share nothing; overlays share with
  each other via h_exact at the same vram, and CALL not embed the resident). h_exact is the
  format-independent cross-tool workhorse; full normToken replica is a documented future refinement.
  Scope-guard pre-approved in the plan.
2026-06-16 01:15:07 -06:00
Drew T 685e35fdc6 feat(phase-11): T4 — sig_image.py, Ghidra-free h_exact signer + boundary detection
- tools/sig_image.py: linear rabbitizer disassembler that signs a flat image (overlay 0.4.dec /
  resident 1.1) at a vram base, JSONL field-identical to DumpFunctionSignatures.java. h_exact =
  SHA1 of raw bytes (format-independent — the cross-binary workhorse; overlays share the same vram
  so same-offset dups are byte-identical). Seeded + jal-closure bootstrap entry discovery.
- boundary rule: a function ends at the first 'jr $ra'(+delay) at/after every forward branch/jump
  target — handles early-return jr AND ignores the trailing orphan jr;nop (double-epilogue)
- VALIDATED vs the resident Ghidra oracle: 100% h_exact on the contiguous/non-GTE subset (140/140),
  ZERO UNEXPLAINED (whenever nbytes agrees, h_exact agrees) — the byte pipeline is exact; 98.6%
  overall. The 2 misses are non-contiguous Ghidra bodies (D5, inherent to a linear sweep)
- h_norm/h_seq emitted as conservative placeholders (= h_exact -> zero false structural matches)
  until T5 calibrates the normToken/mnemonic replica; overlays aren't signed until T6 (post-T5)
2026-06-16 01:07:28 -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 b06d74c1be feat(phase-11): T2 — dedup.us.yaml registry + dedup_integrate byte-honesty validator
- config/dedup.us.yaml: cross-binary code-share registry (group -> {id,tier,hash,
  source,func,members[{binary,vram,name}]}); empty for now (T3 adds the first group)
- tools/dedup_integrate.py: --check validator. Fail-closed if a shared function's
  current sig hash drifted from the recorded hash (a stale share can never silently
  mislead, P9/G3); unsigned binary -> WARN (unvalidated), not a hard fail
- Makefile: dedup-check is the fail-closed last line of `make report` (gated BINARY=main)
- DEVIATION D1: game-code dedup is SOURCE-LEVEL (shared body in src/shared/<fn>.h,
  instantiated per site), NOT a psyq_integrate object-swap — game funcs are interior to
  one object per binary so the linker can't swap them; the byte-gate is the existing
  per-binary make check. .ld interpose stays the library mechanism (Phase 8)
- verified: --check passes on empty registry; make report runs it; clean rebuild main
  -> 143dbb89 BYTE-IDENTICAL (T2 is a proven build no-op, R22)
2026-06-16 00:47:20 -06:00
Drew T 7cc2911456 feat(phase-11): T1 — cross-binary dup_report --cross → duplicates.cross.md
- dup_report.py: additive --cross mode ingests all BINARIES sigs, tags each row
  with its binary, buckets by h_exact then h_norm across binaries, splits
  cross-binary (binaries>1, the Phase-12/13 work queue) vs intra-binary, ranks by
  collapsible bytes (count-1)*nins*4, one row per member -> docs/duplicates.cross.md
- Makefile: make report emits the cross report once (gated BINARY=main)
- per-binary duplicates.md/.resident.md stay byte-stable (per-binary path unchanged)
- EXE<->resident cross-binary groups = 0 (4.0 vs 4.7 + different roles, as the
  byte-finding predicted); real cross groups arrive with overlays (T6)
- phase-ends/CURRENT_PHASE.md: Phase 11 plan + per-task log
2026-06-16 00:37:18 -06:00
Drew T 6df7e79c5d docs(phase-10): store the plain-English recap in the PhaseEnd + rule R25
- add a '## Plain-English Recap' section to PhaseEnd_Phase10.md (was chat-only, ephemeral)
- R25 (extends R18): every PhaseEnd carries a durable Plain-English Recap section, not just a
  chat message — the PhaseEnds are the state a fresh session reconstructs from (load order), so
  the plain-language orientation has to live there. Applies Phase 10 forward.
- Drew's feedback (2026-06-15): the R18 recap wasn't persisted anywhere; memory updated
2026-06-15 23:39:56 -06:00
Drew T 702b94fd7d docs(phase-10): close-out — PhaseEnd_Phase10 + flat-blob recipe (v1.10.0)
- PhaseEnd_Phase10.md: resident engine blob byte-identical from source (8e17e02f) at 100%
  INCLUDE_ASM; the binary-agnostic toolchain proven on a real 2nd binary; main still 143dbb89
- docs/SETUP.md §6.7: the resident first-instantiation + the reusable flat-blob <bin> recipe
  (per-binary OBJS prune, build_path=build, flat config, leading-data-word-as-rodata); 2 new
  Ghidra tools in the inventory (R21)
- rule R24 (per-binary compiler/SDK provenance — resident is PsyQ 4.7 vs EXE 4.0)
- worklog archived CURRENT_PHASE.md -> phase-ends/logs/Phase10.md (R19)
- bumps project version 1.9.0 -> 1.10.0
2026-06-15 23:35:11 -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 cc73951128 feat(phase-10): T3 — per-binary reports/diff/expected for the resident binary
- diff_settings.py + progress.py/difficulty.py/dup_report.py: add the `resident` BINARIES entry
  (build/resident/, config/check.resident.sha, src/resident, asm/resident/nonmatchings, per-binary docs)
- dup_report.py: degrade gracefully when the Ghidra sig (.run/sig.resident.jsonl) is absent —
  write a placeholder + exit 0 instead of crashing the whole `make report` (sig is a T4 export)
- progress.py: scope linked_subsegs() to BINARY==main — PsyQ library linking is the EXE's layout
  (Phase 8, gated ifeq BINARY,main), so a second binary has 0 LINKED (was: listed main's libs)
- Makefile expected: per-binary-safe — drop `rm -rf expected/build` (clobbered every sibling
  baseline); refresh only the active binary's image dir + merge-copy (cp never deletes siblings)
- reports: resident = 0 REAL / 143 INCLUDE_ASM stubs / 100% stub (correct); main UNCHANGED
  (52 REAL / 959 LINKED / 50.24%); both expected/ baselines coexist (verified)
2026-06-15 23:06:25 -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 95ade84768 feat(phase-10): T1 — scaffold the resident second binary (Makefile no-op on main)
- Makefile: BINARIES += resident; resident_* var block (vram 0x800CEDF8, build/resident/,
  config/*.resident.*); per-binary ASM_DIR/SRC_DIR + $(BINARIES)-derived OBJS prune-list so
  main (asm/+src/) and resident (asm/resident/+src/resident/) object sets stay disjoint;
  per-binary UNDEF_SYMS/UNDEF_FUNCS (resident writes under build/resident/)
- config/splat.resident.yaml: flat blob config (NO header, NO gp_value, single c seg @
  vram 0x800CEDF8, stacked symbols [symbols.us.txt, symbols.resident.txt], per-binary
  asm/src/build/undefined paths, EOF 0x5935C -> end vram 0x80128154)
- config/check.resident.sha (8e17e02f… = extracted MAIN.CD/FILE_010/1.1, 365,404 B, type-1)
- config/symbols.resident.txt (R13/R15 provenance banner; seeded empty, populated in T4)
- gates: (a) main clean rebuild 143dbb89… (refactor is a no-op on the byte-locked EXE);
  (b) make extract BINARY=resident -> 144 INCLUDE_ASM stubs + .ld @0x800CEDF8;
  (c) main OBJS=81 excludes resident even with resident on disk + main stays 143dbb89…
- src/resident/*.c left WIP-untracked (reshaped by T2 boundary carving)
2026-06-15 22:50:55 -06:00
Drew T d380b13fc5 feat(phase-9): close-out — PhaseEnd_Phase9 + binary-agnostic toolchain (v1.9.0)
- PhaseEnd_Phase9.md written; CURRENT_PHASE.md archived -> phase-ends/logs/Phase9.md (R19)
- MILESTONE (gate-2 confirmed): the toolchain is binary-agnostic — EXE rebuilds
  143dbb89 through the parameterized path WITH and WITHOUT SDK objects; make report
  52/959/7/50.24%; every binary-specific value a required param (no EXE default);
  wrong --vram-base -> cae22f7e (negative control). Landed as 11 per-tool checkpoints.
- R23: stop the Ghidra MCP + commit the DB at phase-end/RE-checkpoint (lock won't
  release until MCP closes; SessionEnd is too late for a mid-session commit). This
  commit reconciles the Ghidra program DB (db.12 -> db.15, 99% identical: Phase 9 did
  zero RE writes) after a clean ghidra_mcp_stop.sh save.
- .gitignore: ignore /ghidra/**/*.lock~ (the lock-backup that churned every session)
- bumps project version 1.8.0 -> 1.9.0
2026-06-15 22:01:17 -06:00
Drew T 6345b5012a docs(phase-9): T10 — binary-agnostic toolchain docs + final milestone proof (R16/R21)
- SETUP.md §6.7: the binary-agnostic toolchain (make build BINARY=<alias>, the
  required --vram-base/--exe/--symbols flags, BFM_BINARY for asm-differ, and the
  future-binary path convention config/splat.<bin>.yaml / build/<bin>/ etc.)
- matching-cookbook.md §9.7: the reusable refactor pattern for Gen2 (required params/
  no defaults, --vram-base scalar vs window, transitional-default + leaf-first
  technique, the negative control, the progress.py regex lockstep gotcha)
- psyq-worklist.md: per-library recipe updated with the now-required flags
- README.md: status -> 52 REAL / 959 LINKED / ~50% byte-identical / Gen2 underway
  (binary-agnostic toolchain)
- MILESTONE (all green): EXE rebuilds 143dbb89 with AND without SDK objects; report
  52/959/7/50.24%; wrong --vram-base -> cae22f7e (negative control); expected/ refreshed
2026-06-15 21:09:06 -06:00