re: the base-solver -- 277 name-block loaders indexed, and the analog block is SOLVED

New reusable tool, tools/re-capture/name_block_bases.py -> docs/re/data/name-block-bases.txt
(2880 lines, ~65 s, byte-identical across two runs).

A loader that reads a table by field name keeps one base pointer and emits
"addi rX, rBASE, -N" per name, so no static xref sees the strings.  Solve the base
from the DISPLACEMENT SET alone: every (string address, displacement) pair implies
a candidate base, and the true base collects a vote from every name it explains,
so it wins outright.  My first cut took candidates from ONE displacement and
scored the unit loader at 52/226 against the right answer's 217/226 -- vote over
the whole set, not a probe.

Control passes with no prior knowledge: the tool recovers sub_82341A20 -> r30 =
0x82088F94 at 217/226, and independently recovers sub_8230D1F8 (129/132),
sub_822F9498 (90/91) and sub_822AE628 (81/108).  277 name-block-reading functions
image-wide, with the schema each names.

The analog block is SOLVED: sub_821A6CF0, r29 = 0x820A1630, 22/24.  In code order
it names ControlTweakName, YawMagForNormal, the 12 Tweak fields, the 8
AnalogRevice_* curves and GP_MAIN_GAME -- the whole schema in the object's own
order plus its pak.  r29 is built at 0x821A6D34 as addi r29, r11, 5680 =
0x820A0000 + 5680, matching the solved base exactly.  It is the same function that
reads PlayerParams.

Two of my own verdicts withdrawn: "referenced by nothing" and the softened "not
found by these routes".  The measurements behind them were right; the conclusions
were wrong.  The base was solvable from the data the whole time.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
This commit is contained in:
Claude (auto)
2026-08-27 21:22:50 +00:00
parent 38e0a63946
commit ae37e15d7d
5 changed files with 3067 additions and 21 deletions

View File

@@ -5039,3 +5039,46 @@ in `player-tuning-tables.md`; runtime watch still the cheap way in.
🟡 Not settled: which table governs the measured player speeds (unchanged); a
base-tracking sweep strong enough to follow register-passed bases was not built.
---
## ✅✅ 2026-08-27 — the base-solver: 277 name-block loaders, and the analog block is SOLVED
Item (b). New regenerator `tools/re-capture/name_block_bases.py` →
`docs/re/data/name-block-bases.txt` (2 880 lines, ~65 s, byte-identical across
two runs). **This is a reusable tool, not a one-off.**
🔑 **The method.** A loader that reads a table by field name keeps one base
pointer and emits `addi rX, rBASE, -N` per name, so no static xref sees the
strings. Solve the base from the **displacement set alone**: every (string
address, displacement) pair implies a candidate base, and the true base collects
a vote from **every name it explains**, so it wins outright.
⚠️ My first cut took candidates from ONE displacement and scored the unit loader
at **52/226** against the right answer's **217/226** — a plausible wrong base.
**Vote over the whole set, not a probe.**
✅ **Control passes with no prior knowledge:** the tool recovers
`sub_82341A20 → r30 = 0x82088F94`, **217/226**. It also independently recovers
`sub_8230D1F8` (129/132), `sub_822F9498` (90/91) and `sub_822AE628` (81/108),
and reports **277** name-block-reading functions image-wide with the schema each
names — an index the corpus did not have.
✅✅ **The analog block is SOLVED: `sub_821A6CF0`, `r29 = 0x820A1630`, 22/24.**
In code order it names `ControlTweakName`, `YawMagForNormal`, the 12 `Tweak`
fields, the 8 `AnalogRevice_*` curves and `GP_MAIN_GAME` — the whole schema in
the object's own order, plus its pak. `r29` is built at `0x821A6D34` as
`addi r29, r11, 5680` = `0x820A0000 + 5680`, matching the solved base exactly.
🔑 **It is the same function that reads `PlayerParams`** (it references that
literal and calls `sub_822F9498`): one function loads the player parameter object
*and* the control-tweak/analog table.
🔴 **Two of my own verdicts withdrawn.** "Referenced by nothing" (🔴) and the
softened "not found by these routes" (🟡) were both wrong; the measurements
behind them — 0/28 xrefs, 0 hits from naive base tracking — were right. **The
base was solvable from the data the whole time.** ⚠️ `r1` groups are the tool's
noise floor (stack frames) and are excluded.
🟡 Not settled: how the 11 curve samples are *applied* (the loader names the
records; the interpolation is downstream); the remaining 255 of the 277 solved
functions are listed but unexamined; what selects `Booster` (unchanged).