mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-27 22:45:39 -04:00
b6ea3a2747
- 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
86 lines
9.5 KiB
Markdown
86 lines
9.5 KiB
Markdown
# 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.
|