Skip to content

ci(release): gate releases on a hosted Linux Xvfb lane - #166

Merged
abrichr merged 1 commit into
mainfrom
ci/hosted-linux-release-gate
Oct 17, 2026
Merged

abrichr merged 1 commit into
mainfrom
ci/hosted-linux-release-gate

Conversation

@abrichr

@abrichr abrichr commented Oct 17, 2026

Copy link
Copy Markdown
Member

Why

The release gate (scripts/check_release_ci.py) has required a live-qualification.yml run on a self-hosted, qualified Linux desktop since #132 (Sep 3). That runner was never registered. CAPTURE_SELF_HOSTED_QUALIFIED_LINUX_RUNNERS is unset, and the repo and org both have 0 runners. So no release could pass. The 1.3.0 release run 39075912841 failed closed on exactly this. Richard approved making the GitHub-hosted Ubuntu Xvfb lane the release gate.

What changes

  • New job in production-qualification.yml: Hosted Linux live qualification (ubuntu-latest, Xvfb). It installs the exact candidate wheel with [linux] into an isolated venv. Then, inside one dbus-run-session, it starts:

    • Xvfb 1280x1024x24 with RECORD and XTEST (both checked with xdpyinfo)
    • at-spi-bus-launcher and openbox
    • a focused GTK Entry window (relaunched for each trial)

    It runs three counted trials of tests/test_structural_observation.py and tests/test_performance.py -m slow, which is 8 tests per trial. That covers the recorder lifecycle, pynput→XTEST→X RECORD input capture, memory/CPU bounds, and AT-SPI structural observation. Each trial must pass check_junit_no_skips.py --expected-tests 8, and then aggregate_qualification_trials.py --expected-trials 3 must pass. The evidence is uploaded as an artifact.

  • check_release_ci.py: the new job joins EXPECTED_QUALIFICATION_JOBS. The live-qualification.yml requirement and its Linux-job filtering are removed. Every release requirement now runs on GitHub-hosted runners.

  • live-qualification.yml is unchanged in behaviour. It still runs weekly on its schedule and on dispatch, but it is documented as outside the release gate.

  • Tests, release.yml step names, docs/DESIGN.md, docs/WINDOW_CAPTURE.md, and the v1.3.0 CHANGELOG are updated to match.

What the gate no longer proves (honest scope)

The hosted lane is weaker than the self-hosted lane was meant to be. A release no longer proves:

  • more than one monitor. MSS on Xvfb reports a single monitor, so the topology check uses --minimum-monitors 1.
  • real input hardware. Input is injected through XTEST, not a physical keyboard or mouse.
  • a real compositor, real window moves, or a real desktop session.

The weekly non-blocking live-qualification.yml lanes remain the place for those, once a qualified desktop exists.

Verification

  • I extracted the exact run: block of the trial step from this YAML and ran it on a Debian 13 box with the 571d530 wheel. All 3 trials passed with 8 passed, 0 skipped each. Each trial passes check_junit_no_skips.py --expected-tests 8, and the aggregate reports passed: true. An earlier 1920x1080 screen exceeded the 500 MB memory bound in test_memory_bounded (511.6 MB), so the lane uses 1280x1024. The threshold is unchanged.
  • uv run --extra dev pytest -q tests: 1036 passed, 22 skipped. ruff check openadapt_capture/ is clean. scripts/check_changelog.py is OK.

Signed-off-by: Richard Abrich richard.abrich@mldsai.com

The release gate required live-qualification.yml on a self-hosted
qualified Linux desktop. No such runner was ever registered, so no
release could pass (1.3.0 release run 39075912841 failed closed).

Replace that requirement with a GitHub-hosted ubuntu-latest job in
production-qualification.yml. It runs three counted trials under Xvfb
with X RECORD and XTEST, openbox, AT-SPI, and a focused GTK window:
the structural observation test and the slow recorder and input tests,
8 tests per trial, no skips.

The gate no longer proves more than one monitor, real input hardware,
a compositor, or real window moves. live-qualification.yml keeps those
lanes weekly and outside the gate.

Signed-off-by: Richard Abrich <richard.abrich@mldsai.com>
@abrichr

abrichr commented Oct 17, 2026

Copy link
Copy Markdown
Member Author

Self-review before merge:

  • Gate logic. REQUIREMENTS is now test.yml (package-contract) plus production-qualification.yml at the exact SHA. A run counts only if every job in EXPECTED_QUALIFICATION_JOBS succeeded, and that set now includes the hosted Linux job. A skipped or missing Linux job fails closed (covered by test_release_gate_requires_the_hosted_linux_xvfb_lane). The release never queries live-qualification.yml (test_release_requirements_never_include_a_self_hosted_workflow, and the dispatch test asserts on that URL).
  • Same tests as the old lane. Both test files run with no -k filter, 8 tests per trial and 3 trials, with no skips allowed. test_hosted_linux_release_lane_runs_input_and_structural_trials pins this.
  • Thresholds. None are loosened. The only loosened check is --minimum-monitors 1, because Xvfb reports a single monitor to MSS.
  • Scope. The PR body, the workflow headers, DESIGN.md, WINDOW_CAPTURE.md and the CHANGELOG all say the gate no longer proves multi-monitor capture or real input hardware.
  • Known risk. production-qualification.yml can only be dispatched on main, so the new job's first GitHub-hosted run happens after merge. I ran the exact YAML step locally (3/3 trials). I'll dispatch qualification at the merge SHA before re-running the release.

Signed-off-by: Richard Abrich richard.abrich@mldsai.com

@abrichr
abrichr merged commit 66c9d25 into main Oct 17, 2026
12 checks passed
@abrichr
abrichr deleted the ci/hosted-linux-release-gate branch October 17, 2026 23:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant