Files
Sylpheed/docs/re/guest-frame-rate-resolved.md
sylph-decoder 60145720ed re: the guest presents at 60 fps -- 120 units/s, and the port's plate IS ~2 s late
Answered against the pre-registration committed before the capture, with a
content hash added to the draw logger.

The buffer rotates three times faster than the content changes: 177
presents carry 3 base addresses but only 102 distinct content hashes, and
the modal run is exactly 2 presents per decoded frame. Consecutive presents
with changed content = 0.5739, inside the pre-registered R band of
0.40-0.60.

That is precisely the failure that invalidated my first answer this
morning. The base address changed every present, which I measured and read
as one decode per present. The content did not.

ADV.wmv is authored at 30.000 fps, so 2 presents per movie frame is 60
presents/s, and 2 units/present x 60 = 120 units/s.

Both controls pass, and they are the ones the withdrawn version lacked --
its two guards tested how I READ the buffer, neither tested whether a
buffer change meant a decode.

Control 1, a static texture must hash constant: the splash atlas changes
once, at an era boundary, and never within an era -- 1 change in 403
samples. Noting that I first wrote this control as "must be constant" and
it read FAIL; stated that way it was wrong, because a re-upload is real
content change and the control has to separate temporal from alternating.
A control that is too strong gets waved away, which is its own failure.

Control 2, the movie luma hash must not be constant: 102 distinct.

Consequence: the plate's t=236 is 1.97 s, not 3.93 s, and the port shows it
~1.96 s late. That is play-test finding 3, and "about two seconds" is the
size the human reported. Every declared duration in seconds across the
corpus is half what we have been quoting; unit counts are untouched.

The 2.13 s third route is explained by emulator speed, and that explanation
is labelled POST-HOC and is not offered as support -- fitting a speed
factor to close a gap is what this corpus keeps losing claims to.

Reach: one boot. This number has moved twice today and a second independent
boot should come before the port rewrites a timeline.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
2026-09-01 19:23:13 +00:00

5.4 KiB
Raw Blame History

The guest presents at 60 fps120 units/s, and that is the plate-late cause

Status: measured, against movie-decode-vs-rotate-preregistration.md, committed before the capture. Instrument: ⟨capture⟩ — the real game in Canary with a texture content hash added to the draw logger for this question. Data: data/movie-decode-vs-rotate.txt.

⚠️ This is my third position on this number today. The first (60 units/s) was withdrawn by me; this reverses it. What is different is not confidence — it is that the instrument now tests the thing that was assumed before, and the control that would expose the failure passed. Read the controls before the verdict.


The result

predicted measured
D decode per present ⇒ 30 fps ⇒ 60 units/s ≥ 0.90
R rotate per present ⇒ 60 fps ⇒ 120 units/s 0.400.60 0.5739
movie luma draws                    177   (presents 422..599)
distinct BASES                        3   59 uses each  <- rotation
distinct CONTENT HASHES             102   <- decodes
consecutive presents, content changed  101/176 = 0.5739

run lengths (presents showing the SAME content):
   1 present :  29
   2 presents:  72   <-- the mode
   4 presents:   1

The buffer rotates three times faster than the content changes. 177 presents carry only 102 distinct frames, and the modal run is exactly 2 presents per decoded frame. That is R.

📌 And this is precisely the failure that invalidated my first answer. The base address changed every present — which is what I measured and read as "one decode per present". The content did not. A base-keyed census cannot see the difference; a content hash can, and it says the guest presents twice per decoded movie frame.

ADV.wmv is authored at 30.000 fps ⟨disc⟩, so 2 presents per movie frame is 60 presents per second ⇒ 2 units/present × 60 = 120 units/s.

The controls, both of which had to pass

Control 1 — a static texture must hash constant. The splash sprite atlas (1280×768) is uploaded once per splash and sampled throughout. If its hash moved between presents, the hash would be racing the writer and nothing else could be read.

h=54D8DB4A2249A978  frames   1..219   n=218
h=478C1E9F56EE5485  frames 224..409   n=186
hash changes between consecutive samples: 1 of 403   ranges disjoint: True

PASS, and in the informative way: it changes once, at an era boundary — a genuine re-upload between the two splashes — and never within an era. ⚠️ I first wrote this control as "must be constant" and it read as FAIL. Stated that way it was wrong: a re-upload is real content change and the control has to distinguish temporal change from alternating change. Recorded because a control that is too strong gets waved away, which is its own failure mode.

Control 2 — the movie luma hash must NOT be constant, or I am hashing the wrong bytes and would manufacture R. PASS: 102 distinct hashes.

These are the controls the withdrawn version lacked. Both of its guards tested how I read the buffer; neither tested whether a buffer change meant a decode.

🔴 What this means for the play-test

The plate's t = 236 is 1.97 s, not 3.93 s. The port shows it ~1.96 s late.

That is finding 3, and "about two seconds" is the size a human reported. Two of the play-test's four named candidates were eliminated earlier (the ramp is drawn; the onset is a completion) — the survivor is the unit→seconds constant, which is where the play-test put it first.

Everything downstream of units/s moves with it: every declared duration on every screen is half what the corpus has been quoting in seconds. Unit counts are untouched, and so is 2 units per present.

Reconciling the third route — and this part is POST-HOC, labelled as such

title-plate-delay-measured.md measured 120 declared units at 2.13 s, twice, agreeing to 6 ms ⇒ ~56 units/s. At 120 units/s that interval is 1.00 s true, so that run's emulator was at ~47 % speed. Plausible — its own harness documents screenshot costing 10.8 s while xenia is running — and this capture independently measured only 44.5 presents per host-second against a 60 fps guest, i.e. 74 % speed with a far lighter harness.

⚠️ But I fitted a speed factor to close a gap, which is what this corpus keeps losing claims to. It is an explanation, not evidence, and it is not offered as support for 120. The support for 120 is the hash ratio and its two controls.

Reach, and what is still not settled

⟨capture⟩, one boot, one movie region, this emulator. The ratio is inside its band and both controls pass, but this number has now moved twice and a second independent boot is the obvious next step before the port rewrites a timeline.

  • Whether Canary's cadence equals a real console's. The vblank interval (one vblank 71.7 %, two 24.6 %) is consistent with a 60 fps guest, but it is host time. A 360 vblanks at 60 Hz and the game presents every vblank here; that it would do the same on hardware is an inference.
  • The clock origin — untouched, and still the other half of finding 3. A common offset survives everything measured here, because every quantity above is a ratio or a count.