Skip to content

Harden flaky integration tests: poll for state instead of fixed sleeps - #14

Merged
amanjaiman merged 1 commit into
mainfrom
test/fix-flaky-integration
Jul 4, 2026
Merged

Harden flaky integration tests: poll for state instead of fixed sleeps#14
amanjaiman merged 1 commit into
mainfrom
test/fix-flaky-integration

Conversation

@amanjaiman

Copy link
Copy Markdown
Owner

Summary

CI's "integration (tmux + pty)" job has been flaky across recent runs on main, failing on a different script each time (different assertions, same shape of problem).

Root cause: several test/integration_*.sh scripts assert a supervisor state change (limit detected → wait → inject, or detach/kill) after a fixed sleep N, racing the real timing budget (poll_interval + reset wait + buffer + process/IO overhead). That budget gets tight under a loaded CI runner.

  • Verified fix: test/integration_attach.sh's fixed sleep 7 reproduced the exact reported failure ("normal attach injected the resume prompt") — 5/10 failures under simulated CPU load with the old code, 0/15 with the new polling loop (plus 0/10 clean). Replaced with a bounded poll of the marker file.
  • Same fixed-sleep-racing-a-state-change pattern found and fixed in test/integration.sh, test/integration_codex.sh, test/integration_reprompt.sh (all had sleep 14 before checking an injected marker) and test/integration_m2.sh (sleep 5 after detach/stop --kill) — all converted to bounded polling loops.
  • test/integration_m2_autodetach.sh already polled (from an earlier flake fix) but still failed once on main. Could not reproduce despite 60+ local runs (clean, CPU-stressed, concurrent). Hardened defensively anyway: require the simulated tmux attach to be seen on two consecutive checks 100ms apart (guards a hypothetical flapping attach), widened both polling ceilings, and added diagnostics (ps, tmux list-clients) on failure so any future recurrence is debuggable. Being upfront: this one is not a verified fix, since the failure never reproduced locally — just defensive hardening plus better failure diagnostics.
  • test/integration_pty.sh and test/integration_dead_session.sh already used correct polling and were left untouched.

No Go source changed — this is test-script-only.

Test plan

  • Full suite via test/run_all.sh: 5/5 clean runs, 40/40 individual script passes (WSL + real tmux)
  • Exact CI integration-job script sequence run under simulated CPU load: all 7 scripts passed
  • go build ./..., go vet ./..., gofmt -l . clean (no Go files touched)
  • Reviewer: watch this PR's own CI run land clean, and keep an eye on main over the next several CI runs for integration_m2_autodetach.sh specifically, since that one's fix is unverified

🤖 Generated with Claude Code

CI's integration job has been flaky across recent runs, failing on a
different script each time. Root cause: several scripts assert a
supervisor state change (limit->wait->inject, detach, kill) after a
fixed `sleep N`, racing the real timing budget (poll_interval + reset
wait + buffer + process/IO overhead), which gets tight under a loaded
CI runner.

Reproduced the integration_attach.sh failure locally under simulated
CPU load (5/10 failures on "normal attach injected the resume prompt"
with the old fixed sleep 7 vs. 0/15 with the new polling loop, and
0/10 clean). Could not reproduce the integration_m2_autodetach.sh
failure despite 60+ local runs (clean, CPU-stressed, and concurrent),
so it's hardened defensively: require the simulated attach to be seen
on two consecutive checks before treating it as settled, widen the
polling ceilings, and print extra diagnostics (ps/tmux state) on
failure to make any future recurrence debuggable.

Also fixed the same fixed-sleep-racing-a-state-change pattern in
integration.sh, integration_codex.sh, integration_reprompt.sh (sleep 14
before checking the injected marker) and integration_m2.sh (sleep 5
after detach/stop --kill), all replaced with bounded polling loops.
integration_pty.sh and integration_dead_session.sh already polled
correctly and were left alone.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@amanjaiman
amanjaiman merged commit b000d81 into main Jul 4, 2026
4 checks passed
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