Files
Sylpheed/docs/port/BLOCKED.md
Sylpheed port agent 678467549b port: a withholding reason was false -- the hidden leaf is a visible expanding ring
authored/rendering.json justified not drawing build_12,15/pgloading_loop5 with
'leaf scale (0,0)'. That describes t=0 and t=30 and nothing after. The leaf holds
pgloading_ring, scale ramping 0 -> 250 -> 800 -> 1000 with alpha full at t=55 --
an expanding fading ring, visible at scale 140 alpha 143 at the port's own pose
instant near t=44. Withholding it declines to draw SOMETHING.

Still withheld, on the reason already in the file: no oracle capture for a
loading screen and verify-screen's reference draws no leaves, so the content is
unadjudicable. Behaviour unchanged at 59530 px.

The two entries in that list were written to different standards -- ptlogo_eff2
gets four paragraphs working through both readings, pgloading_loop5 got one false
line. The difference is that one was interesting and one was a loading screen.

Also verifies the measurement in the same paragraph: 'max went 155 -> 232 when
drawn' reproduces at 231, differing pixels 20498 -> 58313. The file's numbers
were sound and its reasoning was not, in adjacent sentences.

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

66 KiB
Raw Blame History

Waiting on the RE agent

This page is the port's standing ask list. If you are the Decoder and you have just started: everything the port needs from you is in the tables below, with the HANDOFF commit each row was derived from. You do not have to ask what is blocking the port; this is the answer, and it survives a restart.

⚠️ It is not in your loop brief's read list. docs/agents/decoder-loop.md names PROTOCOL, MISSION.md, HANDOFF.md, REFUTED.md, METHOD.md, INDEX.md, docs/game/navigation.md and CONTAINER-NOTES.md — not this file. That gap has now cost three sessions: the port's open asks have been delivered by message three times and lost three times, because a message dies with the container and this page does not. Whether the brief should change is the human's call, not either agent's. Until it does, read this page anyway.

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.

Provenance of this page

🟢 The oracle is live again (2026-08-29). The Decoder reports over the message channel that MISSION's 🔴 "emulator-side questions are blocked / the title is not reachable" banner is withdrawn — two boots reached the interactive title with no pad input. A message is not a mission change and this line does not act as one (PROTOCOL: only the human changes a mission). It is recorded here for one practical reason: several rows below say "what settles it: a capture" and were written when no capture could be taken. Those are now askable.

Reconciled 2026-08-29 against docs/port/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. Re-checked at P5 against HEAD = 60595d4: git log -1 --format=%h -- docs/port/HANDOFF.md still answers 9ca1eb5, so HANDOFF itself has not moved.

Re-checked at P6 against HEAD = aebd79a (merged with origin/main at 2021eee). HANDOFF still answers 9ca1eb5 — it has not moved in three milestones — and the second-half check below is what found this iteration's change, exactly as it was written to.

🔴 HANDOFF has not moved, and that is now the problem. The check above tests whether this page is stale relative to HANDOFF. It cannot see the other direction, and the other direction is what happened: 7eeae30 ("re(ui): the focus ring SPINS, the game draws it, and the leaf owns the f record", 08:46) lands 27 minutes after HANDOFF was last written (9ca1eb5, 08:19) and answers a question HANDOFF still lists as open under "Questions this port has raised". Both are ancestors of HEAD.

So the staleness check needs a second half, and this is it:

git log --oneline 9ca1eb5..HEAD -- docs/re/    # RE landed since HANDOFF was written?

Anything it lists may already answer a row below. The Decoder has been told over the message channel that HANDOFF needs 7eeae30 folded in; rewriting HANDOFF is not the port's to do.

⚠️ 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:

git log -1 --format=%h -- docs/port/HANDOFF.md   # newer than 9ca1eb5? re-reconcile

Still open — these block work

🔴 This table's rows carry no derivation sha, and that is why they rot. The standing instruction is to record the HANDOFF commit each row was derived from; every prose section added since does, and every row in this table and the next does not. On 2026-08-30 an audit found three stale rows here — one of them contradicted by a struck row four lines below it, claiming the boot ends on a plateless title when it had drawn the plate for weeks. The undated rows are exactly the ones that went stale, which is as close to a controlled experiment as this page is going to get.

⚠️ Rows are not being back-dated: nobody knows when most were written, and inventing a sha would be worse than admitting there is none. New rows carry one. This table was last audited 2026-08-30 against a running port.

Re-checked at the voice export, HEAD = 3a4c6ac (merged with origin/main at 1b1a4df). git log -1 --format=%h -- docs/port/HANDOFF.md still answers 9ca1eb5 — HANDOFF has not moved in four milestones. The second-half check, git log --oneline 9ca1eb5..HEAD -- docs/re/, lists four commits, of which 3491d30 ("the disc ships movies in TWO audio profiles, and 28 of them are 5.1") is the one this iteration used and 7eeae30 is still unfolded into HANDOFF.

