Recipes

CI guard against short hard timeouts in a Swift/macOS agent app

Discovered from README cross-links · today

Software & DevOps

Added a shrink-only allowlist guard blocking new sub-30s hard timeouts.

What they did

The author added a CI guard for the cmux repo that fails when new hard timeout literals below 30 seconds appear in the app/daemon, acpmux, CLI, and agent-session paths. Existing violations are captured in `tests/short-timeout-allowlist.json`, and the counts are only allowed to shrink. A helper, `python3 scripts/ci/check_short_timeouts.py --update`, regenerates the snapshot after an intentional fix while preserving the recorded reasons, so the timeout-removal lanes can ratchet entries down after merge. The guard accepts an adjacent `// timeout: <reason>` or `# timeout: <reason>` comment only when a real hazard justifies a bound, and it excludes Rust `*_tests.rs` files and `#[cfg(test)]` modules. Regression coverage lives in `tests/test_short_timeout_guard.py`, which proves a new 2-second deadline fails, the same line with `// timeout: hung peer` passes, and that wrapped Swift durations, millisecond units, the language patterns, Rust test-module exclusion, and ratchet growth/shrink behavior all work. On the merged head `2073305d5eec`, the test file passes 5 tests and the checker reports 276 retained hits across 192 file:pattern entries. The branch also merged the current `feat-cmux-next` tip to resolve a landing conflict. The guard is registered in `tests/test-execution.toml` as `linux-guard` and runs in `.github/workflows/ci-guards.yml`. The post also enumerates the pre-existing gates found at the merged base, each marked as retained debt to remove, replace with liveness, or lower the allowlist count.

How it went

The guard landed with passing regression tests (5 tests) and a baseline of 276 retained hits across 192 file:pattern entries. The allowlist is shrink-only, so future fixes ratchet counts down. The author also catalogued the existing short timeouts as debt to remove or replace with liveness checks.

Worth knowing

The guard only blocks new violations; the 276 existing hits remain as debt and are not fixed by this change. The allowlist requires manual regeneration via `--update` after intentional fixes, and reasons must be preserved. The guard is Linux-only and excludes Rust test modules, so test-only timeouts are not covered.

Wiring

The guard is a Python script at `scripts/ci/check_short_timeouts.py` that scans source files for hard timeout literals below 30 seconds, matching language-specific patterns for Swift durations, millisecond units, and socket timeouts. It compares hits against `tests/short-timeout-allowlist.json`, which stores file:pattern entries with reasons; new hits fail, and the allowlist may only shrink. The `--update` flag regenerates the snapshot after intentional fixes while preserving reasons. The script is registered in `tests/test-execution.toml` as `linux-guard` and invoked from `.github/workflows/ci-guards.yml`. Regression tests in `tests/test_short_timeout_guard.py` exercise the checker directly. The branch merged `feat-cmux-next` to resolve a landing conflict before merge.

Try it yourself

Add a CI guard to this repo that fails when new hard timeout literals below 30 seconds are introduced in the app/daemon, CLI, and agent-session paths. Capture existing violations in `tests/short-timeout-allowlist.json` as a shrink-only allowlist. Allow an adjacent `// timeout: <reason>` or `# timeout: <reason>` comment only when a real hazard justifies the bound. Exclude Rust `*_tests.rs` and `#[cfg(test)]` modules. Add `scripts/ci/check_short_timeouts.py` with an `--update` flag that regenerates the snapshot while preserving reasons. Add `tests/test_short_timeout_guard.py` covering: a new 2-second deadline fails, the same line with `// timeout: hung peer` passes, wrapped Swift durations, millisecond units, language patterns, Rust test-module exclusion, and ratchet growth/shrink. Register the guard in `tests/test-execution.toml` as `linux-guard` and run it in `.github/workflows/ci-guards.yml`.

Source

Tools in this stack