- 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
9.4 KiB
CURRENT_PHASE — Phase 10: Resident engine blob (splat config + all-asm byte-match)
Generation: Gen2 (phase 3 of the 8→9→10→11→{12,13}→14 arc) · Started: 2026-06-15
Plan approved: yes (gate 1 passed) · Effort: planning Max (done); execution xHigh (T2→Max if the split fights)
Plan file: /home/musashi/.claude/plans/plan-mode-enabled-max-giggly-hollerith.md
Milestone (gate 2)
make build BINARY=resident && make check BINARY=resident → SHA1 8e17e02ff8954d07c979449198f7e1645046b353
at 100% INCLUDE_ASM, with main still 143dbb89f34491258bbc27810d0a12ec8b43a8dd (no regression).
Target facts (verified this session)
- File:
extracted/retail/MAIN.CD.dir/FILE_010.dir/1.1— 365,404 B, SHA18e17e02f…, PAC type-1 (uncompressed), gitignored, manifest-verified. - Load vram 0x800CEDF8 (Phase-3 T6b proven);
VRAM_BASE=0x800CEDF8 (fileoff 0→vram). Computed end vram 0x80128154 (4 B under overlay slot 0x80128158 — boundary corroboration). - First word = data
0x00000036; code at +0x04. Flat image, NO header segment. - Alias
resident, basenameresident. Paths:build/resident/,config/splat.resident.yaml,config/check.resident.sha,config/symbols.resident.txt,.run/sig.resident.jsonl,asm/resident/,src/resident/.
Decisions locked (owner-confirmed 2026-06-15)
- Ghidra = second program in the
bfmproject (not a region in main). - Defer EXE→resident pointer table (Q#2) to Phase 11/12.
- Keep stacked
symbol_addrs_path: [config/symbols.us.txt, config/symbols.resident.txt]— 0 func syms in the resident window, 27 shared engine globals in symbols.us.txt the blob references; byte-identity is symbol-name-independent (no relocations). - c-mode INCLUDE_ASM (match-ready); asm-mode is the de-risk fallback for the milestone.
Tasks
- T1 — Scaffold
residentinstance + prove no-op onmain(xHigh) ✅ DONE- Makefile:
BINARIES += resident;resident_*block; per-binary OBJS prune-list (<bin>_ASM_DIR/SRC_DIR+$(BINARIES)-derived prune); per-binaryUNDEF_SYMS/UNDEF_FUNCSaliases (resident→build/resident/undefined_*). config/splat.resident.yaml(flat, no header, no gp_value, single code seg c-mode, stacked symbols, per-binary asm/src/build/undefined paths, find_file_boundaries False).config/check.resident.sha(seed8e17e02f… resident);config/symbols.resident.txt(provenance banner, count=0).- Exit: (a) main
make clean&&extract&&build&&check→143dbb89…(refactor is a no-op); (b)make extract BINARY=residentcompletes; (c) interleave check:make build BINARY=mainafter a resident extract still green.
- Makefile:
- T2 — Iterate split to byte-identical (THE milestone) (xHigh) ✅ DONE — MILESTONE REACHED
- Converge subseg boundaries vs SHA1; handle leading data word; confirm -G0 (grep
($gp)); ld_interleave only if a rodata island appears. - Exit: clean-rebuild →
8e17e02f…, last byte @0x80128154; main re-verified143dbb89…. → progress report to Drew.
- Converge subseg boundaries vs SHA1; handle leading data word; confirm -G0 (grep
- T3 — Close per-binary tooling gaps (xHigh) ✅ DONE
diff_settings.py+tools/progress.py+tools/difficulty.py+tools/dup_report.pyget aresidententry;expectedmade per-binary-safe (no sibling clobber).- Exit:
make report BINARY=residentshows 100% INCLUDE_ASM;make expected BINARY=residentno-clobber; main report unchanged.
- T4 — Ghidra 2nd program + seed
config/symbols.resident.txt(xHigh) ✅ DONE- + parameterized
make sig-refreshby BINARY (per-binary GHIDRA_PROG; resident →.run/sig.resident.jsonl). - Import blob as 2nd program @0x800CEDF8 (MCP stopped for the lock); auto-analysis + PsyQ sigs + DetectPsyQ; light seeding; export blob-only symbols (R13/R15, never merged into symbols.us.txt).
- Exit: rebuild still
8e17e02f…(symbols don't change bytes); R9 persistence; R23 stop-MCP-before-commit.
- + parameterized
- Phase close — P7 checkbox sweep; gate-2 milestone confirm (Drew); PhaseEnd_Phase10.md (Tier-1 Max); archive CURRENT_PHASE.md→logs/Phase10.md (R19); R18 recap; P8 hard stop.
Commit cadence
Per-task checkpoint commits, each byte-gated (R20 + Phase 8/9 precedent). Claude commits locally; Drew pushes (R6). T4 commit includes Ghidra DB → stop MCP first (R23).
Key finding (T4, 2026-06-15) — resident is PsyQ 4.7.0, not 4.0.0
DetectPsyQ on the imported resident program reports PsyQ Version = 470 (the EXE is 4.0.0); the import
associated a psyq470 source archive alongside psyq400; the one PsyQ-signature hit in-range is DsMix
(libsnd → the resident holds the sound driver). Drew (2026-06-15): the archive.org PsyQ link has the 4.7
libs. Provenance (G5): detected, to be CONFIRMED in Phase 11/12 by linking real 4.7 libs and byte-matching.
Implication: the resident's PsyQ library linking (Phase 11/12) uses 4.7, not the EXE's 4.0 — so the
4.7 .LIBs are a needed asset (R20: stage the hard-to-source tooling). Does NOT affect the Phase-10
byte-match (100% INCLUDE_ASM, no resident code compiled yet).
DECISION (Drew 2026-06-15): DEFER the 4.7 .LIBs to Phase 11 START (archive.org link); CARRY this
finding into PhaseEnd_Phase10 "Notes for Future Phases" so Phase 11 fetches+sha-verifies them then. Phase 10
needs nothing from PsyQ 4.7. → also record provenance in docs/memory-map.md.
Blockers
(none)
Worklog
- 2026-06-15: Phase planned (Max), 3 Explore + 1 Plan agent; gate-1 approved. Beginning T1.
- 2026-06-15: T1 DONE. Makefile:
BINARIES += resident;resident_*block; per-binaryASM_DIR/SRC_DIR+$(BINARIES)-derived OBJS prune-list; per-binaryUNDEF_SYMS/UNDEF_FUNCS. New:config/splat.resident.yaml(flat, no header, no gp_value, singlecseg @0x800CEDF8, stacked symbols, per-binary undefined paths under build/resident/),config/check.resident.sha(8e17e02f…),config/symbols.resident.txt(R13 banner, 0 entries). Gates all green: (a) main clean rebuild →143dbb89…(refactor = no-op); (b)make extract BINARY=resident→ 144 INCLUDE_ASM stubs, src/resident/resident.c + .ld @vram 0x800CEDF8; (c) main OBJS still 81 (excludes resident)- main rebuild
143dbb89…with resident on disk (prune isolates).src/resident/*.cleft untracked WIP (reshaped by T2 boundary carving — commit at T2). Committed config+Makefile checkpoint.
- main rebuild
- 2026-06-15: T2 DONE — MILESTONE REACHED. Mapped the blob structure vs the bytes:
word0 = data header (0x36); clean code 0x4..0x4610 (145 funcs, 0 embedded jtbls/trap-ops);
data tail 0x4610..EOF (pointer tables + 78.5 KB zero run). Split =
[0x0, rodata, hdr]+[0x4, c, resident]+[0x4610, data, tail]. Two fixes found: (1) leading word before code fights section_order → emit it as rodata (no-dot; section_order places .rodata first) — a 1-word analogue of main's island, NO ld_interleave; (2)build_path: build(not build/resident) so the .ld's object paths match the Makefile'sbuild/asm/**+build/src/**rules.make build BINARY=resident→8e17e02f…BYTE-IDENTICAL (365,404 B, end vram 0x80128154); -G0 confirmed (0 gp refs); R22 clean-rebuild green; main still143dbb89…. src/resident/resident.c (143 stubs) now committed (boundaries final). asm/resident/** regenerated (gitignored, like main). - 2026-06-15: T3 DONE.
residententries added to diff_settings.py + progress/difficulty/dup_report. Two real bugs fixed: (1) dup_report crashed on the absent.run/sig.resident.jsonl→ now writes a placeholder + exits 0 (sig is a T4 Ghidra export); (2) progress.py listed MAIN's LINKED libs for resident → scopedlinked_subsegs()to BINARY==main (library linking is the EXE's layout, Phase 8).expectedmade per-binary-safe (merge-copy, norm -rf expected/buildsibling clobber — verified both baselines coexist). Reports: resident = 0 REAL / 143 stubs / 100% INCLUDE_ASM; main UNCHANGED (52 REAL / 959 LINKED / 50.24%). Carried into T4: parameterizemake sig-refreshby BINARY. - 2026-06-15: T4 DONE. New reusable tooling:
tools/ghidra_import_raw.sh(BinaryLoader + base + PSX:LE:32 — the Gen2 raw-blob importer, reusable for Phase-13 overlays) andtools/ghidra_scripts/DefineFunctions.java(seed splat's validated boundaries — raw-binary auto-analysis finds only the reachable subset). Imported the resident as the bfm project's 4th programresident@0x800CEDF8; auto-analysis (PsyQ sigs) → PsyQ 4.7.0 detected +DsMix(libsnd) named. Defined splat's 143 boundaries (created=120/existed=23/failed=0); R9-verified 143 funcs persisted via read-only sig-refresh. Seededconfig/symbols.resident.txtwithDsMix(R13 candidate); re-extract applied it; resident + main both clean-rebuild byte-identical (R22). Makefile: per-binaryGHIDRA_PROG→make sig-refresh BINARY=resident. dup_report now real (6 byte-identical groups intra-resident — Phase-11 dedup fodder). Ghidra DB committed (R23, MCP stopped): newresidentprogram (00000003.*) + main's incidental db.15→db.16 no-op renumber. 4.7 libs DEFERRED to Phase 11 (Drew) — carry to PhaseEnd Notes. - 2026-06-15: T5 / phase close. P7 checkbox sweep complete (all 4 tasks + roadmap items met). Final clean-rebuild proof presented; Drew confirmed gate 2. SETUP §6.7 extended with the flat-blob recipe + 2 new tools (R21). PhaseEnd_Phase10.md written (Tier-1 Max). Rule R24 proposed (per-binary SDK provenance). This worklog archived → logs/Phase10.md (R19). v1.9.0 → v1.10.0.