Milestone Needs HANDOFF State
P1P7 — the paint-order tie-break how many pixels can a wrong tie-break cost? Q3 MEASURED TO ZERO on every screen this port ships, 2026-08-29 (docs/re/structures/ui-tie-break-cost-at-settle.md). The old figure — 24 overlapping tied pairs — was a rest() count, and 10 of the title's 11 tied pairs are between the five transient flashes, which are transparent on a settled screen. The only non-zero anywhere in GP_TITLE is 1 px at Δ1 on the Japanese title. Not a knife-edge either: sweeping every keyframe time and midpoint, the live-pair count is flat across the whole settle window. ⚠️ Four loading bundles report zero with no live control, so those are a weaker zero than the other six. Why ties order as they do is still unknown — it now costs one pixel, on a screen out of scope.
P4/P7 — the intro's dialogue why the intro has no voices Q9 answered and TAKEN 2026-08-29, and the obvious diagnosis was wrong. Not a transcode fault: ADV.wmv carries music and effects only, and a cutscene's voice is a separate continuous XMA stream in sound.pak bound by the movie manifest. audio::export_voice now resolves it with media::resolve_movie_voice_region — never by filename, because RT01A's voice lives inside VOICE_ADV.slb and a name match is right on exactly the two movies this port would have spot-checked. This is decoded, nothing authored. ⚠️ This row's original text said the region's chunks are "concatenated (one continuous stream), not summed" — that was the first of three wrong readings and it is superseded; see the incomplete-export row below for where it ended up. Left visible rather than silently rewritten, because the sequence of wrong readings is what makes the final one checkable.
P4/P7 — the movie downmix is the exporter allowed to ship a matrix MISSION §6 did not pin? 🔴 with the HUMAN, not the Decoder, and now visible for the first time. §6 pins the 5.1 fold as a human decision of 2026-08-29; video.rs has shipped that matrix scaled by 0.4142 since P4 — same weighting, 7.65 dB quieter — and said so nowhere. Re-measured this iteration with the right instrument (float decode, whole file, count the samples that would clamp, not a peak reading): under the pinned matrix ADV peaks at +4.26 dBFS with 4 406 samples at or over full scale and 1 874 more than 1 dB over, while S00A peaks at 1.34 dBFS and never clips. So the pin overloads one movie and the exporter's constant is over-broad for the other. Smallest single scalar under which neither clamps: 0.612, +3.39 dB on today. Not changed — the level of a mix is what §6 reserves. The export now carries a manifest warning with these numbers.
P4/P7 — a voice region's chunks what is the leading chunk, and is the second one played? CLOSED 2026-08-29, decoded disc-wide, and it cost this exporter three wrong readings in one session. A region carries three presentations of one take — the Decoder counted stream starts inside every inter-descriptor span: 258 spans hold one, 28 hold three, nothing holds two (auto/no-disc-and-menu-captures at 801062c). So 359 = 84.55 + 137.32 + 137.32. My concatenation was wrong, my "two stems" reading was wrong (and had already been adopted into the Decoder's page before I tested it — withdrawn in both), and summing was wrong a third time because a take plus a 0.60× copy of itself is ~4 dB louder and coloured. The exporter now keeps one stream and does no arithmetic on it. The leading chunk is this movie's own dialogue, and I measured it to be the tail of the kept stream (r=0.998 / 0.932, controls 1.000 and 0.289), so dropping it removes a duplicate. 🟡 What is left open is which presentation to keep: the selector is highest byte rate on the Decoder's recommendation, nothing on the disc says which the game plays, and on ADV it picks the quieter of two. Settled by a capture of the movie's dialogue level. Why the disc stores three at all is unanswered by either agent.
P4 — is an attract movie skippable at all? does the real game let Ⓐ end ADV, or does it play through? Q9 🟡 (a) ANSWERED, (b) still open — corrected 2026-08-30. The headline used to say the port could not tell which bug that is. It can and it did: DECISIONS.md records does skip the intro in this build, and every boot run since prints video skipped at …. It is implemented, not assumed: authored/flow.json carries skippable: true with a why citing Q9 as measured (title at 57 s against a 193 s baseline), and boot.gd _unhandled_input acts on it. What did not exist was any way to test it: --script structurally cannot press during a movie, because _script_settled waits while _player != null. --skip-at=SECONDS was added this iteration to close that hole. ⚠️ Two different questions sit behind the one symptom, and only the first is mine: (a) does the synthetic press reach _unhandled_input — measurable here; (b) does the game permit skipping an attract movie — INDEX.md still marks skippability 🟡 and only a capture settles it. If (b) is no, the port's skip path is deleted rather than debugged. Asked 2026-08-29.
P5 — a real submenu cycle is any submenu reachable without a new archive? Q2/Q4 already shipped at P5, and one premise of the ask is refuted by this repo. ptbtn05 (EXTRAS) → screen extras (entries 6/9), and extras' on_cancel returns to main_menu with focus restored — a full main-menu → submenu → back cycle, in GP_TITLE, live since P5. ⚠️ Build 8 is not a submenu. It is main_menu_jp, the Japanese five-button main menu; authored/screen_names.json records that an earlier reading called 8 a submenu and that HANDOFF Q2 withdrew it against a capture. That coordinates identical to build 5 mean a language twin rather than a second menu is exactly the inference the port is not allowed to make on layout similarity — in either direction. The other four main-menu items really are blocked: GP_SAVE_LOAD, GP_OPTIONS, GP_MISSION_SELECT and the DIFFICULTY/TUTORIAL_MENU builds are not in this archive.
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. TAKEN at P6, 2026-08-29. The three offsets now live in authored/audio.json se.*not in the exporter — because MISSION §3 puts a measured value in authored/ and a measured offset compiled into a Rust const is a measurement wearing the costume of a decoded field. sylpheed_formats::media::se_wave_riff does the assembly.
P6 audio which BGM the menu plays Q10 🔴 THIS ROW WAS WRONG WHEN IT WAS WRITTEN, and the port acted on it. It read "not on the disc … the port is choosing a track, and that choice is authored", and P6 duly picked BGM_001 and labelled it arbitrary. The menu's music is BGM_103, and it is in HANDOFF at 9ca1eb5 — the exact commit this page says it was reconciled against. Not stale: misread. HANDOFF's negative is bounded and the bound is the whole content of it — the tables (SOUNDS, FILES, bank headers) name no screen; GamePart_Title's sub_821C5580 carries li r5, 1103, cue 1103 is BGM_103, and BGM_103.slb's two declared waves (3 876 864 / 3 930 112 B) are byte-for-byte the two streams the XMA probe saw decoding at the main menu. HANDOFF's own sentence: "The port does not have to choose a track." The lesson is not "re-read HANDOFF" — this page's own staleness check passed. It is that a row here must quote the reach of a negative, because a negative summarised without its bound reads as a bigger negative than it is.
P6 looping where a menu loop restarts Q10 still open, and the port shipped the ugly answer on purpose. No loop-point field has been identified in any bank — BGM_001 is the one characterised end to end (fades out at 167.663 s into 6.15 s of silence) and nothing suggests BGM_103 differs in kind. authored/audio.json sets loop: "restart" — replay from sample 0 — so the listener hears the fade-out and the trailing silence at the seam. Trimming to the fade would sound better and be worse: it would invent a loop point, and an invented one is indistinguishable from a decoded one a month later. What settles it: a loop-point field, or a capture of the real menu looping. ⚠️ The cost is now measured, 2026-08-30. The bed loops at 87.8 s against the track's own 87.7 — loop: "restart" behaves exactly as authored — and the seam is 36 consecutive near-silent 50 ms windows, 84.4087.80 s: about 3.4 seconds of silence after a fade from RMS 2057 to 431. Long enough to read as the music having stopped rather than looped. That does not license trimming to the fade, which would still invent a loop point; it is recorded so the missing field's price is a number rather than an adjective.
P5 focus marker the focus ring's spin PERIOD, and whether it loops Q1 + "groups hold" answered 2026-08-29, and NOT ON main YET. The Decoder pointed at it over the message channel and the pointer resolves: branch auto/no-disc-and-menu-captures, commit 4fa3099 (branch head 66e74d4), file docs/re/focus-ring-spin-measured.md, frames under docs/re/captures/focus-ring/. The ring spins continuously — period 2.177 s wall-clock, eight evenly spaced autocorrelation peaks over nine revolutions, with no angle estimated anywhere (both angle estimators failed their own controls and were not used). It also reconciles with the declared t=120 without a new constant: 120 units = 60 rendered frames, which is 2.00 s at a true 30 Hz and 2.082.17 s at the 27.628.8 fps this emulator runs, so the measurement sits at the top of the predicted band. 🟡 The Decoder is explicit that this is consistency, not closure — the guest frame rate was not measured in the same run. ⚠️ Do not read captures/focus-ring/ring-20s-mean-uniform.png as a frame: the spin averages to a uniform circle, which is the finding, not a headless ring. The port has not implemented this yet — it still draws 0°, which the same corpus says is a pose the game never shows. That is next iteration's work and it is no longer blocked.
P3/P5 — the title screen does the idle post-boot title show the PRESS Ⓐ plate? Q2 STALE — struck 2026-08-30, and it had been wrong for weeks. Every factual claim in it is now false: the boot does not end on a plateless build 4, press_start is not unused, and the port has drawn two builds at once since the plate-delay work. Verified this iteration — boot ends on title + press_start, overlay press_start … drew 1: ptbtn00, plate region mean 95.70 against 33.6 for the bare title. 🔴 The row directly below it was already marked answered and TAKEN for the same question: two rows on one question, one struck and one live claiming the opposite, and the live one was the stale one. That is this page's own documented failure mode, caught by auditing it rather than by reading it. ⚠️ What remains open is a different question and has its own row: whether the plate stays up after its 8-unit window.
P5 — Ⓑ on the main menu is Ⓑ what returns to the title, or the idle timer? Q5 🟡 stated in HANDOFF, no capture behind it. The title self-returns after ~810 s idle, so one unrecorded observation cannot separate them. authored/flow.json implements it and marks it authored — likely but UNPROVEN. Not blocking — P5 shipped with it — but it is the only navigation rule on that screen with nothing under it. Settled by one run that presses Ⓑ well inside the idle window, timestamped.

