port: audit the handoff -- four stale statements, a broken link, and the

residue in one place

Every MISSION row is answered, so this iteration checked the deliverable
itself rather than opening new scope: an answer that is not reachable
from HANDOFF.md has not been delivered, and I have been editing that page
by surgical replacement for a dozen iterations.

Four things were wrong or stale:

- the Q5 row still said initial focus was 2x TUTORIAL, 1x NEW GAME while
  its own bullet said four boots -- I updated the body last time and not
  the row;
- the Q2 bullet still described the other four main-menu destinations as
  "likely by name -- an inference, not a measurement", which Q4 has since
  MEASURED, and it listed GP_MISSION_SELECT as a main-menu destination
  when MISSION SELECT lives under EXTRAS;
- the Q1 bullet claimed that if the game presents at 60 Hz "nothing else
  on this page changes". That is now false: Q7's declared fade-in lengths
  are keyframe-derived and would halve. The same bullet also missed that
  the transition capture is a SECOND independent measurement supporting
  1 unit = 1/60 s -- the quad is declared black for 12 units, 0.20 s
  under the conversion, and the capture measured the plateau at
  0.17-0.23 s. Recorded as corroboration, not proof, because the plateau
  spans two screens' fades and cannot separate them;
- bgm-two-stems.md linked ../port/MISSION.md from inside structures/,
  which resolves nowhere.

Also named the two videos actually in scope, since "3.3 GB of video, two
files are in scope" is not much use without the filenames.

And added a What Is Still Open section. With every row green the residue
was scattered across eight pages; it is now one table with why each item
is stuck. Two entries share a single unblocker -- an emulator whose audio
path can be observed -- and they are the only ones that would change a
port decision.
This commit is contained in:
Sylpheed RE agent
2026-08-28 19:02:49 +00:00
parent f5e7426cfa
commit 2c4005795b
2 changed files with 41 additions and 12 deletions

View File

