port: the ring spins, the plate needs no constant, and rest.t was never the settle

Two milestones' known-wrong bits, both now answered by the RE agent, both taken.

P5 -- the focus ring. It was drawn at 0 with a comment saying so. The period is
now measured (continuous spin, eight evenly spaced autocorrelation peaks over
nine revolutions, no angle estimated anywhere) and it needs NO authored
constant: the period is the element's own declared t=120, and what the
measurement adds is only that the turn repeats rather than stopping -- which
"groups hold" could not decide, because 0 and 360 are the same pose.

`spin_period_units` is structural and narrow on purpose: two keyframes,
differing in nothing but rotation_deg, by a full 360, first timed and second
untimed. 16 of 212 elements in this export match and all 16 are focus rings,
zero false positives. That check is the point -- the measurement was taken on
ONE button of ONE screen, and a rule that caught anything else would be
extrapolating it to elements nobody watched.

Verified on the port's own render with the RE agent's own control: bit-identical
one period apart across the whole frame, 3.6/255 inside the ring's box at
quarter-period steps, and box luminance conserved to 0.027 % over eight phases
-- which is the observable they used to separate rotation from a pulse. Not
claimed: direction (no signed angle was ever measured) and phase across a focus
change (their run held focus throughout).

P3 -- the plate. Last iteration I refuted their authoring instruction and
shipped it anyway rather than pick between two of their numbers. The refutation
held and the answer came back better than either option I offered: AUTHOR
NOTHING. Both builds run on one clock started together and the plate arrives at
its own declared t=238. The 2.13 s constant is deleted.

The premise that failed was mine: rest.t IS NOT WHEN A SCREEN SETTLES. It is the
last hold keyframe before the exit. ptlogo1 stops MOVING at t=42 and then creeps
5 px and 31 alpha steps to t=251. Reading rest.t put build 4's arrival at 4.350 s
instead of 1.967 s, and the "2.51 s, which is not a landmark of anything" I sent
them is that error wearing a decimal point. 238 - 118 = 120 units = 2.000 s
against a measured 2.135 s at 28.1 fps presentation. Checked against my own
export before touching anything.

`ScreenView.settle_time()` still uses rest.t, and so the boot sequencer paces
every screen off the wrong landmark. NOT changed here: "visible arrival" is a
heuristic and getting it wrong re-paces everything. Filed, and asked for a timed
boot instead now that their oracle is live.

REFUTATION: two of their pages measure the same declared 120 units of wall clock
during a static hold and disagree by 2 % -- plate 2.135 s (28.10 fps implied),
ring 2.177 s (27.56 fps). That is seven times the plate page's own 6 ms
run-to-run agreement, and it lands on the argument that page uses to justify
itself: "the build-in is where frames are dropped; the static hold is not". Also
the ring page's band, 27.6-28.8 fps, does not contain its own measurement -- the
mean needs 27.56 and four of seven spacings are outside. Filed, not worked
around: my port uses the declared 120 units either way.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WM5XL4HfrHuxz8RiMWdCMC
This commit is contained in:
Sylpheed port agent
2026-08-29 12:50:35 +00:00
parent 4f767e72f6
commit f8a8d17327
5 changed files with 261 additions and 49 deletions

View File

