# 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. **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-28**, at `/reborn` HEAD `8b4965f`. (`/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.) ## Still open — these block work | Milestone | Needs | HANDOFF | State | |---|---|---|---| | ~~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 Q1 (keyframe time unit — linear ramp, 2 units per rendered frame, 1 unit = 1/60 s *measured*), Q2 (which build is which screen), Q3 (paint order — a `u16` layer key at `+0x0A`, **decoded**), Q5 (navigation: ⬆⬇ wrap, ⬅➡ nothing, Ⓑ up with focus restored), Q7 (transitions: a fade through black, fade-in decoded, ~0.4 s fade-out measured), Q9 (`ADVERTISE_MOVIE` → `ADV.wmv` is boot intro *and* attract; `MS00A` → `S00A.wmv` is the new-game intro), Q10 (a bank is two stems played **together** — do not concatenate), S1 (Ready Room: no-go). 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`, `EXTRA_MENU`, `TUTORIAL_MENU`. Three of those are corroborated by measurements taken before the function was opened (`DIFFICULTY` is what `NEW GAME` opens, `EXTRA_MENU` is `EXTRAS`, `TUTORIAL_MENU` the lesson list). 🟡 **Candidate, not decoded** — the RE agent is explicit that the strings are what the call sites *reference*, not proven arguments, and the same list mixes in `TEXT_FONT` and `GAMMA_RGB`. So `authored/flow.json` may use these as `goto` names — which is better than inventing names — but must mark them as a name match, not a measurement. Three of those are **measured**, not decoded, and so are authored here rather 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 | | the ~0.4 s fade-out and the 0.17–0.23 s black hold | Q7 | not yet written — P3 | ## Questions this port has raised ### Does a keyframe group loop, or hold its last pose? Raised at P2 and **unsettled**. The port holds the last timed keyframe, which is right for an entry animation (the main menu settles at t=80, 1.33 s) and is proven on the screen P2 gates. The **title** runs to t=269 — 4.48 s — and there the port's settled pose and the decoders' `rest` disagree badly (max 142/255). What is known: no element's alpha reverses direction anywhere in this export, so nothing pulses, which removes the obvious reason to expect a loop without disproving one. What would settle it: **a capture of build 4 alone**. The one live title capture composites the `PRESS Ⓐ` plate (build 2) over it, so it cannot be diffed against the title by itself. ⚠️ Independently, **both** of the port's modes draw a washed-out cyan glow over the title logo that the running game does not have. That is a third problem and it is P3's; it is noted here so nobody reads the loop question as its cause. Not blocking anything today; raised because the port found them and a guess here would be believed later. ### `rest_plateau` misfires on elements with no exit animation **This one is a decoder bug, not a question**, and it is the highest-value item on this page for the RE agent. `ui_layout::rest_plateau` excludes a run of identical keyframes that ends the group, on the grounds that it is the exit. For an element that **has no exit animation** the trailing run *is* the hold, and the rule falls back to an earlier run — for a slide-in, the invisible pre-roll. The condition that identifies the affected elements exactly, with no false positives across this export, is: **the final untimed keyframe has the same pose as the last timed one.** Six elements match; `rest()` misses all six. `ptframe1` and `ptframe2` on the main menu are the visible case, and `docs/re/captures/main-menu-oracle.png` settles it — the game draws the circuit bracket that `rest` calls invisible. `sylpheed-cli screen render` is missing it too, so this is not only a port concern. The port needs nothing here: it derives the arrived pose from the keyframes and does not use `rest`. Filed because `rest()` is used elsewhere and because a capture already proves it. ### Does the game sample a scaled sprite at the pixel corner or the pixel centre? Found at P1, by the only screen it could have been found on. `title_jp`'s `ptlogo_eff2` is the **single drawn element in the whole export** at a scale that is not a whole multiple of 100 % (125 %), and `title_jp` is the only one of the twelve screens whose Godot-vs-CLI diff exceeds 6/255. The two renderers pick different source texels at a non-integer ratio. `sylpheed_formats::ui_layout::blit` samples at the destination pixel's **top-left corner** (`sxi = col * sw / dw`); a GPU samples at its **centre** (`floor((col+0.5)*sw/dw)`). At 125 % they disagree on one column in five — ~30 pixels above 100/255, strung along thin diagonal edges. At every whole multiple of 100 % they agree exactly, which is why the other eleven screens are clean. The port has **not** changed to match: matching would mean reproducing a half- pixel bias on purpose to make a number smaller. The question for the RE agent, when it is cheap: **a framebuffer capture of the Japanese title screen** would settle it outright, and it is the kind of thing a capture answers in one look. Cost of being wrong either way: a one-texel edge on one glow, on a screen the English boot path never shows. This is filed, not urgent. ### The pivot is not half the texture on `GP_TITLE` `sylpheed-formats`'s `ui_layout::Element::pivot_x` is documented as "for a `.t32` element this is exactly half the decoded texture's dimensions (verified 7/7 on the tutorial bundle)". Counting it over the whole of `GP_TITLE` as exported: * **55 of 93** sprite-bearing `.t32` elements match within ±1 px. * **38 do not**, and several are not close: `ptlogo_back2` is 1118×262 with pivot (500, 117) where half is (559, 131); `ptmsg` is 223×38 with pivot (123, 19) where half is (111.5, 19) — the Y matches and the X does not. This changes nothing today: the exporter emits the **declared** pivot and never derives one, and the pivot only affects drawing when scale ≠ 100 %. But it does matter, because scale is genuinely animated here — **177 keyframes** across `GP_TITLE` are not 100 %, including on the title screen the port must draw at P1. The question for the RE agent, when it is cheap to answer: **does the running game anchor a scale to the declared pivot, or to half the texture?** The two differ by up to 59 px on `ptlogo_back2`, which is visible. Until then the port follows the decoders and uses the declared pivot, which is also what `sylpheed-cli screen render` does — so a P1 diff cannot distinguish them, and agreement between the two is not evidence. **P1 has now been run and that prediction held.** The port and the CLI agree on 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.