Drew T 9937fd7e39 docs+kit(phase-33.5): task 14 — the S91-b types hindsight implemented in the kit + the wiki page Start-a-new-decomp-project.md + the rows
- kit: DK-65 "types are a banking lever and a width lever, not a byte lever" (kernel, when, cost, calibration fence, provenance;
  the kernels file now states its own total "In all: DK-1 … DK-65" and SETUP Step 6 compares grep -c against it instead of a typed
  64); intake row 6's milestone gains the canonical type layer (one definition per shape, widths proven by the bytes at bank time,
  a bank refused for a duplicate definition or a raw address cast) + the type tools moved forward + G62/DK-65 in its columns; row 10
  reads "short if Part C and Phase 6's type layer held"; G62 extended with the bank-time clause (G1–G67 kept); tool_dictionary:
  lift_types + canon_sig_reconcile P10 → P6 and the five type tools' need-keys name the type layer at Phase 6 (the phase column is
  one token — the corpus dir derives from it); the cookbook front page's type-verdict sentence (a NAME never moves a byte, a WIDTH
  or SIGNEDNESS is the one place a type does, the permuter cannot reach it); the methodology's "Types — the two-sided verdict"
  paragraph; the kit README's table + tree now name the two dictionaries and layout-contract.md; make kit-corpus regenerated the
  tool index, the MANIFEST and the corpora (302 copies + 28 pointers)
- wiki: docs/wiki/Start-a-new-decomp-project.md — the three steps, what it installs / does not (the two dictionaries), the ladder
  (11 rows), the five AI-use rules, the six inversions (raw casts → declared symbols; DK-65), the compiler question, the accelerators
  one line each (58 rows), the four dry-runs, how it is kept honest; sidebar + Home rows; Tools-from-this-project rows for the kit
  and the tool index; README bullets for both; SETUP row for decomp-architect/ (R21); Where-the-project-goes-next links the page and
  records the probe PASS (2026-09-07); phase34-seed: task 0 PASSED, the kit carried whole through the flip and split later
