Commit Graph

6 Commits

Author SHA1 Message Date
Sylpheed RE agent
5ec24b8ef9 re: S14's 13 are dangling deployments - the unit chain is absent for them
Two measurements settle the last open cell of the unit partition.

The deployment side is identical. S14's asteroid-cmesh squadron records match a
declaring stage's field for field - same squadron ids (GNN901, GNN902, ...) and
the same Count 1 / SideID Neutral / AIID AI_Structure / FormationID
Formation_1_only / DisableInterval No. Nothing about how S14 deploys them
differs, and these are the same kind of record compared like for like.

The definition side differs completely. Per stage, deployed / declared /
Generic-with-HP / any Generic: S01 8/8/8/8, S04 10/10/10/10, S05 5/5/5/5,
S08 6/6/6/6, S13 4/4/4/4 - 33/33/33 for the five - and S14 p1 9/0/0/0,
S14 p2 4/0/0/0.

So the 13 are not a manifest omission: they have no unit definition anywhere on
the disc, not even an un-HP'd Generic row. UnitGroup_S14.tbl names entities that
do not exist - 13 dangling references. That rescues the law (nothing is
deployed-without-being-loaded in any working sense) and explains why the gap is
exactly the cmesh class and nothing else in S14.

What it predicts needs the emulator: either those collision meshes fail to
appear in Stage 14 - a shipped bug - or another route supplies them. Flying S14
and checking whether the large asteroids collide distinguishes the two; no
static route can. Recorded as NEEDS-HUMAN.

Also recorded so the two asteroid populations are not conflated: asteroid-fields'
AsteroidGroup_00N tables scatter mob_n0NN models, while these are
UN_<stage>_Asteroid_cmesh_* squadron entities. S28.Phase_1 borrows
S14_p2_asteroid.tbl but deploys no cmesh of its own, so the borrow does not
carry the dangling references.

All fifteen artefacts byte-identical.
2026-08-28 05:39:44 +00:00
Sylpheed RE agent
f0dfff4fcd re: EnumUnit_S<NN> is the stage's LOAD MANIFEST; all 9 never-deployed units named
Joining each stage's own EnumerateUnit table to its own EnumerateSquadron table
is far sharper than the global partition: declared == deployed EXACTLY in 20 of
22 stages. S16 declares 4 it never deploys; S14 deploys 13 it never declares.
Every per-stage deployed-but-undeclared count is 0 except S14's 13, and that 13
is the entire disc-wide total - so the exception is one stage, not a scattering.

S16 explains what the table is. It declares 6 and deploys 2, and two of the six
are UN_e901_ADAN_Boss and UN_e910_core_ADAN_GeneratorCore - exactly the units
stage16-boss shows are brought in by their own loader chain (sub_82315AE8),
not by the squadron roster. So EnumUnit_S<NN> is the stage's load manifest, not
a mirror of the roster: a unit that code spawns is declared but never deployed.

That also closes the 9 declared-but-never-deployed units by name: the S16
code-spawned pair above, Test_ADAN_PrometheusDriver_InsideP2_01, and six
Ship_Test* placeholders.

S14 remains the one unexplained cell, and it is not a missing table:
EnumUnit_S14.tbl exists and declares six names, one of which is
UN_mn040_Asteroid_Big. S14 therefore declares an asteroid but not the 13
Asteroid_cmesh entities it deploys, which refutes "asteroids are exempt from the
manifest". Whatever the cause, it is specific to the collision-mesh entities.

All fifteen artefacts byte-identical.
2026-08-28 05:24:09 +00:00
Sylpheed RE agent
0ae295e9eb re: the weapon law does not generalise to units; the whole exception is S14
Applied the declared x deployed partition to units. Three vocabularies had to
be separated first: declared = field names of the 31 EnumUnit records (118);
deployed = slot 0 of each UnitGroup member tuple (122); datasheet = Generic
records carrying HP (114, which re-derives unit-datasheet-static's own number
from a different direction, as a control). Declared and deployed share the UN_*
vocabulary and overlap on 109; the datasheet's IDs are a third naming, disjoint
from both.

                    deployed   not deployed
  declared            109           9
  not declared         13           1

The cell that is empty for weapons (0 mounted-but-undeclared of 131) holds 13
for units, so the general form of that law is refuted: a unit CAN be deployed
with no table declaring it.

But the 13 are one coherent family - every one is UN_S14_p1_Asteroid_cmesh_* or
UN_S14_p2_Asteroid_cmesh_*. Asking the other population settles it: S01 8/8,
S04 10/10, S05 5/5, S08 6/6, S13 4/4 declared - 33 of 33 - while S14 declares
0 of 13, and non-asteroid deployed-but-undeclared is 0. The law survives in a
narrower form: every deployed unit is declared, except S14's asteroid collision
meshes.

Why S14 differs is not settled. It is the stage whose asteroid table S28
borrows, but nothing measured connects the borrow to the missing declarations,
so that is recorded as a coincidence rather than a cause.