| P6 BGM — the sub-wave count | is a music bank's LEADING REGION a stem, or a decoder artefact? | Q10 | CLOSED 2026-08-29 — the census was right and the port was summing a bank header into the music. Decoded and timed, sub-wave 0 of BGM_103, BGM_102 and BGM_001 is identical: 10 300 B → 0.009 s, peak inf, i.e. digitally silent. 10 300 B is the 10 240-byte bank header (the Decoder's disc-wide census) plus a 60-byte RIFF wrapper. So it is not a stem, and export_bgm had been counting it in the divisor — putting every real stem at 1/3 instead of 1/2, 3.52 dB of attenuation on all menu music shipped since P6. Dropping a silent input is arithmetic, not a decoding decision, so this closed on the port's side; measured after the fix, main_menu.ogg goes 7.69 → 4.20 dBFS, +3.49 dB against 3.52 predicted. Corroborates the Decoder's c1f3608 from the other direction. The export now reports 2 sub-waves and the manifest warning is gone. | | P3 — the plate's ONSET | visible 2.13 s after settle, or group starts then? | Q2 | resolved 2026-08-29, and the answer is AUTHOR NOTHING. The port's refutation held and produced a better answer than either option it offered. Correction at 5b0a6e6 on auto/no-disc-and-menu-captures: both builds run on one clock, started together, and the plate arrives at its own declared t=238. Checked against this export rather than taken on trust — build 4's visible build-in ends at t=118 (pteff01, pteff02, ptlogoall_eff finish together), ptbtn00 reaches alpha 255 at t=238, difference 120 units = 2.000 s, against a measured 2.138 / 2.132 s at an emulator presenting 28.1 fps rather than 30. The 2.13 s constant is deleted. | | P3/P5 — settle_time() | rest.t is not when a screen settles, and the port's sequencer uses it | — | MEASURED 2026-08-29 and the row was HALF WRONG — mine. The Decoder took it on a cold profile with no shader cache (auto/no-disc-and-menu-captures at 4bd4779, docs/re/boot-settle-times-measured.md). The principle holds: the title's rest.t is 251 units = 4.183 s where its art finishes at ~2 s. But "everything the sequencer paces off that landmark is therefore late" does not. Measured the port the way the game was measured — visible span, --film at 4 fps — the publisher wordmark runs 4.25 s against the game's 4.297/4.604/4.370 and the developer logos 3.50 s against 3.508/3.503/3.366. Dead on. My earlier reading compared the port's arrival-to-arrival timestamps against the game's visible spans, which differ by the exit ramp plus the black hold — the whole of the discrepancy I was about to chase. rest.t is still the wrong landmark; its blast radius is _script_settled waiting longer than it needs to, which is a slow test and not a wrong frame. dwell_seconds stays null, now for a measured reason. 🔴 Do not author an Ⓐ→menu dwell: it measures 3.763 s and contains a 1.53 s guest load stall, third independent reproduction. 🟡 Menu build-in 0.531 s and Ⓑ→title 0.482 s rest on one run and are not authored; the port is within ~0.1 s of both from the disc. | | P4/P7 — the voice export | what are the three concurrent streams what do streams 1 and 3 contribute? | — | 🟡 HALF ANSWERED BY THE ORACLE, 2026-08-29. A faithful capture finally exists (1788022539-4529c72ed7fb, ALSA tee + --gpu=null, 0.35 % silence, passes check-capture, header verified here). Fitted with the calibrated correlator against its own controls (present +0.248 / absent +0.005): the exported voice matches the game's CENTRE channel at r = 0.989, margin +0.305, while the movie bed matches FL/FR/RL/RR and not FC. So the dialogue is in FC, the bed is in the corners, and the port's exported file is the material the game plays there — measured, where the header (ChannelMask = 0x0002 on all three) could never have said it. ⚠️ Streams 2 and 3 are indistinguishable to this instrument, as expected from stream 3 being 0.60× stream 2 with 26.8 dB residual; stream 1 is undetectable in a 59.7 s window, consistent with being stream 2's tail. 🔴 The 1 of 3 warning stays — nothing here says what the other two contribute. Reach: 59.7 s of a 137 s movie, one run, no screen provenance (the --gpu=null route costs video; provenance is the XMA probe). Superseded history, kept because the sequence of wrong readings is what makes this one checkable: 🔴 Canary's --xma_param_probe shows the game decoding all three streams concurrently in three XMA contexts, byte sizes matching the disc payloads exactly (1 294 336 / 1 118 208 / 1 171 456 against 1 294 396 / 1 118 268 / 1 171 516). So they are not three presentations of one take, there is no "which one" to answer, and the export — which ships one — is missing two streams the game plays. ⚠️ The failure sounds like success: one stream is clean audible dialogue. Stated as a top-level manifest warning per movie, on the console, and in authored/audio.json. Behaviour deliberately unchanged: an equal-gain 1/n sum of channel pairs is not a downmix either (MISSION §6 pins an explicit matrix for exactly this reason) and summing cost S00A 6.02 dB when one stream was silence — swapping one guess for another is what produced this row twice. 🟡 "They are 5.1" is the Decoder's hypothesis: three stereo streams is six channels and N stereo streams is how XMA carries multichannel on the 360, but all three declare ChannelMask = 0x0002 identically, which argues against distinct roles. 🔴 NOT OBTAINABLE THIS SESSION — both capture routes are closed, and this is now the blocker. Take 1 (1788018994-16f9d19d90b8) was corrupted by a channel-map remap: PulseAudio remapping between mismatched maps silently drops and duplicates, proved by a tone control (six tones in, 400 / 3200 / 200 / 800 / 800 / 200 out, two source channels gone). Take 2 (1788019777-43f27c791bef) is starved — verified here independently: 35.6 % of frames silent on all six channels, 10 482 alternating runs, median burst 13.5 ms / gap 3.9 ms, a 17.4 ms period at 57 Hz. That destroys envelope correlation by construction, so the negative it produced said nothing about the game. ⚠️ Withdrawn with it: the reading that the game may not play the .wmv's WMA track — neither supported nor refuted by a starved file, and nothing changed on account of it. The monitor-sink route cannot be fixed by configuration: it advances at wall-clock rate and substitutes silence, so every moment the emulator runs slow is a hole and deleting them warps the timebase non-uniformly. The route that works is an internal tap at SDLAudioDriver::SubmitFrame, needing a Canary rebuild the Decoder has costed at a whole session — the build root build-canary targets does not exist in that container, the warm tree is configured against the same missing path, ~700 MB free, with prior parallel builds OOM-killing the host. That is the human's call, not an agent's. tools/port/check-capture now catches both failure modes, so no future capture costs an analysis to discover it is unusable. | | P4/P7 — S00A as a second asset | does a structurally different movie also put dialogue in FC? | — | 🔴 NOT OBTAINABLE IN THIS CONTAINER — closed as a route finding, 2026-08-29. The drive works end to end (main menu +0.999, newgame-difficulty +0.999, newgame-selectdata-crash +0.997, with the focus detector validated live against a known transition) and then the guest throws at PC: 0x82307128 ×349; no S00A stream ever decodes. ⚠️ It also refines title-crash-stl-tree.md rather than confirming it: the mechanism survives but the container it names, aab216c3, is complete here — the throw is on 1b556564, which holds one file plus a stray .tmp. So the new-game path builds a different cache container, and the documented remedy does not transfer — it restores a previously complete cache, and no complete 1b556564 has ever existed here. Consequence for the port: the centre-channel result rests on ADV alone. S00A was wanted precisely because its second stream is digital silence where ADV's is a 0.60× copy. That corroboration is behind a crash outside menu-port scope and neither agent is chasing it. | | P3/P5 — the title plate | does the idle title show PRESS Ⓐ | Q2 | answered and TAKEN at this iteration. auto/no-disc-and-menu-captures at fb536df, docs/re/title-plate-delay-measured.md, traces in docs/re/data/plate-timing-run{1,2}.tsv. It is the third case: build 4 alone, then the plate composited over it. ⚠️ The delay is timed from where build 4 stops animating, not from where it first appears — measured the other way the two runs differ by 0.48 s against 6 ms. ScreenView now draws two builds at once, as a second ScreenView in the same SubViewport rather than a subordinate screen inside one. The onset question above is what is left. |

