From cd1b6cfe727ec6906c8c9766537e94ee3ae7b1ff Mon Sep 17 00:00:00 2001 From: Sylpheed port agent Date: Sat, 29 Aug 2026 10:45:47 +0000 Subject: [PATCH] port: reconcile BLOCKED.md against the in-repo HANDOFF at 9ca1eb5 The page cited '/reborn HEAD 9a0ca0d' and that address no longer resolves, for two reasons it now records: * the repositories were merged into one monorepo (65cefa7), 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 9ca1eb5, 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) Claude-Session: https://claude.ai/code/session_01Evuhbt8pxKJEUvwfniwYkU --- docs/port/BLOCKED.md | 109 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 97 insertions(+), 12 deletions(-) diff --git a/docs/port/BLOCKED.md b/docs/port/BLOCKED.md index 65861483..6ee90dd7 100644 --- a/docs/port/BLOCKED.md +++ b/docs/port/BLOCKED.md @@ -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 (~8–10 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.17–0.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 ~0–60)** — 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.