re: F1 measured -- held DOWN moves the cursor once and no more, via the file driver
Some checks failed
CI / Native — linux (pull_request) Failing after 33m54s
CI / WASM — Web (pull_request) Successful in 32m1s
CI / Formatting (pull_request) Failing after 1m21s

Fifth boot attempt this session, first clean one, using the harness debugged
last iteration (env-safe input, wide capture window, signed-in profile,
blanked X root). Reached the menu, held DOWN 2.5s wall-clock, armed the F10
draw capture, released, killed -- zero crashes.

Achieved vs requested: 433 of 600 requested frames, spanning 14.43s of GUEST
time against ~4.5s wall-clock for the hold+tail window -- this run went at
~3.2x real time (a cheap static menu, nothing pacing it to a display
refresh). The 2.5s wall-clock hold covers roughly 8s of that guest time.

Method: track one quad shape's position per frame via read_draws.py, not a
screen diff -- the approach f1-menu-repeat-harness-built-not-answered.md
already named as correct. Exactly one shape-group moves at all: one jump of
~0.21-0.225 NDC units (matching the known one-menu-item pitch), complete
within 4 frames / 133ms guest time of arming, then flat (a ~0.0125 pulse
wobble only) for the remaining 427 frames / 14.3s of guest time. Broadening
the match threshold finds no other moving element.

This is a STRONGER negative than the 2026-08-30 result it agrees with (that
one sampled a screen diff at ~4-5fps for 2.0s; this reads every quad every
frame for ~8s of guest-time held) -- it survives, rather than confirms, last
iteration's "coarse sampling hid a fast repeat" alternative, which does not
survive a per-frame instrument over a much longer window. Refutation
attempt against my own prior lean, recorded: it does not survive.

