re: the disc ships the unit datasheet's own SCHEMA (and 文字列 was not a placeholder)

This corrects the previous commit. 文字列 is not a developer's leftover: it is
one member of a six-word Shift-JIS TYPE vocabulary, and the records carrying it
are a machine-readable schema for the unit datasheet.

The whole non-ASCII population on the disc is 6 distinct values out of 99328 -
0 of 3496 record names and 0 of 12173 field names - and all six are type words:

  文字列              string                366 uses
  NS_"文字列"         NS_ string             12
  整数 / 整数値        integer            66 / 6
  浮動小数値           floating-point value  504
  浮動小数値[0〜1]     float in [0,1]         36

990 type-valued fields. So the reader defect noted last time is real but bounded
to these six strings, and name_hash re-encodes Latin-1 byte-for-byte, so hashing
was never affected.

They sit in 15 records x 6 GP_MAIN_GAME_* paks = 90 instances, i.e. 15 records
with ONE user. The names are exactly the unit substructure family, and six carry
a literal wildcard: Turret_???, Hatch_???, Bridge_???, Thruster_???,
ShieldGenerator_???, Versatile_???, and NS_*. ??? is the numeric-suffix wildcard
at record AND field level - Turret_??? is the schema for Turret_000..00N, and
inside it CannonFrame_??? / MuzzleFrame_??? stand for the numbered slots.

Where a field's type is an enumeration the schema holds an EXAMPLE value instead
of a type name: Yes for the five booleans, Vessel for Generic.Type (the 43
Craft + 71 Vessel split), Ship_ for the ID prefix convention. Maneuver is the
one fully-typed record, 34 of 34. Every ResistanceTo* and every Color_* channel
is declared FLOAT[0..1] - normalised by declaration, matching the sampled values
in unit-datasheet-static. Generic.NozzleSpec_??? has its own type NS_"文字列"
and NS_* is a record, so the nozzle spec is a nested sub-schema.

Control separates schema from data cleanly: the _??? records and NS_* exist ONLY
as schema, 6 of 6 instances typed, while the eight real substructure names are
typed in 6 instances and untyped in the rest - Generic 6 of 3651, the others
6 of 684 each.

Turret_??? carries the game's own typo NomalModel beside DamagedModel.

This gives the port an authoritative field-type table: types the disc declares,
rather than types inferred from sampled values.

New artefact with its regenerator: tools/re-capture/datasheet_schema.py ->
docs/re/data/datasheet-schema.txt. All fifteen existing artefacts byte-identical.
This commit is contained in:
Sylpheed RE agent
2026-08-28 08:22:36 +00:00
parent 44bdbad2d6
commit fa8a538c33
4 changed files with 398 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
# ✅ The unit datasheet ships its own schema
Chasing the previous iteration's Shift-JIS value turned up something much larger
than the placeholder I called it. **Correction to that entry: `文字列` is not a
developer's leftover — it is one member of a six-word *type* vocabulary, and the
records carrying it are a machine-readable schema for the unit datasheet.**
## The whole non-ASCII population is six words
Across every parsed IDXD string on the disc:
| | distinct | non-ASCII |
|---|---|---|
| values | 99 328 | **6** |
| record names | 3 496 | 0 |
| field names | 12 173 | 0 |
All six decode cleanly as Shift-JIS, and all six are type names:
| bytes | Shift-JIS | meaning | uses |
|---|---|---|---|
| `95B68E9A97F1` | `文字列` | string | 366 |
| `4E535F22…22` | `NS_"文字列"` | NS_ string | 12 |
| `90AE9094` | `整数` | integer | 66 |
| `90AE9094926C` | `整数値` | integer value | 6 |
| `958293AE8FAC9094926C` | `浮動小数値` | floating-point value | 504 |
| `…5B308160315D` | `浮動小数値[0〜1]` | float in [0,1] | 36 |
990 type-valued fields in total. So the reader defect noted last time is real but
**bounded to these six strings** — nothing else on the disc is non-ASCII, and
`name_hash` re-encodes Latin-1 byte-for-byte, so hashing was never affected.
## 15 wildcard schema records, one per substructure
The 990 fields sit in **15 records × 6 `GP_MAIN_GAME_*` paks = 90 instances**,
i.e. **15 records with one user** under the per-pak-copy rule. Their names are
exactly the unit substructure family — and six of them carry a literal wildcard:
`Generic`, `Maneuver`, `Effect`, `Shield`, `Mass`, `SE`, `Explosion`,
`StructureCount`, plus `Turret_???`, `Hatch_???`, `Bridge_???`, `Thruster_???`,
`ShieldGenerator_???`, `Versatile_???` and `NS_*`.
🔑 **`???` is the numeric-suffix wildcard**, at record *and* field level:
`Turret_???` is the schema for `Turret_000…00N`, and inside it
`CannonFrame_???` / `MuzzleFrame_???` stand for the numbered frame slots.
⚠️ The control separates schema from data cleanly. The six `_???` records and
`NS_*` exist **only** as schema — 6 of 6 instances typed. The eight real
substructure names are typed in 6 instances and untyped in the rest:
`Generic` 6 of 3 651, `Maneuver`/`Shield`/`Mass`/`SE`/`Explosion`/`Effect`/
`StructureCount` 6 of 684 each. A schema record is one extra instance of a name
the datasheets already use.
## Where the type is an enum, the schema holds an example
Not every field is typed — `Generic` is 20 typed of 23, `Turret_???` 20 of 25.
The untyped slots hold a **sample value** instead, which names the enum:
| field | schema slot | reading |
|---|---|---|
| `IsDestructible`, `IsAuto`, `IsShielded`, `IsRadarVisible`, `IsInvolved` | `Yes` | boolean |
| `Generic.Type` | `Vessel` | the Craft/Vessel enum (43 + 71) |
| `Generic.ID` | `Ship_` | the ID *prefix* convention |
`Maneuver` is the one fully-typed record: **34 of 34**.
Two readings worth keeping for the port:
* every `ResistanceTo*` (`Shell`, `Explosion`, `Optics`) and every `Color_*`
channel is **`FLOAT[0..1]`** — declared normalised, matching the sampled
values (`ResistanceToShell 0.1`, `ResistanceToExplosion 0.5`) in
[[unit-datasheet-static]];
* `Generic.NozzleSpec_???` has its own type `NS_"文字列"`, and `NS_*` is a
record — the nozzle spec is a nested sub-schema, not a plain string.
⚠️ `Turret_???` carries the game's own typo **`NomalModel`** (beside
`DamagedModel`), which is a join key in the usual way.
This is the authoritative field-type table for the unit datasheet: types the
disc declares, rather than types inferred from sampled values.
Regenerate with `tools/re-capture/datasheet_schema.py` →
[`docs/re/data/datasheet-schema.txt`](../data/datasheet-schema.txt).