re: correction -- the naming sweep already covered the 24; it just never said so

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
This commit is contained in:
Claude (auto)
2026-08-27 19:25:30 +00:00
parent 589d09f2b5
commit a543b8da96
5 changed files with 1801 additions and 3 deletions

View File

@@ -4715,3 +4715,41 @@ table, so the link is not through the stage record. ⚠️ I first sampled
**Method note:** the win was harvesting *all* disc strings and hashing them,
after guessing filenames had failed twice. The real name resembled nothing I
would have guessed.
---
## ❌✅ 2026-08-27 — correction: the naming sweep already covered the 24; it just never said so
**Docs checked first, and this time the grep contradicted me.**
[`archive-naming.md`](structures/archive-naming.md) owns disc-wide pak naming,
and `archive_naming.py` already harvests **6 027** candidate names under **16**
prefixes. Testing its candidate set directly: **it names all 24
`StageParameter_S<NN>.tbl` objects, 24/24** — they were covered from the start.
❌ **Correction to the previous entry.** It presented "hashing every string on the
disc resolves all 24" as a new capability. It is not new. What was genuinely new
was the **identification** — which object is which stage, that the six tutorials
share one table, that `IsBoss16Enable` is S16 — not the naming method. The
standing note that "the sweep has never been run corpus-wide" was also wrong: it
has, and its artefact is `data/archive-naming.txt`.
✅ **The real gap, now closed.** The sweep reported only per-archive
*percentages* — `GP_MAIN_GAME_E … 751 named, 67.1 %` — and never emitted **which**
entry got which name. That is exactly why nobody could say the settings objects
were `StageParameter_*`. `archive_naming.py` now also prints, per archive, the
**resolved name families** (digits collapsed to `#`) with counts: **6 573 named
entries, 1 631 families** across the disc, e.g. `GP_MAIN_GAME_E` = 751 named in
212 families (`EnumUnit_S#.tbl` ×28, `StageResource_S#.tbl` ×28,
`StageParameter_S#.tbl` ×22, …). A coverage statistic is not a name table.
⚠️ **Determinism, caught again by the verify loop.** The resolved map is built by
iterating the candidate **set**, so collided hashes got a different winner each
run and the artefact failed its own byte-identical check. Now iterated `sorted()`.
Second time this class of bug has appeared in two iterations — **any map built by
iterating a set needs a sort**.
🟡 Not settled: the low-coverage archives are unchanged — `DefTables` 8.9 %,
`GP_HANGAR_ARSENAL` 22.6 %, `GP_MISSION_SELECT` 25.0 %,
`GP_DEBRIEFING_PILOTLOG` 33.3 % — and the content index now makes it possible to
say *what kind* of thing is missing from each, which is the obvious next step.
🔴 The 2D / `GP_READY_ROOM` archives stay blocked.

File diff suppressed because it is too large Load Diff

View File

@@ -39,6 +39,34 @@ these archives are outside it.
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

View File

@@ -19,9 +19,18 @@ nothing.
## ✅ Every settings object is named — `stage\StageParameter_S<NN>.tbl`
**Settled 2026-08-27, 24/24.** Hashing **every string that appears anywhere in
any IDXD object on the disc** (rather than guessing filenames) resolves all
twenty-four:
**Settled 2026-08-27, 24/24.** Hashing every string that appears on the disc
resolves all twenty-four:
> ❌ **Correction (same day).** The first write-up of this presented the naming
> *method* as new. It is not: `archive_naming.py` — the sweep behind
> [`archive-naming.md`](archive-naming.md) — already harvests 6 027 candidate
> names under 16 prefixes and **already covered all 24 of these hashes**. What
> was new here is the **identification** (which object is which stage, and what
> follows from it), not the ability to name them. The reason nobody could say
> so before is that the sweep reported only per-archive *percentages* and never
> emitted **which** entry got which name — now fixed, see that document.
| name | count |
|---|---|

View File

@@ -43,6 +43,25 @@ def main():
nd = sum(1 for h in ent if h in H)
print(" %-30s %6d %6d %5.1f%%" % (nm, len(ent), nd, 100.0 * nd / len(ent) if ent else 0))
# WHICH entries got named — the per-archive content index. The percentage
# above is a statistic; this is the part that is actually usable.
NAMES = {}
for n in sorted(names): # sorted: a set's order varies per run
for p in PRE:
NAMES.setdefault(U.name_hash(p + n), p + n)
total = sum(1 for ent in toc.values() for h in ent if h in NAMES)
print("\n## What each archive is made of (resolved names, digits collapsed to #)")
print(" total named entries across the disc: %d" % total)
for nm, ent in rows:
res = [NAMES[h] for h in ent if h in NAMES]
if not res:
continue
fam = collections.Counter(
re.sub(r'\d+', '#', r.rsplit('\\', 1)[-1]) for r in res)
print("\n %s %d named, %d families" % (nm, len(res), len(fam)))
for k, c in sorted(fam.items(), key=lambda kv: (-kv[1], kv[0])):
print(" x%-4d %s" % (c, k))
def _ix(t): return U.ixud_hash([ord(c) for c in t])
FN = [('name_hash', U.name_hash), ('tag_hash', U.tag_hash), ('ixud_hash', _ix)]
SUB = ['', '2d\\', 'eng\\', 'Data\\', 'ArmsSt\\', 'Marker\\']