Skip to content

ci: bound the apt install and prefer the canonical Ubuntu archive - #289

Merged
abrichr merged 1 commit into
mainfrom
claude/bound-apt-install
Aug 19, 2026
Merged

ci: bound the apt install and prefer the canonical Ubuntu archive#289
abrichr merged 1 commit into
mainfrom
claude/bound-apt-install

Conversation

@abrichr

@abrichr abrichr commented Aug 19, 2026

Copy link
Copy Markdown
Member

What

In complex-visual.yml, job headed-pixel-campaign has timeout-minutes: 15, but the step Ensure local X11 fixture tools had no bound of its own.

  • Step Ensure local X11 fixture tools: no timeout -> 5 minutes, plus the mirror preference and a bounded apt-get update retry.

Runner OS for the changed job: ubuntu-latest. It is the only job in this file.

Why

A job-level timeout is not enough. One hung apt call spends all 15 minutes and the headed pixel campaign -- the entire point of the job -- never runs. The job fails on a timeout that names the wrong cause.

The hosted runner resolves its Ubuntu mirror through /etc/apt/apt-mirrors.txt, which points at azure.archive.ubuntu.com. That mirror fails intermittently. apt does fall back to the canonical archive, but it spends the whole budget getting there. Two incidents on 2026-08-19: in openadapt-flow a TeX install ran 3h11m and hit the run limit, and in openadapt-capture a test job ran over an hour on main.

Measured results of the same fix elsewhere: openadapt-flow #374 took the TeX install from a 10-minute timeout to 83s; openadapt-capture #81 takes 19s.

Why 5 minutes

It has to fit inside the 15-minute job and still leave room for the real work:

  • The equivalent apt step in openadapt-capture takes 19s, so 5 minutes is roughly a 15x margin.
  • Worst realistic in-bound case is 3 apt-get update attempts plus 10s + 20s of backoff, then the install -- comfortably under 5 minutes.
  • It leaves at least 10 of the 15 job minutes for uv sync --locked and the campaign itself.
  • A slow mirror now fails this step fast instead of starving the campaign.

What did not change

  • The package list is identical: sudo apt-get install --yes xvfb xauth.
  • The command -v Xvfb/xvfb-run guard is preserved, so when the tools already exist no apt runs at all.
  • The trailing python -c 'import tkinter' check is preserved and still fails the step.
  • No other step in this file runs apt. I checked; Ensure local X11 fixture tools is the only one.

Tests

  • actionlint .github/workflows/complex-visual.yml -- clean (shellcheck present, so the run blocks were shell-linted too).
  • python3 -c "import yaml; yaml.safe_load(open(F))" -- parses.
  • bash -n on all 5 run blocks in the file -- all parse.
  • The step's logic was exercised locally against a stubbed apt-get, sudo, sleep, and python, in four paths:
    • Xvfb absent, mirror healthy -> install --yes xvfb xauth runs, tkinter checked, exit 0.
    • Xvfb absent, mirror fails 3x -> 3 warnings, one error, exit 1, install never runs (fails closed).
    • Xvfb present -> no apt at all, tkinter still checked, exit 0.
    • Xvfb present but tkinter missing -> exit 1, confirming the pre-existing check was not weakened.

This PR changes .github/workflows/complex-visual.yml, which is in the workflow's own paths trigger, so the changed job runs on this PR.

Pre-existing unrelated failure: does not actually appear here

The brief for this change warned that evidence-freshness fails because published evidence is pinned to openadapt-flow 1.30.0 while 1.31.0 is current. I checked rather than assumed, and the accurate position is:

  • It is real and it is not mine. The scheduled run on main has failed every day from 2026-08-12 through 2026-08-19 (runs 31575973097 ... 32226408725), with no commit of mine involved.
  • But it does not run on this PR. Its pull_request trigger is path-filtered to docs/eval_results/**, scripts/check_published_evidence_freshness.py, and .github/workflows/evidence-freshness.yml. This PR touches only .github/workflows/complex-visual.yml, so the check is not queued here at all.

Out of scope for this PR either way, and left alone deliberately.

🤖 Generated with Claude Code

The hosted runner resolves its Ubuntu mirror through /etc/apt/apt-mirrors.txt,
which points at azure.archive.ubuntu.com. That mirror fails intermittently and
apt spends minutes of retries before it falls back, so an unbounded package
step can consume a whole run: in openadapt-flow a TeX install ran 3h11m and hit
the run limit, and in openadapt-capture a test job ran over an hour on main.

headed-pixel-campaign has a 15-minute job budget but the X11 fixture step had
no bound of its own, so one hung apt call could spend all 15 minutes and the
campaign -- the point of the job -- would never run. Bound the step to 5
minutes and prefer the canonical archive.

Five minutes is a wide margin: the equivalent apt step in openadapt-capture
takes 19s, and 5 minutes still covers three update attempts plus 30s of backoff
while leaving at least 10 of the 15 job minutes for `uv sync` and the campaign.

The package list, the `command -v` guard that skips apt when the tools already
exist, and the trailing tkinter check are unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@abrichr
abrichr merged commit 233d832 into main Aug 19, 2026
2 checks passed
@abrichr
abrichr deleted the claude/bound-apt-install branch August 19, 2026 19:57
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