Skip to content

Fix the flaky autosave-yield test that broke CI on main#144

Merged
dovvnloading merged 1 commit into
mainfrom
fix/flaky-autosave-yield-test
Jul 26, 2026
Merged

Fix the flaky autosave-yield test that broke CI on main#144
dovvnloading merged 1 commit into
mainfrom
fix/flaky-autosave-yield-test

Conversation

@dovvnloading

Copy link
Copy Markdown
Owner

Summary

test_a_user_save_waits_out_a_real_in_flight_autosave_tick_instead_of_being_dropped failed on main after #142 merged. It is a flake, and the fragility is mine — I wrote this test in #138.

Evidence it's a flake, not a regression: the identical code passed CI on the PR branch and failed on the post-merge run; the test and the code under it were untouched by #142/#143.

That said, a flaky test in CI is a real defect, so it's fixed properly rather than re-run.

Cause

The test raced the real autosave loop at interval_seconds=0.02 while each tick held the guard for ~0.1s. _loop sleeps after a tick, so ticks ran effectively back-to-back — the user's save had to win a scheduling race in the narrow window between one tick releasing the guard and the next re-claiming it. On top of that it asserted a 1.0s wall-clock bound against a 2.0s production timeout: a 2× margin on a contended 2-core Windows runner.

Fix — remove the race, don't widen the bound

  • register_autosave now exposes bus.autosave_guarded_tick, the same testability seam already used for bus.autosave_task and bus.chat_save_state (that file's own comments justify exactly this: a closure-local is unreachable to the tests that must prove the wiring works).
  • The test drives exactly one real tick through that seam with interval_seconds=3600, so the periodic loop never fires and no second tick can steal the guard back mid-handoff.
  • The tick's duration is controlled by a gate instead of a sleep, so the user's save provably arrives while the guard is genuinely held.
  • AUTOSAVE_YIELD_TIMEOUT_SECONDS is patched to 30s and the save asserted within 5s — a missing release signal still fails it, now with a 6× margin instead of 2×.

It still catches what it exists to catch

Verified by mutation against the real _guarded_tick:

Mutation Result
Drop the AUTOSAVE_OWNER tag fails
Drop the released.set() signal fails

Ran 25/25 green locally.

Validation

  • python -m compileall -q . passes
  • Full backend suite: 2438 passed
  • Target test: 25/25 consecutive runs green
  • Both mutations confirmed still fatal

Note

I did also try to reproduce under synthetic CPU load; my load generator failed to spawn, so that run proved nothing and I discarded it rather than citing it as evidence.

test_a_user_save_waits_out_a_real_in_flight_autosave_tick_instead_of_being_dropped
failed once on main after #142 merged, then passed on a re-run of identical
code. It is a genuine flake, and the fragility is mine - I wrote this test
in #138.

Cause: the test raced the real autosave loop with interval_seconds=0.02
while each tick held the guard for ~0.1s. Because _loop sleeps AFTER a tick,
ticks ran effectively back-to-back, so the user's save had to win a
scheduling race in the narrow window between one tick releasing the guard
and the next re-claiming it. On top of that it asserted a 1.0s wall-clock
bound against a 2.0s production timeout - a 2x margin on a contended
2-core CI runner.

Fixed by removing the race rather than widening the bound:
- register_autosave now exposes bus.autosave_guarded_tick, the same
  testability seam already used for bus.autosave_task and
  bus.chat_save_state (the file's own comments justify exactly this: a
  closure-local is unreachable to the tests that must prove the wiring).
- The test drives exactly ONE real tick through that seam with
  interval_seconds=3600, so the periodic loop can never fire and no second
  tick can steal the guard back mid-handoff.
- The tick's duration is controlled by a gate instead of a sleep, so the
  user's save provably arrives while the guard is genuinely held.
- AUTOSAVE_YIELD_TIMEOUT_SECONDS is patched to 30s and the save asserted
  within 5s: a missing release signal still fails it, now with a 6x margin
  instead of 2x.

Still drives the REAL _guarded_tick, so it keeps catching what it exists to
catch - verified by mutation: dropping the AUTOSAVE owner tag fails it, and
dropping the released.set() signal fails it. Ran 25/25 green locally.

Full suite: 2438 passed, compileall clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@dovvnloading
dovvnloading merged commit 1ca4544 into main Jul 26, 2026
2 checks passed
@dovvnloading
dovvnloading deleted the fix/flaky-autosave-yield-test branch July 26, 2026 14:08
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