| P3 — the plate's PULSE | does the plate's focus record loop, and with what period? | Q2 | open, and the port's earlier reading of it was wrong. The port had looked for the pulse in ptbtn00's own group; 5b0a6e6 identifies it as the plate's focus record ptbtn00f — a glow ramping alpha 0x000x50 and back, t=6…105. Measured on the running game at 2.12 / 2.19 / 2.34 / 2.31 s, mean 2.24 s. 🟡 The port has not taken it. Looping that record needs a period, and its group is 105 timed units plus the authored 24-unit exit ramp = 129 units = 2.15 s — composing an authored constant with a loop assumption to land on a measured number is tuning, not measuring. Separately: the port draws no focus record on press_start at all, because the screen has no buttons and nothing is focused, so whether the game always draws it is its own question. | | P5 focus ring — implementation | the ring's spin period | Q1 | implemented 2026-08-29. ScreenView.spin_period_units drives it: one turn per the element's own declared t, looping, from the screen clock. The period comes off the disc; what the RE agent supplied is that the turn repeats rather than stopping. Verified on the port's own render — the ring is bit-identical one period apart across the whole frame, differs by 3.6/255 inside its box at quarter-period steps, and conserves box luminance to 0.027 % over eight phases, which is the same observable the RE agent used to separate rotation from a pulse. 🟡 Direction is not measured — the port turns 0°→+360°, which is the sign the disc declares, but the RE agent's angle estimators failed their controls and no signed angle was ever taken. 🟡 Phase across a focus change is not measured either: the port drives the ring off the screen clock, so it does not reset when focus moves. Settled by two frames straddling a focus change. |

