Files
Sylpheed/docs/re/structures/build-ordinal-vs-entry.md
sylph-decoder c364cde476 re: sweep the disc for the ordinal foot-gun -- GP_TITLE was the mildest case
Last iteration I retracted three claims because `--build 10/11` on GP_TITLE are
entries 12/15, and named the untested remainder in my own report: how much else
in the corpus used a build ordinal as an entry index. This is that sweep.

`screen --build N` indexes a predicate-filtered list, so every rejected entry
shifts every later ordinal. Disc-wide: 21 of 24 build-bearing archives diverge,
18 of them at ordinal 0 -- `--build 0` is entry 108 in each GP_MAIN_GAME_*2D,
24/26 in GP_HANGAR_ARSENAL/GP_READY_ROOM. GP_TITLE is the ONLY archive whose
first ten ordinals are the identity, which is the sole reason 207 of the
corpus's 226 build citations are safe. Second foot-gun: `--all` swaps the
predicate and renumbers 18 archives, so `--build N` and `--build N --all` are
not the same object.

The instrument failed its control first. A version using parse_build as the
predicate reported GP_TITLE as 16 builds, ordinal == entry throughout -- it
would have certified the exact bug it was built to find. The shipped version
uses the same predicates screen_builds() uses and reproduces `screen list` on
GP_TITLE exactly.

Audited all 226 citations. One real defect: a five-row table in
ui-keyframe-time-unit.md headed "declared element (build 11)" spans builds 10
and 11 -- palogo_sqex is in 10. All five placements re-verified and correct, so
the linear-ramp measurement is untouched; only the label was wrong. Fixed with a
per-row bundle column. GP_DIALOG --build 0 and GP_DEBRIEFING_PILOTLOG --build 10
re-run and reproduce.

Refutation attempted: sylpheed-port's corrected mid-ramp test rests on
ptlogo_all_eff holding a=127 from t=112 to t=246. Their quote is exact and it is
a plateau. The refutation fails; their correction stands.

METHOD already carried the rule I broke, and ui-splash-addressing already said
the splashes need --all. The failure was not missing knowledge -- it was
addressing a bundle by index without grepping for the index first.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wuu56cE8vJGTBtn1ppsk8v
2026-08-30 13:20:41 +00:00

