Skip to content

test(realtime): wait for the idle read the streak test depends on - #6673

Merged
icecrasher321 merged 1 commit into
stagingfrom
fix/file-doc-store-streak-test-race
Aug 13, 2026
Merged

test(realtime): wait for the idle read the streak test depends on#6673
icecrasher321 merged 1 commit into
stagingfrom
fix/file-doc-store-streak-test-race

Conversation

@icecrasher321

Copy link
Copy Markdown
Collaborator

file-doc-store.test.ts fails intermittently in CI:

AssertionError: expected 1870 to be less than 1000
 ❯ src/handlers/file-doc-store.test.ts:226

That number is the diagnosis. 1870ms sits in the carried-streak band (2000ms ±20% = 1600–2400), not the reset band (500ms ±20% = 400–600) — so the streak was never cleared before the phase that measures it. The reader fix is fine; the test's middle phase is racy.

The race

The test has three phases. The middle one cleared the fault and then waited a fixed 1000ms for an idle read to land:

state.backing!.readerClosed = false
await sleep(1000)

But the pending backoff from the two failures before it is 400–600ms then 800–1200ms, so the next read is due anywhere up to ~1805ms — and that phase ends at 1800ms. When both jitters draw high the read arrives after the fault has been re-armed, so it fails instead of succeeding. The streak survives at two, and the final phase measures the third backoff instead of the first.

It needs both draws near the top, which is why it passed 20-plus local runs and only surfaced in CI.

Fix

Waiting a duration for an event is the bug. Each phase now waits for its own event:

  • build the streak → wait for two failed reads
  • clear it → wait for a read that actually returns (the thing that resets the streak)
  • measure → wait for two failed reads again

Also measure failure-to-failure rather than read-to-read. A successful read can land in the instant after the fault is re-armed; as the first sample it would make the gap ~5ms and pass for the wrong reason — the same false-pass shape review caught in this test last round.

The bound moves 1000 → 1200ms, still between the two bands (reset ≤600, carried ≥1600) with room on both sides so a loaded runner stretching the short sleep can't flip the verdict.

Verification

  • 20/20 consecutive runs green.
  • Still fails on the un-fixed reader every time — 1753ms, 1688ms, 1881ms, 1701ms, 1837ms against the 1200ms bound — so it still guards the regression it was written for.
  • 279 realtime tests, tsc and biome clean.

Test-only; no production code changes.

The guard failed intermittently in CI — `expected 1870 to be less than 1000`,
which is the carried-streak backoff, meaning the streak was never reset before
the phase that measures it.

The middle phase cleared the fault and then waited a FIXED 1000ms for an idle
read to land. It usually did. But the pending backoff from the two failures
before it runs 400–600ms then 800–1200ms, so the next read is due anywhere up
to ~1805ms — and the phase ends at 1800ms. When both jitters drew high the read
arrived after the fault had already been re-armed, so it failed instead of
succeeding, the streak survived at two, and the measurement caught the third
backoff (1600–2400ms) rather than the first.

Waiting for a duration where the thing being waited for is an event is the bug.
Each phase now waits for its own event: two failed reads to build the streak,
then a read that actually RETURNS to clear it.

Also measure failure-to-failure rather than read-to-read. A successful read can
land in the instant after the fault is re-armed, and as the first sample it
would make the gap ~5ms — passing for the wrong reason, the same false-pass
shape review caught in this test last round.

20 consecutive runs green; still fails on the un-fixed reader every time
(1753ms, 1688ms, 1881ms, 1701ms, 1837ms against the 1200ms bound).
@vercel

vercel Bot commented Aug 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Aug 13, 2026 7:56pm

Request Review

@cursor

cursor Bot commented Aug 13, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Test-only changes to mocks and timing assertions; no production code paths modified.

Overview
Fixes intermittent CI failures in ends the failure streak on an idle read by replacing fixed sleep waits with vi.waitFor on the events each phase actually depends on (two failed reads, then an idle read that returns, then two failed reads again).

The in-memory Redis fake now tracks failedReadTimes and idleReads separately instead of every read attempt, so the final assertion measures failure-to-failure delay and avoids a successful read right after re-arming the fault from trivially passing.

The upper bound on the measured gap moves from 1000ms to 1200ms so a loaded runner can still distinguish a reset streak (short first backoff) from a carried streak (long third backoff).

Reviewed by Cursor Bugbot for commit 57ca1bb. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR makes the realtime reader backoff test synchronize on actual failed and successful read events instead of fixed-duration sleeps.

  • Records failed-read timestamps separately from successful idle reads.
  • Waits for the idle read that resets the failure streak.
  • Measures failure-to-failure timing and uses a threshold separating reset and carried-streak backoff bands.

Confidence Score: 5/5

The PR appears safe to merge, with the revised test matching the reader loop’s reset and backoff behavior.

Successful reads reset the production failure count, failed-read timestamps isolate one retry interval, and the 1200ms assertion remains between the reset and carried-streak timing bands.

Important Files Changed

Filename Overview
apps/realtime/src/handlers/file-doc-store.test.ts Replaces racy fixed waits and all-read timing with event-driven synchronization and failure-only backoff measurement; no actionable defect identified.

Reviews (1): Last reviewed commit: "test(realtime): wait for the idle read t..." | Re-trigger Greptile

@icecrasher321
icecrasher321 merged commit 2da8855 into staging Aug 13, 2026
30 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