Files
BFM-decomp/phase-ends/PhaseEnd_Phase2.md
T
Drew T b6ea3a2747 feat(phase-2): deterministic disc/.CD/PAC/LZSS extraction pipeline
- extract.py: one-command full-disc extraction (27 files: 24 Track-1 verbatim
  + 3 .DA as raw CD-DA audio from tracks 2-4) over the frozen iso9660.py
- cd_archive.py + pac.py: .CD TOC walker + PAC splitter, {index}.{type} naming
  (no collisions; 447 sub-files, 1189 entries), SQV detection (98)
- lzss.py: game-semantics decoder (pos==0 terminator, -1 bias) + 5 unit tests;
  138 type-4 decoded clean (0 warnings)
- manifest.py: deterministic JSON-Lines manifest (1801 artifacts) + --verify
- crosscheck.py + tools/brave-CUE/posix_shim.h: build CUE's brave from source
  (GPL untouched), byte-compare; 1484 raw identical, 138/138 type-4 F6
- docs/formats.md: F5 counts (SC02=43), F2 refuted, F6 resolved, F1 type-7=139
- docs/effort-map.md + CLAUDE.md: Effort-map check rule (R7), Ultracode fix
- .gitignore: /extracted/* + !manifest/EXE exceptions; brave _build/
- install gcc 13.3.0 for the oracle
- milestone: one command extracts the full disc; MAIN.CD=49 sub-files; decoder
  agrees byte-for-byte with CUE up to the game pos==0 terminator; zero ROM
  staged; project version 1.1.0 -> 1.2.0
2026-06-13 19:47:42 -06:00

86 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PhaseEnd — Phase 2: Deterministic disc & .CD extraction pipeline
**Date:** 2026-06-13 · **Project Version:** 1.2.0 · **Phase Status:** Complete
## Build Log
**Files created/changed and complete — do not recreate:**
- `tools/bfm_extract/extract.py` — unified full-disc CLI. Walks the ISO root (over the frozen `iso9660.Iso9660Image`), writes every file, splits `.CD`→PAC→type-4, writes the manifest; `--list` / `--verify`. Composes `cd_archive` + `pac` + `lzss` + `manifest`; reuses `extract_exe` EXE constants. Also contains the multi-track `AudioTrack` reader for the 3 `.DA` files.
- `tools/bfm_extract/cd_archive.py` — `.CD` TOC walker (`parse_toc`, `iter_subfiles`) + `classify_subfile` (pac/sqv/raw). Excludes LIST.CD by caller contract.
- `tools/bfm_extract/pac.py` — PAC chain splitter (`is_pac`, `split_pac`); `{index}.{type}` model with `+0x08` and full-header capture.
- `tools/bfm_extract/lzss.py` — game-semantics LZSS decoder (`pos==0` terminator, −1 bias, length cross-check). Pure function; ring re-zeroed per call.
- `tools/bfm_extract/test_lzss.py` — 5 standalone synthetic unit tests (literals, terminator, −1 bias, overlapping copy, cross-check warnings).
- `tools/bfm_extract/manifest.py` — deterministic JSON-Lines manifest (`build`/`render`/`write`/`verify`); `manifest.jsonl` + `manifest.sha1`.
- `tools/bfm_extract/crosscheck.py` — CUE `brave` oracle harness: builds brave, maps type-only names → `{index}.{type}`, byte-compares, classifies F6/shadowed, writes `_build/divergence.log`.
- `tools/brave-CUE/posix_shim.h` — glibc build shim (`filelength`→`fstat`; 1-arg `mkdir` macro) so the GPL `brave.c`/`common.inc` compile **unmodified**.
- `tools/bfm_extract/extract_exe.py` — added `EXPECTED_EXE_SHA1` constant (round-trip anchor).
- `.gitignore` — `/extracted/*` + `!`-exceptions for `SLUS_007.26`/`manifest.jsonl`/`manifest.sha1`; `/tools/brave-CUE/_build/`.
- `docs/SETUP.md` — §4.4 note: disc staged on ext4 (Phase 2), WSL `--verify-disc` PASS (closes Phase-1 deferral).
- `docs/formats.md` — §2.2 verified US sub-file counts; §3.1 `+0x08` finding; §3.2 type distribution; §4.4 F6 resolution; §5/§7 SQV/.DA; §8 F1/F2/F4/F5/F6/F7 status + Phase-2 summary block.
- `CLAUDE.md` — Reasoning & Model Protocol: corrected the "Ultracode is an effort level" error; added the Effort-map check rule (→ R7); Session Start now states next-task effort.
- `docs/effort-map.md` — **new** evolvable reference: verified effort mechanics, two-axis depth/breadth model, Max-default policy, per-phase Gen1 map.
- `phase-ends/CURRENT_PHASE.md` — **absorbed into this file and deleted** (P8).
**Local artifacts (gitignored / outside the repo — present on this machine, do NOT recreate; a fresh clone must redo them):**
- `disks/Brave Fencer Musashi (USA) (Track 1..4).bin` + `.cue` — all 4 tracks copied once from `/mnt/z` (Track 1 = 364,846,944 B; tracks 2-4 = CD-DA audio). Gitignored.
- `extracted/` bulk — 1801 artifacts (raw `.CD`, `FILE_%03d`, `{index}.{type}`, `.dec`, FMV, `.DA` audio). Regenerable via `extract.py`. **Committed** subset: `manifest.jsonl`, `manifest.sha1`, `SLUS_007.26`.
- `tools/brave-CUE/_build/brave` (+ `divergence.log`) — compiled oracle + scratch (gitignored).
**Tools/packages installed:** gcc 13.3.0 (`Ubuntu 13.3.0-6ubuntu2~24.04.1`) — to build the `brave` cross-validation oracle (user-approved; `build-essential` is a Phase-4 dependency regardless).
**Verification results (literal):**
- LZSS unit tests: **5/5 pass**.
- `extract.py`: 27 files (24 Track-1 verbatim + 3 `.DA` raw CD-DA audio); 447 sub-files, 348 PAC chains, **1189 PAC entries** (138 type-4 decoded, **0 LZSS warnings**), 98 SQV. **EXE round-trip PASS** (SHA1 `143dbb89f34491258bbc27810d0a12ec8b43a8dd`).
- Manifest: **1801 artifacts**; `manifest.sha1 = e5c6019249dec3c71bb2cf40658a78439dddb037`; **identical across re-runs** (deterministic); `--verify` **PASS**.
- `crosscheck.py --sample all` (brave built with gcc): **1484 raw payloads byte-identical** (0 diff); **138/138 type-4 F6** (ours = the game-correct prefix; brave over-decodes exactly 2 B per stream = 276 B total); **0 raw mismatches, 0 decode mismatches — PASS**. 14 "shadowed" entries in MAIN.CD confirm the brave naming collision our `{index}.{type}` fixes.
- `git status`: only tooling/docs/manifest tracked; bulk payloads + `_build/` ignored (**zero ROM-derived files staged**).
- Open-question results: **F5** US counts (MAIN=49, SC01=86, **SC02=43**, SC03=140, SC04=31, SC05=30, SC06=39, SC07=29); **F2** `+0x08`=0 for all type-4 (size-hint refuted; non-zero only type 0=301, type 6=29); **F1** type 7=139 (common), no type 5; **F6** resolved (no within-payload divergence).
**Milestone achieved:** `python3 tools/bfm_extract/extract.py` extracts the full disc in one command, MAIN.CD yields its 49 sub-files, the decompressed type-4 payloads are byte-identical to CUE's `brave` up to the game `pos==0` terminator (138/138), the SHA1 manifest is deterministic, and `git status` shows zero ROM-derived files staged.
**Next:** Phase 3 — File-loader & overlay-map RE (+ PCSX-Redux harness). Start with Ghidra seeded with the provenance-tagged ledger from `docs/memory-map.md`. (Phase 3 is RE work — MCP precondition G2 applies; and per `docs/effort-map.md` the US address derivation + RAM-dump proof are **Max** tasks.)
## Deviations
| Item | Plan | Actual | Reason |
|---|---|---|---|
| Disc staging | Track 1 only | All 4 tracks + `.cue` staged on ext4 | User directed extracting the `.DA` files, whose data lives in tracks 2-4 |
| `.DA` files | Out of scope / skip | Extracted as raw 2352-B/sector CD-DA audio (tracks 2-4) | User "extract every byte"; `.DA` ISO entries point past Track 1 into the audio tracks |
| Cross-val tool | brave.exe (Windows) via wibo/wine | Build `brave.c` from source via `posix_shim.h` (gcc) | Cleaner than Wine; GPL upstream untouched; gcc is a Phase-4 dep anyway (user-approved early install) |
| Commit cadence | One commit per task (P4/R6) | One commit at phase end | User directive 2026-06-13 (→ rule R8) |
| Effort-map work | (not in the phase plan) | Added `docs/effort-map.md` + R7 + CLAUDE.md correction at session start | User requested before planning the phase |
| F4 (LIST.CD regen) | Resolve during the run | Deferred (extractor excludes LIST.CD; regen+diff is a cheap follow-up) | Optional; not a milestone item |
| Output tree | (raw split only) | Keep raw `.CD` + raw sub-files + `{index}.{type}` + `.dec` (all gitignored bulk) | Faithful "every byte" + diffable-against-brave structure |
## Commit Message
```
feat(phase-2): deterministic disc/.CD/PAC/LZSS extraction pipeline
- extract.py: one-command full-disc extraction (27 files: 24 Track-1 verbatim
+ 3 .DA as raw CD-DA audio from tracks 2-4) over the frozen iso9660.py
- cd_archive.py + pac.py: .CD TOC walker + PAC splitter, {index}.{type} naming
(no collisions; 447 sub-files, 1189 entries), SQV detection (98)
- lzss.py: game-semantics decoder (pos==0 terminator, -1 bias) + 5 unit tests;
138 type-4 decoded clean (0 warnings)
- manifest.py: deterministic JSON-Lines manifest (1801 artifacts) + --verify
- crosscheck.py + tools/brave-CUE/posix_shim.h: build CUE's brave from source
(GPL untouched), byte-compare; 1484 raw identical, 138/138 type-4 F6
- docs/formats.md: F5 counts (SC02=43), F2 refuted, F6 resolved, F1 type-7=139
- docs/effort-map.md + CLAUDE.md: Effort-map check rule (R7), Ultracode fix
- .gitignore: /extracted/* + !manifest/EXE exceptions; brave _build/
- install gcc 13.3.0 for the oracle
- milestone: one command extracts the full disc; MAIN.CD=49 sub-files; decoder
agrees byte-for-byte with CUE up to the game pos==0 terminator; zero ROM
staged; project version 1.1.0 -> 1.2.0
```
## Rules Added This Phase
| Rule | Reason |
|---|---|
| **R7 — Effort-map check.** Before each Phase Start, state the recommended effort for planning that phase per `docs/effort-map.md` and confirm the developer has it set; annotate every task in the plan with its effort; restate the recommended effort whenever presenting the NEXT task. `docs/effort-map.md` is the evolvable source of truth (it also records the verified harness mechanics: effort ladder `low..xHigh/Max`; Max & Ultracode are session-only; Ultracode = xHigh + multi-agent orchestration, not a deeper level). | User requested a persistent effort guide and noticed Ultracode "reverting to xHigh"; corrects CLAUDE.md's mislabeling of Ultracode as an effort level. |
| **R8 — One commit at phase end (supersedes the per-task-commit part of P4/R6).** Work accumulates UNCOMMITTED during a phase; `CURRENT_PHASE.md` is the per-task crash-recovery log; a single commit lands at phase close. The user commits AND pushes it (R6 phase-boundary exception, extended to the whole phase). | User directive 2026-06-13 — fewer commits to manage with the WSL-commit / GitHub-Desktop-push workflow. |
## PhaseEnd Changelog
**v1.1.0 → v1.2.0** — Phase 2 complete. The deterministic disc/.CD/PAC/LZSS extraction pipeline is live (pure-stdlib Python over the frozen `iso9660.py`): one command extracts the full disc into 1801 manifest-tracked artifacts; the game-semantics LZSS decoder decodes all 138 type-4 overlays cleanly and is byte-validated against CUE's `brave` (built from source). Open questions resolved: F5 (US sub-file counts, SC02=43), F2 (`+0x08` is not a size hint), F6 (no within-payload game/tool divergence); F1 partially (type 7 common). Two rules added (R7 effort-map check, R8 one-commit-at-phase-end). gcc 13.3.0 installed. Deviations: all 4 tracks staged + `.DA` extracted as raw audio (user scope change).
## 🛑 Stop Here
Start a fresh session for the next phase. Keep this file forever.