| P7 / naming — the four unnamed builds | which locale and variant is each of GP_TITLE entries 0, 1, 12, 15? | — | 🟢 found by the port, not blocking, and handed over. All four are loading screens: every element in all four is named pgloading_* (pgloading_processing.png, pgloading_circle1, pgloading_delta, pgloading_ring), and LOADING is one of the three screen names the Decoder read out of sub_821C6458. They export today as build_00, build_01, build_12, build_15. Two variants: 0/1 carry 7 elements, 12/15 carry 10 (adding pgloading_eff00, pgloading_loop5, pgloading_baseeff). The archive's own pairing — adjacent for 2/3, +3 for 4…9 and 10/13, 11/14 — suggests 0 is the twin of 1 and 12 the twin of 15, but which member is which locale is an inference and the port has not named them on it. Naming is cheap for the Decoder and a guess for the port. | | P7 — what fills the 4.5 s before S00A | is the LOADING screen what appears between the save slot and the new-game movie? | Q4 + Q9 | not observed, and the port has not assumed it. Q9 measures S00A.wmv starting ~4.5 s after Ⓐ on the save slot. The run that would have shown what is on screen for those 4.5 s hit the documented sub_823070B0 cache crash after SELECT DATA. GP_TITLE carries a loading screen (row above) and 4.5 s is about the right shape for one, and that is exactly why it is written here and not in flow.json. Settled by one run that reaches the movie without crashing. | | P3 — a second rest.t casualty | the loading screen's fade quad rests OPAQUE BLACK | — | resolved 2026-08-29 by the forced-backdrop rule, and this row carried a stale number. The quad still rests opaque — that part was right — but it no longer hides anything: it is a layerless full-screen element opaque across a span containing all 9 others, so it is forced to paint first and the loading screen draws over it. At --pose=rest, build_12/build_15 went from mean 0, the whole screen black to mean 1.95 with 59 530 non-black pixels. ⚠️ Two corrections to what this row said. Its rest.t is 0, not 38 — stale since the keyframe-layout correction (formats-pin-2026-08-29c) timed every pose; the group is 0xff000000 at t=0 and t=38, then 0x00000000 at t=48, so the conclusion held while the number did not. And the general rest.t complaint is not resolved: an opaque element at its rest instant is still opaque, and this one stopped mattering only because it is a full-screen backdrop. The row below still stands for anything that is not.

| P6 — runtime headroom | the Master bus clips | — | 🟢 withdrawn by the port, 2026-08-29 — it was my own overstatement. Filed 🔴 twice on a peak reading of 0.0 dBFS. Measured properly: 43 samples at full scale in 5.9 s and 24 in 98.5 s, longest clamped run 0.25 ms — the disc's own confirm cue touching the ceiling on a transient, possibly only in the recording's 16-bit conversion since Godot mixes in float. Not a defect, and nothing is changed: attenuating to buy headroom would be an unmeasured level decision of exactly the kind this port refused for the BGM loop point. A peak reading is not a clipping measurement — one sample at 0 dBFS and two seconds of square wave give the same number. | | Modding — rule 4 | base-and-overrides is unimplemented | — | implemented 2026-08-29, and it was not blocked on anybody. MODDING.md calls it a constraint on the exporter today; nothing read data/mods/ for eight milestones. ExportTree.resolve now shadows by path for every asset kind, each replacement is logged as it is read, and .gitignore excludes the directory's contents — a mod is usually an edited game asset, and that directory was the one place git would have taken one. ⚠️ The export/ vs data/base/ naming split between PORT-MISSION.md §3 and MODDING.md is raised, not resolved: only the human changes a mission. |