All fifteen artefacts byte-identical.
2026-08-28 05:07:35 +00:00
Sylpheed RE agent
b273ee9f48 re: WITHDRAWN — "FormationID does not hash into the table". It does.
The refutation used the wrong hash function. A record key is tag_hash of the
record's own name, not the pak-TOC name_hash which lowercases and uses a
different modulus:

  tag_hash("Formation_4_Bird")  = 0x22a5eeed   <- exactly the record key
  name_hash("Formation_4_Bird") = 0x6286edad   <- the wrong hash, hence
                                                  the recorded "0 of 16"

Formation_4_Bird IS a record name in FormationSet_S02.tbl and every record in
that table keys by tag_hash of its name. Across all 28 UnitGroup_S<NN>.tbl the
same holds for field keys: 6960 of 6960 are tag_hash(field name), 0 are
name_hash. So FormationID resolves by a direct hash lookup and the roster
indirection is NOT required for it.

This is exactly the trap idxd-container.md warns about, and it cost this file
a spurious refutation. The original text is kept below the correction.

The squadron half of the claim still stands and is marked so: a squadron
record's key is not tag_hash of the squadron id either -- tag_hash("TCN001")
is 0x760cdeaa against keys running 0x659aff47 -- because the record's NAME is
not the squadron id. That roster indirection is real.

Also closes the file's standing "the key derivation stays open, a second hash
function is unidentified": that function is tag_hash, recovered since.

Found while checking a subagent's claim rather than taking it -- it reported
the hash correction, and verifying it turned up that the FormationID half was
a stronger result than reported.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PMRJjbxLqZtsb5Vb7KunPE
2026-08-26 01:48:14 +00:00
Sylpheed RE agent
de42fbd742 re: UnitGroup member field n is a unit count, bounded by the formation
FormationSet_S<NN>.tbl records are slot lists -- 1 + 8*FrameCount fields,
exactly. Resolving every squadron's FormationID and comparing gives
sum(n) <= FrameCount holding 1159/1160 across all 28 stages, 0 unresolved, with
539 filling the formation exactly. The single violation is a debug leftover
(S20, AI_Test / MessageSet_test, Formation_1_only with n=2) and is recorded.

The old 'n is not the _NN suffix of FormationID' observation was right but drew
the wrong conclusion: the suffix IS FrameCount, so n=9 against _30 just means 9
units in 9 of 30 slots.

Also: FormationID does not hash into its table (0/16). FormationSet carries a
name roster record -- no FrameCount, fields are (tag, name, '') with the tags
being the record keys -- the same convention as Enumerate_Squadrons. Second
occurrence of 'keys are resolved by an in-table roster, not by hashing'.

Does not close the 387-vs-300 gap, and the key derivation stays open.
2026-08-25 10:04:20 +00:00
Sylpheed RE agent
b39aabf5c3 re: decode the UnitGroup squadron roster, and correct yesterday's container reading
stage\UnitGroup_S<NN>.tbl is now fully readable. A squadron record is Count
member tuples -- (unit model, message set, n, identity/nameplate) -- followed by
five named fields: Count, SideID, AIID, FormationID, DisableInterval. The
property entries carry their own field names inline, so the tag hash never has
to be inverted.

Two independent self-checks validate it corpus-wide, 1160/1160 each across all
28 stage tables on the disc:

  - the length identity len(fields) == Count * 4 + 5, which is what pins the
    member-tuple width at 4 and the named-field count at 5;
  - agreement with the file's own Enumerate_Squadrons roster, which maps record
    key to squadron id independently of the per-record string offset.

Adds tools/re-capture/unitgroup.py (pure static, runs no emulator) with a
--all --check self-check mode, and commits the Stage 02 dump as evidence.

Corrections to the container layout written yesterday, all three wrong:

  - the 20-byte "(tag, 0, 0, count, size) section header" does not exist. It
    was the file's last 16-byte record followed by a plain npool word. The
    corrected layout is uniform across all 28 files; the old one failed on 9.
  - squadron ids do not use a separate string base. Every offset in the file is
    relative to the one string pool. The earlier "109 of 111" score was an
    artefact of the uniform 7-byte id stride and had silently shifted every
    name by three entries, which is why 17 TC*-named squadrons came out as
    SideID=ADAN. The roster record refuted it outright.
  - the roster is not always the last record; 9 stages put it elsewhere, so it
    is found by its missing Count.

Refuted and kept: the 4-byte record key is not the squadron id's name hash
(0 of 112).

Not settled: what the key encodes, the member tuple's third field n, and where
the arrival interval values live. DisableInterval is only a per-squadron flag
(Yes for 31 of 1160); the durations, triggers and arrival positions are not in
this file. Formation_*.tbl and EnumSquadron_Test.tbl are next.
2026-08-24 11:07:33 +00:00