@@ -31,7 +31,7 @@ authored version can be deleted.
| Q2 | which build is which screen state | ✅ answered | `GP_TITLE` is **8 screens shipped twice, EN/JP**: 4/7 title art, 2/3 the `PRESS Ⓐ` plate, 5/8 main menu, 6/9 `EXTRAS`, 0/1 and 10/11 two unidentified `DELTASABER` plates — [`ui-title-build-map.md`](../re/ui-title-build-map.md) |
| Q3 | paint order for the six screens | ✅ answered | **decoded**: a `u16` layer key at `+0x0A` of each `T8aD` sprite header, stable-sorted with declaration index; unkeyed elements get an implied key. Confirmed on 5 measured orders + `EXTRAS` vs a capture. One residual: the **tie-break** is unknown and bites on one element of the title — [`structures/ui-paint-order-key.md`](../re/structures/ui-paint-order-key.md) |
| Q4 | button → GamePart | ✅ answered | **measured** which screen all **5** buttons open — `NEW GAME``DIFFICULTY``SELECT DATA`, not a hang. The **GamePart id is still a name match**, not a measurement — [`menu-navigation-semantics.md`](../re/menu-navigation-semantics.md) |
| Q5 | navigation semantics | ✅ answered | **measured**: initial focus varies boot to boot (2× `TUTORIAL`, 1× `NEW GAME`); ⬆⬇ one step, **wraps both ends**; ⬅➡ do nothing; Ⓑ returns to the parent **with focus restored**; Ⓑ on the main menu → title; Ⓑ on the title → nothing — [`menu-navigation-semantics.md`](../re/menu-navigation-semantics.md) |
| Q5 | navigation semantics | ✅ answered | **measured**: initial focus varies boot to boot (2× `TUTORIAL`, 2× `NEW GAME`); ⬆⬇ one step, **wraps both ends**; ⬅➡ do nothing; Ⓑ returns to the parent **with focus restored**; Ⓑ on the main menu → title; Ⓑ on the title → nothing — [`menu-navigation-semantics.md`](../re/menu-navigation-semantics.md) |
| Q6 | boot sequence + what drives it | ✅ answered | sequence **measured** end to end; the driver is **code, not data** — four search spaces closed, so the port **authors** the sequence — [`boot-config-and-gamepart-registry.md`](../re/boot-config-and-gamepart-registry.md) |
| Q7 | transitions | ✅ answered | a **fade through black**, drawn by the screen's own last-painting `.prm` quad. Fade-in ramp is **decoded** from its keyframes; the ~0.4 s fade-out is **measured** (not in the file) — [`screen-transitions.md`](../re/screen-transitions.md) |
| Q8 | menu audio bindings | ✅ answered | cue vocabulary + bank **decoded**; event binding is a **name match** (the authors' own event names); SE audio is **undecodable from the disc** — no XACT container exists anywhere — [`menu-audio-cues.md`](../re/menu-audio-cues.md) |
@@ -51,9 +51,8 @@ authored version can be deleted.
captures for the four English screens the boot path shows;
[`ui-title-build-map.md`](../re/ui-title-build-map.md).
**Withdrawn:** the earlier "builds 6/8/9 are submenus" — 8 is the Japanese main
menu. The other four main-menu buttons leave the archive (`GP_SAVE_LOAD`,
`GP_TUTORIAL`, `GP_OPTIONS`, `GP_MISSION_SELECT` are the likely destinations by
name — an inference, not a measurement).
menu. The other four main-menu buttons leave the archive, and where each one
goes is **measured** — see the button-destination bullet below.
* **Buttons are identifiable as data.** Element kind `0x3002` = button, `0x0` =
decoration, `0x10` = primitive. ✅ decoded **for the title-side screens**.
⚠️ `0x3002` is one member of a `0x3000` family with sub-bits, and it is not the
@@ -78,10 +77,18 @@ authored version can be deleted.
with `k` stepping 2, 4, 6, 8, 10, 12, 14 on seven consecutive submitted frames.
**measured**, not decoded — the disc says `t=30`, it does not say what a `t` is.
The seconds conversion (`1 unit = 1/60 s`, so a 30 fps screen) rests on a
measured 27.6 present-frames/second and is the one part still worth re-testing;
[`ui-keyframe-time-unit.md`](../re/ui-keyframe-time-unit.md) names the test.
If it turns out the game presents at 60 Hz, every duration halves — nothing
else on this page changes.
measured 27.6 present-frames/second; [`ui-keyframe-time-unit.md`](../re/ui-keyframe-time-unit.md)
names the re-test. 🟡 **A second, independent measurement now supports it**: the
transition quad is declared black from `t=0` to `t=12` — 12 units, i.e. 0.20 s
under this conversion — and a 30 fps capture measured the pure-black plateau at
**0.170.23 s** ([`screen-transitions.md`](../re/screen-transitions.md)). That
is corroboration and not proof: the plateau spans the outgoing screen's
fade-out tail as well as the incoming screen's black, and this measurement
cannot separate them.
⚠️ If the game turns out to present at 60 Hz, **every duration on this page
derived from keyframe units halves** — including Q7's declared fade-in lengths
(0.87 s / 0.97 s / 4.08 s). The wall-clock numbers measured off a capture (the
~0.4 s fade-out, the black hold, the attract timings) do not move.
* **The paint order is derivable from the file.** Each `T8aD` sprite header
carries a **`u16` layer key at `+0x0A`** (the upper half of the 32-bit word at
`+0x08` is zero in all 21 184 sprites on the disc). Paint order is that key,
@@ -105,7 +112,8 @@ authored version can be deleted.
nothing. Ⓑ goes up one level **and restores focus to the item you came from**;
Ⓑ on the main menu returns to the title; Ⓑ on the title does nothing. **Initial
focus is not stable**: four boots of the same script gave `TUTORIAL`,
`TUTORIAL`, `NEW GAME`, `NEW GAME`. Do not hardcode it; pick one and say you picked it. All **measured**, none of it on the disc.
`TUTORIAL`, `NEW GAME`, `NEW GAME`. Do not hardcode it; pick one and say you
picked it. All **measured**, none of it on the disc.
* **Each button's destination is measured; its GamePart id is not.**
**`NEW GAME``DIFFICULTY`** (`EASY`/`NORMAL`/`HARD`/`BACK`, opening on
`NORMAL`) **`SELECT DATA`** — it does *not* hang; the run then hits the
@@ -208,8 +216,10 @@ authored version can be deleted.
* **`ADV.wmv` is WMV3 video + WMA Pro audio**, 1280×720 at 30 fps, 137 s. Godot 4
plays only Ogg Theora natively. How to handle that is the port's decision, not
ours — but it is not optional.
* **The disc holds 3.3 GB of video.** Only the boot intro and the one new-game
intro are in scope.
* **The disc holds 3.3 GB of video, and exactly two files are in scope:**
`dat/movie/ADV.wmv` (the boot intro *and* the attract loop — one asset) and
`dat/movie/S00A.wmv` (the new-game intro, 93.9 s). Named from the movie
manifest, ✅ decoded.
* **`Static.slb` over-declares its size** by 616 768 bytes — it is the
highest-offset entry in `sound.pak` and its size field is an allocation size. A
reader must allow a short read there and only there.
@@ -234,6 +244,25 @@ authored version can be deleted.
* **`JNGL_001.slb` does not decode.** One bank in 9 519; its payload is not a whole
number of XMA1 packets from any known data offset.
## What is still open
Every question above is answered, so this is the honest residue rather than a
work queue. **None of it blocks the five screens.**
| | what | why it is stuck |
|---|---|---|
| 🟡 | **cue → event binding as a measurement** (Q8) | nobody has watched the game emit `SE_UI_CURSOR` on a d-pad press. Needs the guest's cue call observed with its argument |
| ❔ | **the wave index into `Static.slb`** (Q8) | same instrumentation. This container runs `--mute=true` against an SDL dummy device, so it cannot watch the audio path at all |
| 🟡 | **the paint-order tie-break** (Q3) | eight candidates refuted; costs one element's blend on one screen |
| 🟡 | **GamePart ids behind the buttons** (Q4) | the *screens* are measured; the ids are a name match onto the executable's class names |
| 🟡 | **`1 unit = 1/60 s`** (Q1) | two independent measurements agree, neither is proof; if it is 60 Hz every keyframe-derived duration halves |
| ❔ | **the boot transitions in code** (Q6) | bounded as code-not-data, not proven. `sub_821C6458` — the substantial function in `GamePart_Title`'s neighbourhood — has **not been read** |
| ❔ | **`MS00A``S00A.wmv` never watched** (Q9) | decoded from the manifest; the one run that reached it crashed at `SELECT DATA` first |
| ❔ | **builds 0/1 and 10/11**, the `DELTASABER` plates (Q2) | never seen on screen anywhere in the boot path, the title-side screens or the attract loop |
The first two share one unblocker — an emulator build whose audio path can be
observed — and would be the only entries here that change a port decision.
## Reference data
Committed alongside the findings, so the port can be built without a disc in the

View File

@@ -5,7 +5,7 @@ over all 32 BGM banks. 🟡 for the *role* of the second wave — **measured** b
signal analysis, and the two readings that survive are named below. ❔ which bank
is the menu's music is **undecodable from the disc**, with the reach stated.
Answers [MISSION Q10](../port/MISSION.md). It also **withdraws the premise**: the
Answers [MISSION Q10](../../port/MISSION.md). It also **withdraws the premise**: the
handoff said `BGM_001.slb` is *three* sub-waves of 10 KB / 4.47 MB / 4.67 MB. The
10 KB is the bank **header**, not a wave.