153 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ✅ `--build N` is an ordinal into a filtered list — and on 21 of 24 archives it is not the entry
**Status:****decoded**, disc-wide, instrument controlled against the CLI's own
output. The object decoded is *the addressing*, not a file field: how
`sylpheed-cli screen --build N` resolves, and where that number stops agreeing
with the pak entry index a reader will assume it means.
## Why this was swept
Last iteration I rendered `--build 10` and `--build 11` of `GP_TITLE` believing
they were the two splash screens, wrote three claims on the output, and every
downstream number validated. They are entries **12** and **15** — the loading
screens. I retracted it, and named the untested remainder in my own report:
*"how much else in the corpus used `--build` as an entry index — not swept."*
This is that sweep.
## The mechanism
`crates/sylpheed-cli/src/main.rs:394` builds the list:
```rust
fn screen_builds(pak: &Path, all: bool) -> Result<Vec<(usize, Vec<u8>)>> {
for (i, e) in ar.entries().iter().enumerate() {
let keep = if all { ui_layout::is_composable(&bytes) }
else { ui_layout::is_build(&bytes) };
if keep { out.push((i, bytes)); } // (entry, bytes)
}
}
```
`--build N` indexes `out`, so `N` counts only entries that **passed a predicate**.
Every entry the predicate rejects shifts every later ordinal down by one.
## 🔴 The result: `GP_TITLE` is the mildest case on the disc
[`data/ordinal-entry-map.txt`](../data/ordinal-entry-map.txt) — all 24 archives
holding builds:
* **21 of 24 diverge.** Only `GP_MOVIE_THEATER`, `GP_SYSTEM` and `GP_TUTORIAL`
have ordinal == entry throughout.
* **18 of the 21 diverge at ordinal 0** — `--build 0` is *not* entry 0. The worst
are the six `GP_MAIN_GAME_*2D` paks, where `[0]` is entry **108**, and
`GP_HANGAR_ARSENAL` / `GP_READY_ROOM`, where `[0]` is entry **24** / **26**.
* `GP_TITLE` is the **only** archive whose first ten ordinals happen to be the
identity. It diverges at ordinal 10 and nowhere earlier.
So the corpus was not lucky in general — it was lucky in the one archive almost
all of it is about, and unlucky in exactly the two indices I used.
## ⚠️ Second foot-gun: `--all` renumbers, on 18 archives
`--all` swaps the predicate, which changes the list, which changes the ordinals.
**`--build N` and `--build N --all` are not the same object** on 18 of 24
archives — including `GP_TITLE`, where `--build 10` is entry 12 but
`--build 10 --all` is entry 10. Any citation of a build index that does not also
record whether `--all` was passed is under-specified.
## ✅ Audit of every build citation in `docs/`
226 citations of a build index across `docs/` (this file excluded). The 207 that
name an ordinal 09 of `GP_TITLE` are safe by the accident above. The **19** that
name an ordinal ≥10, or a non-`GP_TITLE` archive, are the ones that can be wrong,
so each was opened and checked rather than counted:
| # | citations | verdict |
|---|---|---|
| 6 | carry `--all`, where ordinals 10/11 *are* entries 10/11 | ✅ correct |
| 4 | inside last iteration's retraction, already marked void | ✅ n/a |
| 2 | `GP_TITLE` `--build 10` bare — `ui-title-build-map.md:85` | ✅ correct: it names what comes back, the **loading screen** `pgloading_str.t32` |
| 2 | `GP_DIALOG --build 0` (`[0]` is entry 2) | ✅ re-run, reproduces |
| 2 | `GP_DEBRIEFING_PILOTLOG build 10` (`[10]` is entry **131**) | ✅ re-run, reproduces |
| 2 | prose about an unfinished sweep / the renumbering warning itself | ✅ n/a |
| **1** | `ui-keyframe-time-unit.md:59` | 🔴 **wrong, and fixed** |
### The two re-runs
Neither claim asserted an entry number — both cite *the output of a command*, so
a reader running it gets the same object the author had. Confirmed by running
them, not by arguing it:
```
$ sylpheed-cli screen info --build 0 --geometry /disc/dat/GP_DIALOG.pak
4 pceff03.t32 0: a=0 r=90 8: a=128 r=30 12: a=192 r=10 14: a=224 r=3 16: a=255
5 pceff04.t32 0: a=0 r=90 8: a=128 r=30 12: a=192 r=10 14: a=224 r=3 16: a=255
$ sylpheed-cli screen info --build 10 --geometry /disc/dat/GP_DEBRIEFING_PILOTLOG.pak
5 pjeff24a.t32 382x140 0: 335,49 210%,210% a=53 r=90 (one keyframe)
```
Both stand unchanged.
### 🔴 The one real defect the sweep found
[`ui-keyframe-time-unit.md`](../ui-keyframe-time-unit.md) headed a five-row table
*"declared element (build 11)"*. Its first row is `palogo_sqex.t32` — and
`--all --build 11` does not contain it:
```
--all --build 10 palogo_sqex, palogo_sqex_eff
--all --build 11 palogo_gamearts{,_eff}, palogo_seta{,_eff}, palogo_anima{,_eff}
```
The rows span **two** bundles. All five placements re-verified and are correct —
`palogo_sqex.t32` 666×68 @ (309,330) in build 10, `palogo_gamearts_eff.t32`
521×91 @ (379,154) in build 11 — so the measurement the table supports (the ramp
is linear) is untouched. Only the label was wrong. Fixed: the table now carries a
per-row bundle column.
That is the shape worth remembering: **the index error did not corrupt the
numbers, it corrupted the sentence around them**, and the numbers kept validating.
## ⚠️ For the port: this is an addressing hazard, not a decoding one
If you address bundles by **pak entry index** — which
[`ui-splash-addressing.md`](../ui-splash-addressing.md) recommends for the
splashes — and cross-reference a doc that says "build 6", those are different
objects on 21 archives. When quoting an index, say which kind it is. Our docs
now say *ordinal* or *entry*.
## Refutation attempted — `sylpheed-port`'s corrected mid-ramp test — **survives**
The port withdrew their own `title_jp` "separating case" this iteration, on the
grounds that `ptlogo_all_eff` **holds** a=127 from t=112 to t=246 rather than
ramping through it, so their old `0 < alpha < 255` test had counted a steady
semi-transparent glow as a transition. Their whole correction — and the 5/5
result they say survives it — rests on the keyframes of that one element, which
is disc data and therefore mine to check. Quoted against the disc:
```
$ sylpheed-cli screen info --build 7 --geometry /disc/dat/GP_TITLE.pak
29 ptlogo_all_eff.t32 538x255 0: a=0 76: a=0 112: a=127 246: a=127 258: a=0
(kind 0x3000, 200%,200%, position constant)
```
Their quote `[0:a0 76:a0 112:a127 246:a127 258:a0]` is **exact**, and a=127 is
held flat across 134 units with nothing else moving. It is a plateau. The
refutation fails and their correction stands — including the part that costs
them, since it removes the one case that would have separated their hypothesis
from mine.
⚠️ Note what this does *not* establish: that a=127 is a glow. That reading is
theirs and rests on kind `0x3000` and the 200 % scale, neither of which I have
tested against the running game. What I checked is the keyframes.
## What this does not settle
* Whether anything **outside `docs/`** — scripts under `tools/`, committed test
fixtures — hard-codes a build ordinal for a diverging archive. I swept the
prose, not the code.
* The three identity archives are identity *today*. Nothing enforces it; a change
to `is_build` moves every ordinal on the disc. This is a property of a
predicate, not of the format.