archive_naming.py already harvests 6027 candidate names under 16 prefixes, and testing its candidate set directly shows it names all 24 StageParameter_S<NN> objects, 24/24. The previous entry presented that naming as new -- it is not. What was new was the identification (which object is which stage, the shared _Tutorial table, IsBoss16Enable = S16), not the method. The real gap, now closed: the sweep reported only per-archive percentages and never emitted WHICH entry got which name, which is exactly why nobody could say the settings objects were StageParameter_*. It now prints the resolved name families per archive -- 6573 named entries, 1631 families disc-wide. Determinism caught again by the verify loop: the resolved map was built by iterating a set, so collided hashes picked a different winner each run. Now iterated sorted(). Second time in two iterations -- any map built from a set needs a sort. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
134 lines
6.7 KiB
Markdown
134 lines
6.7 KiB
Markdown
# ✅ Which archives the disc can name — and the two it cannot
|
||
|
||
The previous pass found that **0 of 419** in-game HUD config paths hash to a pak
|
||
entry ([hud-config](hud-config.md)). Chasing more prefixes would have been the
|
||
same mistake twice, so this censuses the whole disc instead: harvest **every**
|
||
plausible asset-name string from **every** archive, hash each under the 16 known
|
||
path prefixes, and ask per archive **what fraction of its TOC that explains**.
|
||
|
||
`idxd-container.md` and `idxd-tag-hash.md` own the hash (`name_hash` = a
|
||
checksum byte over a 24-bit modular value, case-insensitive, distinct from
|
||
`tag_hash`); neither says which archives are *reachable* by it. Artefact
|
||
`../data/archive-naming.txt`, regenerator `tools/re-capture/archive_naming.py`
|
||
(**6 027** candidate names × 16 prefixes).
|
||
|
||
## The result is bimodal
|
||
|
||
| archive | entries | named | |
|
||
|---|---:|---:|---|
|
||
| `GP_TITLE`, `GP_PAUSE_MENU`, `GP_STAGE_CLEAR`, `GP_CHALLENGE`, `GP_MOVIE_THEATER`, `GP_GAMEOVER`, `GP_BUNK`, `GP_SYSTEM`, `GP_TUTORIAL`, `MiscBin`, `fonts` | 2–151 | **all** | **100 %** |
|
||
| `tables.pak` | 79 | 78 | 98.7 % |
|
||
| `GP_DIALOG` | 140 | 139 | 99.3 % |
|
||
| `deu/eng/esp/fra/ita/jpn.pak` | 117 | 115 | 98.3 % |
|
||
| `GP_SAVE_LOAD` / `GP_LEADERBOARD` / `GP_OPTIONS` / `GP_MISSION_LOG` | 24–108 | | 91–94 % |
|
||
| `GP_MAIN_GAME_{D,E,F,I,J,S}` | 1 119 | 751 | 67.1 % |
|
||
| `GP_DEBRIEFING_PILOTLOG` | 234 | 78 | 33.3 % |
|
||
| `GP_HANGAR_ARSENAL` | 1 538 | 347 | 22.6 % |
|
||
| `DefTables` | 1 465 | 130 | 8.9 % |
|
||
| `GP_MISSION_SELECT` | 88 | 22 | 25.0 % |
|
||
| **`GP_READY_ROOM`** | **1 106** | **6** | **0.5 %** |
|
||
| **`GP_MAIN_GAME_{D,E,F,I,J,S}2D`** | **711** each | **0** | **0.0 %** |
|
||
| `sound.pak` | 9 519 | 1 | 0.0 % (a separate format — [sound-pak-contents](sound-pak-contents.md)) |
|
||
|
||
🔑 **The six 2D paks are at exactly 0.0 %, all six, 711 entries each** — while
|
||
eleven menu paks are at 100 % by the same method in the same run. That is the
|
||
control that makes it a finding rather than a failed guess: the method works, and
|
||
these archives are outside it.
|
||
|
||
🔑 **`GP_READY_ROOM` is a second such archive** — 1 106 entries, **6** named.
|
||
Not previously noted anywhere in `docs/re/`; it is the largest UI pak on the
|
||
disc and its names are as unreachable as the 2D paks'.
|
||
|
||
## ✅ The sweep now says WHICH entry, not just how many (2026-08-27)
|
||
|
||
The percentages above were the whole output for a long time, and that hid
|
||
something: the sweep had **already named** the 24 `StageParameter_S<NN>.tbl`
|
||
objects that a later iteration "discovered" — they were in the 6 027-candidate
|
||
set from the start. Nobody could tell, because the artefact only reported
|
||
`GP_MAIN_GAME_E … 751 named, 67.1 %`.
|
||
|
||
`archive_naming.py` now also emits, per archive, the **resolved name families**
|
||
(digits collapsed to `#`) with counts — **6 573 named entries, 1 631 families
|
||
across the disc**. That turns the statistic into a content index; the
|
||
`GP_MAIN_GAME_E` head is
|
||
|
||
```
|
||
x28 EnumUnit_S#.tbl x28 StageResource_S#.tbl
|
||
x28 FormationSet_S#.tbl x28 UnitGroup_S#.tbl
|
||
x28 Route_S#.tbl x22 AIParams_S#.tbl
|
||
x22 StageParameter_S#.tbl x22 UnitMessageSet_S#.tbl …212 families
|
||
```
|
||
|
||
**Method lesson, paid for twice now:** a coverage percentage is not a name table.
|
||
If a sweep can name a thing, make it *say* the name, or the next reader will
|
||
redo the work.
|
||
|
||
⚠️ Determinism: the resolved map is built by iterating the candidate set, so it
|
||
is now iterated **sorted** — a plain `set` gave a different winner for collided
|
||
hashes on each run and the artefact failed its own byte-identical check.
|
||
|
||
## What that means for the 419
|
||
|
||
The in-game HUD's asset paths are not "missing". **Nothing in the 2D paks is
|
||
reachable by name from the disc's own strings**, whatever the extension. So the
|
||
2D and READY_ROOM TOC keys are hashes of names that are **not written anywhere
|
||
we can read** — built by the tool chain, or from a string the executable
|
||
composes, or from a name list held outside these archives.
|
||
|
||
## 🧪 Also refuted here — 13 name transformations
|
||
|
||
Before the census, the 419 config values were re-hashed under 13 rewrites:
|
||
as-is, forward slashes, basename, basename without extension, without extension,
|
||
uppercased, `.rat` substituted, `2d\`/`eng\`/`hud\`/`GP_MAIN_GAME_2D\` prefixed,
|
||
and first-directory stripped. **Every one scored 0, both against the E2D pak's
|
||
711 entries and against all 16 630 entries on the disc.**
|
||
|
||
## 🔴 BLOCKED — three routes to those names, all closed
|
||
|
||
Followed up the next iteration. Every avenue the container can reach is now
|
||
tried, each with a positive control in the same run:
|
||
|
||
**1. A different hash family.** The corpus knows three
|
||
([idxd-tag-hash](idxd-tag-hash.md)): `name_hash` (pak TOC), `tag_hash` (IDXD
|
||
keys) and `ixud_hash`. Scoring all 5 977 harvested names × 6 prefixes:
|
||
|
||
| archive | `name_hash` | `tag_hash` | `ixud_hash` |
|
||
|---|---:|---:|---:|
|
||
| `GP_TITLE` (control) | **8 / 16** | 0 | 0 |
|
||
| `GP_PAUSE_MENU` (control) | **6 / 11** | 0 | 0 |
|
||
| `GP_MAIN_GAME_E2D` | **0 / 711** | 0 | 0 |
|
||
| `GP_READY_ROOM` | 6 / 1 106 | 0 | 0 |
|
||
|
||
`tag_hash` and `ixud_hash` explain **nothing anywhere**, including the paks
|
||
`name_hash` does explain — so they are not the TOC function, and the two
|
||
unnameable archives are not simply keyed by a different one.
|
||
|
||
**2. The executable.** `sylpheed.db`'s `strings` table holds **7 140** rows, of
|
||
which exactly **two** look like asset paths — `Data\gmicon002_2.t32` and
|
||
`Data\gmicon006_2.t32`, in a `Data\` directory nothing else on the disc uses.
|
||
**Neither resolves in any archive.** So the binary is not the name source
|
||
either; it holds two strays and no table.
|
||
|
||
**3. Name transformations** of the config paths — 13 of them, all 0 (above).
|
||
|
||
🔴 **This is where the container runs out.** The 2D and `GP_READY_ROOM` TOC keys
|
||
hash names that are on neither the disc nor the executable in readable form. The
|
||
remaining lever is a *dictionary attack* using `name_hash`'s shape — the top byte
|
||
is the character-sum checksum, so candidates are cheap to reject — but that needs
|
||
a plausible name corpus, and this disc does not contain one. **Noted as blocked
|
||
rather than improvised around.**
|
||
|
||
⚠️ The port does not need these names: the sprites and bundles are readable by
|
||
*content* (T8aD, RATC), and the config records already say which asset each HUD
|
||
element uses. Only the archive-key ↔ name mapping is missing.
|
||
|
||
## 🟡 Not settled
|
||
|
||
* What names the 2D and `GP_READY_ROOM` TOCs actually hash. The one lever left is
|
||
the hash's own shape — the top byte is the character-sum checksum, so any
|
||
candidate is cheap to reject — but that needs a name corpus this disc does not
|
||
contain.
|
||
* Why `DefTables` (8.9 %) and `GP_HANGAR_ARSENAL` (22.6 %) sit in the middle;
|
||
probably just that most of their entries are tables referenced by records this
|
||
harvest does not treat as filenames. Not chased.
|