@@ -83,11 +83,12 @@ git log -1 --format=%h -- docs/port/HANDOFF.md # newer than 9ca1eb5? re-reconc
| 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 | 🔴 **HANDOFF and the decoders disagree, and P6 ships the disagreement.** `media::sound_bank_riffs("BGM_103.slb")` returns **three** sub-waves; HANDOFF Q10's census says a music bank is *"exactly two waves of identical duration (32/32 banks on the disc)"*. The third comes from `slb.rs:380` `to_xma_riffs`, whose hybrid branch emits a leading headerless packet region ahead of the `RIFF` waves — and `docs/re/REFUTED.md` already records that region as what makes `BGM_106``BGM_109` *"break the two-wave rule"*. Derived at HANDOFF `9ca1eb5`. **The exporter sums all three and writes a manifest warning**, because choosing which sub-wave to drop is a decoding question and MISSION §2 forbids this exporter answering one. So the menu currently plays a sum of three things where the census predicts two. What settles it: whether that leading region carries music. Raised with the Decoder 2026-08-29. |
| P3 — the plate's ONSET | **does the plate become visible 2.13 s after settle, or does its GROUP START then?** | Q2 | 🔴 **new, and it is a disagreement between two of the Decoder's own numbers.** `docs/re/title-plate-delay-measured.md` (`auto/no-disc-and-menu-captures` at `fb536df`, **not on `main`**) measures the plate *becoming visible* at settle + **2.13 s**, and instructs the port to *"wait 2.13 s, composite build 2"*. Those are 3.97 s apart, because build 2 has a group of its own and the port plays it: `press_start`'s `ptbtn00` is alpha `0x00` at t=214, `0x00` at t=236 (it slides y 560→550 invisible), `0xff` at t=238 — **3.967 s** from group start to full alpha at 60 u/s. Neither landmark reconciles them: both groups starting together puts full alpha 0.38 s *before* build 4 settles (`title` settles at t=261 = 4.350 s); build 2 starting at settle puts it at settle + 3.97 s. Landing on settle + 2.13 s needs build 2's group to start 2.51 s after build 4's, which is neither. **The port ships the instruction, not its own arithmetic**, prints the discrepancy on every boot, and is not choosing. First thing to check, and it is about the instrument rather than the game: is *"title settled"* (the glyph counter first reading 154) the same instant as the port's last-element settle? Raised 2026-08-29. |
| ~~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** | — | 🔴 **new, mine, and it is the premise that produced the wrong plate arithmetic.** `5b0a6e6` states it plainly: `rest.t` is the last *hold* keyframe before the exit. `title`'s `ptlogo1` has `rest.t=251` and stops **moving** at `t=42`, then creeps 5 px while its alpha crawls `0xe0``0xff` over 209 units. `ScreenView.settle_time()` returns the max `rest.t`**4.350 s** for the title where the visible build-in is over at `t=118` = **1.967 s**. Everything the boot sequencer paces off that landmark is therefore late: `publisher_logo` is held to t=235, `developer_logos` to t=190, and `_script_settled` waits on it too. ⚠️ **Not changed this iteration**, because "visible arrival" is a heuristic and getting it wrong re-paces every screen; it needs its own gate. **What settles it outright:** the oracle is live — a timed boot with screen-to-screen transitions would give the real dwells directly. Asked 2026-08-29. |
| ~~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 | **what period does the plate pulse at, and which group boundary repeats?** | Q2 | ❔ **open, and the port draws no pulse.** The same finding measures the running plate pulsing continuously — peak/trough intervals 2.12 / 2.19 / 2.34 / 2.31 s, mean **2.24 s**. `press_start`'s group encodes exactly one cycle (`0x00``0xff` at t=238244 → `0x00` untimed), and **no reading of it produces 2.24 s**: the whole group is 268 units = 4.47 s, and from its first keyframe 54 units = 0.90 s. So repeating the group would be inventing a period. The port holds the plate at its settle (t=238, alpha `0xff`), which is what it does on every other screen and what the static oracle capture `live-title-press-a.png` shows. What settles it: which instant the group restarts from. |
| P5 focus ring — implementation | ~~the ring's spin period~~ | Q1 | ✅ answered (2.177 s, `4fa3099`) and **still not implemented** — the port draws 0°, a pose the corpus says the game never shows. Not blocked on anybody; it is queued behind P3's plate this iteration. |
| 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 `0x00``0x50` 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. |
## Answered since this file was last written — no longer blocking

View File

@@ -1750,3 +1750,154 @@ Two things the run made obvious and that are now fixed:
of the title". It applies **no** delay: the delay is a measurement and lives in
`authored/flow.json`. The boot-mode narration is suppressed there, because a
log line that describes a sequence it is not running is worse than no log line.
## P5 — the focus ring spins, 2026-08-29
The ring was drawn at 0° and the file said so: *"THIS IS KNOWN TO BE WRONG, and
is drawn anyway because the right answer is a guess."* What was missing was the
**period**, and it is now measured — `docs/re/focus-ring-spin-measured.md`
(`auto/no-disc-and-menu-captures` at `4fa3099`): a continuous spin, from eight
evenly spaced autocorrelation peaks over nine revolutions, **with no angle
estimated anywhere** — both angle estimators failed their own controls and were
not used.
### The period comes off the disc; the RE agent supplied only that it repeats
`ptbtneff01` declares two keyframes that differ in **nothing but**
`rotation_deg`, 0 → 360, the first timed at `t = 120` and the second untimed.
The port turns once per **120 units**. Nothing is authored: the number is on the
disc, and what the measurement adds is that the turn **repeats** rather than
stopping at 360 = 0, which "groups hold" could not distinguish because those are
the same pose.
`ScreenView.spin_period_units` is the rule, and it is structural and narrow:
exactly two keyframes, differing only in rotation, by a full 360, first timed and
second untimed. **Disc-wide check over this export: 16 of 212 elements match, and
all 16 are focus rings** — `ptbtneff01` on the five main-menu buttons and
`ptbtneff02` on the three `EXTRAS` buttons, in both locales, every one declaring
`t = 120`. Zero false positives.
That check is the point rather than a formality. The measurement was taken on
**one** button of **one** screen; a rule that also caught something else would be
extrapolating it to elements nobody watched.
⚠️ It is a rule about **shape**, not a decoded field. Nothing on the disc says
"this loops". The day a loop flag is decoded, this goes.
### Verified on the port's own render, with the RE agent's own control
Captures at `--time=` 2.0 … 4.0 s on the settled main menu, `ptbtn01` focused:
| | |
|---|---|
| t=2.0 vs t=4.0 (one full period apart), **whole frame** | **0.0000 / 255** — bit-identical |
| t=2.5, 3.0, 3.5 against t=2.0, inside the ring's box | 3.60, 3.71, 3.58 / 255 |
| sum of box luminance across **eight** phases | spread **0.027 %** of the mean |
The last row is deliberately the RE agent's own observable: they separated
rotation from a brightness pulse by showing total annulus brightness is conserved
while per-bin brightness moves. The port's render conserves it to 0.027 % (theirs
was 0.4 % over 16 s, with capture noise in it). A filmstrip of the four
quarter-period phases shows the bright head at top, right, bottom, left.
### Two things it does not settle
* **Direction.** The port turns 0° → +360°, the sign the disc declares. No signed
angle was ever measured — the estimator that would have given one failed its
control and was not used.
* **Phase across a focus change.** The port drives the ring off the **screen**
clock, so moving the cursor does not restart the turn. The alternative — the
record's group restarting when the record is instantiated — is the stronger
claim, and the oracle run held focus on one button throughout, so nothing
separates them. Two frames straddling a focus change would.
## P3, corrected — the plate needs no authored delay at all, 2026-08-29
Last iteration the port refuted the RE agent's authoring instruction (*"when
build 4 has settled, wait 2.13 s, composite build 2"*) with arithmetic off the
disc, shipped the instruction anyway rather than pick between two of their
numbers, and printed the discrepancy on every boot.
**The refutation held, and the answer that came back is better than either option
the port offered: author nothing.** `5b0a6e6`.
### The premise that failed was the port's, and it will bite again
> 🔴 **`rest.t` is not when a screen settles.** It is the last *hold* keyframe
> before the exit.
Checked here rather than taken on trust. `title`'s `ptlogo1`:
```
t=26 (-116,-7) 150% a=0x00 the pre-roll
t=42 (179,186) 101% a=0xe0 it has arrived
t=251 (184,193) 100% a=0xff 5 px and 31 alpha steps later, 3.5 s on
```
It **stops moving at t=42** and then creeps for 209 units. `rest.t = 251` is the
end of that creep, not the arrival. The title's visible build-in is over at
**`t = 118`**, where `pteff01`, `pteff02` and `ptlogoall_eff` finish together.
Every reconciliation the port computed last iteration was wrong by exactly that
error: reading `rest.t` put build 4's arrival at 4.350 s instead of 1.967 s, and
the "2.51 s, which is not a landmark of anything" that looked so damning is
`(4.350 1.967) + 0.13` — the error itself, wearing a decimal point.
### One clock, and the interval is declared
| | units |
|---|---|
| build 4's last build-in ramp | `t = 118` |
| `ptbtn00` reaches `a = 255` | `t = 238` |
| **difference** | **120 units = 2.000 s** |
Measured: **2.138 s** and **2.132 s**. The 6.7 % is presentation rate — 120 units
in 2.135 s is 56.2 units/s, the emulator running 28.1 fps against a nominal 30,
and the corpus had independently measured the idle title at 28.5 fps *before*
these runs.
So `authored/flow.json` carries `"clock": "shared"` and **no delay**, `boot.gd`
raises the overlay when the step's screen loads rather than at its settle, and
`overlay.time_units = view.time_units` — assigned, not accumulated, because two
independently advanced clocks drift by a frame here and there and the whole
content of the finding is that 120 units is a fixed interval on one timeline.
⚠️ **The general hazard, stated by the RE agent and worth repeating where the
port will read it: discount a wall-clock number off that oracle by ~6 %.** It is
Canary's presentation rate baked into whatever it measures. A port at a true
30 Hz that authored 2.13 s would be visibly late.
### Refutation — two of the RE agent's numbers for the same 120 units disagree by 2 %
Both findings measure the same declared quantity: **120 keyframe units of wall
clock, during a static hold, in Xenia Canary.**
| | | implied presentation |
|---|---|---|
| plate: settle → plate, two runs | 2.138, 2.132 s → mean **2.135 s** | 28.10 fps |
| ring: one revolution, seven spacings | 2.18 2.16 2.18 2.16 2.16 2.20 2.20 → mean **2.177 s** | 27.56 fps |
| **disagreement** | **0.042 s = 1.97 %** | |
That is **seven times** the plate finding's own run-to-run agreement of 6 ms, and
it lands on the argument that finding uses to justify trusting itself: *"the
build-in is where frames are dropped; the static hold is not. A model in which
the game's own timing varied would have to move both."* Two static-hold
measurements are exactly what should agree under that model.
A second, smaller arithmetic slip in the same place: the ring page reconciles
2.177 s against a band of "27.628.8 fps", saying the measurement *"sits at the
top of that band"*. It does not sit in it. 60 rendered frames at 27.6 fps is
2.1739 s; the mean needs **27.56 fps** and the two slowest spacings (2.20 s)
need **27.27 fps**. Four of the seven spacings are above the band's top.
**Verdict: the containment claim is refuted; the spin, the period and the
reconciliation are untouched.** Either the presentation rate genuinely differed
between the two sessions — which the plate page's own corroboration argues
against for static holds — or the ring's revolution is not exactly 120 units.
The corpus should say which, because they are the same claim measured twice.
🟢 **Nothing in the port moves either way.** `spin_period_units` uses the
declared 120 units at 60 units/s = **2.000 s of port time**, which is the
true-30 Hz value both readings agree the disc means. This is a corpus
consistency problem, not a port one — which is why it is filed rather than
worked around.