# Project: named-retail decompilation foundation **Agreed 2026-04-25.** Read once per session. Foundation commits: `a9a01d8` (corpus), `69d884a` (pdb-extract tool). ## What changed The retail-client decompilation has gone from "FUN_xxx Ghidra chunks + 71 hand-mapped functions" to **"18,366 named retail functions + 5,371 named struct types + verbatim retail headers"**, all committed under `docs/research/named-retail/`. The `acclient.pdb` (Sept 2013 EoR build, MSVC 7.00) is the source of truth. ## Files at `docs/research/named-retail/` | File | What | When to use | |---|---|---| | `acclient_2013_pseudo_c.txt` (62 MB / 1.44 M lines) | Binary Ninja pseudo-C with 99.6% naming. Address-prefixed lines. | **Primary symbol lookup.** Grep by `class::method`. | | `acclient.h` (1.7 MB / 70K lines) | IDA-decompiled retail headers. Every struct verbatim. | **Struct field names + offsets.** Grep by struct name. | | `acclient.c` (46 MB / 1.3 M lines) | IDA full-binary export. Mixed FUN_/named, but has named struct fields. | **Cross-reference when pseudo-C body is corrupt.** | | `symbols.json` (3 MB) | 18,366 entries: `address` + `name` (demangled `Class::Method`) + `mangled` (raw MSVC ABI). | **Programmatic name↔address lookup via jq.** | | `types.json` (506 KB) | 5,371 named class/struct records with size + kind. | **Programmatic type-layout queries.** | ## Workflow change — STEP 0 GREP NAMED FIRST `CLAUDE.md` workflow now starts with **Step 0** before the older DECOMPILE step: ```bash # Find a function body grep -n "CEnchantmentRegistry::EnchantAttribute" \ docs/research/named-retail/acclient_2013_pseudo_c.txt # Find a struct grep -n "^struct.*CEnchantmentRegistry" \ docs/research/named-retail/acclient.h # Programmatic cat docs/research/named-retail/symbols.json | \ jq '.[] | select(.name == "CEnchantmentRegistry::EnchantAttribute")' ``` The older `docs/research/decompiled/` Ghidra chunks remain a fallback for the obfuscated/packed minority that pseudo-C lacks. ~5 second grep replaces ~30 minute archaeology for typical lookups. ## Hard rules 1. **Grep `named-retail/` first.** Always. The "Do not guess" rule in CLAUDE.md is upgraded: with the PDB available, guessing is no longer recoverable error — it's negligence. 2. **Match by name, not raw address.** The PDB build has a ~0xC00 byte delta vs the binary that produced our older chunks. Address lookups in `symbols.json` are correct; the older `acclient_function_map.md` had several mid-body addresses (issue #9 sweep corrected them). 3. **Regenerate JSON sidecars when needed:** ```powershell py tools\pdb-extract\pdb_extract.py refs\acclient.pdb ``` 4. **`refs/` stays gitignored.** It's per-developer download cache; the committed extracts at `docs/research/named-retail/` are what subagents and post-compaction sessions inherit. ## Counts (Sept 2013 EoR build) - 18,366 named public function symbols (`S_PUB32`, code flag set) - 5,371 unique named class/struct types (filtered for non-forward-declared) - 1,053 .obj compilation units recorded in DBI - Build root preserved in PDB: `d:\ac1_sep13\` ## Why this matters Closes / unblocks issues #6 (enchantment buffs in vital max — uses `CEnchantmentRegistry::EnchantAttribute` at `0x594570`), #7 (PlayerDescription trailer — uses `CPlayerSystem::Handle_PlayerDescription` at `0x5636A0`), plus reduces the cost of every future port from "30 min archaeology" to "5 sec grep". ## Links - Plan: `C:/Users/erikn/.claude/plans/ticklish-conjuring-cake.md` (8-phase foundation) - Tool: `tools/pdb-extract/` (pure Python, no deps) - Reference: `docs/research/named-retail/README.md`