re: every AIParams object mapped to its stage, zero residual

StageResource.EnumerateAIParams names the table, and every name resolves.

29 StageResource records; 28 carry EnumerateAIParams (the one without it is the
_Test template); 23 distinct table names declared; 23/23 hash to an AIParams
object key under the prefix "stage\"; 0 objects left unnamed; 0 declared names
with no object.

AIParams_S01..S16 (16) + AIParams_S24..S29 (6) + AIParams_Tutorial.tbl shared by
six (UnitGroup_S18..S23, the tutorials) = 23 tables over 16 + 6 + 6 = 28 records.
The arithmetic closes both ways and matches the 23-object count found last
iteration.

Same sharing shape as the settings family (stage-settings-table.md: 24 objects,
StageParameter_Tutorial shared by six tutorials).  Two independent families agree
on how the tutorials are handled -- n=2, a pattern rather than a rule.

aiparams_census.py extended with the stage mapping; artefact +7/-0, byte-identical
across two runs; the other fourteen verify unchanged.

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 22:12:58 +00:00
parent 2456d28f1a
commit 9e2524d028
4 changed files with 102 additions and 0 deletions

View File

@@ -58,6 +58,47 @@ def main():
% (sum(len(p) for _h, _d, p in objs), len(objs),
len(objs[0][2]) if objs else 0))
# Which object is which stage? `StageResource.EnumerateAIParams` names it.
stageres = []
for h, b in pak_entries(paks[0]):
if b[:4] != b'IDXD':
continue
try:
recs = U.parse(b)
except Exception:
continue
for r in recs:
if r['squadron'] == 'StageResource':
stageres.append(dict((n, v) for _t, n, v in r['fields'] if n))
named = sorted({d['EnumerateAIParams'] for d in stageres
if d.get('EnumerateAIParams')})
keys = {h for h, _d, _p in objs}
resolved = {}
for n in named:
for pre in ('', 'stage\\', 'table\\'):
k = U.name_hash(pre + n)
if k in keys:
resolved[n] = (pre + n, k)
break
print("\n## Which object is which stage")
print(" StageResource records: %d carrying EnumerateAIParams: %d"
% (len(stageres), sum(1 for d in stageres if d.get('EnumerateAIParams'))))
print(" distinct table names declared: %d AIParams objects: %d"
% (len(named), len(objs)))
print(" names that hash to an object key: %d / %d (prefix `stage\\`,"
" name_hash is case-insensitive)" % (len(resolved), len(named)))
print(" objects left unnamed: %d declared names with no object: %d"
% (len(keys - {v[1] for v in resolved.values()}),
len([n for n in named if n not in resolved])))
share = collections.defaultdict(list)
for d in stageres:
v = d.get('EnumerateAIParams')
if v:
share[v].append(d.get('EnumerateSquadron', '?'))
for v, who in sorted(share.items()):
if len(who) > 1:
print(" shared: %-24s by %d -> %s" % (v, len(who), sorted(who)))
ct = collections.Counter()
byname = collections.defaultdict(set)
for _h, _d, p in objs: