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).
7.1 KiB
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,
after the four fixes in
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.21–0.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 ((390−315)/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 ~4–5 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:
- 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. - 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). - This measurement went through the file driver, whose
GetKeystroke()is deliberately built to emit exactly one event per press and never aREPEAT-flagged one — and now, measured rather than argued, holding the button via that driver's continuously-reportingGetState()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
REPEATflag 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 —
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.