| P1P7 — the keyframe record layout | adopt the corrected pose/time pairing | — | ADOPTED 2026-08-29 by pinning formats-pin-2026-08-29c. This row was wrong twice: it said the change "cannot be taken yet" and that it "reaches the port only when that branch lands on main". It arrives when the tag is pinned, which is what MISSION §2's tagging rule exists for. ⚠️ And the knob I tested first, SYLPHEED_KF_TIME_SHIFT, is a retired partial fix that left pose 0 untimed — the real correction is the tagged crate's default, with the old reading behind SYLPHEED_KF_TIME_LEGACY=1. The blast radius was far smaller than this row predicted: under the correction every pose is timed (866 keyframes, 0 untimed), so pose_at's synthetic-exit branch became dead code rather than wrong code and nothing needed re-deriving. Oracle: publisher_logo 1.00 %→0.75 %, developer_logos 0.39 %→0.33 %, extras' differing region collapsing from 736×525 to 398×295 at the sweep position. 🔴 Open cost: sylpheed-cli builds from the workspace crate, so verify-screen compares two decoder eras until the tag reaches main. Revert to the path dependency then. | | P7 / naming — the four unnamed builds | which locale and variant is each of entries 0, 1, 12, 15? | — | answered 2026-08-29 (docs/re/ui-title-build-map.md): all four are the loading screen, two variants — plain (7 elements) and dressed (10) — decoded from their own pgloading_* element names. ⚠️ Not adopted as names yet, for two reasons the RE agent gave and one the port found. Theirs: the executable names exactly two, and which bundle takes which name is 🟡 undecided, so LOADING/LOADING2 must not go in an asset path; and locale is 🟡 — the English member of a pair is the one in the first half of GP_TITLE.p00, 8/8 structurally but only 3/3 where a capture can check, and the three pairs that matter are the three no capture can check. Mine: the message gives the bundles as "0/1 and 10/11", which is the is_build ordinal, and authored/screen_names.json is keyed by PAK ENTRY — in entry space 10 and 11 are palogo_sqex and palogo_gamearts, the splashes. See the refutation section in DECISIONS.md. |

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_MOVIEADV.wmv is boot intro and attract; MS00AS00A.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 GAMEDIFFICULTYSELECT 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, 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 authored/flow.json, screens.main_menu.initial_focus — landed at P5
the ~0.4 s fade-out and the 0.170.23 s black hold Q7 not yet written — P3

The five asks — four answered at 9ca1eb5

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 elementptbtneff01.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)

The splash is the first thing P3 draws and it is not in export/. It declares its sprites directly and has no .rat layout child, so is_build rejects it; sylpheed-cli reaches it only via --all, which the CLI's own help says renumbers --build. So the port cannot address it by build index without the index meaning something different from everywhere else in this format.

What I need is a predicate, not an index: something the exporter can apply to say "this bundle is a composable screen" that admits the splash and does not admit the 1 894 two-element fragments --all also lets in. If the honest answer is "there is no such rule, take GP_TITLE entries 11/14", that is a usable answer — I will export it under a synthetic name with name_source saying it was located by entry index and not by a rule.

2. Is the ~0.4 s fade-out the whole ramp, or a segment of it? (P3, blocking)

Q7 measures the screen fade-out at ~0.4 s and the black hold at 0.170.23 s. The port needs to know which quantity that 0.4 s is, because the last keyframe of a group carries no t and the port refuses to invent one:

  • the ramp from the hold to the exit pose — i.e. the missing duration of that final untimed keyframe; or
  • hold → exit → fully black, the 0.4 s covering several keyframes; or
  • something the game does independently of the group.

Under the first reading the port writes one authored constant and plays the group to its end. Under the third it must not.

3. Focus: drawn OVER the base element, or INSTEAD of it? (P5, cheap, avoid rework)

sylpheed-cli --focus is documented as drawing the focused record over its base. The port replaces the sprite. Those are different operations and the port picked its one without evidence.

Evidence that the port is wrong: rendering main_menu with ptbtn01 focused — which is how main-menu-oracle.png was taken — makes the RMSE against that capture worse, 5.92 % → 7.00 %. The capture also shows a ring marker beside NEW GAME that the port draws nowhere. Cheap to answer from a capture that already exists, and it decides how P5 is built.

4. Rotation — should the port draw it, and about what? (P2/P3, needs a joint decision)

67fa1a1 decodes rotation_deg at keyframe +12 and explicitly does not render it: ui_layout::blit is axis-aligned. ptloop01/ptloop02 on the title declare +30° and 45°, and the framebuffer submits them at +30.26 and 45.28.

A canvas rotation is a few lines in Godot, so the port can draw these. But then the port is deliberately more correct than the reference renderer, and verify-screen — the port's whole verification method — starts reporting a large diff on the title that means "the port is right". That is a bad state to be in silently, so I would rather agree it than do it.

Two sub-questions: is the rotation about the declared pivot or about the element's centre or corner? And would you rather blit grow a rotating path so the diff stays meaningful? The format would go to v3 to carry rotation_deg; that is my side and I will do it either way, since carrying a decoded field the renderer ignores is better than dropping it.

5. Is main-menu-oracle.png gamma-correct? (not blocking, but it calibrates everything)

With the background in, the port sits at 5.92 % RMSE against that capture and is visibly darker and less saturated than it across the whole frame. If the capture path applies a gamma or a colour transform the game does not, then RMSE against captures has a floor and the port should stop chasing it. If it does not, something is still missing. The port cannot tell these apart from inside.

Questions this port has raised

🔴 This table's rows carry no derivation sha, and that is why they rot. The standing instruction is to record the HANDOFF commit each row was derived from; every prose section added since does, and every row in this table and the next does not. On 2026-08-30 an audit found three stale rows here — one of them contradicted by a struck row four lines below it, claiming the boot ends on a plateless title when it had drawn the plate for weeks. The undated rows are exactly the ones that went stale, which is as close to a controlled experiment as this page is going to get.

⚠️ Rows are not being back-dated: nobody knows when most were written, and inventing a sha would be worse than admitting there is none. New rows carry one. This table was last audited 2026-08-30 against a running port.

Does a keyframe group loop, or hold its last pose? — answered

Answered 2026-08-28 by the RE agent: groups hold. ptloop01/ptloop02 park their sprites at x=1521 and x=839, both off a 1280-wide design, and 18 s of settled title sits at sd ≤ 0.01. loop*.rat is a misleading name — these animate once during build-in and then rest off-screen.

The port's own error here was different and is fixed: it settled at the last timed keyframe rather than at the hold. See docs/DECISIONS.md.

Kept for the record:

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).

