Closes the reach caveat the `opt ` name fix left behind: 60 of 18 002 RATC children carry no `opt ` block, and it was not established whether they lack one or sit past our 128-byte window. Neither. They are not children. `examples/ratc_optless_children.rs` re-runs `ratc::parse`'s own guards over the disc and reports which one fired: all 60 are "tag beyond the window", none is rejected by length, gap or charset, none is child #0, and all 60 live in six bundles of one archive. Within a bundle the distances back to the nearest tag are an exact arithmetic progression, step 60 600 -- ten different records finding the SAME tag, because there is only one. Reading a bundle directly: children 1..10 are equal-size T8aD blocks under a single `opt ` name, `pb_f15_eg_anm.tan`. `.tan` is a FRAME SEQUENCE. One block declares the resource; its payload is a run of T8aD frames. Disc-wide, over all 18 718 `opt ` names in all 33 paks: a RATC bundle names exactly six kinds of resource -- `.t32` 14 756, `.rat` 3 311, `.prm` 367, `.tbm` 224, `.sbo` 54, `.tan` 6. Six `.tan`, ten frames each = 60, the entire population with nothing left over. The negative is closed, not narrowed. Consequence recorded but deliberately not fixed: `ratc::parse` over-reports there, listing a `.tan`'s frames as anonymous children. Nothing in the menu milestone reads a `.tan` -- it occurs only in GP_READY_ROOM, which S1 ruled out -- so no screen the port draws changes. Also a METHOD entry for this container OOM-killing `slb_leading_segment_disc` under default test parallelism (SIGKILL, no assertion; 8/8 pass with --test-threads=1).
5.6 KiB
.tan — one name over a run of frames, and the 60 "nameless" children it explains
Status: ✅ DECODED, with a disc-wide check. This closes the 🟡 reach caveat
left open by ratc-child-names.md: "60 children have no
opt block within 128 bytes and still fall back to the scan — whether they
genuinely lack the block or sit past the search window is not established."
Neither. They are not children. They are the ten frames of a single .tan
resource, and the one opt block that names the whole run sits up to 545 KB
behind the last of them.
What was measured
examples/ratc_optless_children.rs
re-runs ratc::parse's own guards over every child on the disc and reports, for
each rejection, which guard fired and whether a tag exists further back
(data):
| RATC children scanned | 18 002 |
with no accepted opt block |
60 |
| of those, rejected by length, gap or charset | 0 |
| of those, rejected because the only tag is beyond the 128-byte window | 60 |
| of those, that are child #0 of their bundle | 0 |
| archives involved | 1 — GP_READY_ROOM.pak |
| bundles involved | 6 — entries 26, 30, 159, 160, 1029, 1050, each exactly 706 609 B |
| children involved | 1…10 of each, never 0 and never 11+ |
The distances are the tell. Within one bundle they are
213, 60 813, 121 413, 182 013, 242 613, 303 213, 363 813, 424 413, 485 013, 545 613
— an exact arithmetic progression, step 60 600. Ten different children all
find the same opt tag, because there is only one. Nine of them do not have
a block that is merely far away; they have no block.
What they are
Reading bundle 26 directly, without the Rust parser, the 15 "children" resolve:
| # | offset | kind | size | opt at |
name |
|---|---|---|---|---|---|
| 0 | 0x000444 |
T8aD | 1 933 | −40 | pbf15_energie_generator2.t32 |
| 1…9 | 0x000bd1 … |
T8aD | 60 600 each | −213 … −485 013 | pb_f15_eg_anm.tan |
| 10 | 0x085e49 |
T8aD | 60 632 | −545 613 | pb_f15_eg_anm.tan |
| 11 | 0x094b21 |
T8aD | 17 523 | −32 | pbf15_pd_inside2.t32 |
| 12 | 0x098f94 |
T8aD | 75 068 | −35 | pbenergie_generator.t32 |
| 13 | 0x0ab4d0 |
T8aD | 4 697 | −28 | pbf15_eg_eff.t32 |
| 14 | 0x0ac729 |
RATC | 264 | −25 | pb_s15_eg.rat |
So the format is doing something perfectly ordinary that our scan had no concept
of: .tan is a frame sequence. One opt block declares the resource, and
its payload is a run of equal-size T8aD blocks, one per frame. The name is on
the disc and always was. What was missing was the idea that one name can cover
more than one block.
anm in pb_f15_eg_anm is the authors' own abbreviation, and it agrees.
The disc-wide check
Every opt block in every RATC bundle in all 33 dat/*.pak, by the extension
it names
(tools/re-capture/ratc_opt_name_census.py):
| extension | count | what it is |
|---|---|---|
.t32 |
14 756 | a T8aD sprite |
.rat |
3 311 | a nested RATC leaf |
.prm |
367 | a primitive |
.tbm |
224 | — |
.sbo |
54 | — |
.tan |
6 | a frame sequence |
| 18 718 |
A RATC bundle names exactly six kinds of resource, and .tan occurs six times
on the whole disc — all of them pb_f15_eg_anm.tan, one per language copy of
the same bundle, each holding 10 frames.
6 × 10 = 60. That is the entire population of opt-less children, with nothing left over. The negative is closed, not narrowed.
⚠️ What this says about ratc::parse
The child list over-reports. parse finds children by scanning for the four
child magics, so a .tan's ten frames are listed as ten anonymous children of the
bundle rather than as one named resource with ten frames. The disc's "18 002
children" is therefore 18 002 magic-delimited blocks, of which 60 are frames.
Not changed here, deliberately: nothing in the menu milestone reads a .tan,
and a rewrite of the child model is a bigger change than the one fact it would
buy. Recorded so that a later consumer of .tan knows the shape it needs.
❔ Not established
- The frame timing. Ten frames of the same size is a sequence; nothing here shows the rate, whether it loops, or whether the frames are equal-duration. No field was looked for.
- The pixel layout of a 60 600-byte frame. They decode as
T8aDlike any other sprite as far as the magic goes; their dimensions were not read. - What
.tbmand.sboare. They surfaced from the same census and are recorded above as counts only. - The two
opttotals do not reconcile exactly and are not forced to. This census counts 18 718 blocks; the Rust audit inratc-child-names.mdcounts 17 942 children with a block. They apply different guards — the Rust one additionally requires the named thing to be one of the four child magics and to follow within 8 bytes, which.prm/.tbm/.sbo(645 blocks) never satisfy. That accounts for most of the 776 difference but not all of it, and the remainder was not chased. Each number is reported as what its own script measured.
Scope
GP_READY_ROOM.pak is out of scope for the menu milestone (S1 is a
no-go), and .tan occurs in no other archive. None of
the five menu screens contains a .tan, so nothing the port draws changes.
This closes a caveat on a decode the port does depend on, rather than adding a
capability.