PR #615 follow-ups: budget_ms window, focus-ring interior pin, S8's --fixed-fps nf-34x ← Beads

open priority 2 task unassigned

Twinned from https://github.com/cfsh/ninefold/issues/617 by tools/beads/import_github.py's reconcile pass.

Suggestions from ninefold-reviewer's review of #615. Advisory residuals only — #615 converged; none of these blocked it. Unclaimed.

1. budget_ms measures ~half the window the assertion actually depends on

shared/VisualProbe.cs_waitStartedMs is stamped when the wait step is dequeued and the budget is evaluated when _waitLeft hits 0. Every other step burns its own frame (case "joydown" sets _waitLeft = 1; expect_bar is dequeued a frame later still), so butterbar-gate's first budgeted leg runs:

``` F2 dequeue joydown a -> press sent, _waitLeft = 1 F3 _waitLeft -> 0 (PianoRoll sets _barHeldSinceMs here) F4 dequeue wait 2 / budget_ms 300 <- _waitStartedMs stamped HERE F5 _waitLeft -> 1 F6 _waitLeft -> 0 <- budget evaluated HERE (2 frames) F7 dequeue expect_bar "" <- assertion reads BarShown HERE ```

The claim the assertion really makes is t(F7) - t(F3) < 300ms — four frames. The budget covers t(F6) - t(F4) — two. So HOST TOO SLOW fires only above ~150 ms/frame, while expect_bar "" starts failing for host-speed reasons above ~75 ms/frame. Between those, the run prints a bare expect_bar '' FAILED — bar is 'RESIZING · ...' with no diagnostic, which is the misdiagnosis budget_ms exists to prevent.

Not hypothetical for the gating VM: it fires correctly at the measured 850-1150 ms/frame under load, but #615's own open question 1 notes idle frame pacing is unmeasured. An idle llvmpipe VM around 100 ms/frame lands in the hole.

Either fix works: stamp _waitStartedMs at the preceding input step rather than at the wait, or set budget_ms in the probe below the gate it stands in for (e.g. 150) so the margin absorbs the untimed frames. Whichever, notes/probes.md should say the budget covers the wait step only.

2. focus-ring's top pin has an exact interior sample available

Design 003 S7 asked for the stroke *interior* rather than its boundary. focus-ring.json's _intent records the Windows ring spanning y125-182, so the top stroke is y=125-126 with (180,126) its last row; #615 measures the Linux stroke at y=124-125. y=125 is stroke on both, so (180,125) is an exact within: 0 assertion that satisfies S7 literally and drops the relaxation for that pin.

The _intent's rebuttal — the re-pin treadmill this file has been on twice — argues against re-pinning to a *boundary*, which is what both previous re-pins did; it does not cover pinning to the intersection of the measured strokes.

The left sample is genuinely harder and within may well be right for it: x=172 is antialiased on Linux with the core at x=174-175, and the Windows core was not measured.

3. --fixed-fps (design 003 S8) will not fix butterbar-gate

Design 003 P0.7 calls --fixed-fps "the structural fix" for frame/wall-clock decoupling, and #615's body cites S8. It re-couples delta, not the clock: games/tonapse/ui/PianoRoll.cs:1086 gates on Godot.Time.GetTicksMsec() — real wall time, which --fixed-fps does not slow. On a host at 900 ms/frame the 300 ms gate still expires between the press and the assertion. Worth recording before S8 is picked up expecting it to close this probe. (--audio-driver Dummy, the other half of S8, is unaffected and still worth doing.)

4. Minor: a test comment names a probe that does not carry the assertion

games/tonapse/tests/DemoSeedOrderTests.cs — the comment on Starter_demo_opens_on_home says expect_prop PatternRoster 'home,lift' is asserted "in new-pattern.json / focus-grammar.json". Only tools/probes/new-pattern.json has it; focus-grammar.json has no PatternRoster assertion.

Dependencies

None.

Comments

No comments.

Add a comment