probe_gate.py: with no display, all 34 probes 'fail' and it offers a paste-ready issue claiming main regressed every one nf-jo4t ← Beads

closed priority 2 task unassigned activesession:probe-gate

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

**With no display available, probe_gate.py reports every probe as a regression and hands the operator a paste-ready gh issue create command claiming main broke all 34.** The real cause is one line of Godot output near the top.

Measured on nf-dev-sg today, running the post-merge gate for #553. Filed unclaimed.

What it printed

``` ──── 0 passed, 34 failed ──── Most likely this branch carries the regression, or main has moved on. File it (not filed automatically — outward-facing): gh issue create -R cfsh/ninefold \ --title "detached: d49a920 regressed butterbar-gate chit-budget cold-start colour-modes cujs-gaps delete-confirm dial-reset explore-walk …" ```

Thirty-four names. The actual cause, identical in every one of the 34 blocks:

``` ERROR: X11 Display is not available WARNING: Display driver x11 failed, falling back to wayland. libwayland-cursor.so.0: cannot open shared object file: No such file or directory ERROR: Unable to create DisplayServer, all display drivers failed. ```

Not one probe ran a frame. Re-run as xvfb-run -a ./tools/pr/probe_gate.py: 33 passed, 1 failed — the single failure being focus-ring's known Linux pixel divergence (`expect_pixel (180,126) FAILED — got (98,191,133), want (244,232,135) ±30`), already diagnosed and fixed in flight by #615.

Why this is worth a guard

The sweep is outward-facing by design — the gate deliberately does not file automatically, and instead composes a command for a human to run *"at the exact moment a human is present"*. That makes a wrong diagnosis expensive: the low-friction action it offers is filing a false 34-probe regression against a named commit, and the message it pairs with it (*"most likely this branch carries the regression"*) actively points away from the cause.

It also silently mis-attributes: I ran this immediately after merging #553, so the obvious reading was that my merge broke everything.

⚠️ This is not the same as wrapping the display. Design 003 S9 (*"display strategy in probe.pyxvfb-run on Linux"*, still not started) tracks making probes *run* headless, and the board already notes merge_pr.py needs xvfb-run on this box. This issue is about what the gate says **when they could not run at all** — which stays worth fixing even after S9 lands, for a box where the wrapper is missing or Xvfb dies.

Direction, not a prescription

- Detect Unable to create DisplayServer (or a zero-frame/no-[probe] done result) and abort the sweep with an environment error, not a regression report: *"no display server — wrap in xvfb-run or set DISPLAY; not a regression."* - A cheap generalisation: **if every probe fails, prefer an environment explanation to a regression one.** 34-for-34 is far more often a host problem than 34 independent regressions, and the issue-creation command should not be offered in that case.

Dependencies

None.

Comments

No comments.

Add a comment