re: the guest presents at 30 fps -- 60 units/s, and the port was right
Answered against the pre-registration committed before the capture.
Units per second was the last open number on the PRESS (A) plate, and both
prior measurements of it were wall-clock readings off an emulator that runs
the guest slow by an unknown factor. They disagreed by 2.9x, because a 30 Hz
guest at full speed and a 60 Hz guest at half speed look identical on a wall
clock.
The ruler here is not a clock. ADV.wmv declares 30.0000 fps in its own ASF
header, so a decoded movie frame is a tick the emulator's speed cannot
stretch. Presented frames per decoded movie frame is guest_fps/30 with no
wall clock in the chain.
predicted H_A 30 fps -> 60 units/s -> 1.0
H_B 60 fps -> 120 units/s -> 2.0
measured 1.0000
Both pre-registered guards pass. Guard 2: a perfect repeating 3-buffer
cycle, 52 uses each (exactly 156/3), 2 chroma planes per luma on 156 of 156.
Guard 1: run lengths are 156 runs ALL of length 1 -- no smear, so the
dropped-movie-frame bias that would have pushed the answer toward 120 is
measurably absent rather than argued away.
So H_A. The port keeps its 60 and changes nothing.
REFUTES the live H3 hypothesis that 120 units/s explains the play-test's
late plate. That hypothesis was well-formed and attractive precisely because
it would have explained the complaint, which is why it needed a ruler that
is not a clock.
Which means finding 3 still has no cause. The strongest remaining candidate
is decoded rather than speculative: the plate's declared onset is t=214, not
t=236 -- a 22-unit fade, matching the T=22 the oracle confirmed by measuring
+23 alpha per presented frame on that element.
The pre-registered control could NOT be run: this logger build emits vb=
addresses, not vertex contents, so there was no alpha to check +34 against.
A weaker control is substituted and labelled -- the splash shader/blend
census, which validates the log's structure (what this measurement uses) and
not alpha extraction (which it does not).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jc4pciRArGHfxGGhEbwp5t
This commit is contained in:
@@ -499,6 +499,62 @@ constructed in `sub_8220B610` and released in `sub_821A6470`. A *decoder* betwee
|
||||
`wButtons` and the menus is where repeat timing, edge detection and remapping
|
||||
live. That is the next read.
|
||||
|
||||
---
|
||||
## ✅✅ 2026-09-01 (eighth) — **KEEP YOUR 60.** The guest presents at 30 fps, measured against a ruler that is not a clock
|
||||
|
||||
[`../re/guest-frame-rate-measured.md`](../re/guest-frame-rate-measured.md) ·
|
||||
[pre-registration](../re/guest-frame-rate-preregistration.md) ·
|
||||
[data](../re/data/guest-frame-rate-cadence.txt)
|
||||
|
||||
§H3 said units per second was *"the only place the disagreement lives"* and told
|
||||
you not to change your 60 on my account yet. **It is settled and your 60 is
|
||||
right.** The plate's `t = 236` is **3.93 s**. Change nothing.
|
||||
|
||||
| | predicted | measured |
|
||||
|---|---|---|
|
||||
| **H_A** guest 30 fps ⇒ **60 units/s** | 1.0 presented frames per movie frame | **1.0000** |
|
||||
| H_B guest 60 fps ⇒ 120 units/s | 2.0 | — |
|
||||
|
||||
**The ruler is a disc fact, not a wall clock.** `ADV.wmv` declares 30.0000 fps in
|
||||
its own ASF header, so a decoded movie frame is a tick Canary's speed cannot
|
||||
stretch. Counting presented frames per decoded movie frame gives `guest_fps / 30`
|
||||
with no wall clock in the chain — which is why it succeeds where two wall-clock
|
||||
readings disagreed by 2.9×.
|
||||
|
||||
Both pre-registered guards pass, and cleanly: a perfect repeating 3-buffer cycle
|
||||
(52 uses each, exactly 156/3), 2 chroma planes per luma on 156 of 156, and a
|
||||
run-length distribution that is **156 runs all of length 1** — no smear, so the
|
||||
dropped-frame bias that would have favoured 120 is measurably absent.
|
||||
|
||||
⚠️ The control I pre-registered could **not** be run — this logger build emits
|
||||
`vb=` addresses, not vertex contents, so there was no alpha to check the +34 step
|
||||
against. I substituted the splash shader/blend census, which validates the log's
|
||||
structure (what this measurement uses) and not alpha extraction (which it does
|
||||
not). Recorded in the finding rather than glossed.
|
||||
|
||||
### 🔴 So finding 3 is still unexplained — and here is where I would look
|
||||
|
||||
Units per second was the leading candidate and it is now **eliminated**. The
|
||||
strongest remaining one is decoded, not speculative:
|
||||
|
||||
> **The plate's declared onset is `t = 214`, not `t = 236`.**
|
||||
|
||||
```
|
||||
ptbtn00.t32 0: a=0 214: a=0 236: a=255 238: a=255 244: a=0
|
||||
```
|
||||
|
||||
A keyframe is the start of a ramp, so the plate **fades in across `214 → 236`** —
|
||||
a 22-unit ramp, and that is exactly the `T = 22` the oracle confirmed by measuring
|
||||
**+23 alpha per presented frame** on this very element (`255 × 2 / 22 = 23.18`).
|
||||
|
||||
**At your 60 units/s the plate starts appearing at 3.57 s and is full at 3.93 s.**
|
||||
If your build shows nothing until `t = 236`, it is 0.367 s late *at onset* and it
|
||||
replaces a 22-unit fade with a pop — and a human judges a fade by when it starts.
|
||||
|
||||
⚠️ I am not asserting that is what you do. The play-test says you raise the plate
|
||||
at `t = 236`; whether that is your onset or your completion is yours to check.
|
||||
The disc fact and the arithmetic are what I am handing you.
|
||||
|
||||
---
|
||||
## 🔴🔴 2026-09-01 (seventh) — **THE PAD BIT NUMBERING IS NOT XINPUT'S.** I gave you a wrong table
|
||||
|
||||
|
||||
@@ -137,6 +137,7 @@ files, which is how the same ground got covered twice.
|
||||
| [`structures/stage-mission-tables.md`](structures/stage-mission-tables.md) | The stage table set — phases, routes, sub-objectives and AI parameters | ✅ the table set and how the stage record reaches it, validated across; **`AIParams` disc-wide: 23 objects, one shared 34-profile roster (782 records), loader `sub_8233C368`; `Type`→field-count holds except the two `_Test` templates** |
|
||||
| [`structures/texture-color-k8888.md`](structures/texture-color-k8888.md) | Texture colour interpretation — `k_8_8_8_8` (32bpp UI/HUD textures) | — |
|
||||
| [`ui-keyframe-time-unit.md`](ui-keyframe-time-unit.md) | What a keyframe time is worth, and what shape the ramp has | ✅ CONFIRMED from the running game's own draw stream — the ramp is **linear** (a declared 15-unit fade lands on `round(255·k/15)` for all seven samples) and the animation clock advances **2 time units per submitted frame**. 🟡 the seconds conversion (`1 unit = 1/60 s`) rests on a measured 27.6 present-frames/second |
|
||||
| [`guest-frame-rate-measured.md`](guest-frame-rate-measured.md) | Does the guest present at 30 or 60 fps — i.e. is the UI clock 60 or 120 units/s | ✅ **MEASURED — 30 fps, so 60 units/s.** Answered against a [pre-registration](guest-frame-rate-preregistration.md) committed **before** the capture. **The ruler is ⟨disc⟩, not a clock**: `ADV.wmv` declares 30.0000 fps in its ASF header, so a decoded movie frame is a tick Canary's speed cannot stretch; presented frames per decoded movie frame = `guest_fps/30` with no wall clock in the chain. Predicted 1.0 (H_A) vs 2.0 (H_B); **measured 1.0000**. ✅ Both guards pass: a perfect repeating 3-buffer cycle (52/52/52), 2 chroma per luma on 156/156, and **156 runs all of length 1** — the dropped-frame bias that would have favoured 120 is measurably absent. 🔴 **Refutes** the live H3 hypothesis that 120 units/s explains the play-test's late plate. 🔴 **So finding 3 has no cause yet**; the strongest remaining candidate is decoded — the plate's onset is `t=214` (a 22-unit fade to `t=236`), not `t=236`. ⚠️ The pre-registered +34/frame control could NOT be run (this logger emits `vb=` addresses, not vertex contents); a weaker shader/blend census was substituted and labelled. ⚠️ Reach: one boot |
|
||||
| [`splash-declared-vs-captured.md`](splash-declared-vs-captured.md) | Does the declared keyframe timeline reproduce the captured splash, and is the unit rate global? | ✅ **YES, to ONE alpha level, 2026-09-01** — settles the R1-re-opened 🟡 `⟨our-reader⟩` entry with a disc-table-vs-vertex-stream comparison, **no renderer in the chain**. 50 captured alphas: 39 exact under truncation (30 under rounding), **max error 1 level in 255 (0.39 %)**, and all 11 non-exact are low by exactly 1 on falling segments. The old ❌ rested on an `a=32` that the fixed record layout puts at t=206, four units from the end. ❌ **The per-GamePart RATE claim on this page is WITHDRAWN** — see [`splash-rate-withdrawn.md`](splash-rate-withdrawn.md). The three rates came from three regions of one run at 3.39 / 15.33 / 23.20 labels per guest second and order the same way; it is emulator pacing, already documented in `boot-splash-dwells-are-declared.md`. **60 units/s stands for every screen.** §1 above is untouched — it compares a disc table against vertex alphas at integer t and never divides by a duration. |
|
||||
| [`splash-rate-withdrawn.md`](splash-rate-withdrawn.md) | Why my per-GamePart rate was the emulator's frame rate | ❌ **my claim, refuted within the hour** — by the Port's arithmetic (a 160-unit sub-interval cannot outlast the 210-unit group containing it) and then by my own capture: the three regions ran at **3.39 / 15.33 / 23.20 labels per guest second** and produced 35 / 40 / 57 units/s, monotonically. 🔴 **Instrument lesson:** the guest timebase does NOT remove the pacing artefact — the game's animation clock is frame-coupled, so a slow run advances less animation per guest second. My control verified that the timebase tracks real time, which is capability, not the configuration that mattered. **No rate measured on this emulator is the console's; all are biased low.** The best estimate stays the declared timeline against the fastest runs: **60 units/s**. |
|
||||
| [`units-per-second-measured.md`](units-per-second-measured.md) + [pre-reg](units-per-second-preregistration.md) | Is the animation clock frame-counted or time-integrated, and at what rate | 🟡 **half-answered, 2026-09-01, one prediction HELD and one FAILED.** ✅ **The clock is NOT frame-counted**: the same animation takes 21 labels in one capture and 33 in another, and splash A's logo steps `+136,+34` in one and `+17,+51,+34,+34,+17,+17` in the other. Steps are always integer multiples of **17** (255/15 = one unit), so the clock advances in whole units at a rate set by frame duration. 📌 **This retires "2 units per submitted frame" as a MECHANISM** — 2 was that run's frame pacing, so `units = 2 × frames` computes an emulator artefact. ✅ **RESOLVED later the same iteration: 56.8 units per guest second**, on `ptbtn00`'s ramp with the clamped final step excluded, `T=22` attested by two readers with no clock in the chain — **inside the pre-registered 55–65 band; 30 and 120 both excluded**. Control passed at **1.15 %**: `ptcopyright` gives 650.4 α/s against the plate's 657.9, implying its own `T=22.25`. The earlier 29.9 was a borrowed `T=15` that does not apply to those elements (implied `T` there is 23–34). ⚠️ `60` is **not** refuted — 5.6 % away against ~5 % quantisation — so the port keeps it; but the unit constant is eliminated as a cause of a late plate (t=236 → 4.15 s vs the port's 3.93 s, i.e. fractionally *early*). Instrument: guest timebase (50 MHz, scalar 1.0), control passed — 123.24 guest s over ~118 wall s. |
|
||||
|
||||
41
docs/re/data/guest-frame-rate-cadence.txt
Normal file
41
docs/re/data/guest-frame-rate-cadence.txt
Normal file
@@ -0,0 +1,41 @@
|
||||
# Guest presentation cadence against ADV.wmv's declared 30.000 fps.
|
||||
# One presented frame = one RESOLVE to dest=0x14570000 (595 of them here,
|
||||
# against the logger's own FRAMES=600 budget, so the two agree).
|
||||
|
||||
presented frames in log : 595
|
||||
movie luma draws : 156
|
||||
movie spans frames : 439..594 (156 frames)
|
||||
presented frames per movie fr: 1.0000
|
||||
|
||||
distinct luma bases : 3 ['0x11590000', '0x11720000', '0x118B0000']
|
||||
uses of each : [('118B0000', 52), ('11720000', 52), ('11590000', 52)]
|
||||
perfect repeating 3-cycle : True (pattern ['0x118B0000', '0x11720000', '0x11590000'])
|
||||
chroma planes per luma draw : {2: 156} (YUV420 -> expect 2)
|
||||
|
||||
run lengths (frames holding one luma base):
|
||||
1 frame(s): 156
|
||||
|
||||
RATIO = 1.0000 labels per movie frame
|
||||
H_A 30 fps guest -> 60 units/s predicted 1.0 (band 0.85-1.15)
|
||||
H_B 60 fps guest -> 120 units/s predicted 2.0 (band 1.70-2.30)
|
||||
VERDICT: H_A
|
||||
|
||||
=> guest presents at 30 x 1.0000 = 30.00 fps ; units/s = 2 x that = 60.00
|
||||
|
||||
# CONTROL -- the splash era of this SAME log, frames 4..226.
|
||||
# The PRE-REGISTERED control was the +34/frame alpha step. It could NOT be
|
||||
# run: this logger build emits vb= addresses, not vertex contents. A weaker
|
||||
# control is substituted and labelled as such -- the three splash pixel
|
||||
# shaders and their blend states must reproduce.
|
||||
# Committed, splash-draw-pass-census.txt, an INDEPENDENT boot:
|
||||
# 0xE59B2B3DA4AA9008 blend=0x07010701 the sprite shader
|
||||
# 0x2E372EA28CC404B7 blend=0x00010001 the clear
|
||||
# 0x5773DC18083C4C20 blend=0x07010701 the black backdrop
|
||||
# This capture:
|
||||
# 0xE59B2B3DA4AA9008 blend=0x07010701 x446
|
||||
# 0x2E372EA28CC404B7 blend=0x00010001 x223
|
||||
# 0x5773DC18083C4C20 blend=0x07010701 x223
|
||||
# Same three, same blends, on an independent boot. This validates the log's
|
||||
# STRUCTURE -- frame delimitation, shader and blend fields -- which is what
|
||||
# the cadence measurement uses. It does NOT validate alpha extraction, and
|
||||
# the cadence measurement does not use alpha.
|
||||
166
docs/re/guest-frame-rate-measured.md
Normal file
166
docs/re/guest-frame-rate-measured.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# ✅ The guest presents at **30 fps**, so the UI clock runs at **60 units/s** — the port's value stands
|
||||
|
||||
**Status: ✅ measured.** Instrument: ⟨capture⟩ — the real game in Xenia Canary,
|
||||
per-draw, one boot, 2026-09-01. Ruler: ⟨disc⟩ — `ADV.wmv`'s own ASF header.
|
||||
Answered against
|
||||
[`guest-frame-rate-preregistration.md`](guest-frame-rate-preregistration.md),
|
||||
committed **before** the capture was taken.
|
||||
Data: [`data/guest-frame-rate-cadence.txt`](data/guest-frame-rate-cadence.txt).
|
||||
|
||||
---
|
||||
|
||||
## The result
|
||||
|
||||
| | predicted | measured |
|
||||
|---|---|---|
|
||||
| **H_A** guest 30 fps ⇒ **60 units/s** | 1.0 labels per movie frame | — |
|
||||
| **H_B** guest 60 fps ⇒ 120 units/s | 2.0 | — |
|
||||
| | | **1.0000** |
|
||||
|
||||
**H_A, and not marginally.** The plate's `t = 236` is **3.93 s**.
|
||||
|
||||
🔴 **This closes the question the port was blocked on, and the answer is that the
|
||||
port was already right.** `HANDOFF.md` §H3 said *"units per second is still open,
|
||||
and it is now the only place the disagreement lives"*, and warned *"do not change
|
||||
your 60 on my account yet."* Good: 60 is correct and nothing should change.
|
||||
|
||||
⚠️ **So the play-test's "the plate arrives late" is NOT a units-per-second
|
||||
error.** The leading candidate is eliminated. See "what this re-opens" below.
|
||||
|
||||
## Why this measurement does not have the defect the previous two had
|
||||
|
||||
Canary presents at ~27–28 fps and runs the guest slower than real time by an
|
||||
unknown factor, so *a 30 Hz guest at full speed* and *a 60 Hz guest at half speed*
|
||||
produce the identical wall-clock observation. Both earlier readings were wall
|
||||
clock, and they disagree by **2.9×** (2.13 s vs 0.73 s for the same interval).
|
||||
|
||||
The ruler here is not a clock at all. `ADV.wmv` — the boot intro and the attract
|
||||
movie, the same asset — declares its video rate **in the shipped file**:
|
||||
|
||||
```
|
||||
ExtendedStreamProperties stream #2 avgTimePerFrame = 333333 x100ns -> 30.0000 fps
|
||||
```
|
||||
|
||||
⚠️ Stream **#1** is the audio and its `avgTimePerFrame` is 3 276 559, which reads
|
||||
as 3.05 fps. Reading the wrong stream is the obvious way to get this wrong, so it
|
||||
is recorded rather than silently avoided.
|
||||
|
||||
A decoded movie frame is therefore a tick that the emulator's speed cannot
|
||||
stretch: however slowly Canary runs, the guest still decodes 30 movie frames per
|
||||
second **of movie time**. Counting presented frames per decoded movie frame gives
|
||||
`guest_fps / 30` with **no wall clock anywhere in the chain**.
|
||||
|
||||
## The measurement, and both guards
|
||||
|
||||
One presented frame = one `RESOLVE` to `dest=0x14570000`. There are **595** of
|
||||
them against the logger's own `FRAMES=600` budget, so the two notions of "frame"
|
||||
agree and the count is not the harness's.
|
||||
|
||||
```
|
||||
movie luma draws : 156
|
||||
movie spans frames : 439..594 (156 frames)
|
||||
presented frames per movie fr : 1.0000
|
||||
```
|
||||
|
||||
**Guard 2 — is it really a buffer cycle?** Yes, and stronger than asked:
|
||||
|
||||
```
|
||||
distinct 1280x720 luma bases : 3 0x11590000 0x11720000 0x118B0000
|
||||
uses of each : 52, 52, 52 (156/3 exactly)
|
||||
perfect repeating 3-cycle : True (not merely 3 distinct)
|
||||
chroma planes per luma draw : 2, on 156 of 156 (YUV420)
|
||||
```
|
||||
|
||||
**Guard 1 — a spike, not a smear.** The pre-registration said H_A is a spike at
|
||||
1, H_B a spike at 2, and frame-dropping a smear with a tail:
|
||||
|
||||
```
|
||||
run lengths (frames holding one luma base):
|
||||
1 frame(s): 156
|
||||
```
|
||||
|
||||
**156 runs, all of length 1, nothing else.** No tail, no smear, no dropped movie
|
||||
frames. The bias that would have pushed the answer toward H_B is measurably
|
||||
absent rather than argued away.
|
||||
|
||||
## 🔴 The control was NOT the one I pre-registered, and that is stated plainly
|
||||
|
||||
The pre-registered control was *"the splashes' established +34/frame alpha step
|
||||
must reproduce in the same log."* **It could not be run**: this logger build emits
|
||||
vertex-buffer *addresses* (`vb=0x14CD00BC`), not vertex contents, so there is no
|
||||
alpha to extract. I did not discover that until the log was in hand.
|
||||
|
||||
Substituted, and weaker in a way worth naming: the three splash pixel shaders and
|
||||
their blend states must reproduce against the committed census from an
|
||||
**independent boot**.
|
||||
|
||||
| | committed census | this capture |
|
||||
|---|---|---|
|
||||
| sprite shader | `0xE59B2B3DA4AA9008` `0x07010701` | ✅ ×446 |
|
||||
| the clear | `0x2E372EA28CC404B7` `0x00010001` | ✅ ×223 |
|
||||
| black backdrop | `0x5773DC18083C4C20` `0x07010701` | ✅ ×223 |
|
||||
|
||||
This validates the log's **structure** — frame delimitation, shader and blend
|
||||
fields — which is what the cadence measurement actually uses. It does **not**
|
||||
validate alpha extraction, and the cadence measurement does not use alpha. That
|
||||
is why the substitution is acceptable here and would not have been for a claim
|
||||
about a ramp.
|
||||
|
||||
## Independent corroboration, from data already committed
|
||||
|
||||
[`data/attract-frame-match.txt`](data/attract-frame-match.txt) matched captured
|
||||
attract frames to timestamps inside `ADV.wmv`. Over its fourteen high-confidence
|
||||
`ADV` matches, movie time advances **≈ 5.77 movie-seconds per capture step**
|
||||
against a harness that sleeps 5 s plus grab overhead — i.e. the movie plays at
|
||||
roughly **real time**. A movie playing at real time, with one present per movie
|
||||
frame, is a guest presenting at ≈ 30 fps. Consistent, from a different capture,
|
||||
a different instrument, and a measurement taken for a different purpose.
|
||||
|
||||
## 🔴 What this re-opens: finding 3 still has no cause
|
||||
|
||||
Units per second was the leading candidate for *"the `PRESS Ⓐ` plate arrives
|
||||
late"* and it is now **eliminated**. The play-test's remaining candidates were:
|
||||
the clock origin, `rest.t`, and the record layout. One of them is now the most
|
||||
likely, and it is **decoded**, not speculative:
|
||||
|
||||
> **The plate's declared onset is `t = 214`, not `t = 236`.**
|
||||
|
||||
```
|
||||
$ sylpheed-cli screen info --build 2 --geometry $SYLPHEED_DISC/dat/GP_TITLE.pak
|
||||
ptbtn00.t32 0: a=0 214: a=0 236: a=255 238: a=255 244: a=0
|
||||
```
|
||||
|
||||
A keyframe is the **start of a ramp** (an established ✅ law), so the plate fades
|
||||
in across `214 → 236` — a **22-unit ramp**, which is exactly the `T = 22` the
|
||||
oracle independently confirmed by measuring **+23 alpha per presented frame** on
|
||||
this element (`255 × 2 / 22 = 23.18`).
|
||||
|
||||
**At 60 units/s the plate begins appearing at 3.57 s and is full at 3.93 s.** A
|
||||
port that shows nothing until `t = 236` is 22 units — **0.367 s** — late at
|
||||
onset, and replaces a 22-unit fade with a pop. A human watching judges a fade by
|
||||
when it *starts*.
|
||||
|
||||
⚠️ **I am not claiming that is what the port does.** The play-test reports the
|
||||
port raising the plate at `t = 236`; whether that is its onset or its completion
|
||||
is the port's to check. What is decoded here is the disc fact and the arithmetic.
|
||||
|
||||
## Reach
|
||||
|
||||
⟨capture⟩ over **one** boot, English locale, one machine, and the movie region of
|
||||
one log. The ratio is exact and both guards pass, but a second independent boot
|
||||
would make it ⟨capture⟩×2 — worth having before anything irreversible rests on
|
||||
it, though nothing needs to, because the answer is "keep 60".
|
||||
The 30.000 fps ruler is ⟨disc⟩ and generalises.
|
||||
|
||||
## Refutation attempt, recorded per the adversarial duty
|
||||
|
||||
**Target:** my predecessor's own H3 note that *"`2 × 60 fps` is 120 units/s, which
|
||||
puts the plate at 1.97 s instead of 3.93 s — and 'about two seconds early' is the
|
||||
size of what the human reported."* That is a live hypothesis with a plausible
|
||||
motive, and it is the one I expected to confirm.
|
||||
|
||||
**Result: REFUTED.** The guest presents one frame per decoded movie frame, on a
|
||||
perfect 3-buffer cycle with no dropped frames. 120 units/s requires two presents
|
||||
per movie frame and there are none. The hypothesis was well-formed and wrong, and
|
||||
the reason it was attractive — it would have explained the play-test — is exactly
|
||||
why it needed a ruler that is not a clock.
|
||||
Reference in New Issue
Block a user