diff --git a/Makefile b/Makefile index f2aa182810..2c70c98890 100644 --- a/Makefile +++ b/Makefile @@ -320,6 +320,8 @@ ifeq ($(BINARY),main) $(VENV_PY) tools/dup_report.py --cross # Fleet roll-up (Phase 15): deterministic per-binary table + fleet totals -> docs/progress.fleet.md. $(VENV_PY) tools/progress.py --fleet + # P33 D1/D3: the same numbers as DATA — docs/progress.json + the README block (never typed by hand) + $(VENV_PY) tools/progress.py --json --readme # Backlog compaction (Phase 29): the near-miss log is append-only, so it fills with already-banked # noise (measured 6,867 rows, 98% banked). prune rewrites .run/backlog.jsonl to the open near-misses # (drop-now-matched P9 + best-per-addr) so the ledger tracks reality instead of drifting stale. diff --git a/README.md b/README.md index 1cf9117b49..45470b24d1 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,144 @@ -# BFM-decomp +# BFM-decomp — Brave Fencer Musashi, decompiled -A matching decompilation of **Brave Fencer Musashi** (PlayStation, SLUS-00726, USA 1998) — the first public decompilation effort for this game. +![instruction-weighted](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Druthulu/BFM-decomp/main/docs/badges/fleet_instr.json) +![binaries byte-identical](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Druthulu/BFM-decomp/main/docs/badges/binaries.json) +![no-rom CI](https://github.com/Druthulu/BFM-decomp/actions/workflows/no-rom.yml/badge.svg) -## What "matching" means +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 goal is C source code that, compiled with the original-era toolchain (PsyQ 4.x / GCC 2.7.2-family + ASPSX via maspsx), produces a byte-for-byte identical `SLUS_007.26` and, eventually, byte-identical overlay binaries. SHA1 checksums are the ground truth; "functionally equivalent" does not count. +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. -## No ROM content +## Where it stands -This repository contains **no game assets, no disassembly output, and no ROM-derived data** — only source code, build configuration, symbol names/addresses, hashes, and documentation. To build or contribute you must provide your own dump of the game disc (4-track BIN/CUE, redump layout). See `.gitignore` for the firewall. + +| 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% | -## Project status +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. -> **Latest (Phase 19, 2026-06-20):** the project builds **136 binaries byte-identical from a clean tree** (the EXE + the resident engine + all **134 location overlays**); **`make check-all` → 136/136**. Fleet byte-identical-from-source is **58.0%** (function-instance-weighted; see the PhaseEnds for the byte-weighted ~30% figure and what it includes). Shared engine functions are matched once in `ov_SC01_077` and propagated **×134** via `tools/dedup_propagate.py`. *(The narrative below is Phase-11/12-era; a full refresh is part of the public-flip prep.)* +_Generated by `tools/progress.py --readme` from `docs/progress.json` — numbers are never typed by hand._ + -**Gen1 (foundation) complete — the matching pipeline is proven end-to-end.** `make extract && make build && make check` rebuilds `SLUS_007.26` **byte-for-byte identical** (SHA1 `143dbb89…`) from C + assembly, reproducibly across many sessions. +Two things in those binaries are deliberately **not** our C, and are stated as such: -- **Compiler pinned by evidence:** `gcc-2.7.2-psx -O2 -G0 -mips1 -mcpu=3000` + `maspsx --aspsx-version=2.56 --expand-div`. -- **52 functions hand-matched** to byte-identical machine code — including the LZSS streaming decompressor — with a decomp-permuter + matching-cookbook "flywheel" to accelerate the next. -- **959 PsyQ SDK functions linked byte-identical** (libcd, libgs, libgte, libspu/libsnd, libgpu, libc2, libmcrd, libapi/libcard, libetc) straight from the real PsyQ 4.0 libraries instead of re-decompiling them — bringing byte-identical-from-source coverage of the EXE to **~50%**. -- **File-loader / overlay system reverse-engineered**, with the resident engine blob + location overlays' load addresses **proven byte-identical against a live PCSX-Redux RAM dump**. +- **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`). -About half the EXE is still `INCLUDE_ASM` stubs (correct bytes, not yet C), and the bulk of the game lives in compressed overlays inside the `.CD` archives — **Gen2** (overlays & engine at scale) is underway: +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`](docs/verification.md). -- The build toolchain is **binary-agnostic** (one parameterized pipeline builds any binary), and the always-resident **engine blob** rebuilds **byte-for-byte from source** (SHA1 `8e17e02f…`) — the *second* binary reconstructed exactly, after the EXE — and is now **86% hand-matched C** (123 / 146 functions, up from 0): its scripting turned out to be **compiled-MIPS state/mode dispatch, not a bytecode VM**, and the save-file + sound (SQV) formats are documented. The harvest used a reusable **swarm-of-agents + bit-for-bit byte-gate** method (a wrong match can't be accepted) — `tools/harvest_verify.py` + `tools/match_one.py`, which carry straight into the overlay phase. -- A **cross-binary deduplication pipeline** is live: a Ghidra-free signer fingerprints all 134 location overlays, and the report finds **~9,000 byte-identical function groups shared across binaries (~28 MB of collapsible code)** — a single engine function is byte-identical in all 134 overlays. This is "one match unlocks many": each engine match will be auto-credited across the overlay fleet. +## Build it from your own disc -Current phase and detailed progress live in `phase-ends/` (newest `PhaseEnd_*.md` = current state); methodology, rules, and the full roadmap are in `PROJECT_CONTEXT.md`; environment setup in `docs/SETUP.md`. +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). -This project is developed primarily by Claude Code driving Ghidra through an MCP server; see `CLAUDE.md`. +```bash +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`](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`](PROJECT_CONTEXT.md)), a session protocol ([`CLAUDE.md`](CLAUDE.md)), +two human gates per phase, an append-only record of every phase ([`phase-ends/`](phase-ends/)), and a growing rule set +distilled from what went wrong. The framework is published separately as +[**ProjectArchitect**](https://github.com/Druthulu/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: + +- [`docs/matching-cookbook.md`](docs/matching-cookbook.md) — the idioms, each byte-proven, and the compiler-internals laws +- [`docs/gcc-2.7.2-map/`](docs/gcc-2.7.2-map/) — the codegen map of the pinned compiler, by pass +- [`docs/decision-log.md`](docs/decision-log.md) — every strategic pivot with its measurement and its hindsight +- [`docs/accelerators.md`](docs/accelerators.md) — what would have made earlier phases faster +- [`docs/story.md`](docs/story.md) and [`docs/retrospective.md`](docs/retrospective.md) — the timeline and the retrospective +- [`docs/public-flip-runbook.md`](docs/public-flip-runbook.md) — how a private repository with game bytes in its history + became this public one + +**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`](docs/commit-map.tsv) maps +them to the commits you see, and documents at the tip cite the current hashes directly. ## License -Private repository for now. **AGPL-3.0 is planned at public release**, modeled on [sotn-decomp](https://github.com/Xeeynamo/sotn-decomp). `tools/brave-CUE/` is CUE's BRAVE extractor (GPL, source included) and retains its own license. +- `tools/` and `docs/` (the project's own work): **AGPL-3.0** — see [`LICENSE`](LICENSE). +- `src/`: a reimplementation of copyrighted game code, provided for study and preservation; **no license is asserted** — + see [`src/NOTICE.md`](src/NOTICE.md). +- Third-party components keep their own licenses — see [`THIRD_PARTY.md`](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](https://github.com/Xeeynamo/sotn-decomp), whose method this project followed from +day one — this work stands on: + +- [splat](https://github.com/ethteck/splat), [spimdisasm](https://github.com/Decompollaborate/spimdisasm) and + [rabbitizer](https://github.com/Decompollaborate/rabbitizer) — the split and the disassembly +- [maspsx](https://github.com/mkst/maspsx) (mkst) — ASPSX's quirks, reproduced +- [asm-differ](https://github.com/simonlindholm/asm-differ) and [decomp-permuter](https://github.com/simonlindholm/decomp-permuter) (simonlindholm) +- [m2c](https://github.com/matt-kempster/m2c) (matt-kempster) — the scaffolds +- [old-gcc](https://github.com/decompals/old-gcc) (decompals) — the compilers, and the gcc 2.7.2 source itself +- [Ghidra](https://github.com/NationalSecurityAgency/ghidra), [ghidra_psx_ldr](https://github.com/lab313ru/ghidra_psx_ldr) (lab313ru) + and [GhidrAssistMCP](https://github.com/symgraph/GhidrAssistMCP) — the static oracle and its hands +- [psyq-obj-parser](https://github.com/decompme/compilers) (decomp.me) — Sony's objects, readable +- [PCSX-Redux](https://github.com/grumpycoders/pcsx-redux) — the runtime oracle +- [brave-CUE](tools/brave-CUE/) (CUE) — the reference extractor ours was validated against +- The Xenogears, Vagrant Story and Tomba! decompilations — sibling PsyQ idioms +- [redump](http://redump.org/), [TCRF](https://tcrf.net/) and [gamehacking.org](https://gamehacking.org/) — the ground truth on the disc and in memory +- The [Brave Fencer Musashi Archipelago world](https://github.com/AegeusEvander/Brave-Fencer-Musashi-AP-World) (AegeusEvander) — the living RAM map +- [ProjectArchitect](https://github.com/Druthulu/ProjectArchitect) and [Claude Code](https://claude.ai/code) — the method and the hands + +*Brave Fencer Musashi is © 1998 Square. This project is not affiliated with or endorsed by Square Enix.* diff --git a/docs/progress.json b/docs/progress.json new file mode 100644 index 0000000000..4125fa48e3 --- /dev/null +++ b/docs/progress.json @@ -0,0 +1,1790 @@ +{ + "schema": 1, + "note": "generated by tools/progress.py --fleet/--json from the committed sources \u2014 every number carries its denominator; regenerate, never edit", + "binaries": 218, + "fleet": { + "fn_count": { + "matched": 363214, + "total": 363214, + "pct": 100.0, + "what": "functions byte-identical / matchable, every binary (one shared body counts once per overlay it is instantiated in)" + }, + "instr_weighted": { + "matched": 13492113, + "total": 13492113, + "pct": 100.0, + "what": "shipped .text instructions across all binaries (the decomp.dev-style display number)" + }, + "distinct_code": { + "matched": 5820205, + "total": 5820205, + "pct": 100.0, + "unique_fns_matched": 90984, + "unique_fns_total": 90984, + "what": "each distinct function body counted once, instruction-weighted (the distinct reverse-engineering number)" + }, + "main_game_code": { + "matched": 45150, + "total": 45150, + "pct": 100.0, + "what": "SLUS_007.26 game-code instructions (excludes the linked Sony PsyQ objects); build-derived boundaries" + } + }, + "counts": { + "real_c_functions": 360737, + "dedup_shared_of_real": 255632, + "linked_psyq_objects": 1256, + "verbatim_asm_bodies": 5, + "include_asm_stubs": 0, + "non_matching": 0, + "matchable": 363214, + "dedup_groups": 2220, + "dedup_instances": 255708 + }, + "per_binary": [ + { + "binary": "main", + "real": 789, + "shared": 2, + "linked": 1256, + "byte_identical": 2091, + "matchable": 2091 + }, + { + "binary": "resident", + "real": 143, + "shared": 0, + "linked": 0, + "byte_identical": 145, + "matchable": 145 + }, + { + "binary": "md_MAIN_001", + "real": 11, + "shared": 0, + "linked": 0, + "byte_identical": 11, + "matchable": 11 + }, + { + "binary": "md_MAIN_003", + "real": 58, + "shared": 0, + "linked": 0, + "byte_identical": 64, + "matchable": 64 + }, + { + "binary": "md_MAIN_007", + "real": 19, + "shared": 0, + "linked": 0, + "byte_identical": 19, + "matchable": 19 + }, + { + "binary": "md_MAIN_008", + "real": 6, + "shared": 0, + "linked": 0, + "byte_identical": 6, + "matchable": 6 + }, + { + "binary": "md_MAIN_009", + "real": 11, + "shared": 0, + "linked": 0, + "byte_identical": 12, + "matchable": 12 + }, + { + "binary": "md_MAIN_011", + "real": 20, + "shared": 0, + "linked": 0, + "byte_identical": 21, + "matchable": 21 + }, + { + "binary": "md_MAIN_013", + "real": 16, + "shared": 0, + "linked": 0, + "byte_identical": 16, + "matchable": 16 + }, + { + "binary": "md_MAIN_014", + "real": 12, + "shared": 0, + "linked": 0, + "byte_identical": 13, + "matchable": 13 + }, + { + "binary": "md_MAIN_015", + "real": 20, + "shared": 1, + "linked": 0, + "byte_identical": 20, + "matchable": 20 + }, + { + "binary": "md_MAIN_016", + "real": 11, + "shared": 0, + "linked": 0, + "byte_identical": 12, + "matchable": 12 + }, + { + "binary": "md_MAIN_017", + "real": 10, + "shared": 0, + "linked": 0, + "byte_identical": 10, + "matchable": 10 + }, + { + "binary": "md_MAIN_018", + "real": 10, + "shared": 0, + "linked": 0, + "byte_identical": 11, + "matchable": 11 + }, + { + "binary": "md_MAIN_019", + "real": 22, + "shared": 0, + "linked": 0, + "byte_identical": 22, + "matchable": 22 + }, + { + "binary": "md_MAIN_020", + "real": 13, + "shared": 0, + "linked": 0, + "byte_identical": 14, + "matchable": 14 + }, + { + "binary": "md_MAIN_021", + "real": 10, + "shared": 0, + "linked": 0, + "byte_identical": 11, + "matchable": 11 + }, + { + "binary": "md_MAIN_022", + "real": 31, + "shared": 0, + "linked": 0, + "byte_identical": 33, + "matchable": 33 + }, + { + "binary": "md_MAIN_023", + "real": 5, + "shared": 1, + "linked": 0, + "byte_identical": 6, + "matchable": 6 + }, + { + "binary": "md_MAIN_024", + "real": 4, + "shared": 0, + "linked": 0, + "byte_identical": 6, + "matchable": 6 + }, + { + "binary": "md_MAIN_025", + "real": 30, + "shared": 0, + "linked": 0, + "byte_identical": 30, + "matchable": 30 + }, + { + "binary": "md_MAIN_026", + "real": 24, + "shared": 0, + "linked": 0, + "byte_identical": 24, + "matchable": 24 + }, + { + "binary": "md_MAIN_027", + "real": 27, + "shared": 0, + "linked": 0, + "byte_identical": 29, + "matchable": 29 + }, + { + "binary": "md_MAIN_028", + "real": 22, + "shared": 0, + "linked": 0, + "byte_identical": 22, + "matchable": 22 + }, + { + "binary": "md_MAIN_029", + "real": 10, + "shared": 0, + "linked": 0, + "byte_identical": 11, + "matchable": 11 + }, + { + "binary": "md_MAIN_030", + "real": 10, + "shared": 0, + "linked": 0, + "byte_identical": 10, + "matchable": 10 + }, + { + "binary": "md_MAIN_031", + "real": 18, + "shared": 0, + "linked": 0, + "byte_identical": 18, + "matchable": 18 + }, + { + "binary": "md_MAIN_032", + "real": 10, + "shared": 1, + "linked": 0, + "byte_identical": 10, + "matchable": 10 + }, + { + "binary": "md_MAIN_033", + "real": 19, + "shared": 0, + "linked": 0, + "byte_identical": 19, + "matchable": 19 + }, + { + "binary": "md_MAIN_034", + "real": 27, + "shared": 0, + "linked": 0, + "byte_identical": 28, + "matchable": 28 + }, + { + "binary": "md_MAIN_035", + "real": 15, + "shared": 0, + "linked": 0, + "byte_identical": 16, + "matchable": 16 + }, + { + "binary": "md_MAIN_036", + "real": 27, + "shared": 0, + "linked": 0, + "byte_identical": 28, + "matchable": 28 + }, + { + "binary": "md_MAIN_037", + "real": 17, + "shared": 0, + "linked": 0, + "byte_identical": 17, + "matchable": 17 + }, + { + "binary": "md_MAIN_038", + "real": 20, + "shared": 0, + "linked": 0, + "byte_identical": 20, + "matchable": 20 + }, + { + "binary": "md_MAIN_039", + "real": 26, + "shared": 0, + "linked": 0, + "byte_identical": 26, + "matchable": 26 + }, + { + "binary": "md_MAIN_040", + "real": 19, + "shared": 0, + "linked": 0, + "byte_identical": 19, + "matchable": 19 + }, + { + "binary": "md_MAIN_041", + "real": 15, + "shared": 1, + "linked": 0, + "byte_identical": 15, + "matchable": 15 + }, + { + "binary": "md_MAIN_042", + "real": 4, + "shared": 0, + "linked": 0, + "byte_identical": 4, + "matchable": 4 + }, + { + "binary": "md_MAIN_043", + "real": 22, + "shared": 0, + "linked": 0, + "byte_identical": 23, + "matchable": 23 + }, + { + "binary": "md_MAIN_044", + "real": 42, + "shared": 0, + "linked": 0, + "byte_identical": 43, + "matchable": 43 + }, + { + "binary": "md_MAIN_045", + "real": 20, + "shared": 0, + "linked": 0, + "byte_identical": 21, + "matchable": 21 + }, + { + "binary": "md_MAIN_046", + "real": 38, + "shared": 0, + "linked": 0, + "byte_identical": 39, + "matchable": 39 + }, + { + "binary": "md_MAIN_047", + "real": 11, + "shared": 0, + "linked": 0, + "byte_identical": 12, + "matchable": 12 + }, + { + "binary": "md_SC02_009", + "real": 40, + "shared": 0, + "linked": 0, + "byte_identical": 40, + "matchable": 40 + }, + { + "binary": "md_SC03_053", + "real": 15, + "shared": 0, + "linked": 0, + "byte_identical": 15, + "matchable": 15 + }, + { + "binary": "md_SC03_054", + "real": 7, + "shared": 0, + "linked": 0, + "byte_identical": 7, + "matchable": 7 + }, + { + "binary": "md_SC03_056", + "real": 4, + "shared": 0, + "linked": 0, + "byte_identical": 4, + "matchable": 4 + }, + { + "binary": "md_SC03_073", + "real": 28, + "shared": 10, + "linked": 0, + "byte_identical": 28, + "matchable": 28 + }, + { + "binary": "md_SC03_074", + "real": 29, + "shared": 10, + "linked": 0, + "byte_identical": 29, + "matchable": 29 + }, + { + "binary": "md_SC03_075", + "real": 41, + "shared": 10, + "linked": 0, + "byte_identical": 41, + "matchable": 41 + }, + { + "binary": "md_SC03_076", + "real": 64, + "shared": 0, + "linked": 0, + "byte_identical": 66, + "matchable": 66 + }, + { + "binary": "md_SC03_077", + "real": 33, + "shared": 0, + "linked": 0, + "byte_identical": 35, + "matchable": 35 + }, + { + "binary": "md_SC03_078", + "real": 27, + "shared": 9, + "linked": 0, + "byte_identical": 27, + "matchable": 27 + }, + { + "binary": "md_SC03_079", + "real": 27, + "shared": 0, + "linked": 0, + "byte_identical": 29, + "matchable": 29 + }, + { + "binary": "md_SC03_132", + "real": 26, + "shared": 0, + "linked": 0, + "byte_identical": 28, + "matchable": 28 + }, + { + "binary": "md_SC03_133", + "real": 27, + "shared": 1, + "linked": 0, + "byte_identical": 29, + "matchable": 29 + }, + { + "binary": "md_SC03_134", + "real": 39, + "shared": 1, + "linked": 0, + "byte_identical": 41, + "matchable": 41 + }, + { + "binary": "md_SC03_135", + "real": 64, + "shared": 0, + "linked": 0, + "byte_identical": 66, + "matchable": 66 + }, + { + "binary": "md_SC03_136", + "real": 33, + "shared": 0, + "linked": 0, + "byte_identical": 35, + "matchable": 35 + }, + { + "binary": "md_SC03_137", + "real": 25, + "shared": 1, + "linked": 0, + "byte_identical": 27, + "matchable": 27 + }, + { + "binary": "md_SC03_138", + "real": 33, + "shared": 1, + "linked": 0, + "byte_identical": 37, + "matchable": 37 + }, + { + "binary": "md_SC04_024", + "real": 26, + "shared": 0, + "linked": 0, + "byte_identical": 28, + "matchable": 28 + }, + { + "binary": "md_SC04_025", + "real": 27, + "shared": 0, + "linked": 0, + "byte_identical": 29, + "matchable": 29 + }, + { + "binary": "md_SC04_026", + "real": 39, + "shared": 0, + "linked": 0, + "byte_identical": 41, + "matchable": 41 + }, + { + "binary": "md_SC04_027", + "real": 64, + "shared": 0, + "linked": 0, + "byte_identical": 66, + "matchable": 66 + }, + { + "binary": "md_SC04_028", + "real": 33, + "shared": 0, + "linked": 0, + "byte_identical": 35, + "matchable": 35 + }, + { + "binary": "md_SC04_029", + "real": 25, + "shared": 0, + "linked": 0, + "byte_identical": 27, + "matchable": 27 + }, + { + "binary": "md_SC04_030", + "real": 27, + "shared": 0, + "linked": 0, + "byte_identical": 31, + "matchable": 31 + }, + { + "binary": "md_SC05_023", + "real": 26, + "shared": 0, + "linked": 0, + "byte_identical": 28, + "matchable": 28 + }, + { + "binary": "md_SC05_024", + "real": 27, + "shared": 0, + "linked": 0, + "byte_identical": 29, + "matchable": 29 + }, + { + "binary": "md_SC05_025", + "real": 39, + "shared": 0, + "linked": 0, + "byte_identical": 41, + "matchable": 41 + }, + { + "binary": "md_SC05_026", + "real": 64, + "shared": 0, + "linked": 0, + "byte_identical": 66, + "matchable": 66 + }, + { + "binary": "md_SC05_027", + "real": 33, + "shared": 0, + "linked": 0, + "byte_identical": 35, + "matchable": 35 + }, + { + "binary": "md_SC05_028", + "real": 25, + "shared": 0, + "linked": 0, + "byte_identical": 27, + "matchable": 27 + }, + { + "binary": "md_SC05_029", + "real": 27, + "shared": 0, + "linked": 0, + "byte_identical": 31, + "matchable": 31 + }, + { + "binary": "md_SC07_003", + "real": 100, + "shared": 0, + "linked": 0, + "byte_identical": 100, + "matchable": 100 + }, + { + "binary": "md_SC07_004", + "real": 315, + "shared": 0, + "linked": 0, + "byte_identical": 315, + "matchable": 315 + }, + { + "binary": "ov_MAIN_012", + "real": 2322, + "shared": 1693, + "linked": 0, + "byte_identical": 2401, + "matchable": 2401 + }, + { + "binary": "ov_SC01_000", + "real": 2403, + "shared": 1814, + "linked": 0, + "byte_identical": 2403, + "matchable": 2403 + }, + { + "binary": "ov_SC01_001", + "real": 2464, + "shared": 1816, + "linked": 0, + "byte_identical": 2466, + "matchable": 2466 + }, + { + "binary": "ov_SC01_004", + "real": 2413, + "shared": 1807, + "linked": 0, + "byte_identical": 2414, + "matchable": 2414 + }, + { + "binary": "ov_SC01_005", + "real": 2503, + "shared": 1838, + "linked": 0, + "byte_identical": 2503, + "matchable": 2503 + }, + { + "binary": "ov_SC01_006", + "real": 2503, + "shared": 1838, + "linked": 0, + "byte_identical": 2503, + "matchable": 2503 + }, + { + "binary": "ov_SC01_008", + "real": 2424, + "shared": 1808, + "linked": 0, + "byte_identical": 2426, + "matchable": 2426 + }, + { + "binary": "ov_SC01_009", + "real": 2506, + "shared": 1808, + "linked": 0, + "byte_identical": 2507, + "matchable": 2507 + }, + { + "binary": "ov_SC01_074", + "real": 2424, + "shared": 1808, + "linked": 0, + "byte_identical": 2426, + "matchable": 2426 + }, + { + "binary": "ov_SC01_077", + "real": 2584, + "shared": 1769, + "linked": 0, + "byte_identical": 2586, + "matchable": 2586 + }, + { + "binary": "ov_SC01_080", + "real": 2512, + "shared": 1813, + "linked": 0, + "byte_identical": 2512, + "matchable": 2512 + }, + { + "binary": "ov_SC01_084", + "real": 2574, + "shared": 1824, + "linked": 0, + "byte_identical": 2579, + "matchable": 2579 + }, + { + "binary": "ov_SC02_000", + "real": 2683, + "shared": 1902, + "linked": 0, + "byte_identical": 2683, + "matchable": 2683 + }, + { + "binary": "ov_SC02_003", + "real": 2683, + "shared": 1902, + "linked": 0, + "byte_identical": 2683, + "matchable": 2683 + }, + { + "binary": "ov_SC02_004", + "real": 2401, + "shared": 1813, + "linked": 0, + "byte_identical": 2401, + "matchable": 2401 + }, + { + "binary": "ov_SC02_005", + "real": 2916, + "shared": 1807, + "linked": 0, + "byte_identical": 2926, + "matchable": 2926 + }, + { + "binary": "ov_SC02_011", + "real": 2883, + "shared": 1815, + "linked": 0, + "byte_identical": 2893, + "matchable": 2893 + }, + { + "binary": "ov_SC02_015", + "real": 2414, + "shared": 1819, + "linked": 0, + "byte_identical": 2414, + "matchable": 2414 + }, + { + "binary": "ov_SC02_016", + "real": 2542, + "shared": 1815, + "linked": 0, + "byte_identical": 2545, + "matchable": 2545 + }, + { + "binary": "ov_SC02_017", + "real": 2724, + "shared": 1815, + "linked": 0, + "byte_identical": 2732, + "matchable": 2732 + }, + { + "binary": "ov_SC02_021", + "real": 2437, + "shared": 1819, + "linked": 0, + "byte_identical": 2437, + "matchable": 2437 + }, + { + "binary": "ov_SC02_026", + "real": 2566, + "shared": 1812, + "linked": 0, + "byte_identical": 2572, + "matchable": 2572 + }, + { + "binary": "ov_SC02_027", + "real": 2683, + "shared": 1833, + "linked": 0, + "byte_identical": 2692, + "matchable": 2692 + }, + { + "binary": "ov_SC02_028", + "real": 2691, + "shared": 1832, + "linked": 0, + "byte_identical": 2701, + "matchable": 2701 + }, + { + "binary": "ov_SC02_031", + "real": 2557, + "shared": 1814, + "linked": 0, + "byte_identical": 2562, + "matchable": 2562 + }, + { + "binary": "ov_SC02_035", + "real": 2517, + "shared": 1811, + "linked": 0, + "byte_identical": 2520, + "matchable": 2520 + }, + { + "binary": "ov_SC02_037", + "real": 2433, + "shared": 1708, + "linked": 0, + "byte_identical": 2515, + "matchable": 2515 + }, + { + "binary": "ov_SC02_039", + "real": 2416, + "shared": 1819, + "linked": 0, + "byte_identical": 2416, + "matchable": 2416 + }, + { + "binary": "ov_SC02_041", + "real": 2558, + "shared": 1811, + "linked": 0, + "byte_identical": 2561, + "matchable": 2561 + }, + { + "binary": "ov_SC03_001", + "real": 2852, + "shared": 1812, + "linked": 0, + "byte_identical": 2869, + "matchable": 2869 + }, + { + "binary": "ov_SC03_002", + "real": 2616, + "shared": 1820, + "linked": 0, + "byte_identical": 2631, + "matchable": 2631 + }, + { + "binary": "ov_SC03_003", + "real": 2422, + "shared": 1811, + "linked": 0, + "byte_identical": 2423, + "matchable": 2423 + }, + { + "binary": "ov_SC03_006", + "real": 2758, + "shared": 1819, + "linked": 0, + "byte_identical": 2767, + "matchable": 2767 + }, + { + "binary": "ov_SC03_007", + "real": 2619, + "shared": 1813, + "linked": 0, + "byte_identical": 2623, + "matchable": 2623 + }, + { + "binary": "ov_SC03_010", + "real": 2471, + "shared": 1812, + "linked": 0, + "byte_identical": 2471, + "matchable": 2471 + }, + { + "binary": "ov_SC03_011", + "real": 2521, + "shared": 1812, + "linked": 0, + "byte_identical": 2527, + "matchable": 2527 + }, + { + "binary": "ov_SC03_012", + "real": 2405, + "shared": 1813, + "linked": 0, + "byte_identical": 2406, + "matchable": 2406 + }, + { + "binary": "ov_SC03_013", + "real": 2493, + "shared": 1812, + "linked": 0, + "byte_identical": 2493, + "matchable": 2493 + }, + { + "binary": "ov_SC03_014", + "real": 2685, + "shared": 1879, + "linked": 0, + "byte_identical": 2685, + "matchable": 2685 + }, + { + "binary": "ov_SC03_015", + "real": 2468, + "shared": 1879, + "linked": 0, + "byte_identical": 2468, + "matchable": 2468 + }, + { + "binary": "ov_SC03_023", + "real": 2434, + "shared": 1813, + "linked": 0, + "byte_identical": 2435, + "matchable": 2435 + }, + { + "binary": "ov_SC03_024", + "real": 2634, + "shared": 1837, + "linked": 0, + "byte_identical": 2641, + "matchable": 2641 + }, + { + "binary": "ov_SC03_028", + "real": 2660, + "shared": 1816, + "linked": 0, + "byte_identical": 2664, + "matchable": 2664 + }, + { + "binary": "ov_SC03_029", + "real": 2634, + "shared": 1815, + "linked": 0, + "byte_identical": 2644, + "matchable": 2644 + }, + { + "binary": "ov_SC03_030", + "real": 2493, + "shared": 1816, + "linked": 0, + "byte_identical": 2495, + "matchable": 2495 + }, + { + "binary": "ov_SC03_031", + "real": 2511, + "shared": 1813, + "linked": 0, + "byte_identical": 2514, + "matchable": 2514 + }, + { + "binary": "ov_SC03_089", + "real": 2574, + "shared": 1824, + "linked": 0, + "byte_identical": 2581, + "matchable": 2581 + }, + { + "binary": "ov_SC03_090", + "real": 2617, + "shared": 1824, + "linked": 0, + "byte_identical": 2625, + "matchable": 2625 + }, + { + "binary": "ov_SC03_091", + "real": 2632, + "shared": 1833, + "linked": 0, + "byte_identical": 2640, + "matchable": 2640 + }, + { + "binary": "ov_SC03_092", + "real": 2576, + "shared": 1824, + "linked": 0, + "byte_identical": 2588, + "matchable": 2588 + }, + { + "binary": "ov_SC03_093", + "real": 2560, + "shared": 1834, + "linked": 0, + "byte_identical": 2563, + "matchable": 2563 + }, + { + "binary": "ov_SC03_094", + "real": 2571, + "shared": 1811, + "linked": 0, + "byte_identical": 2577, + "matchable": 2577 + }, + { + "binary": "ov_SC03_095", + "real": 2471, + "shared": 1811, + "linked": 0, + "byte_identical": 2474, + "matchable": 2474 + }, + { + "binary": "ov_SC03_096", + "real": 2462, + "shared": 1811, + "linked": 0, + "byte_identical": 2465, + "matchable": 2465 + }, + { + "binary": "ov_SC03_097", + "real": 2596, + "shared": 1832, + "linked": 0, + "byte_identical": 2603, + "matchable": 2603 + }, + { + "binary": "ov_SC03_098", + "real": 2538, + "shared": 1833, + "linked": 0, + "byte_identical": 2541, + "matchable": 2541 + }, + { + "binary": "ov_SC03_099", + "real": 2501, + "shared": 1811, + "linked": 0, + "byte_identical": 2504, + "matchable": 2504 + }, + { + "binary": "ov_SC03_100", + "real": 2535, + "shared": 1833, + "linked": 0, + "byte_identical": 2539, + "matchable": 2539 + }, + { + "binary": "ov_SC03_101", + "real": 2524, + "shared": 1824, + "linked": 0, + "byte_identical": 2528, + "matchable": 2528 + }, + { + "binary": "ov_SC03_102", + "real": 2489, + "shared": 1811, + "linked": 0, + "byte_identical": 2492, + "matchable": 2492 + }, + { + "binary": "ov_SC03_103", + "real": 2507, + "shared": 1813, + "linked": 0, + "byte_identical": 2510, + "matchable": 2510 + }, + { + "binary": "ov_SC03_104", + "real": 2609, + "shared": 1824, + "linked": 0, + "byte_identical": 2616, + "matchable": 2616 + }, + { + "binary": "ov_SC03_105", + "real": 2590, + "shared": 1816, + "linked": 0, + "byte_identical": 2597, + "matchable": 2597 + }, + { + "binary": "ov_SC03_107", + "real": 2413, + "shared": 1693, + "linked": 0, + "byte_identical": 2496, + "matchable": 2496 + }, + { + "binary": "ov_SC03_108", + "real": 2443, + "shared": 1819, + "linked": 0, + "byte_identical": 2443, + "matchable": 2443 + }, + { + "binary": "ov_SC03_109", + "real": 2422, + "shared": 1812, + "linked": 0, + "byte_identical": 2424, + "matchable": 2424 + }, + { + "binary": "ov_SC03_110", + "real": 2468, + "shared": 1835, + "linked": 0, + "byte_identical": 2468, + "matchable": 2468 + }, + { + "binary": "ov_SC03_111", + "real": 2507, + "shared": 1811, + "linked": 0, + "byte_identical": 2510, + "matchable": 2510 + }, + { + "binary": "ov_SC03_112", + "real": 2524, + "shared": 1813, + "linked": 0, + "byte_identical": 2526, + "matchable": 2526 + }, + { + "binary": "ov_SC03_113", + "real": 2465, + "shared": 1813, + "linked": 0, + "byte_identical": 2468, + "matchable": 2468 + }, + { + "binary": "ov_SC03_114", + "real": 2413, + "shared": 1812, + "linked": 0, + "byte_identical": 2415, + "matchable": 2415 + }, + { + "binary": "ov_SC03_115", + "real": 2470, + "shared": 1812, + "linked": 0, + "byte_identical": 2472, + "matchable": 2472 + }, + { + "binary": "ov_SC03_116", + "real": 2435, + "shared": 1811, + "linked": 0, + "byte_identical": 2438, + "matchable": 2438 + }, + { + "binary": "ov_SC03_117", + "real": 2551, + "shared": 1811, + "linked": 0, + "byte_identical": 2557, + "matchable": 2557 + }, + { + "binary": "ov_SC03_118", + "real": 2683, + "shared": 1869, + "linked": 0, + "byte_identical": 2684, + "matchable": 2684 + }, + { + "binary": "ov_SC03_119", + "real": 2684, + "shared": 1869, + "linked": 0, + "byte_identical": 2685, + "matchable": 2685 + }, + { + "binary": "ov_SC03_121", + "real": 2457, + "shared": 1812, + "linked": 0, + "byte_identical": 2459, + "matchable": 2459 + }, + { + "binary": "ov_SC03_124", + "real": 2721, + "shared": 1807, + "linked": 0, + "byte_identical": 2741, + "matchable": 2741 + }, + { + "binary": "ov_SC03_125", + "real": 2576, + "shared": 1820, + "linked": 0, + "byte_identical": 2588, + "matchable": 2588 + }, + { + "binary": "ov_SC03_126", + "real": 2423, + "shared": 1815, + "linked": 0, + "byte_identical": 2423, + "matchable": 2423 + }, + { + "binary": "ov_SC04_000", + "real": 2537, + "shared": 1816, + "linked": 0, + "byte_identical": 2546, + "matchable": 2546 + }, + { + "binary": "ov_SC04_002", + "real": 2632, + "shared": 1811, + "linked": 0, + "byte_identical": 2636, + "matchable": 2636 + }, + { + "binary": "ov_SC04_003", + "real": 2499, + "shared": 1818, + "linked": 0, + "byte_identical": 2502, + "matchable": 2502 + }, + { + "binary": "ov_SC04_004", + "real": 2556, + "shared": 1812, + "linked": 0, + "byte_identical": 2558, + "matchable": 2558 + }, + { + "binary": "ov_SC04_005", + "real": 2606, + "shared": 1811, + "linked": 0, + "byte_identical": 2612, + "matchable": 2612 + }, + { + "binary": "ov_SC04_006", + "real": 2452, + "shared": 1817, + "linked": 0, + "byte_identical": 2454, + "matchable": 2454 + }, + { + "binary": "ov_SC04_007", + "real": 2565, + "shared": 1812, + "linked": 0, + "byte_identical": 2569, + "matchable": 2569 + }, + { + "binary": "ov_SC04_008", + "real": 2415, + "shared": 1811, + "linked": 0, + "byte_identical": 2415, + "matchable": 2415 + }, + { + "binary": "ov_SC04_009", + "real": 2438, + "shared": 1811, + "linked": 0, + "byte_identical": 2441, + "matchable": 2441 + }, + { + "binary": "ov_SC04_010", + "real": 2418, + "shared": 1811, + "linked": 0, + "byte_identical": 2419, + "matchable": 2419 + }, + { + "binary": "ov_SC04_011", + "real": 2798, + "shared": 1824, + "linked": 0, + "byte_identical": 2804, + "matchable": 2804 + }, + { + "binary": "ov_SC04_012", + "real": 2419, + "shared": 1811, + "linked": 0, + "byte_identical": 2420, + "matchable": 2420 + }, + { + "binary": "ov_SC04_015", + "real": 2600, + "shared": 1812, + "linked": 0, + "byte_identical": 2611, + "matchable": 2611 + }, + { + "binary": "ov_SC04_016", + "real": 2438, + "shared": 1812, + "linked": 0, + "byte_identical": 2440, + "matchable": 2440 + }, + { + "binary": "ov_SC04_018", + "real": 2857, + "shared": 1896, + "linked": 0, + "byte_identical": 2857, + "matchable": 2857 + }, + { + "binary": "ov_SC04_019", + "real": 2857, + "shared": 1899, + "linked": 0, + "byte_identical": 2857, + "matchable": 2857 + }, + { + "binary": "ov_SC04_020", + "real": 2555, + "shared": 1820, + "linked": 0, + "byte_identical": 2567, + "matchable": 2567 + }, + { + "binary": "ov_SC04_021", + "real": 2423, + "shared": 1815, + "linked": 0, + "byte_identical": 2423, + "matchable": 2423 + }, + { + "binary": "ov_SC05_000", + "real": 2419, + "shared": 1815, + "linked": 0, + "byte_identical": 2422, + "matchable": 2422 + }, + { + "binary": "ov_SC05_001", + "real": 2569, + "shared": 1813, + "linked": 0, + "byte_identical": 2574, + "matchable": 2574 + }, + { + "binary": "ov_SC05_002", + "real": 2439, + "shared": 1811, + "linked": 0, + "byte_identical": 2442, + "matchable": 2442 + }, + { + "binary": "ov_SC05_003", + "real": 2480, + "shared": 1811, + "linked": 0, + "byte_identical": 2481, + "matchable": 2481 + }, + { + "binary": "ov_SC05_004", + "real": 2462, + "shared": 1811, + "linked": 0, + "byte_identical": 2464, + "matchable": 2464 + }, + { + "binary": "ov_SC05_005", + "real": 2490, + "shared": 1825, + "linked": 0, + "byte_identical": 2491, + "matchable": 2491 + }, + { + "binary": "ov_SC05_006", + "real": 2430, + "shared": 1813, + "linked": 0, + "byte_identical": 2430, + "matchable": 2430 + }, + { + "binary": "ov_SC05_007", + "real": 2477, + "shared": 1812, + "linked": 0, + "byte_identical": 2482, + "matchable": 2482 + }, + { + "binary": "ov_SC05_008", + "real": 2541, + "shared": 1812, + "linked": 0, + "byte_identical": 2543, + "matchable": 2543 + }, + { + "binary": "ov_SC05_009", + "real": 2434, + "shared": 1811, + "linked": 0, + "byte_identical": 2438, + "matchable": 2438 + }, + { + "binary": "ov_SC05_010", + "real": 2584, + "shared": 1816, + "linked": 0, + "byte_identical": 2588, + "matchable": 2588 + }, + { + "binary": "ov_SC05_011", + "real": 2408, + "shared": 1812, + "linked": 0, + "byte_identical": 2409, + "matchable": 2409 + }, + { + "binary": "ov_SC05_017", + "real": 2831, + "shared": 1811, + "linked": 0, + "byte_identical": 2842, + "matchable": 2842 + }, + { + "binary": "ov_SC05_018", + "real": 2660, + "shared": 1819, + "linked": 0, + "byte_identical": 2673, + "matchable": 2673 + }, + { + "binary": "ov_SC05_019", + "real": 2423, + "shared": 1815, + "linked": 0, + "byte_identical": 2423, + "matchable": 2423 + }, + { + "binary": "ov_SC06_000", + "real": 2688, + "shared": 1841, + "linked": 0, + "byte_identical": 2691, + "matchable": 2691 + }, + { + "binary": "ov_SC06_006", + "real": 2510, + "shared": 1813, + "linked": 0, + "byte_identical": 2511, + "matchable": 2511 + }, + { + "binary": "ov_SC06_008", + "real": 2536, + "shared": 1813, + "linked": 0, + "byte_identical": 2542, + "matchable": 2542 + }, + { + "binary": "ov_SC06_010", + "real": 2512, + "shared": 1811, + "linked": 0, + "byte_identical": 2517, + "matchable": 2517 + }, + { + "binary": "ov_SC06_011", + "real": 2464, + "shared": 1811, + "linked": 0, + "byte_identical": 2468, + "matchable": 2468 + }, + { + "binary": "ov_SC06_013", + "real": 2424, + "shared": 1811, + "linked": 0, + "byte_identical": 2425, + "matchable": 2425 + }, + { + "binary": "ov_SC06_014", + "real": 2451, + "shared": 1811, + "linked": 0, + "byte_identical": 2453, + "matchable": 2453 + }, + { + "binary": "ov_SC06_015", + "real": 2421, + "shared": 1811, + "linked": 0, + "byte_identical": 2421, + "matchable": 2421 + }, + { + "binary": "ov_SC06_016", + "real": 2547, + "shared": 1816, + "linked": 0, + "byte_identical": 2549, + "matchable": 2549 + }, + { + "binary": "ov_SC06_018", + "real": 2658, + "shared": 1812, + "linked": 0, + "byte_identical": 2665, + "matchable": 2665 + }, + { + "binary": "ov_SC06_020", + "real": 2517, + "shared": 1813, + "linked": 0, + "byte_identical": 2518, + "matchable": 2518 + }, + { + "binary": "ov_SC06_022", + "real": 2634, + "shared": 1811, + "linked": 0, + "byte_identical": 2642, + "matchable": 2642 + }, + { + "binary": "ov_SC06_024", + "real": 2661, + "shared": 1811, + "linked": 0, + "byte_identical": 2667, + "matchable": 2667 + }, + { + "binary": "ov_SC06_025", + "real": 2567, + "shared": 1811, + "linked": 0, + "byte_identical": 2572, + "matchable": 2572 + }, + { + "binary": "ov_SC06_027", + "real": 2407, + "shared": 1811, + "linked": 0, + "byte_identical": 2408, + "matchable": 2408 + }, + { + "binary": "ov_SC06_029", + "real": 2651, + "shared": 1816, + "linked": 0, + "byte_identical": 2663, + "matchable": 2663 + }, + { + "binary": "ov_SC06_030", + "real": 2456, + "shared": 1816, + "linked": 0, + "byte_identical": 2456, + "matchable": 2456 + }, + { + "binary": "ov_SC06_032", + "real": 2651, + "shared": 1812, + "linked": 0, + "byte_identical": 2658, + "matchable": 2658 + }, + { + "binary": "ov_SC06_033", + "real": 2623, + "shared": 1812, + "linked": 0, + "byte_identical": 2630, + "matchable": 2630 + }, + { + "binary": "ov_SC07_000", + "real": 2519, + "shared": 1816, + "linked": 0, + "byte_identical": 2521, + "matchable": 2521 + }, + { + "binary": "ov_SC07_001", + "real": 2452, + "shared": 1812, + "linked": 0, + "byte_identical": 2454, + "matchable": 2454 + }, + { + "binary": "ov_SC07_002", + "real": 2575, + "shared": 1816, + "linked": 0, + "byte_identical": 2579, + "matchable": 2579 + }, + { + "binary": "ov_SC07_006", + "real": 2377, + "shared": 1630, + "linked": 0, + "byte_identical": 2457, + "matchable": 2457 + }, + { + "binary": "ov_SC07_007", + "real": 2529, + "shared": 1666, + "linked": 0, + "byte_identical": 2612, + "matchable": 2612 + }, + { + "binary": "ov_SC07_008", + "real": 2386, + "shared": 1812, + "linked": 0, + "byte_identical": 2386, + "matchable": 2386 + }, + { + "binary": "ov_SC07_009", + "real": 2428, + "shared": 1811, + "linked": 0, + "byte_identical": 2430, + "matchable": 2430 + }, + { + "binary": "ov_SC07_010", + "real": 2441, + "shared": 1689, + "linked": 0, + "byte_identical": 2523, + "matchable": 2523 + }, + { + "binary": "ov_SC07_011", + "real": 2368, + "shared": 1664, + "linked": 0, + "byte_identical": 2448, + "matchable": 2448 + } + ] +} diff --git a/phase-ends/CURRENT_PHASE.md b/phase-ends/CURRENT_PHASE.md index e54733fb84..193e0267ce 100644 --- a/phase-ends/CURRENT_PHASE.md +++ b/phase-ends/CURRENT_PHASE.md @@ -71,7 +71,7 @@ one-time snapshot, `CLAUDE.md` gains "never `git clean -x`" (R20 amendment propo - [x] **C8** R22 clean rebuild on the adopted tree — xHigh — see Log 2026-09-07 C8 - [x] **C9** Final gate + Drew's force-push + local gc — xHigh — see Log 2026-09-07 C9 - [ ] **C10** Support purge → probe gate → FLIP (Drew) — decision Max -- [ ] **D1** README rewrite — Max +- [x] **D1** README rewrite — Max — see Log 2026-09-07 D1 - [ ] **D2** LICENSE + `src/NOTICE.md` + `THIRD_PARTY.md` — Max wording - [ ] **D3** Progress publishing (progress.json, badges, frogress_upload, objdiff_report + progress.yml) — xHigh - [ ] **D4** SETUP.md public-clean pass — xHigh @@ -348,14 +348,28 @@ Mid-phase rules check after every 4 completed tasks (P6). Commit banked artifact commit found") as gone (it had counted the vanished tag tip as alive). The rewritten history is the only one reachable locally and the only one reachable on `origin`; the old objects remain SERVABLE on GitHub until Support purges — hence C10. Runbook §10/§12 updated with the measured procedure. Commit: see below. +- **2026-09-07 (S87, Max) — D1 the README rewrite.** The old README was Phase-19 era (136 binaries, 52 functions, "about + half the EXE is stubs") — every number stale, so a full rewrite. **The numbers are GENERATED:** `tools/progress.py --json` + → `docs/progress.json` (schema 1: the four metrics with numerator/denominator/pct + a one-line "what", the counts — real + 360,737 / shared 255,632 / linked 1,256 / verbatim 5 / stubs 0 / non-matching 0 / matchable 363,214 / dedup 2,220 groups, + 255,708 instances — and 218 per-binary rows; no run date, so it never churns) and `--readme` rewrites the block between + `` (refuses a README without the markers — control run; `--check` asserts both are fresh); + wired into `make report BINARY=main` after `--fleet`. README (144 lines): the claim and the contract · the generated block + · what is NOT our C (1,256 Sony objects + 5 verbatim) · build from your own disc (the verification.md recipe, redump SHA1/ + CRC32, the EXE SHA1, the pinned triple, the optional SDK) · repository layout · how it was made (ProjectArchitect link, + the governance files, the knowledge base) · **About the history** (the rewrite, the `commit:NNNN` tokens, `docs/commit-map.tsv`) + · the license split · contributing + the no-ROM policy · **Special thanks** (the plan's list, sotn-decomp style) · the + Square trademark line · 3 badges. **Forward references the README makes to files later tasks create** (D5's link checker + must see them by then): `LICENSE`, `src/NOTICE.md`, `THIRD_PARTY.md` (D2); `docs/badges/fleet_instr.json`, + `docs/badges/binaries.json` (D3 — these exact names); `docs/story.md` (F1), `docs/retrospective.md` (F2). Commit: see below. -## 🛑 SESSION CHECKPOINT — A1–A5 ✓, B1–B9/C3 ✓, C1–C9 ✓ — THE REWRITTEN HISTORY IS ON origin (e821833986…), THE OLD ONE IS GONE LOCALLY; NEXT = C10 (Drew: the Support ticket + the daily probe) IN PARALLEL WITH D1 (Claude: the README, Max) (2026-09-07 ~06:45 UTC, written by session fa49faf3 "S87" after the C9 commit; SUPERSEDES the earlier blocks) +## 🛑 SESSION CHECKPOINT — A1–A5 ✓, B1–B9/C3 ✓, C1–C9 ✓, D1 ✓; C10 IN PROGRESS ON DREW'S SIDE (the Support ticket + the daily probe); NEXT = D2 (Max wording) (2026-09-07 ~07:30 UTC, written by session fa49faf3 "S87" after the D1 commit; SUPERSEDES the earlier blocks) ### 0. How to use this block You are a FRESH SESSION that has read `PROJECT_CONTEXT.md`, `phase-ends/DIGEST.md`, `PhaseEnd_Phase30/31/32.md` and this file, and nothing else (R64). Replay this block verbatim, state phase / done / NEXT / effort, list the rules from the digest -(R1–R73), then WAIT for Drew. **NEXT = two tracks.** **Drew (C10):** open the GitHub Support ticket (text in `docs/public-flip-runbook.md` §11), then run `tools/public_rewrite/probe_github.sh` daily (gh is authenticated in WSL; 31 of 33 sampled old hashes were alive at S87's baseline) until it prints PASS — only then the visibility flip, and only after Blocks D/E/F have landed. **Claude (D1, Max — prompt per R7/R27):** the README rewrite (the plan's D1 paragraph), then D2 → D3 → D4 → D5 → F1 → F2 → F3 → E3 → E4 → E5 → E6 on the still-private repo; E1/E2 and D3's outward actions after the flip. **Every commit cites NEW hashes only; `.run/public_rewrite/` (scratch: dict, mailmap, old-to-new, bundle 556 MB, the rewritten bare clone) holds the old ones — keep until the probe passes, then delete (C11).** -one TaskCreate per plan item A1…G2, 40 items, mark A1–A5 + B1–B9/C3 + C1–C9 completed; R28). The SessionStart hook restarts the headless +(R1–R73), then WAIT for Drew. **NEXT = two tracks.** **Drew (C10):** open the GitHub Support ticket (text in `docs/public-flip-runbook.md` §11), then run `tools/public_rewrite/probe_github.sh` daily (gh is authenticated in WSL; 31 of 33 sampled old hashes were alive at S87's baseline) until it prints PASS — only then the visibility flip, and only after Blocks D/E/F have landed. **Claude (NEXT = D2, Max wording):** root `LICENSE` = AGPL-3.0 VERBATIM (fetch `https://www.gnu.org/licenses/agpl-3.0.txt` — X2: data; never retype), `src/NOTICE.md` (reimplementation-for-study wording, no license asserted, © Square 1998 acknowledged, NEVER the phrase "clean-room"), `THIRD_PARTY.md` (the plan's D2 rows: brave-CUE GPL-3.0 source only; submodules maspsx MIT / decomp-permuter MIT / asm-differ Unlicense / m2c GPL-3.0 — VERIFY each upstream license file; old-gcc 0.17 GPL + sha256; GhidrAssistMCP MIT download; ghidra_psx_ldr — re-check upstream for a license; Ghidra Apache-2.0; binutils; splat/spimdisasm/rabbitizer pip; PsyQ SDK user-supplied never distributed; gcc-2.7.2 source GPL-2.0 sha256 `7cd8bce5…`; ProjectArchitect — Drew decides keep-or-link for `docs/history/project_architect_v1.3.0.md`); one statement in `tools/README.md` (no per-file SPDX). Then D3 → D4 → D5 → F1 → F2 → F3 → E3 → E4 → E5 → E6 on the still-private repo; E1/E2 and D3's outward actions after the flip. **Every commit cites NEW hashes only; `.run/public_rewrite/` (scratch: dict, mailmap, old-to-new, bundle 556 MB, the rewritten bare clone) holds the old ones — keep until the probe passes, then delete (C11).** +one TaskCreate per plan item A1…G2, 40 items, mark A1–A5 + B1–B9/C3 + C1–C9 + D1 completed; R28). The SessionStart hook restarts the headless MCP server when `ghidra/bfm.rep` exists (it did not stay up in S87 — `ss -tln` showed nothing on :8080; harmless): B6/B7/B8 need no Ghidra; run `tools/ghidra_mcp_stop.sh` before any headless step (R23). @@ -391,16 +405,15 @@ still stand for the tasks ahead — restate them, Drew decides (R7/R27). 1. **C10** (Drew; decision Max): the Support ticket (text in `docs/public-flip-runbook.md` §11), then `tools/public_rewrite/ probe_github.sh` daily until PASS (gh auth done in S87; `old-to-new.tsv` + `old_tag_tip.txt` in scratch); the flip only after the probe passes AND Blocks D/E/F have landed. -2. **D1 — README rewrite** (Max; the plan's D1 paragraph: what/why · the numbers table WITH denominators generated by - `tools/progress.py --readme` from `docs/progress.json` (D3 provides progress.json — D1 may stub the block and D3 wires the - generator, or do D3's progress.json first; decide at D1) · "what is not our C" · build-from-your-own-disc · verification - evidence (`docs/verification.md`) · method (ProjectArchitect link, CLAUDE.md, phase-ends, decision-log, accelerators) · - story/retrospective/wiki links · license split · contributing / no-ROM policy · **Special thanks** (the plan's list) · - badges). Then D2 (LICENSE AGPL-3.0 verbatim, `src/NOTICE.md`, `THIRD_PARTY.md` — never the phrase "clean-room"), D3, D4, D5. +2. **D2 — LICENSE + `src/NOTICE.md` + `THIRD_PARTY.md`** (Max wording, xHigh to place): see the NEXT line above. Verify + every third-party license from the upstream file (submodule LICENSE files are on disk under `tools//`). + Log, tick, refresh, commit. Then **D3** (progress.json exists since D1; add `docs/badges/{fleet_instr,binaries}.json` + in shields endpoint format written by `--json`, `make audit-digest` extended to `progress.py --json --readme --check`, + `tools/frogress_upload.py --dry-run`, `tools/objdiff_report.py` + `.github/workflows/progress.yml`). 3. Aftercare reminders (C11): `gh auth logout` in WSL after the flip; `git remote remove archive`; other clones reset, never pull; `.run/public_rewrite/` deleted after the probe passes (keep the bundle off-machine if wanted). ### 4. Files S87 touched -C9: `tools/public_rewrite/probe_github.sh` (422 = gone), `docs/public-flip-runbook.md` §10/§12; `.git` (the archive remote removed, 12 worktrees removed, repacked to one 80 MB pack). C8: `.run/P33/verify/*` (the recorded run, tracked), `docs/verification.md` §2, `docs/family-hseq.md`, `tools/verify_contract.sh` (the step-00 fix). C4–C7: `docs/commit-map.tsv` (new), the 98 token-resolved files (see the C7 entry), `tools/public_rewrite/resolve_tokens.py` (the skip rule), `.git/config` (repo-local noreply identity). Scratch `.run/public_rewrite/`: `pre-rewrite.bundle`, `repo.git` (the rewritten bare clone, keep until C9), `c4c5.{sh,log}`, `old-to-new.tsv`, `unchanged_commits.txt`, `old_tag_tip.txt`, `c5_commit-map.tsv`, `ids_after.txt`, `refs_*.txt`. C1: `tools/public_rewrite/{common,hash_dict,scrub,gate_scan,run_filter,verify_rewrite,build_commit_map,resolve_tokens,absent_scan}.py`, `probe_github.sh`, `expected_offenders.txt` (all new), `requirements-python.txt`, `docs/SETUP.md`, `docs/public-flip-runbook.md`. Scratch `.run/public_rewrite/`: `dict.json`, `mailmap`, `rom_blob_ids.txt`, `old_tag_tip.txt`, `trial*.{sh,log}`, `trial_commit-map.tsv`, `trial_old-to-new.tsv`, `unchanged_commits.txt`, `nonpurge_blob_ids.txt`, `filter.log`. B9/C3: 251 index removals (files on disk), `docs/public-flip-runbook.md` (new), `docs/SETUP.md` §2.3/§2.4, `docs/verification.md`, `CLAUDE.md`, `docs/decision-log.md`. A5: `tools/verify_contract.sh` (new), `tools/audit_frontier.py` (derived denominator lines), `.gitignore` (the `.run/P33/verify/` allowlist), `.run/P33/verify/*` (tracked evidence), `docs/verification.md` §2, regenerated `docs/family-hseq.md` + `docs/progress*.md`/`duplicates*.md`. B8: `docs/verification.md` (new), `docs/SETUP.md` (§4.4/§4.6/§4.8/§6.3 pointers, backup posture). B7: `.github/workflows/no-rom.yml`, `tools/audit_public.py`, `tools/compile_only.py`, `tools/public_rewrite/purge_set.txt` (all new), `docs/SETUP.md`. B6: `dumps/CHECKSUMS.sha1` (new), `dumps/INDEX.md`, `docs/memory-map.md`. B5: `tools/ghidra_scripts/ImportAnnotations.java` (3 compile fixes + the `/undefined` resolver), `tools/ghidra_rebuild.sh` +D1: `README.md` (rewritten), `docs/progress.json` (new, generated), `tools/progress.py` (`--json`/`--readme`/`--check`), `Makefile` (report wiring). C9: `tools/public_rewrite/probe_github.sh` (422 = gone), `docs/public-flip-runbook.md` §10/§12; `.git` (the archive remote removed, 12 worktrees removed, repacked to one 80 MB pack). C8: `.run/P33/verify/*` (the recorded run, tracked), `docs/verification.md` §2, `docs/family-hseq.md`, `tools/verify_contract.sh` (the step-00 fix). C4–C7: `docs/commit-map.tsv` (new), the 98 token-resolved files (see the C7 entry), `tools/public_rewrite/resolve_tokens.py` (the skip rule), `.git/config` (repo-local noreply identity). Scratch `.run/public_rewrite/`: `pre-rewrite.bundle`, `repo.git` (the rewritten bare clone, keep until C9), `c4c5.{sh,log}`, `old-to-new.tsv`, `unchanged_commits.txt`, `old_tag_tip.txt`, `c5_commit-map.tsv`, `ids_after.txt`, `refs_*.txt`. C1: `tools/public_rewrite/{common,hash_dict,scrub,gate_scan,run_filter,verify_rewrite,build_commit_map,resolve_tokens,absent_scan}.py`, `probe_github.sh`, `expected_offenders.txt` (all new), `requirements-python.txt`, `docs/SETUP.md`, `docs/public-flip-runbook.md`. Scratch `.run/public_rewrite/`: `dict.json`, `mailmap`, `rom_blob_ids.txt`, `old_tag_tip.txt`, `trial*.{sh,log}`, `trial_commit-map.tsv`, `trial_old-to-new.tsv`, `unchanged_commits.txt`, `nonpurge_blob_ids.txt`, `filter.log`. B9/C3: 251 index removals (files on disk), `docs/public-flip-runbook.md` (new), `docs/SETUP.md` §2.3/§2.4, `docs/verification.md`, `CLAUDE.md`, `docs/decision-log.md`. A5: `tools/verify_contract.sh` (new), `tools/audit_frontier.py` (derived denominator lines), `.gitignore` (the `.run/P33/verify/` allowlist), `.run/P33/verify/*` (tracked evidence), `docs/verification.md` §2, regenerated `docs/family-hseq.md` + `docs/progress*.md`/`duplicates*.md`. B8: `docs/verification.md` (new), `docs/SETUP.md` (§4.4/§4.6/§4.8/§6.3 pointers, backup posture). B7: `.github/workflows/no-rom.yml`, `tools/audit_public.py`, `tools/compile_only.py`, `tools/public_rewrite/purge_set.txt` (all new), `docs/SETUP.md`. B6: `dumps/CHECKSUMS.sha1` (new), `dumps/INDEX.md`, `docs/memory-map.md`. B5: `tools/ghidra_scripts/ImportAnnotations.java` (3 compile fixes + the `/undefined` resolver), `tools/ghidra_rebuild.sh` (`.proof` markers; dies unless `failed=0`), `tools/ghidra_annotations_delta.py` (the three drift classes), new `tools/ghidra_roster.py`, `tools/ghidra_mcp_start.sh` (silent no-op guard), `.claude/settings.json` (relative hooks), `Makefile` (roster check in tools-health), `docs/SETUP.md` (P33 B5 section, 5 inventory rows, §2.8), `config/ghidra/*` diff --git a/tools/progress.py b/tools/progress.py index b4478eaef9..f9bc0e2bd3 100644 --- a/tools/progress.py +++ b/tools/progress.py @@ -1072,9 +1072,97 @@ def fleet(): text = "\n".join(head + table) + "\n" print("\n".join(head[:-1])) # the summary block (drop the trailing blank) (ROOT / "docs/progress.fleet.md").write_text(text) + # P33 D1/D3: the same numbers as DATA (docs/progress.json, README block, badges, frogress/objdiff feeds) + nverb = 0 + vp = ROOT / "config/verbatim_manifest.json" + if vp.exists(): + try: + import json as _json + vm = _json.loads(vp.read_text()) + nverb = len(vm.get("rows", vm) if isinstance(vm, dict) else vm) + except Exception: + nverb = 0 + return { + "schema": 1, + "note": "generated by tools/progress.py --fleet/--json from the committed sources — every number carries its denominator; regenerate, never edit", + "binaries": len(rows), + "fleet": { + "fn_count": {"matched": BYTE, "total": MATCH, "pct": round(100 * BYTE / MATCH, 2) if MATCH else 0.0, + "what": "functions byte-identical / matchable, every binary (one shared body counts once per overlay it is instantiated in)"}, + "instr_weighted": ({"matched": wm['fleet_m'], "total": wm['fleet_t'], "pct": round(wm['fleet_pct'], 1), + "what": "shipped .text instructions across all binaries (the decomp.dev-style display number)"} if wm else None), + "distinct_code": ({"matched": wm['dedup_m'], "total": wm['dedup_t'], "pct": round(wm['dedup_pct'], 1), + "unique_fns_matched": wm['dedup_fns'], "unique_fns_total": wm['dedup_total_fns'], + "what": "each distinct function body counted once, instruction-weighted (the distinct reverse-engineering number)"} if wm else None), + "main_game_code": ({"matched": wm['main_m'], "total": wm['main_t'], "pct": round(wm['main_pct'], 1), + "what": "SLUS_007.26 game-code instructions (excludes the linked Sony PsyQ objects); build-derived boundaries"} if wm and wm.get('main_t') else None), + }, + "counts": {"real_c_functions": REAL, "dedup_shared_of_real": SHARED, "linked_psyq_objects": LINKED, + "verbatim_asm_bodies": nverb, "include_asm_stubs": STUBS, "non_matching": NM, "matchable": MATCH, + "dedup_groups": ngroups, "dedup_instances": nmembers}, + "per_binary": [{"binary": r['binary'], "real": r['real'], "shared": r['shared'], "linked": r['linked'], + "byte_identical": r['byteident'], "matchable": r['matchable']} for r in rows], + } + + +README_BEGIN, README_END = "", "" + + +def readme_block(d): + """The README's generated numbers block, from progress.json (D1): a table WITH denominators (R41).""" + f, c = d["fleet"], d["counts"] + rows = [("Functions byte-identical (all binaries)", f["fn_count"]), + ("Instructions byte-identical (instruction-weighted)", f["instr_weighted"]), + ("Distinct code byte-identical (each body once)", f["distinct_code"]), + ("Main executable game code (excl. Sony objects)", f["main_game_code"])] + out = [README_BEGIN, + "| Metric | Matched | Of | % |", "|---|---:|---:|---:|"] + for name, m in rows: + if m: + out.append(f"| {name} | {m['matched']:,} | {m['total']:,} | {m['pct']:.1f}% |" if name.startswith("Functions") is False + else f"| {name} | {m['matched']:,} | {m['total']:,} | {m['pct']:.2f}% |") + out += ["", + f"{d['binaries']} binaries rebuild byte-identical from source · {c['real_c_functions']:,} functions in C " + f"({c['dedup_shared_of_real']:,} of them shared bodies via {c['dedup_groups']:,} dedup groups) · " + f"{c['linked_psyq_objects']:,} Sony PsyQ library functions linked from the SDK objects, not our C · " + f"{c['verbatim_asm_bodies']} hand-written-assembly bodies kept verbatim · {c['include_asm_stubs']} assembly stubs left · " + f"{c['non_matching']} non-matching functions.", + "", f"_Generated by `tools/progress.py --readme` from `docs/progress.json` — numbers are never typed by hand._", + README_END] + return "\n".join(out) + + +def write_json_and_readme(check=False): + import json as _json + d = fleet() + jp = ROOT / "docs/progress.json" + text = _json.dumps(d, indent=1) + "\n" + if check: + if not jp.exists() or jp.read_text() != text: + sys.exit("progress.py --json --check: docs/progress.json is STALE — run `make report BINARY=main`") + else: + jp.write_text(text) + rp = ROOT / "README.md" + if not rp.exists(): + sys.exit("progress.py --readme: README.md missing") + rt = rp.read_text() + if README_BEGIN not in rt or README_END not in rt: + sys.exit(f"progress.py --readme: README.md lacks the {README_BEGIN} … {README_END} markers — refusing (R43)") + a, b = rt.index(README_BEGIN), rt.index(README_END) + len(README_END) + new = rt[:a] + readme_block(d) + rt[b:] + if check: + if new != rt: + sys.exit("progress.py --readme --check: README.md's progress block is STALE — run `make report BINARY=main`") + print("progress.py --check: docs/progress.json + README block are fresh") + return + if new != rt: + rp.write_text(new) + print(f"progress.py: docs/progress.json written; README block {'updated' if new != rt else 'unchanged'}") def main(): + if '--json' in sys.argv or '--readme' in sys.argv: + write_json_and_readme(check='--check' in sys.argv); return if '--fleet' in sys.argv: fleet(); return if '--weighted' in sys.argv: