diff --git a/docs/re/INDEX.md b/docs/re/INDEX.md index 50ab29c2..7492dbda 100644 --- a/docs/re/INDEX.md +++ b/docs/re/INDEX.md @@ -137,7 +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 | -| [`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. ❌ **The rate FAILED its prediction**: predicted 60 units/guest-second, measured **median 29.9** (25.2–36.6) — but that rests on `T=15`, which I have not read off the disc and whose usual derivation is circular with the thing just retired. **Settles with the plate (`T=22`, attested by two readers with no clock in the chain) captured with tick stamps; that run did not reach the title in 531 s.** Instrument: guest timebase (50 MHz, scalar 1.0), control passed — 123.24 guest s over ~118 wall 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. | | [`h3-units-per-frame-measured.md`](h3-units-per-frame-measured.md) | How many keyframe units elapse per guest frame, and which declared time the title's settle anchor is | ✅ **measured against a pre-registration, 2026-09-01. 2 units per guest frame**, on `ptbtn00`'s own declared ramp (`t=214→236`, T=22): three consecutive gap-free steps of **exactly 23** = 255×2/22, ramp span 10 labels against a predicted 11 (±1). The Port's inferred **5 is excluded by >2×**. 🔴 Why 5 appeared: **an alpha step is not a clock rate** — `Δα/frame = 255·(units/frame)/T`, so splash B's 34-with-T=15 and the plate's 23-with-T=22 are ONE clock. Also: the **title settle anchor is t≈160**, not t=118 — it is `ptcopyright`, the last build-in element and the only glyph one, full at label 5350 → t≈168–176. 🔴 **units/SECOND is NOT settled** and two of my own captures disagree ~2.9× on it; the gap is in frames→seconds, not units→frames. | | [`h3-units-per-frame-preregistration.md`](h3-units-per-frame-preregistration.md) | The prediction, committed before the capture was read | ✅ kept as the control on the row above | | [`input-pad-read-path.md`](input-pad-read-path.md) | What the game asks the console for, on the pad | ✅ **decoded from the image, 2026-09-01.** `sub_82457038` is the only function that reads controller *data*, and it compares **every** field of `XINPUT_GAMEPAD` — `wButtons` (full 16 bits), both triggers, all four stick axes — against the previous state. **14/14** loads verified byte-for-byte against `/image/sylpheed.pe`, database used as an index only. **Two input paths**: the polled state and an 8-byte-record `XamInputGetKeystrokeEx` ring. ⚠️ This is the **superset the game can see, not the per-screen set** — reading a field is not acting on it. ❔ Which bits each screen tests is open; footholds are the image's own `C_PAD_DECODER` / `C_PAD_RINGBUF` trace strings (`sub_8220B610` / `sub_821A6470`). | diff --git a/docs/re/data/units-per-second-rate.txt b/docs/re/data/units-per-second-rate.txt new file mode 100644 index 00000000..0cb50cff --- /dev/null +++ b/docs/re/data/units-per-second-rate.txt @@ -0,0 +1,26 @@ +# The animation clock's RATE, in GUEST seconds, off the title's build-in. +# Capture 2026-09-01 (tickcap), augmented draw logger with the guest timebase +# (50 MHz, guest_time_scalar_=1.0). No host wall clock enters any number here. +# The LAST step of a ramp is excluded everywhere: it clamps at 255 and so +# reports more elapsed time than it actually consumed. + +## ptbtn00 (the plate) + ramp (label, alpha): (6709,11), (6710,46), (6711,69), (6712,92), (6713,115), (6715,162), (6716,185), (6717,197), (6718,231), (6719,255) + steps (Δα, ms): (35,31.5), (23,46.0), (23,22.7), (23,69.4), (47,49.4), (23,46.9), (12,35.3), (34,33.2), (24,51.0) + unclamped span: α 11 → 231 (Δα=220) over 334.4 guest ms + -> 657.9 alpha per guest second + -> declared T=22: **56.8 units per guest second** + +## ptcopyright + ramp (label, alpha): (6675,34), (6676,57), (6677,69), (6678,92), (6679,115), (6680,139), (6681,162), (6683,231), (6684,255) + steps (Δα, ms): (23,47.8), (12,30.0), (23,33.2), (23,46.1), (24,24.6), (23,68.9), (69,52.4), (24,45.5) + unclamped span: α 34 → 231 (Δα=197) over 302.9 guest ms + -> 650.4 alpha per guest second + -> T not independently attested; at the plate's rate this implies T = 255·rate/(Δα/Δt) + +## CONTROL (pre-registered): two independent elements, same screen, same run + ptbtn00 (the plate): 657.9 alpha/s + ptcopyright: 650.4 alpha/s + agreement: 1.15 % + -> they share one ramp length as well as one clock; at the plate's T=22 + ptcopyright's implied T is 22.25 diff --git a/docs/re/units-per-second-measured.md b/docs/re/units-per-second-measured.md index 5a25ba8b..71df0f40 100644 --- a/docs/re/units-per-second-measured.md +++ b/docs/re/units-per-second-measured.md @@ -126,3 +126,84 @@ Two captures, the boot splashes in both, one title capture without stamps. The "not frame-counted" conclusion rests on a **comparison between captures** and is as strong as the two captures being of the same animation, which their element rects and declared ramps make certain. The rate has no reach at all yet. + +--- + +# 🔴 RESOLVED LATER THE SAME ITERATION — the title capture landed, and the rate is **~57 units per guest second** + +Everything above was written while the capture was still running. It then reached +the title **after** the harness had stopped classifying, so the plate's ramp is in +the log with tick stamps after all. Kept above rather than rewritten, because the +sequence is the point: the failed prediction was caused by exactly the `T` +circularity the page names, and the fix is the element whose `T` does not need a +clock. + +## The measurement + +[`data/units-per-second-rate.txt`](data/units-per-second-rate.txt) + +``` +ptbtn00 (the plate) α 11 → 231 over 334.4 guest ms 657.9 α/s +ptcopyright α 34 → 231 over 302.9 guest ms 650.4 α/s +``` + +The **last step of each ramp is excluded**: it clamps at 255 and therefore reports +more elapsed time than it consumed. Including it drags the plate from 657.9 to +633.0 α/s — a 4 % error entirely inside the clamp. + +**With `ptbtn00`'s independently attested `T = 22`:** + +> ## **56.8 units per guest second** + +## ✅ Both pre-registered predictions now hold, and the control passes + +| # | prediction | outcome | +|---|---|---| +| 1 | time-integrated | ✅ **held** — and by the between-capture argument above, not the regression | +| 2 | **60 units/s, accept 55–65** | ✅ **56.8 — inside the band** | +| 3 | 120 and 30 excluded | ✅ **both excluded.** 30 would need `T = 11.6` for the plate; 120 would need `T = 46.5` | + +**The control I pre-registered — two independent elements, same screen, same run — +passes at 1.15 %.** `ptcopyright` gives 650.4 α/s against the plate's 657.9. At +one shared clock that makes `ptcopyright`'s own segment **`T = 22.25`**, i.e. the +same 22-unit ramp; two elements agreeing on a rate *and* independently landing on +a round declared length is a stronger result than either alone. + +## Why the earlier ~30 was wrong, and it is the failure the page predicted + +`units/s = (Δα/Δt) × T / 255`. The splash estimate used **`T = 15`**, borrowed +from `ui-keyframe-time-unit.md`. That row is about *an* element with a declared +15-unit fade; **I generalised it to splash B's quads, which is not what it says.** +At the measured 56.8 units/s those elements' implied lengths are: + +| element | measured α/s | implied `T` | +|---|---|---| +| splash A logo | 622.5 | **23.3** | +| splash B logos ×3 | 508.7 | **28.5** | +| splash B companions ×2 | 428.2 | **33.8** | + +None is 15. The page above said the answer would move by exactly the factor the +unknown moved by, and it did — 29.9 × (28.5/15) = 56.8. + +⚠️ **The step-quantum argument does not rescue `T = 15` either.** Splash steps are +multiples of 17 and `255/15 = 17`, which is what made 15 look confirmed — but at +`T = 28.5` a step of 17 is simply **two** units of 8.9. A quantum fixes `T` only +if you already know the step is one unit, and nothing said it was. + +## Resolution and reach + +**Classified: measured.** ⟨capture⟩, guest timebase, control passed. + +* **`56.8` is not `60`, and `60` is not refuted.** The span is 19 units at ~11.6 α + per unit, so one unit of quantisation is ~5 %; 60 sits 5.6 % away, at the edge + of this measurement's resolution. **The port keeps 60.** +* **It does eliminate the unit constant as the cause of a late plate.** At 56.8 + units/s the plate's `t = 236` lands at **4.15 s** after clock zero against the + port's 3.93 s — the port is fractionally *early*, not late. Whatever the human + saw, this is not it. +* 🟡 **Reach is the title.** The splashes are a different `GamePart` and this does + not establish that they tick at the same rate — it establishes that their `T` + is unknown, which is a different statement. Reading `T` off the disc for the + splash elements is the way to close that, and it is static work. +* 🟡 The **structured residual** — long frames advancing less than a constant rate + predicts — is untouched and still unexplained.