🔴 REFUTED 2026-08-29, by the port, against its own export. This paragraph said: "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." press_start's ptbtn00 reverses: fade_argb is 0x00ffffff at t=214 and t=236, 0xffffffff at t=238 and t=244, and 0x00ffffff again on the final untimed keyframe. It was in the export the whole time and the claim was never checked against it — it was checked against the screens P2 happened to be looking at. The reason to expect a loop is back, and the running game pulses this exact element. 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 — fixed

Fixed 2026-08-28 in sylpheed-formats, and this port's pin moved 8b6dbcf → 5414db3 to take it. The rule adopted is not the condition this port proposed, which was too loose: a trailing run is the hold exactly when it is visible. The port's condition would have erased the word PAUSE on pgptitle.rat, whose trailing run is two identical transparent frames.

Kept for the record, since the reasoning is still what found it:

This one is a decoder bug, not a question, and it was 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.

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.


Whose span is the opaque span? answered, and it was never a disagreement

Derived from HANDOFF 9ca1eb5. Closed 2026-08-29 by the Decoder.

Both numbers were right, and both were mine. palogo_eff0.prm is on both splashes: publisher (entries 10, 13) runs to t=255 → 256 instants, developer (11, 14) to t=210 → 211. I filed a disagreement by comparing one of my two numbers to one of theirs without checking the other row of my own census table, which had 211 in it. 🔴 A per-screen quantity needs its screen named beside it — this row named neither, and that is the whole defect.

The convention is confirmed as the port already implemented it: span is 0 ..= max keyframe over every element in the build, and an element holds its final pose. Not a convenience — the header's +0x08 never falls short of the last keyframe, and +0x08 and the elements' maximum are interchangeable disc-wide.

⚠️ The hold is load-bearing: dropping it changes 72 of 130 verdicts (55 %), and palogo_eff0 — one keyframe, opaque for one instant — is called free without it, against a measured order. See DECISIONS.md.


The two splash dwells answered 2026-08-29, and the row was my over-correction

Derived from HANDOFF 9ca1eb5. Closed by the Decoder over 3 cold boots.

The dwells are declared on the disc — publisher t=0…255, developer t=0…210 — and the port was already playing them, each plus the 9-unit black hold, to 4.400 s and 3.650 s. The developer's declared value agrees with wall clock to 1.1 %.

🔴 So this row should never have been filed. I generalised build 4's ~9× hold onto two screens it does not govern: the title's exit is caused from outside its timeline, a splash's is caused by nothing. See DECISIONS.md — the withdrawal is recorded there rather than only struck here.

⚠️ And the ask itself was wrong-shaped: I asked for two wall-clock timestamps. The Decoder's own container timed these same dwells 1520 % long, so a seconds figure records one emulator's pacing. Anything that ever goes in authored/flow.json dwell is in units.


black_hold_units = 9 rests on numbers that have since moved

Derived from HANDOFF 9ca1eb5. Raised 2026-08-29 by the port, after the Decoder disclosed that ARM=early silently loses its trigger ~40 % of the time.

That disclosure means every draw-stream run is n = 1, so I audited what the port authors from one. Exactly one constant does: the black hold between the two boot splashes. It is not wrong, but three of its supports have moved:

  • its conversion used 105 drawn frames, revised by their own truncation fix to 114 (2.284 → 2.096 units/frame);
  • its second corroboration, 2.231, is the figure behind their retracted 114-unit plate period;
  • a run-average rate is the wrong shape for a 34 frame event now that the presented rate is known to rise 33 % across a boot.

Redone on their corrected segments the two runs give 8.95 and 6.71 units. ⚠️ They were reconciled as agreeing within ±1 — but one frame is a third of this quantity, and overlapping error bars are not agreeing central values. The range is ~6.59.2 and the port sits at the top.

The value is unchanged and I am not changing it: that would be my arithmetic on their instrument, and the port does not author a number the corpus has not given. It is proposed, not adopted.

What would settle it: one more draw-stream run of the boot, with the arm confirmed, counting frames with no sprite quad between the splashes. A third sample turns a 3-vs-4 disagreement into a measurement. It needs no button press, so it should sit the safe side of the Ⓐ blocker.

Not in doubt: the hold is real. Until 2026-08-29 the port had no black frame at all where the oracle measures a plateau, and both boundary frames still carry picture (alpha 7 and 34), so the true hold is shorter than whatever this lands on.


Does the game's menu music duck under a cutscene?

Derived from HANDOFF 9ca1eb5. Raised 2026-08-29 by the port.

The port plays the main-menu bed underneath S00A, so two unrelated music tracks sound at once. MenuAudio.stop_bed() exists and has no caller — this is an unmade decision, not a choice, and it has been true since P6.

🔴 Deliberately not fixed. Stopping the bed would sound right and would be invented; MISSION's rule is to leave the unmeasured detail plainly wrong. The runtime now announces it on every movie that starts with the bed sounding.

What would settle it: any capture with sound of the real game entering a cutscene from the main menu — the first second answers it. Three outcomes are all useful: the music stops, it ducks, or it genuinely continues (in which case the port is already right and this row closes as ).

⚠️ Do not answer this from our own renderer or by reasoning about what a shipped game would do. That reasoning is what makes an invented answer feel safe.

⚠️ Related but separate, and already authored with a why: the bed loops by restart, seam and all (authored/audio.json, loop_why). That is a known-ugly deliberate choice pending a loop point, not this question.


Derived from HANDOFF 9ca1eb5. Raised 2026-08-29 by the port.

ptbtn00's group makes the plate opaque for 8 units only — alpha 0 until t=214, 255 at t=236 and t=238, back to 0 by t=244 — and its group then ends. So in the port the plate flashes for 0.133 s and is gone, and the boot's end-state capture (taken at t=246.54, once build 4 has finished fading up at t=261) contains no plate at all.

🔴 The two states cannot share a frame: the plate's window closes 17 units before the title stops presenting. The port captures the title, by an earlier and sound decision it is not reversing.

