Frame-counted waits dominate the corpus (495 vs 32), and `budget_ms` is used twice in one probe nf-j6a ← Beads

open priority 2 task unassigned

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

Measured at 3f9b5c9, filed unclaimed. This is #514's third suggestion — *"sweep the other probes for frame-counted waits standing in for wall-clock facts"* — separated out so it is not lost when #514 closes on the retry fix.

The measurement

``` 34 probes use wait (frame-counted). 0 use wait_ms (wall-clock). 93 wait grid-scroll 21 wait ring-scale 51 wait focus-grammar 19 wait single-screen-pill 28 wait single-screen 19 wait colour-modes 22 wait roll-jumps 17 wait playtest-capture ```

wait_ms has been supported by shared/VisualProbe.cs since #331 and nothing has ever used it as a step. Its own header names the hazard:

> the off-screen probe window runs uncapped under load, so 40 frames can be under 200ms

Why it matters, with the incident attached

#514 traced new-pattern's ~18% flake under sweep load to exactly this, and four consecutive merges then got four wrong signals from one probe. #508 fixed the same class in one probe hours earlier. The pattern is not one bad probe; it is the whole corpus asserting wall-clock facts (a scene loading, a modal animating, a demo seeding) in units of frames, on a box whose frame rate is a function of how many other probes are running.

⚠️ The gate's retry (#665) contains the damage, it does not remove it. A flake now costs a FLAKY line instead of a poisoned baseline entry — but it still costs a re-run, still muddies the signal, and the retry itself runs under the same load.

What this is not

Not a bulk conversion. wait: 45wait_ms: 750 is a guess at what the probe was calibrated against, and 34 probes' worth of guesses, applied at once to a suite that is currently 34/34 green, is a good way to trade an occasional flake for a permanent one. The work wants to be:

  1. A rule first — which waits are load-bearing? A wait before a shot is a frame-count fact; a wait before an expect_focus that follows an animation is a wall-clock fact standing in the wrong units. Only the second class needs converting.
  2. A lint for the first class, in tools/tests/test_probe_corpus.py, which already gates within and _intent — so the next probe cannot reintroduce it. #514 asked for exactly this.
  3. Then the conversions, probe by probe, each with before/after evidence, highest-wait-count first (grid-scroll at 93 is both the worst offender and the best test of the rule).

Steps 1 and 2 are the valuable part; step 3 is mechanical once they exist.

Related: #514 (the flake that became a baseline entry), #508 (F1, same class, one probe), #471 (menu-focus), #331 (wait_ms's own lesson), #543/#548 (the contention that makes load real).

Dependencies

None.

Comments

No comments.

Add a comment