Skip to content

Fix flaky debounce test that failed CI on main - #13

Merged
silentswordfish merged 2 commits into
mainfrom
fix-flaky-debounce-test
Aug 1, 2026
Merged

silentswordfish merged 2 commits into
mainfrom
fix-flaky-debounce-test

Conversation

@silentswordfish

Copy link
Copy Markdown
Contributor

Summary

CI failed on main after #12 merged: WatcherContextDebounceTests.coalescesBursts recorded count == 0 instead of 1. Root cause is unrelated to #12 itself — it's the timing-sensitive test flagged during #10's review (comment: "the serializesAndCoalesces test is timing-sensitive"). It raced a fixed 120ms sleep against a 50ms debounce timer; that margin is fine locally but not always enough on a loaded CI runner.

  • Signal from inside onChange via an AsyncStream continuation instead of guessing a fixed sleep duration — matches the pattern WorkspaceReloadCoordinatorTests already uses for the same kind of async assertion.
  • Added a .timeLimit(.minutes(1)) trait so a genuine regression (onChange never firing) still fails clearly instead of hanging the job.
  • Ran the fixed test 10x locally back-to-back; consistently resolves in ~55ms now (vs. the previous unconditional 120ms sleep).

Test plan

  • swift build / swift test — 40/40 pass
  • swiftlint lint — clean
  • Re-ran coalescesBursts 10x locally to confirm it's no longer racing

🤖 Generated with Claude Code

coalescesBursts raced a fixed 120ms sleep against a 50ms debounce
timer, which flaked on CI's shared runner (count == 0, onChange
hadn't fired yet by the deadline) — this was flagged as timing-
sensitive during PR #10's review but only surfaced once CI actually
ran the suite on a real runner.

Signal from inside onChange via an AsyncStream continuation instead,
matching the pattern WorkspaceReloadCoordinatorTests already uses, so
the test waits for the actual event instead of a wall-clock guess.
A .timeLimit trait bounds the wait if onChange regresses to never
firing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
try await Task.sleep(for: .milliseconds(120))
// Wait for the debounced onChange to actually fire instead of racing a fixed
// sleep against CI scheduling jitter, which flaked in CI (count == 0).
for await _ in changeStream {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AsyncStream wait fixes the count == 0 flake nicely, matching WorkspaceReloadCoordinatorTests. One gap: we assert count == 1 as soon as the first onChange arrives, so a regression that fired multiple times close together could still pass if later increments land after the expect. After the first signal, would a short quiet window (about one more debounce interval) before asserting keep the coalescing check honest without reintroducing the CI race?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a 150ms quiet window after the first signal before asserting. This is safe against the same CI race that caused the original flake: the risk direction is opposite — a slow runner can only delay a fire, never manufacture a spurious extra one, so this can only catch a genuine multi-fire regression, not reintroduce the count == 0 flake.

…ssions

Asserting immediately on the first signal would let a coalescing
regression (onChange firing more than once) slip through if the
second fire landed after the #expect. The added wait is safe against
the same CI race that caused the original flake: a slow runner can
only delay a fire, never manufacture a spurious extra one, so this
can only fail on a genuine regression, not reintroduce count == 0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@silentswordfish
silentswordfish merged commit 476d721 into main Aug 1, 2026
2 checks passed
@silentswordfish
silentswordfish deleted the fix-flaky-debounce-test branch August 1, 2026 17:02
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.

2 participants