Reconciled, not left in conflict: the human's play-test and pad.py's
"auto-repeats" warning almost certainly went through a REAL controller
(Canary's SDL driver), which auto-repeats keystrokes at a documented
upstream 400ms/100ms (guest time) via the REPEAT keystroke flag. The file
driver deliberately never emits that flag, by design -- so it cannot show
repeat regardless of how carefully or how long it's held, which is exactly
the negative measured here. Still no F1 number; now a specific, well-
evidenced reason the file driver alone will never produce one, and a named
next step (add opt-in REPEAT-flag support to the file driver, matching the
SDL driver's constants, then re-run this exact capture) -- not attempted
this iteration, a second unit on an already-complete one.

Reference data: docs/re/data/f1-cursor-quad-y-per-frame.tsv -- the derived
per-frame Y position and guest tick, not the raw draw log itself (a capture
artifact, kept uncommitted per the corpus's game-content rule).
This commit is contained in:
sylph-decoder
2026-09-12 12:13:41 +00:00
parent 089aa8d7c2
commit 2939fa21d8
4 changed files with 302 additions and 0 deletions

View File

@@ -6607,3 +6607,28 @@ read). Ran out of iteration budget before a clean end-to-end run. **Still no
number for you** — keep `-1.0`. The harness should work next attempt;
flagging for whoever's container hits the same profile-crash first, since
every fresh container starts with none.
## 🔴 F1 — clean run landed. Still keep `-1.0`, but now for a sharper reason
[`docs/re/f1-held-down-measured-no-repeat-via-file-driver.md`](../re/f1-held-down-measured-no-repeat-via-file-driver.md).
Fifth boot attempt, all four bugs fixed: reached the menu, armed the draw
capture cleanly, held ⬇ for 2.5 s wall-clock (≈8 s of *guest* time — this
run went at ~3.2× real time, a cheap static menu with nothing pacing it to a
display refresh). **Measured, not inferred:** one cursor step, caught within
133 ms of the press; then zero further moves for the remaining ~14 s of
guest time the capture covers, tracked per-frame off the draw log, not a
screen diff. This is a *stronger* negative than the 2026-08-30 one, not a
different one — it survives the "coarse sampling hid a fast repeat" theory
that seemed to be winning after the previous iteration's static trace.
**Read together with the earlier source finding**, the picture now holds
together instead of conflicting: the human's play-test and `pad.py`'s
"auto-repeats" warning were almost certainly observed through a **real
controller** (Canary's SDL driver), which auto-repeats keystrokes at a
documented 400 ms delay / 100 ms interval (guest time) — upstream Xenia, not
this game's own code. Our **scripted** input goes through the `file` driver,
which deliberately never emits that repeat flag. So: **still no number, and
now a clear reason no amount of re-testing through the file driver will ever
produce one.** The next thing that could is patching repeat support into the
file driver (proposed twice, not yet built) and re-running this exact
capture. `-1.0` stays authored, not guessed, either way.

View File

@@ -1094,6 +1094,20 @@ attached to a right direction; only the reason is refuted here.
emulator needed — or re-run with a repeat-capable file driver and read
cursor position off the draw log per frame, not a coarse screen-diff.
[`f1-no-repeat-was-the-harness.md`](f1-no-repeat-was-the-harness.md) ⟨harness⟩
🔴 **Half of "to settle" done 2026-09-12, and it points back the other
way.** Re-ran with the *existing* file driver, tracking one quad shape's
position per frame (not a screen diff): one real move, caught cleanly at
133 ms guest resolution, then **nothing for the remaining ~8 s of guest
time the button was held** — a stronger negative than the original, not a
reversal of it. This also refutes my own leading alternative from the
`C_PAD_RINGBUF` trace (that a coarse screen-diff was hiding a fast
polled-state repeat): a per-frame instrument over a much longer held
window still finds nothing. Reading now favours Keystroke-`REPEAT`-driven
menu navigation after all — which the file driver cannot produce by
design, regardless of how carefully it's held — over the polled-state theory.
Still 🟡, not ❌: only the file-driver path is tested; the SDL-driver path
(what a real controller and the human's play-test went through) is not.
[`f1-held-down-measured-no-repeat-via-file-driver.md`](f1-held-down-measured-no-repeat-via-file-driver.md) ⟨capture⟩
* "F10-arming a UI draw capture is safe on any settled screen" — **implicit
in every prior use of it, and false in a fresh container.** A `run-canary`
launch with no signed-in profile (every container right after a restart —

View File

@@ -0,0 +1,131 @@
# frame gtick gfreq_hz cursor_quad_y_ndc
# source: xenia_re_ui_draws_01.log, 2026-09-12, f1_hold_capture.py run 5 (f1g)
# quad: page B5B1C73032BA3FA3, ~0.09x0.16 NDC (focus highlight)
# held DOWN written at wall t~=161.6s (script HOLD start), released ~164.1s
1 8077295605 50000000 0.0525
2 8078950338 50000000 0.055
5 8083967064 50000000 -0.16
6 8085646790 50000000 -0.16
7 8087365907 50000000 -0.16
10 8092344928 50000000 -0.1625
11 8094014388 50000000 -0.1625
12 8095718136 50000000 -0.16
13 8097430051 50000000 -0.1625
21 8110812183 50000000 -0.1675
22 8112478213 50000000 -0.17
23 8114208650 50000000 -0.1675
27 8120905050 50000000 -0.17
28 8122530583 50000000 -0.17
29 8124213619 50000000 -0.17
36 8135946976 50000000 -0.17
37 8137620430 50000000 -0.17
57 8171043909 50000000 -0.16
58 8172689798 50000000 -0.16
65 8184394745 50000000 -0.16
66 8186106441 50000000 -0.16
67 8187771244 50000000 -0.16
70 8192768181 50000000 -0.1625
71 8194492771 50000000 -0.1625
72 8196154016 50000000 -0.16
73 8197801248 50000000 -0.1625
81 8211207297 50000000 -0.1675
82 8212855981 50000000 -0.17
83 8214569003 50000000 -0.1675
87 8221264934 50000000 -0.17
88 8222911320 50000000 -0.17
89 8224614159 50000000 -0.17
96 8236285728 50000000 -0.17
97 8237986083 50000000 -0.17
117 8271508635 50000000 -0.16
118 8273209128 50000000 -0.16
125 8284925117 50000000 -0.16
126 8286599612 50000000 -0.16
127 8288306224 50000000 -0.16
130 8293338269 50000000 -0.1625
131 8295030562 50000000 -0.1625
132 8296723652 50000000 -0.16
133 8298377150 50000000 -0.1625
141 8311734503 50000000 -0.1675
142 8313414801 50000000 -0.17
143 8315067618 50000000 -0.1675
147 8321746008 50000000 -0.17
148 8323415335 50000000 -0.17
149 8325134926 50000000 -0.17
156 8336880646 50000000 -0.17
157 8338715074 50000000 -0.17
177 8372226351 50000000 -0.16
178 8373910878 50000000 -0.16
185 8385596519 50000000 -0.16
186 8387262693 50000000 -0.16
187 8388929103 50000000 -0.16
190 8393937806 50000000 -0.1625
191 8395639462 50000000 -0.1625
192 8397278358 50000000 -0.16
193 8398933992 50000000 -0.1625
201 8412260793 50000000 -0.1675
202 8414004734 50000000 -0.17
203 8415667167 50000000 -0.1675
207 8422367364 50000000 -0.17
208 8424030952 50000000 -0.17
209 8425700045 50000000 -0.17
216 8437382342 50000000 -0.17
217 8439068602 50000000 -0.17
237 8472406179 50000000 -0.16
238 8474085108 50000000 -0.16
245 8485743903 50000000 -0.16
246 8487413304 50000000 -0.16
247 8489067654 50000000 -0.16
250 8494081252 50000000 -0.1625
251 8495818763 50000000 -0.1625
252 8497475603 50000000 -0.16
253 8499145711 50000000 -0.1625
261 8512509389 50000000 -0.1675
262 8514145895 50000000 -0.17
263 8515853531 50000000 -0.1675
267 8522549986 50000000 -0.17
268 8524228499 50000000 -0.17
269 8525932669 50000000 -0.17
276 8537663413 50000000 -0.17
277 8539354084 50000000 -0.17
297 8572827882 50000000 -0.16
298 8574531771 50000000 -0.16
305 8586256367 50000000 -0.16
306 8587913956 50000000 -0.16
307 8589566049 50000000 -0.16
310 8594594709 50000000 -0.1625
311 8596292779 50000000 -0.1625
312 8597936103 50000000 -0.16
313 8599628814 50000000 -0.1625
321 8613009386 50000000 -0.1675
322 8614648734 50000000 -0.17
323 8616321818 50000000 -0.1675
327 8622991187 50000000 -0.17
328 8624688470 50000000 -0.1725
329 8626338823 50000000 -0.17
336 8638111132 50000000 -0.17
337 8639823382 50000000 -0.17
357 8673272643 50000000 -0.16
358 8674946981 50000000 -0.16
365 8686603708 50000000 -0.16
366 8688279571 50000000 -0.16
367 8689942913 50000000 -0.16
370 8694996359 50000000 -0.1625
371 8696658822 50000000 -0.1625
372 8698321977 50000000 -0.16
373 8699983034 50000000 -0.1625
381 8713361239 50000000 -0.1675
382 8715049029 50000000 -0.17
383 8716689919 50000000 -0.1675
387 8723381237 50000000 -0.17
388 8725066870 50000000 -0.1725
389 8726756040 50000000 -0.17
396 8738454519 50000000 -0.17
397 8740146250 50000000 -0.17
417 8773614167 50000000 -0.16
418 8775249863 50000000 -0.16
425 8787042967 50000000 -0.16
426 8788724033 50000000 -0.16
427 8790309865 50000000 -0.16
430 8795410469 50000000 -0.1625
431 8797094266 50000000 -0.1625
432 8798815247 50000000 -0.16
1 # frame gtick gfreq_hz cursor_quad_y_ndc
2 # source: xenia_re_ui_draws_01.log, 2026-09-12, f1_hold_capture.py run 5 (f1g)
3 # quad: page B5B1C73032BA3FA3, ~0.09x0.16 NDC (focus highlight)
4 # held DOWN written at wall t~=161.6s (script HOLD start), released ~164.1s
5 1 8077295605 50000000 0.0525
6 2 8078950338 50000000 0.055
7 5 8083967064 50000000 -0.16
8 6 8085646790 50000000 -0.16
9 7 8087365907 50000000 -0.16
10 10 8092344928 50000000 -0.1625
11 11 8094014388 50000000 -0.1625
12 12 8095718136 50000000 -0.16
13 13 8097430051 50000000 -0.1625
14 21 8110812183 50000000 -0.1675
15 22 8112478213 50000000 -0.17
16 23 8114208650 50000000 -0.1675
17 27 8120905050 50000000 -0.17
18 28 8122530583 50000000 -0.17
19 29 8124213619 50000000 -0.17
20 36 8135946976 50000000 -0.17
21 37 8137620430 50000000 -0.17
22 57 8171043909 50000000 -0.16
23 58 8172689798 50000000 -0.16
24 65 8184394745 50000000 -0.16
25 66 8186106441 50000000 -0.16
26 67 8187771244 50000000 -0.16
27 70 8192768181 50000000 -0.1625
28 71 8194492771 50000000 -0.1625
29 72 8196154016 50000000 -0.16
30 73 8197801248 50000000 -0.1625
31 81 8211207297 50000000 -0.1675
32 82 8212855981 50000000 -0.17
33 83 8214569003 50000000 -0.1675
34 87 8221264934 50000000 -0.17
35 88 8222911320 50000000 -0.17
36 89 8224614159 50000000 -0.17
37 96 8236285728 50000000 -0.17
38 97 8237986083 50000000 -0.17
39 117 8271508635 50000000 -0.16
40 118 8273209128 50000000 -0.16
41 125 8284925117 50000000 -0.16
42 126 8286599612 50000000 -0.16
43 127 8288306224 50000000 -0.16
44 130 8293338269 50000000 -0.1625
45 131 8295030562 50000000 -0.1625
46 132 8296723652 50000000 -0.16
47 133 8298377150 50000000 -0.1625
48 141 8311734503 50000000 -0.1675
49 142 8313414801 50000000 -0.17
50 143 8315067618 50000000 -0.1675
51 147 8321746008 50000000 -0.17
52 148 8323415335 50000000 -0.17
53 149 8325134926 50000000 -0.17
54 156 8336880646 50000000 -0.17
55 157 8338715074 50000000 -0.17
56 177 8372226351 50000000 -0.16
57 178 8373910878 50000000 -0.16
58 185 8385596519 50000000 -0.16
59 186 8387262693 50000000 -0.16
60 187 8388929103 50000000 -0.16
61 190 8393937806 50000000 -0.1625
62 191 8395639462 50000000 -0.1625
63 192 8397278358 50000000 -0.16
64 193 8398933992 50000000 -0.1625
65 201 8412260793 50000000 -0.1675
66 202 8414004734 50000000 -0.17
67 203 8415667167 50000000 -0.1675
68 207 8422367364 50000000 -0.17
69 208 8424030952 50000000 -0.17
70 209 8425700045 50000000 -0.17
71 216 8437382342 50000000 -0.17
72 217 8439068602 50000000 -0.17
73 237 8472406179 50000000 -0.16
74 238 8474085108 50000000 -0.16
75 245 8485743903 50000000 -0.16
76 246 8487413304 50000000 -0.16
77 247 8489067654 50000000 -0.16
78 250 8494081252 50000000 -0.1625
79 251 8495818763 50000000 -0.1625
80 252 8497475603 50000000 -0.16
81 253 8499145711 50000000 -0.1625
82 261 8512509389 50000000 -0.1675
83 262 8514145895 50000000 -0.17
84 263 8515853531 50000000 -0.1675
85 267 8522549986 50000000 -0.17
86 268 8524228499 50000000 -0.17
87 269 8525932669 50000000 -0.17
88 276 8537663413 50000000 -0.17
89 277 8539354084 50000000 -0.17
90 297 8572827882 50000000 -0.16
91 298 8574531771 50000000 -0.16
92 305 8586256367 50000000 -0.16
93 306 8587913956 50000000 -0.16
94 307 8589566049 50000000 -0.16
95 310 8594594709 50000000 -0.1625
96 311 8596292779 50000000 -0.1625
97 312 8597936103 50000000 -0.16
98 313 8599628814 50000000 -0.1625
99 321 8613009386 50000000 -0.1675
100 322 8614648734 50000000 -0.17
101 323 8616321818 50000000 -0.1675
102 327 8622991187 50000000 -0.17
103 328 8624688470 50000000 -0.1725
104 329 8626338823 50000000 -0.17
105 336 8638111132 50000000 -0.17
106 337 8639823382 50000000 -0.17
107 357 8673272643 50000000 -0.16
108 358 8674946981 50000000 -0.16
109 365 8686603708 50000000 -0.16
110 366 8688279571 50000000 -0.16
111 367 8689942913 50000000 -0.16
112 370 8694996359 50000000 -0.1625
113 371 8696658822 50000000 -0.1625
114 372 8698321977 50000000 -0.16
115 373 8699983034 50000000 -0.1625
116 381 8713361239 50000000 -0.1675
117 382 8715049029 50000000 -0.17
118 383 8716689919 50000000 -0.1675
119 387 8723381237 50000000 -0.17
120 388 8725066870 50000000 -0.1725
121 389 8726756040 50000000 -0.17
122 396 8738454519 50000000 -0.17
123 397 8740146250 50000000 -0.17
124 417 8773614167 50000000 -0.16
125 418 8775249863 50000000 -0.16
126 425 8787042967 50000000 -0.16
127 426 8788724033 50000000 -0.16
128 427 8790309865 50000000 -0.16
129 430 8795410469 50000000 -0.1625
130 431 8797094266 50000000 -0.1625
131 432 8798815247 50000000 -0.16

View File

@@ -0,0 +1,132 @@
# F1 — measured: held ⬇ moves the cursor once and no more, over ~8 s of guest time, through the file driver
**Status:** ✅ measured (⟨capture⟩), for the path this container can actually
drive. ❔ still not F1's requested initial-delay/interval numbers — this
result explains why they cannot come from this instrument, and names the one
that could. Instrument:
[`tools/re-capture/f1_hold_capture.py`](../../tools/re-capture/f1_hold_capture.py),
after the four fixes in
[`f1-hold-capture-harness-debugged.md`](f1-hold-capture-harness-debugged.md).
2026-09-12, fifth boot attempt, first clean one.
## The run
Reached the settled main menu at 159.3 s (title at 154.3 s, matching the last
clean run's timing), armed the F10 draw capture, held ⬇ for 2.5 s wall-clock,
released, waited 2 s, killed. Zero crashes. 433 of the requested 600 frames
captured before the kill (`ui_draw_capture_frames=600`, bumped from the
default 3 last iteration).
⚠️ **Achieved vs. requested, per `TEMPORAL-VERIFICATION.md`:** the 433 frames
span **14.43 s of *guest* time** (`gtick`/`gfreq` on each frame header, `50 000 000` Hz)
against **~4.5 s of wall-clock** for the hold + tail — this window ran at
roughly **3.2× real time**, not 1:1. A static 2D menu is cheap to render, and
nothing here was pacing the emulation to a display refresh. The 2.5 s
wall-clock hold itself therefore covers **roughly 8 s of guest time** (the
hold is 2.5 of the 4.5 wall-clock seconds captured), not 2.5. Achieved guest
frame rate: **29.87 fps** — close to a 30 Hz internal tick, for what it's
worth, but this is a rate, not a claim about which clock the menu itself
runs on.
## Method — track one quad shape's position, not a screen diff
Read every draw with `read_draws.py`, grouped quads by `(texture page,
width, height)` — the *"track one quad shape's position over time"* approach
`f1-menu-repeat-harness-built-not-answered.md` already named as the correct
one. Exactly one shape-group moves at all across the whole capture: page
`B5B1C73032BA3FA3`, a small (`0.09 × ~0.16` NDC) element — the focus
highlight, by elimination and by the size of its move (below).
## What it shows
| frame | guest ms since frame 1 | Y (NDC) |
|---|---|---|
| 1 | 0 | **+0.0525** |
| 5 | 133 | **0.16** |
| 6…432 | up to 14 297 ms later | **0.1725 … 0.16** (wobble only) |
**One jump, size 0.210.225 NDC units, complete within 4 frames (133 ms
guest) of arming** — close to the one-item pitch computed from
`menu_focus.py`'s known button rows (`(390315)/720×2 = 0.208`), i.e. this
reads as one menu step. **Then nothing.** The 0.16-ish value that follows
oscillates by ≤0.0125 on a ~60-frame cycle for the remaining **427 frames /
14.3 s of guest time** — a pulsing highlight glow, the same shape of
animation this corpus has measured elsewhere, not a second discrete move.
Broadening the shape-match threshold from ≥50 to ≥5 frames-present finds
only one other group, at the same page and a rounding-adjacent height
(`0.17` vs `0.16`, same element split by sub-pixel quantisation), showing
the identical pattern. **Nothing else in the capture moves at all.**
This is a stronger negative than the 2026-08-30 result it agrees with:
`nav_repeat_and_b.py` sampled a screen diff at ~45 fps for 2.0 s wall-clock;
this reads *every submitted quad, every frame*, for a window covering **~8 s
of guest time** the button was actually held. A coarse-sampling explanation
for "no repeat" — the leading alternative hypothesis after last iteration's
`C_PAD_RINGBUF` trace — cannot survive a per-frame instrument that still
finds nothing.
## Reconciling with the standing conflict, not hand-waving past it
Three facts now sit together and are not actually in tension once separated
by **instrument**, not by hand:
1. The human's play-test, and `pad.py`'s own docstring, both describe a real
repeat — almost certainly observed through a **real controller**, i.e.
Canary's **SDL** input driver.
2. That driver's `GetKeystroke()` (`f1-no-repeat-was-the-harness.md`)
auto-repeats keystrokes at a *documented, upstream* 400 ms initial delay
then 100 ms interval, guest time (`HID_SDL_REPEAT_DELAY`/`_RATE`).
3. This measurement went through the **file** driver, whose `GetKeystroke()`
is *deliberately* built to emit exactly one event per press and never a
`REPEAT`-flagged one — and now, measured rather than argued, holding the
button via that driver's continuously-reporting `GetState()` for ~8
guest-seconds produces no second move either.
**The straightforward reading:** menu repeat is driven by `REPEAT`-flagged
keystrokes, not by polling raw held state every frame. The file driver
cannot produce that flag by design, so it cannot show repeat, however long
or precisely you hold the button through it — which is exactly the negative
result above. Last iteration's `C_PAD_RINGBUF` trace (analog-axis-shaped
fields, favouring a polled-state reading) likely belongs to a different
consumer — plausibly raw stick deflection for something else entirely — not
to whatever specifically steps the menu cursor. That inference is not
re-verified here; flagging it as probably-superseded rather than silently
dropping it.
## What would actually answer F1
Give the file driver the same `REPEAT`-flag capability the SDL driver has,
gated behind a new flag so every other scripted script keeps today's
one-event-per-press behaviour (this was proposed, not built, twice already —
`f1-no-repeat-was-the-harness.md`'s original "what would close it" and the
harness-debugging page's "what's left"). Then re-run this exact capture.
Two outcomes, both answers:
* it now shows a genuine repeat, at some interval derived from the SDL
driver's constants or the game's own consumption of them — measure the
interval in frames at the achieved guest rate, not a millisecond guess;
* it still shows nothing, which would mean the menu's repeat is driven by
something other than the Keystroke `REPEAT` flag after all, and the
question reopens from a different angle.
Not attempted this iteration — patching the driver and re-running is a
second, larger unit on top of an already-complete one.
## Reference data
[`data/f1-cursor-quad-y-per-frame.tsv`](data/f1-cursor-quad-y-per-frame.tsv) —
the focus-highlight quad's Y (NDC) per frame it appears in, with the guest
tick/frequency for each, derived from the run's draw log (not the log
itself, which is a capture artifact and stays uncommitted per the corpus's
rule on game content — this is measurement output, numbers only).
## Reach
⟨capture⟩ for the "no repeat via the file driver" result — direct, per-frame,
quantified in guest time, with the instrument's own capability shown by the
one real move it caught. Everything about *why* (Keystroke vs. polled state)
is ⟨canary-source⟩ reasoning connecting this result to the prior static
trace, not itself re-measured. One run only — the corpus's own two-run
minimum for a reproducibility claim is not met, though this run's own
positive control (catching the initial move at 133 ms resolution) is
evidence the null isn't an instrument artifact of *this specific* run.