- verify: wiki_render --selftest 12/12 + reachability 32 pages / 0 unlisted; doc_links --strict 58 documents / 451 links / 0 pending /
  0 broken / coverage 65 of 65 (one BROKEN on the first draft — a foreign project's docs/ path cited in backticks — reworded);
  kit_lint OK (leak 0 / placeholders 22 == 22 / syntax 0 / gitignore 75 identical); tool_census --check OK; 65 DK ids cited, 0
  dangling; audit_public OK on the touched files; no build input changed
- log + checkpoint (NEXT = task 15, Max, Tier 1 — prompt Drew and wait for gate 2)
2026-09-07 22:40:17 -06:00
tools+docs(phase-33.5): task 13.5 — the tools audit + the two dictionaries: tools/tool_census.py (two agreeing enumerations of 327 tool files; docstring/SETUP row/consumers/class derived from the tree; the authored half in config/tool_dictionary.tsv — phase · portability · the NEED each tool answers · what · adapts · verdict — with coverage asserted both ways) → docs/tool-index.md (need-keyed, KEEP-GEN, Reference-index row, wiki + how-to pointers), the kit's tools/MANIFEST.md regenerated (header states live 293 + superseded 28 = 321 rows), and the two verbatim corpora in-tree (Drew, confirmed S91): decomp-architect/corpus/tools/<phase>/ (302 copies + 28 superseded pointers + INDEX) and corpus/cookbook/ (the cookbook, its symptom index, the codegen map, a front page stating what transfers per compiler) — sha1-equal to their sources by tool_census --check in tools-health, regenerated by make kit-corpus; kit_lint exempts the corpus dirs (verbatim evidence) but syntax-checks them; G66 (consult the tool dictionary first) + G67 (translate an inherited idiom through its pass) + two memory seeds (34 at install); SETUP Step 6 installs docs/knowledge-corpus.md and checks the manifest against its own stated total; the ops-setup dictionary rows; the intake's Phase 7 cites G66/G67 and Phase 10 + Part C name the raw-cast → declared-symbol step; templates/layout-contract.md (the five-tool probe, a draft for the split). The review under Drew's criterion: 93 no-consumer tools (one Opus agent's draft, verified: 0 defects, every successor live, 0 live consumers, 0 collisions; four one-off verdicts overturned to STILL-NEEDED) → 34 retired by git mv to tools/sunset/ (28 superseded, 6 one-offs; README review table; SETUP rows moved; Archive-index group). Run 4 (fresh throwaway, the final kit): stopped on my Step-6 check (321 vs the live 293) → both sides derived → resumed → PASS 10/10, manifest 56 == 56, 4 commits, guardrails held (the one foreign path was the timeline regenerated by the detached tools-health). tools-health OK; doc_links --strict rc 0; audit_public OK over 6,842 paths; the purge probe PASSED (Phase 34's gate open). decision-log "P33.5 S91" + accelerators "P33.5 S91" banked; log + checkpoint (NEXT = task 14, xHigh, fresh session)
2026-09-07 22:09:15 -06:00
tools+docs(phase-33.5): task 13.5 — the tools audit + the two dictionaries: tools/tool_census.py (two agreeing enumerations of 327 tool files; docstring/SETUP row/consumers/class derived from the tree; the authored half in config/tool_dictionary.tsv — phase · portability · the NEED each tool answers · what · adapts · verdict — with coverage asserted both ways) → docs/tool-index.md (need-keyed, KEEP-GEN, Reference-index row, wiki + how-to pointers), the kit's tools/MANIFEST.md regenerated (header states live 293 + superseded 28 = 321 rows), and the two verbatim corpora in-tree (Drew, confirmed S91): decomp-architect/corpus/tools/<phase>/ (302 copies + 28 superseded pointers + INDEX) and corpus/cookbook/ (the cookbook, its symptom index, the codegen map, a front page stating what transfers per compiler) — sha1-equal to their sources by tool_census --check in tools-health, regenerated by make kit-corpus; kit_lint exempts the corpus dirs (verbatim evidence) but syntax-checks them; G66 (consult the tool dictionary first) + G67 (translate an inherited idiom through its pass) + two memory seeds (34 at install); SETUP Step 6 installs docs/knowledge-corpus.md and checks the manifest against its own stated total; the ops-setup dictionary rows; the intake's Phase 7 cites G66/G67 and Phase 10 + Part C name the raw-cast → declared-symbol step; templates/layout-contract.md (the five-tool probe, a draft for the split). The review under Drew's criterion: 93 no-consumer tools (one Opus agent's draft, verified: 0 defects, every successor live, 0 live consumers, 0 collisions; four one-off verdicts overturned to STILL-NEEDED) → 34 retired by git mv to tools/sunset/ (28 superseded, 6 one-offs; README review table; SETUP rows moved; Archive-index group). Run 4 (fresh throwaway, the final kit): stopped on my Step-6 check (321 vs the live 293) → both sides derived → resumed → PASS 10/10, manifest 56 == 56, 4 commits, guardrails held (the one foreign path was the timeline regenerated by the detached tools-health). tools-health OK; doc_links --strict rc 0; audit_public OK over 6,842 paths; the purge probe PASSED (Phase 34's gate open). decision-log "P33.5 S91" + accelerators "P33.5 S91" banked; log + checkpoint (NEXT = task 14, xHigh, fresh session)
2026-09-07 22:09:15 -06:00
2026-06-10 22:02:07 -06:00
tools+docs(phase-33.5): task 13.5 — the tools audit + the two dictionaries: tools/tool_census.py (two agreeing enumerations of 327 tool files; docstring/SETUP row/consumers/class derived from the tree; the authored half in config/tool_dictionary.tsv — phase · portability · the NEED each tool answers · what · adapts · verdict — with coverage asserted both ways) → docs/tool-index.md (need-keyed, KEEP-GEN, Reference-index row, wiki + how-to pointers), the kit's tools/MANIFEST.md regenerated (header states live 293 + superseded 28 = 321 rows), and the two verbatim corpora in-tree (Drew, confirmed S91): decomp-architect/corpus/tools/<phase>/ (302 copies + 28 superseded pointers + INDEX) and corpus/cookbook/ (the cookbook, its symptom index, the codegen map, a front page stating what transfers per compiler) — sha1-equal to their sources by tool_census --check in tools-health, regenerated by make kit-corpus; kit_lint exempts the corpus dirs (verbatim evidence) but syntax-checks them; G66 (consult the tool dictionary first) + G67 (translate an inherited idiom through its pass) + two memory seeds (34 at install); SETUP Step 6 installs docs/knowledge-corpus.md and checks the manifest against its own stated total; the ops-setup dictionary rows; the intake's Phase 7 cites G66/G67 and Phase 10 + Part C name the raw-cast → declared-symbol step; templates/layout-contract.md (the five-tool probe, a draft for the split). The review under Drew's criterion: 93 no-consumer tools (one Opus agent's draft, verified: 0 defects, every successor live, 0 live consumers, 0 collisions; four one-off verdicts overturned to STILL-NEEDED) → 34 retired by git mv to tools/sunset/ (28 superseded, 6 one-offs; README review table; SETUP rows moved; Archive-index group). Run 4 (fresh throwaway, the final kit): stopped on my Step-6 check (321 vs the live 293) → both sides derived → resumed → PASS 10/10, manifest 56 == 56, 4 commits, guardrails held (the one foreign path was the timeline regenerated by the detached tools-health). tools-health OK; doc_links --strict rc 0; audit_public OK over 6,842 paths; the purge probe PASSED (Phase 34's gate open). decision-log "P33.5 S91" + accelerators "P33.5 S91" banked; log + checkpoint (NEXT = task 14, xHigh, fresh session)
2026-09-07 22:09:15 -06:00
2026-06-10 22:02:07 -06:00
tools+docs(phase-33.5): task 13.5 — the tools audit + the two dictionaries: tools/tool_census.py (two agreeing enumerations of 327 tool files; docstring/SETUP row/consumers/class derived from the tree; the authored half in config/tool_dictionary.tsv — phase · portability · the NEED each tool answers · what · adapts · verdict — with coverage asserted both ways) → docs/tool-index.md (need-keyed, KEEP-GEN, Reference-index row, wiki + how-to pointers), the kit's tools/MANIFEST.md regenerated (header states live 293 + superseded 28 = 321 rows), and the two verbatim corpora in-tree (Drew, confirmed S91): decomp-architect/corpus/tools/<phase>/ (302 copies + 28 superseded pointers + INDEX) and corpus/cookbook/ (the cookbook, its symptom index, the codegen map, a front page stating what transfers per compiler) — sha1-equal to their sources by tool_census --check in tools-health, regenerated by make kit-corpus; kit_lint exempts the corpus dirs (verbatim evidence) but syntax-checks them; G66 (consult the tool dictionary first) + G67 (translate an inherited idiom through its pass) + two memory seeds (34 at install); SETUP Step 6 installs docs/knowledge-corpus.md and checks the manifest against its own stated total; the ops-setup dictionary rows; the intake's Phase 7 cites G66/G67 and Phase 10 + Part C name the raw-cast → declared-symbol step; templates/layout-contract.md (the five-tool probe, a draft for the split). The review under Drew's criterion: 93 no-consumer tools (one Opus agent's draft, verified: 0 defects, every successor live, 0 live consumers, 0 collisions; four one-off verdicts overturned to STILL-NEEDED) → 34 retired by git mv to tools/sunset/ (28 superseded, 6 one-offs; README review table; SETUP rows moved; Archive-index group). Run 4 (fresh throwaway, the final kit): stopped on my Step-6 check (321 vs the live 293) → both sides derived → resumed → PASS 10/10, manifest 56 == 56, 4 commits, guardrails held (the one foreign path was the timeline regenerated by the detached tools-health). tools-health OK; doc_links --strict rc 0; audit_public OK over 6,842 paths; the purge probe PASSED (Phase 34's gate open). decision-log "P33.5 S91" + accelerators "P33.5 S91" banked; log + checkpoint (NEXT = task 14, xHigh, fresh session)
2026-09-07 22:09:15 -06:00

BFM-decomp — Brave Fencer Musashi, decompiled

instruction-weighted binaries byte-identical no-rom CI

A matching decompilation of Brave Fencer Musashi (PlayStation, Square, 1998 — the USA release, SLUS-00726): C source that, compiled with the game's own 1990s toolchain, rebuilds every shipped code binary byte for byte. It is the first public decompilation of this game, and the whole of its game code is matched: the main executable, the always-resident engine, every location overlay and every code module streamed from the disc — 218 binaries, verified against a redump image of the original disc on every build.

The contract is narrow and machine-checkable. "Matching" means byte-identical output, checked by SHA1 against the originals; nothing "functionally equivalent" counts. What the repository claims is exactly what make check-all proves.

Where it stands

Metric Matched Of %
Functions byte-identical (all binaries) 363,214 363,214 100.00%
Instructions byte-identical (instruction-weighted) 13,492,113 13,492,113 100.0%
Distinct code byte-identical (each body once) 5,820,205 5,820,205 100.0%
Main executable game code (excl. Sony objects) 45,150 45,150 100.0%

218 binaries rebuild byte-identical from source · 360,737 functions in C (255,632 of them shared bodies via 2,220 dedup groups) · 1,256 Sony PsyQ library functions linked from the SDK objects, not our C · 5 hand-written-assembly bodies kept verbatim · 0 assembly stubs left · 0 non-matching functions.

Generated by tools/progress.py --readme from docs/progress.json — numbers are never typed by hand.

Two things in those binaries are deliberately not our C, and are stated as such:

  • 1,256 functions of the main executable are Sony's PsyQ library code (libcd, libgs, libgte, libgpu, libspu/libsnd, libetc, libapi, libcard…). They link byte-identical from the SDK's own objects when you have the SDK, and are carried as assembly tiles taken from the disc when you do not — either way the executable is byte-identical. Reimplementing Sony's libraries is out of scope.
  • Five functions across the fleet are hand-written assembly in the original and are kept as verbatim __asm__ bodies (config/verbatim_manifest.json, audited by tools/verbatim_check.py --strict).

Everything else — every game-code function in all 218 binaries — is C that the pinned compiler turns into the original bytes. Progress numbers are generated from the sources (tools/progress.py), never typed by hand; the full recipe to reproduce them is in docs/verification.md.

Build it from your own disc

The repository contains no game data: no executable, no disassembly, no assets, no memory dumps — only source, build configuration, symbol names and hashes. You need your own redump-layout dump of the USA disc (Track 1 SHA1 b44f0f0a19936f23b26188b658e13201a6a9c211, CRC32 c238191b; the four-track BIN/CUE is ideal, Track 1 alone works).

git clone --recurse-submodules https://github.com/Druthulu/BFM-decomp.git && cd BFM-decomp
make bootstrap                    # toolchain preflight: venv, submodules, the pinned gcc-2.7.2 cc1 (sha256-checked)
mkdir -p disks && cp '/path/to/Brave Fencer Musashi (USA)'*.{bin,cue} disks/
make disc-extract                 # extracts the disc and checks all 1,801 files against the committed manifest
make clean && make -j"$(nproc)" extract-all && make -j"$(nproc)" check-all
                                  # -> "check-all: 218 passed, 0 failed of 218"

Linux (WSL2 Ubuntu 24.04 is what the project uses); binutils-mipsel-linux-gnu, cpp-mipsel-linux-gnu, Python 3.12. The main executable's SHA1 is 143dbb89f34491258bbc27810d0a12ec8b43a8dd. make help lists every target; docs/verification.md gives each step's expected last line and the record of the last full run.

Toolchain (pinned by fingerprint evidence): gcc-2.7.2-psx cc1 -O2 -G0 -mips1 -mcpu=3000 -mgas -msoft-float -fgnu-linker → maspsx --aspsx-version=2.56 --expand-div → mipsel-linux-gnu-as -march=r3000 -mtune=r3000 -no-pad-sections -O1 -G0, with per-file -O0 modules where the bytes demand it. The Sony PsyQ SDK objects are optional and user-supplied (tools/fetch_psyq.sh); they are never redistributed.

What is in the repository

Path What
src/ The C — one directory per binary (src/ itself is the main executable, src/resident/, src/ov_*/, src/md_*/), src/shared/ for the code shared across binaries via the dedup registry
config/ splat configs, symbol files, per-binary SHA1 contracts (check.*.sha), the dedup registry, the Ghidra annotations as text (config/ghidra/)
tools/ Everything the project built to do this: the byte gate, the extractor, the matching harness, the campaign machinery, the CI audits, the public-flip rewrite tooling; pinned submodules (maspsx, asm-differ, decomp-permuter, m2c)
docs/ The matching cookbook (500+ compiler idioms), the gcc-2.7.2 codegen map, the memory map, the decision log, the accelerators, the runbooks, the story and the retrospective
phase-ends/ The project's own governance record: one PhaseEnd per phase, the digest, the per-phase logs
include/, extracted/retail/manifest.* Headers; the sha1 manifest your disc extraction is checked against

How it was made

This project was carried out end to end by an AI coding agent — Claude Code — working inside a governance framework: a static constitution (PROJECT_CONTEXT.md), a session protocol (CLAUDE.md), two human gates per phase, an append-only record of every phase (phase-ends/), and a growing rule set distilled from what went wrong. The framework is published separately as ProjectArchitect; this repository is its largest worked example.

The reverse-engineering side ran on Ghidra driven over MCP, with a PCSX-Redux runtime oracle; the matching side is a byte gate over the whole binary, a permuter, a compiler-idiom cookbook, and — decisively — reading the gcc 2.7.2 source to explain the bytes the compiler emits. Everything that was learned is written down where it can be reused:

About the history. The full development history is here — every commit, date and message — but it was rewritten before publication to remove game-derived files from every revision. Old commit hashes cited inside historical documents were replaced by inert tokens (commit:NNNN, the commit's ordinal); docs/commit-map.tsv maps them to the commits you see, and documents at the tip cite the current hashes directly.

Standards, and how the AI was used

Accuracy. A function is matched only when its compiled instructions are identical to the original, register allocation included, and the whole binary's SHA1 equals the original's. That check runs inside every build of every binary, and a clean rebuild follows every batch of banked functions. Nothing "functionally equivalent" is counted, and the default build never links unmatched C. What is not our C is listed above, not hidden.

Readability. The code is matched but not yet finished in the sense other decompilation projects mean. Most functions still carry generated names, thousands of register hints that were matching levers remain, and shared engine code lives in one large header. Bringing it to the community's standard is the next generation of the project; we adopt sotn-decomp's style guide as the baseline, and the rules are written down in docs/gen3-standards.md: names only with recorded evidence, every match-forcing trick removed or marked, structures unified before they are named, and everything still byte-identical.

How the AI was used. An agent did the work under a written constitution, two human gates per phase, and a rule set distilled from what went wrong. The byte gate, not the model, decides what counts as done. Communication with other projects is written by the maintainer, we do not automate against community infrastructure such as decomp.me, and other projects' policies on AI-assisted contributions are read and followed before anything is submitted.

Tools from this project

Things built here that stand on their own, for other decompilation projects:

  • xsig (MIT; also in tools/xsig/) — relocation-masked function signatures: the same function at two link addresses gets the same signature, so shared code is found across overlays and across games. Against Xenogears, Vagrant Story and Tomba it found 103 shared functions, all PsyQ library code, which is what it is good for: spotting library functions and shared overlay code.
  • The permuter driver (tools/permuter/) — an unattended way to run simonlindholm's decomp-permuter for byte-gated pipelines: a restart loop with guards and a relocation-masked scorer that reaches zero only when the object is link-identical. The upstream permuter is a pinned, unmodified submodule; the driver swaps one class on top of it. Offered upstream and declined (the stock scorer's behaviour is intentional for interactive use), so the only copy lives here.
  • The gcc 2.7.2 codegen map — what the pinned compiler does to your C, pass by pass, each claim tagged with the source tree it was read from and byte-proven on this game.
  • The decomp.me replica — runs a function through decomp.me's own PS1 toolchain locally and compares the words to the target, so a preset or a scratch is proven before it exists (how).
  • The drafter write-up — how a small local model was fine-tuned to draft matches under the byte gate, every measurement in order, and what it was worth.
  • How to AI-decomp — the whole method, for anyone doing this with an agent.
  • The day-one decomp kit (decomp-architect/) — what this project would hand its own day one, as a Phase-0.5 overlay on ProjectArchitect 2.0: the order of work, the ROM firewall from commit one, the rules distilled from the failures, the conduct rules, readability at draft time — and two dictionaries: the tools verbatim, keyed by the need each answers, and the cookbook with its index and the codegen map behind a page that says what transfers to another compiler. Installed four times in a throwaway under a judge script (wiki); split out after the flip.
  • The tool index — every tool in the tree keyed by the need it answers, with what proved it and what it hard-codes; generated by tools/tool_census.py from the tree and an authored dictionary, coverage asserted both ways.

License

  • tools/ and docs/ (the project's own work): AGPL-3.0 — see LICENSE.
  • src/: a reimplementation of copyrighted game code, provided for study and preservation; no license is asserted — see src/NOTICE.md.
  • Third-party components keep their own licenses — see THIRD_PARTY.md. tools/brave-CUE/ (CUE's reference extractor) is GPL-3.0; the Sony PsyQ SDK is never distributed.

Contributing, and the no-ROM policy

Nothing derived from the game may enter the repository: no executable, no disassembly, no assets, no memory image, no SDK. CI enforces the tracked tree (tools/audit_public.py: no ROM-derived content by hash, no purge path, nothing over 50 MiB), keeps every source text and portable, and compiles every translation unit with the pinned compiler. Byte identity itself is verified locally with the disc, and the record of the last full run is committed.

The matching frontier is empty, so contributions that help most are not new matches: readability (structs and names in place of raw addresses), shiftability, tooling, and documentation. Open an issue first if you are unsure whether something is ROM-derived.

Special thanks

In the tradition of sotn-decomp, whose method this project followed from day one — this work stands on:

Brave Fencer Musashi is © 1998 Square. This project is not affiliated with or endorsed by Square Enix.

S
Description
No description provided
Readme AGPL-3.0 492 MiB
Languages
C 96.6%
Python 3%
Makefile 0.2%
Shell 0.1%