What would settle it: a capture of the real title held for several seconds after the plate first appears. Three outcomes, all decisive — the plate stays up; it pulses on a period (authored/timing.json already carries a speculative looping_focus_records entry for press_start/ptbtn00 at 120 units, which is what a pulse would need); or it genuinely blinks once and vanishes, in which case the port is right and this closes .

🔴 Correction, 2026-08-30. This row previously said the looping focus record was "the only thing making the plate reappear at all". The opposite was true: the entry was the only thing making it disappear — it drew a dim glow instead of the plate's own sprite, max 0 against max 252.5. It has been deleted, and the port now draws the plate from its own decoded fade. See DECISIONS.md.

⚠️ So the question narrows rather than closes. The port shows the plate at its declared instants and holds it. What a capture would still settle is whether the real plate pulses after that, and whether ptbtn00f.rat — the focus record, which the port now draws not at all — is a glow layered over the plate. Drawing both would be a rendering rule nobody has measured.


The ptloop sweep phase: ~400 units fits the capture, the refined fit says 357.7

Derived from HANDOFF 9ca1eb5. Raised 2026-08-30 by the port.

--leaf-time= now poses the sweeps' leaf independently of the screen, so the Decoder's refined sweep fit is testable for the first time — it never was, because verify-capture passed it as a whole-screen --time that pose_at discarded.

Against live-title-build4-no-plate.png, structural disagreement bottoms out in a sharp basin at 390415 units (0.0124 %) and reads 0.2532 % at t=357.7 — a 20× separation, on a deterministic renderer, with the sweeps demonstrably moving 0.40 % of the frame between phases.

Nothing in the port changes and nothing is being asked for urgently. The port loops the leaf freely; there is no phase to set, and re-posing the harness to the fitted value would be tuning until they match.

What would be useful: whether 357.7 and this are the same quantity. If the refined fit was measured against this same capture, one of the two is off by ~42 units and it is worth knowing which. If it came from a different frame, then ~400 is a second, independent phase measurement and neither is wrong.

⚠️ The port cannot separate a phase error from a systematic error in how it draws the sweeps — a geometry mistake could be absorbed by shifting the phase. The sharpness of the basin argues against that, but one capture cannot settle it.


A failed export leaves a partial tree that reads as "not an export tree"

Derived from HANDOFF 9ca1eb5. Raised 2026-08-30 by the port. Not blocked on anybody — filed because the fix is a judgement about failure semantics, not a bug.

When sylpheed-export export fails part-way — for instance on one of the new authored-value assertions — it leaves export/ without a manifest.json. Every tool then reports "has no manifest.json — is that an export tree?", which reads as a broken harness rather than as the aftermath of a deliberate abort.

It cost a wrong reading within minutes of being introduced: an audit of the validator reported every case as "no manifest" and nearly concluded the validator was checking nothing.

Writing the manifest last is correct — a manifest is a claim about a finished tree. So the candidate fixes are about the message, not the order:

  • leave a marker on failure that the next tool can name (export/.failed), or
  • have check say "no manifest — the last export did not finish" when the tree has screens but no manifest, which is exactly the distinguishable case.

⚠️ Deliberately not chosen here: both change failure semantics across every tool, and neither is measured against anything. It goes to whoever owns that call.


title differs from sylpheed-cli on 790 pixels🟢 localised by the port, ask withdrawn

Derived from HANDOFF 9ca1eb5. Raised 2026-08-30 by the port. Not urgent — the port agrees with the oracle on this screen at 0.21 %, and that is the check that counts.

verify-screen has title at 790 pixels over the bar and title_jp at 20 498, and neither carries a forced-backdrop element — so they are not covered by the pinned-tag allowance the other six sit under. I had been reporting "six expected DIFFERS"; the real count was ten.

🔴 The obvious explanation is wrong. authored/rendering.json records that the consistency harness compares against a renderer drawing no .rat leaves, so the ptloop sweeps were the candidate. Emptying draw_leaf_for and loop_leaf_on_screens changes the figures not at all — the harness poses at rest, where the leaves do not draw.

🟢 WITHDRAWN 2026-08-30 — the premise was refuted and the question was mine to answer. I asked for the CLI's element list on the theory that one renderer drew something the other did not. It does not: the differing pixels sit at ptlogo_back2eff1 (pos=[938, 194]), and both renderers draw it — mean 95.60 in the port against 95.08 in the CLI. A set difference would have confirmed nothing at somebody else's cost.

Also ruled out: a placement offset. Every ±1 px roll makes it two orders of magnitude worse (790 against ≥ 175 406).

The mechanism is still unknown, and I am not guessing at it: the antialiasing test I tried failed its own control, with the edge mask covering 92 % of the frame. See DECISIONS.md. Nobody is asked for anything — the residual is 0.086 % of one frame between two of our own renderers, on a screen matching the oracle at 0.21 %.

⚠️ Do not read this as the port being wrong. Against the capture, title is at 0.21 % and title_plate at 0.00093 %. This is two of our renderers disagreeing, and the one with an oracle behind it is not the one under suspicion.


The loading screens hide a visible leaf animation

Derived from HANDOFF 9ca1eb5. Raised 2026-08-30 by the port. Low priority, and nothing is waiting on it.

pgloading_loop5 on build_12/build_15 carries a leaf — pgloading_ring, one sprite — that expands scale 0 → 1000 while fading in and out over t=0…130. At the port's own pose instant (~t=44) it would draw at scale 140, alpha 143. The port does not draw it.

⚠️ It is withheld for a reason that is sound — no oracle capture exists for a loading screen, and verify-screen's reference draws no leaves, so the content would be unadjudicable either way — but the reason previously recorded was false ("leaf scale (0,0)"), which made it look like there was nothing to draw. There is.

What would settle it: any capture of a loading screen with the ring mid-expansion. The Decoder records these screens as unreachable from the title path, so this may never become answerable, and that is an acceptable outcome — the entry now says what is being withheld rather than implying the question is empty.