Where a hung package mirror spends your CI budget
On fork PR #3555, three jobs died inside Setup environment without
running a single test. Drag the controls to see why the failure time tracked the
job's own cap instead of the hang.
What actually happened, 2026-08-19
| job | cap | died after | step |
|---|---|---|---|
| Security Tests | 15 min | 15m 16s | Setup environment |
| Compliance Tests | 15 min | 15m 16s | Setup environment |
| Unit Tests (node 20) | 30 min | 30m 15s | Setup environment |
Each job died at its own cap, to the second. That is timeout-minutes
firing, not a test failing and not concurrency cancelling. GitHub reports a
cap-killed job as cancelled, which is what made it read like an infra flake.
Why the existing guard could not help
The call site carried what looks like a safety net:
if ! sudo apt-get update -qq; then
log_warn "apt-get update had issues, continuing anyway..."
fi
That catches a non-zero exit. A hang never exits, so the guard
never runs. Only an external watchdog (timeout) converts a hang into
an exit the guard can see.
Fix: every package install routes through
.github/scripts/ensure-system-deps.sh,
which skips the package manager when the tools are already present and bounds the call at
SYSTEM_DEPS_TIMEOUT (90s default) otherwise.
tests/ci/test-no-unbounded-package-manager.sh greps the whole CI-executed
surface so the next call site cannot reintroduce this. Issue #3557.