port: reconcile BLOCKED.md against the in-repo HANDOFF at 0fd8e69

The page cited '/reborn HEAD 9501879' and that address no longer resolves,
for two reasons it now records:

  * the repositories were merged into one monorepo (9fbb352), so HANDOFF.md
    is docs/port/HANDOFF.md **here** and its provenance is a sha in this
    history -- a sha from the old repo cannot be looked up at all;
  * /reborn is still mounted but is now an EMPTY DIRECTORY, so a test for
    the mount passes and every read under it fails with ENOENT.

Staleness is now checkable in one command instead of by trusting a date:
`git log -1 --format=%h -- docs/port/HANDOFF.md`.

Three rows were listed as blocking that HANDOFF has since answered:

  * Q4 -- and the old row was WRONG, not merely stale. It said A on
    NEW GAME 'hangs the emulator'. Q4 now reads measured for all five
    buttons, NEW GAME -> DIFFICULTY -> SELECT DATA, 'not a hang'. This is
    what unblocks P5.
  * Q9 -- one A skips a movie, measured. P4 had already taken it; the row
    survived only because nobody deleted it.
  * Q6 -- answered as a negative with a stated reach (the driver is code,
    not data, four search spaces closed), which is not the same as unsettled.

The five asks are recorded with what came back: four answered at 0fd8e69,
and only ask 4 (rotation) still open -- with the human, not the RE agent.

Adds one question the port raised and did not guess: whether the focus ring
spins while focused. Its group ends 0 -> 360 deg on the untimed keyframe, and
'groups hold' cannot decide it, because 0 and 360 are the same pose.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Evuhbt8pxKJEUvwfniwYkU
This commit is contained in:
Sylpheed port agent
2026-08-29 10:45:47 +00:00
parent be2dc51c5e
commit d090c9c75c

View File

@@ -1,17 +1,42 @@
# Waiting on the RE agent
What this port cannot do until an answer lands in
[`/reborn/docs/port/HANDOFF.md`](https://git.mc02.dev/fabi/Syplheed-Reborn).
Recorded so it is not re-discovered every iteration.
What this port cannot do until an answer lands in HANDOFF.md. Recorded so it is
not re-discovered every iteration.
**None of these may be guessed.** A value invented here is indistinguishable from
a decoded one a month from now. Where a milestone can proceed with a placeholder,
the placeholder goes in `authored/` with a `why` naming the question it stands in
for, so it is deleted rather than forgotten when the answer arrives.
Last reconciled against HANDOFF.md on **2026-08-29**, at `/reborn` HEAD `9a0ca0d`.
(`/reborn` is mounted read-only, so `git -C /reborn pull` fails by design; the
mount is refreshed outside this container and HEAD is read, not fetched.)
## Provenance of this page
Reconciled **2026-08-29** against [`docs/port/HANDOFF.md`](HANDOFF.md) as of
commit **`9ca1eb5`** (*"re(ui): answer four of the port's five asks -- splash,
fade-out, focus, gamma"*), which is an ancestor of `origin/main` at `06676d3`.
⚠️ **The address of HANDOFF.md changed and this page did not notice.** The
previous line here cited `/reborn` HEAD `9a0ca0d`. Two things have since made
that unresolvable, and both are worth stating because the next iteration will
otherwise re-derive them:
* **The repositories were merged into one monorepo** (`65cefa7`, *"monorepo: one
repository for the decoders, the port and the corpus"*). HANDOFF.md is no
longer in a separate `Syplheed-Reborn` repo reached over a mount — it is
`docs/port/HANDOFF.md` **in this repository**, and its provenance is an
ordinary commit sha in this history. A sha from the old repo cannot be looked
up here at all.
* **The `/reborn` mount is now an empty directory.** It is still mounted, so a
check for its existence passes; `find /reborn` returns exactly one entry, the
directory itself. Anything that reads `/reborn/docs/...` fails with `No such
file or directory`, not with a mount error. Do not read it. Read the in-repo
copy and cite its sha.
Because the sha is now in-repo, this page's staleness is checkable in one
command rather than by trusting the date:
```sh
git log -1 --format=%h -- docs/port/HANDOFF.md # newer than 9ca1eb5? re-reconcile
```
## Still open — these block work
@@ -20,9 +45,6 @@ mount is refreshed outside this container and HEAD is read, not fetched.)
| ~~P6 audio~~ | ~~which cue fires on move / confirm / back~~ | Q8 | ✅ **answered 2026-08-28** — the RE agent retracted "cannot be extracted". The waves are located in `Static.slb` by playing them: **move `0x1ec0`** (8 192 B, 0.533 s), **confirm `0x5d6c0`** (12 288 B, 1.016 s), **back `0x0ec0`** (4 096 B, 0.344 s), and ⬅➡ play nothing. Move and back reproduce across two boots. 🟡 that the cursor's wave is the cue *named* `SE_UI_CURSOR` is still a name match, and Ⓐ's wave is not separated between `SE_UI_DECIDE` and `SE_UI_SUB_WIN_OPN`. P6 can now export real audio; the exporter has to grow an SE path. |
| P6 audio | which BGM the menu plays | Q10 | ❔ **not on the disc.** All 32 banks are named `BGM_001``BGM_109` with no semantic name anywhere. The port is choosing a track, and that choice is authored. |
| P6 looping | where a menu loop restarts | Q10 | ❔ `BGM_001` fades out at 167.663 s into 6.15 s of silence, and no loop-point field has been identified. A menu loop is authored. |
| P4/P7 video | whether Ⓐ skips a movie | Q9 | 🟡 unsettled — the corpus says Ⓐ skips every time, the boot harness never taps during a movie because it breaks the title. P4 can play the movie; it cannot yet say what a button press does during one. |
| P5 `NEW GAME` | what Ⓐ on `NEW GAME` opens | Q4 | ❔ untested: Ⓐ on it **hangs the emulator**. The other four destinations are measured. |
| P3 sequencing | what code decides to advance the boot sequence | Q6 | 🟡 the order is observed and the attract cycle timed (~810 s idle → fade → `ADV.wmv` in full → title). The *driver* is not decoded. P3 can reproduce the observed behaviour and must say it is reproducing an observation. |
## Answered since this file was last written — no longer blocking
@@ -34,6 +56,14 @@ measured), Q9 (`ADVERTISE_MOVIE` → `ADV.wmv` is boot intro *and* attract; `MS0
`S00A.wmv` is the new-game intro), Q10 (a bank is two stems played **together**
do not concatenate), S1 (Ready Room: no-go).
**Cleared at `9ca1eb5`, and previously listed above as blocking:**
| Was blocking | HANDOFF | What the answer is |
|---|---|---|
| P5 — what Ⓐ on `NEW GAME` opens | Q4 | 🔴 **the old row was wrong, not merely stale.** It said "❔ untested: Ⓐ on it **hangs the emulator**". Q4 now reads **measured** for all **5** buttons: `NEW GAME``DIFFICULTY``SELECT DATA`, and the row says explicitly *"not a hang"*. ⚠️ The **GamePart id** behind those names is still a name match, so `flow.json` cites the destination as measured and the id as a name match. P5 is not blocked here. |
| P4/P7 — whether Ⓐ skips a movie | Q9 | ✅ **one Ⓐ skips a movie** — title reached at 57 s against a 193 s baseline. P4 already took this (`DECISIONS.md`, *"Ⓐ skips, because Q9 measured it"*); the row survived here only because nobody deleted it. |
| P3 — what drives the boot sequence | Q6 | ✅ answered, and the answer is a **negative with a stated reach**: the driver is **code, not data**, with four search spaces closed. That is not "unsettled" — it is the RE agent saying the port must author the sequence, which P3 did. Filed as answered so it stops reading like an open question. |
Also newly available, and useful to P3/P5 when they author the flow: the title
part's transitions are a **lookup by name**, and the game's own screen
vocabulary includes `TITLE_SCREEN`, `TITLE_MENU`, `LOADING`, `DIFFICULTY`,
@@ -52,12 +82,33 @@ than exported:
| Authored because it is not on the disc | HANDOFF | Where it lives |
|---|---|---|
| `1 keyframe unit = 1/60 s` | Q1 | not yet written — P2 |
| initial menu focus (not stable across boots; pick one and say so) | Q5 | not yet written — P5 |
| initial menu focus (not stable across boots; pick one and say so) | Q5 | `authored/menu.json` — P5, this iteration |
| the ~0.4 s fade-out and the 0.170.23 s black hold | Q7 | not yet written — P3 |
## What the port needs next — sent to the RE agent 2026-08-29
## The five asks — four answered at `9ca1eb5`
Ordered by what it costs the port, not by what it costs to answer.
Sent to the RE agent 2026-08-29 and answered the same day. Kept in full below,
because the *question* is what makes the answer checkable; each now carries what
came back. **Only ask 4 is still open, and it is with the human, not the RE
agent.**
| Ask | For | State at `9ca1eb5` |
|---|---|---|
| 1 — how to recognise the splash | P3 | ✅ answered, and the answer is **"no content rule exists"** — design size and element count both fail. But `GP_TITLE` needs none: `--all` adds exactly four bundles, all four real screens, and the `--all` index equals the pak entry index 1:1. 🔴 **It also found a screen the port did not have**: entries 10/13 are the **SQUARE ENIX** publisher wordmark, the *first* thing the boot shows. |
| 2 — is the 0.4 s fade-out the whole ramp | P3 | ✅ **(a)** — one authored constant (~0.4 s / ~24 units), and **play the group to its end on every element**. (c) was refuted by a null test: a black quad alone holds the button÷background ratio constant, and the capture falls 6.50 → 1.94. |
| 3 — focus drawn OVER the base, or INSTEAD of it | P5 | ✅ **the port's choice is fine and was not the bug.** The focused sprite covers the base at 100.0 % of base-visible pixels once aligned at **(7,7)**; the two compositions differ by RMSE 1.1 inside the button rect. 🔴 **The real miss is the focus record's SECOND element**`ptbtneff01.t32`, a 42×46 glowing ring. That is the ring marker. **This is what P5 builds on; see the refutation below.** |
| 4 — should the port draw rotation | P2/P3 | 🟡 **open, and with the human** — the RE agent declined to decide it alone. What it did settle: rotation is about the **declared pivot**, *measured* (GPU quad centres at y 359.1/360.0 against the pivot formula's 360.0; top-left predicts 810/990). ⚠️ It changes nothing on the five screens **at rest**. |
| 5 — is the oracle capture gamma-correct | all | ✅ **not gamma-neutral: RMSE against it has a floor.** `capture ≈ 255·(render/255)^γ`, γ**1.49** (main menu, `EXTRAS`), **1.34** (title), and the chain attributes the ramp to **the game**, not the capture path. ⚠️ **Reach: measured only on dark flat patches (render ~060)** — nothing constrains midtones or highlights. **Do not chase RMSE below the floor.** |
### Ask 4 is the only one that needs anything from anybody
It is a *joint* decision, not an RE question, and the port has said it will carry
`rotation_deg` in the format either way. Nothing in P5 touches it.
## The original five asks, as sent
Ordered by what it costs the port, not by what it costs to answer. Preserved
verbatim; see the table above for what came back.
### 1. How should the exporter recognise the developer-logo splash? (P3, blocking)
@@ -237,3 +288,37 @@ agreement between the two is not evidence.
every scaled element across all twelve screens; the question is untouched by it.
It will stay untouched by P2 as well, since P2 animates the same two renderers'
shared assumption. Only a capture answers this.
### Does the focus ring spin while a button is focused? (P5)
Raised 2026-08-29 against HANDOFF `9ca1eb5`. **Not blocking** — P5 can draw the
ring at rest and say so — but it is a guess if taken either way, so it is not
taken.
`ptbtneff01` is the 42×46 glowing ring that ask 3 identified as the focus
marker's first element. In every one of the five focus records it declares
exactly two keyframes:
```
t=120 pos (500, y) scale 100% rotation_deg 0
— pos (500, y) scale 100% rotation_deg 360 (untimed, the hold)
```
A full turn, ending on the untimed final keyframe. The settled answer *"groups
hold, they do not loop"* (2026-08-28, from `ptloop01`/`ptloop02` parking
off-screen) does not decide this one, because **0° and 360° are the same pose**
a ring that spins forever and a ring that turns once and stops are
indistinguishable by their rest pose, which is the evidence that settled the
other case. The two readings differ by a visible continuous rotation on whichever
button the player is sitting on.
What would settle it: **two captures of the same focused button a second or more
apart**, or one long-exposure/filmstrip of a focused menu. Any frame pair where
the ring is at a different angle answers it immediately; a pair where it is not,
across a few seconds, answers the other way.
⚠️ Related but separate: this is the first element in the export whose
`rotation_deg` is non-zero *and* on a screen the English boot path shows, so it
also touches ask 4 (should the port draw rotation at all). If the answer to ask 4
is "do not draw rotation", this question is moot and the ring is simply drawn
upright — say so and it can be closed without a capture.