re: RATC "one level deep" is not a limitation -- measured, plus a second dangling asset

INDEX read as if the parser stopped at one level. Measurement says there is
nothing deeper: 2859 top-level bundles hold 18002 children at depth 1 and ZERO at
depth 2, with no blob failing to parse.

The children that are themselves RATC -- the .rat layout records -- are leaves.
They carry no child list and reference their siblings BY NAME (the sprite they
place, and via "opt " their focused variant): 3311 such leaves, every one
embedding sibling names, and 10144 of 10148 references resolve within the same
bundle. That is the same by-name convention used one level up (a screen config
naming .prt components) and one level up again (the movie table naming
<lang>.pak+<member>).

The 4 unresolved references are a disc defect, not a parse gap: pmbase.rat in
GP_STAGE_CLEAR.pak's four language builds places pmbase.t32, and that sprite
exists nowhere -- not a pak member, not a child of those bundles. Second such
dangling asset after SUBTITLE_S12B.tbl, so a reimplementation should skip a
missing sprite rather than call it a decode failure.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-11 22:44:19 +00:00
parent ac10d3bd19
commit d9ffc223bc
2 changed files with 25 additions and 1 deletions

View File

@@ -15,7 +15,7 @@ Promote to a prose `structures/…md` file when a format needs behavioural notes
| IDXD object/table | ✅ | `sylpheed-formats/src/idxd.rs` | self-describing; ship/weapon stats verified vs known values |
| XPR2 texture + cubemap | 🟡/✅ | `sylpheed-formats/src/texture.rs` + [colour check](xpr2-colour-check.md) | de-tile + A8R8G8B8 and DXT1. **Channel order ✅ confirmed against the running game**: the Delta Saber's decoded atlas is orange-dominant (median saturated hue 23.3°, *zero* cool pixels) and the game renders the same hull at 9.3° — a red↔blue swap would sit at ≈200°. Exact fidelity (gamma/sRGB curve, premultiplied alpha, per-channel scale) is 🟡 untested, since a hue comparison cannot see it; cubemap face ordering ❔ |
| T8aD 2D texture | ✅ | `sylpheed-formats/src/t8ad.rs` | **100 % of the disc decodes** (19 216/19 216, measured). The "~15 % deferred variants" were a wrong model, not a variant: a surface is a list of **arbitrary sub-rectangles**, each with a 16-byte header of `dst X, dst Y, width, height`, not a 256×256 grid — `0x1c` is the **rectangle count**. Uncovered area stays transparent. **Colours ✅ CONFIRMED** ([k8888](structures/texture-color-k8888.md)) |
| RATC bundle | 🟡 | `sylpheed-formats/src/ratc.rs` | child listing confirmed; one level deep |
| RATC bundle | | `sylpheed-formats/src/ratc.rs` | child listing confirmed. **"One level deep" is not a limitation — there is nothing deeper**: 2 859 bundles hold 18 002 children at depth 1 and **0 at depth 2**, with no parse failures. Nested RATC blobs are **leaf records that reference siblings by name** (`opt `, the sprite name): 3 311 leaves, all embedding sibling names, **10 144 of 10 148 references resolve**. The 4 that do not are one dangling asset — `pmbase.rat``pmbase.t32` in `GP_STAGE_CLEAR.pak`'s four language builds, and `pmbase.t32` is **on the disc nowhere** |
| LSTA sprite list | 🟡 | `sylpheed-formats/src/lsta.rs` | inline T8aD frames |
| IXUD subtitle | 🟡/✅ | `sylpheed-formats/src/ixud.rs` + [movie link](movie-subtitle-link.md) | timed cues. **The movie↔subtitle↔voice link is solved — statically**, from the movie config record in `tables.pak` (schema `0x067025b9`), not from the running game as this row previously assumed: [101 movies mapped](captures/movie-subtitle-voice-map.csv), 94 with subtitles, 83 with voice, 21 with a telop overlay. 93 of 94 subtitle refs resolve in the language paks; **`SUBTITLE_S12B.tbl` is missing from all six languages** — a dangling reference on the disc. Naming is `SUBTITLE_<base>.tbl` / `VOICE_<base>` with six documented exceptions. The record's ~104 **script ids** are ❔ — positional pairing drifts by three because the IDXD pool dedupes repeated values |
| Fonts (ttf/otf/ttc) | ✅ | `sylpheed-formats/src/font.rs` | standard OpenType, parsed via ttf-parser |

View File

@@ -314,3 +314,27 @@ buttons are static (every keyframe identical), which is precisely why they make
clean ruler. Validating the animation rule needs an element captured mid-slide.
Evidence: [`captures/arsenal-layout-validation.png`](../captures/arsenal-layout-validation.png).
## RATC nesting, measured
`INDEX` carried the bundle format as 🟡 "one level deep", which reads like a
parser limitation. It is not — **there is nothing deeper on the disc**:
- **2 859** top-level RATC bundles hold **18 002** children at depth 1 and
**0** at depth 2, with **no** blob failing to parse.
- The children that are themselves RATC (the `.rat` layout records) are **leaf
records**: they carry no child list and instead **reference their siblings by
name** — the sprite they place and, via `opt `, their focused variant.
**3 311** such leaves, every one embedding sibling names, and **10 144 of
10 148** references resolve to a sibling of the same bundle.
That is the same by-name convention used one level up, where a screen's config
names `.prt` components, and one level up again, where the movie table names
`<lang>.pak+<member>`.
**The 4 unresolved references are a real defect on the disc**, not a parse gap:
`pmbase.rat` in `GP_STAGE_CLEAR.pak` (four language builds) places `pmbase.t32`,
and that sprite exists **nowhere** — not as a pak member, not as a child of those
bundles. It is the second such dangling asset found, after
[`SUBTITLE_S12B.tbl`](../movie-subtitle-link.md); a reimplementation should skip
a missing sprite rather than treat it as a decode failure.