Fix flaky partial-request shutdown browser tests - #61
Merged
Merged
Conversation
The drain, partial-merge and partial-body shutdown tests slept 10 ms and
assumed the partial request had been admitted. Under load the timer fires
before the server parses the headers, so server.close() drops the idle or
backlogged connection (read/connect ECONNRESET), and afterEach then closes
the already-closed server ("Server is not running.").
Wait for the server's 'request' event before starting shutdown, then send
the rest of the body, so the "partially received, shutdown starts, request
completes" interleaving is ordered by events instead of timers.
The in-flight question edit test now waits until the submission is
intercepted, asserts the submitted body, and checks the durable note list.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013owjkhQZhekCae7KP5rC3P
There was a problem hiding this comment.
Copilot review overview
🟢 Approval recommended
No unresolved review comments remain, and all reviewers assessed it as ready.
Review effort: Lite
Findings: None
What changed in this PR
Fixes flaky partial-request shutdown browser tests and strengthens in-flight edit assertions in the test harness.
Changes:
- Synchronizes tests on actual request admission.
- Orders shutdown and body-completion interleavings deterministically.
- Verifies submitted payloads and durable note persistence.
| File | Description |
|---|---|
test/browser/review.spec.ts |
Stabilizes shutdown tests and strengthens in-flight editing coverage. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes the flaky partial-request shutdown tests in
test/browser/review.spec.ts, and tightens the in-flight question edit test. Only the test harness changes. No product code changes.Root cause (reproduced)
drains an in-flight question request before closing its agent manager(andblocks a partially received merge request when shutdown starts, which uses the same pattern) wrote one byte of the body, slept 10 ms, then calledapp.close(). Nothing proved the server had admitted the request by then. The server runs in the same Node process as the test. If the event loop stalls for more than 10 ms (GC, CPU contention), the timer fires before the server parses the request headers.server.close()then closes the connection, either because it is still idle (read ECONNRESET) or still waiting in the listen backlog (connect ECONNRESET).afterEachthen callsclose()on the server that was already closed, which addsServer is not running.. That is the exact signature in the report.destroys a partial request body after the shutdown drainhad the same gap. It used the socket write callback as its "admitted" signal, so it could pass without ever exercising the bounded drain.Fix
requestAdmitted(server)resolves on the server'srequestevent. By the time it resolves, the handler has registered the request and is reading its body.app.close(), and only then send the rest of the body. The required interleaving (request partially received → shutdown starts → request completes) is now ordered by events, not timers.Promise.race([admitted, completed])makes a client error surface right away instead of hanging.preserves edits made while a question submission is in flightnow waits until the submission is intercepted before editing, asserts the submitted body (text: 'Submitted question'), and checks the durable note list, not just the UI.Assertions are unchanged or stricter. Nothing is skipped, retried, or given a longer timeout.
Evidence
Environment: Node 26.7.0, Playwright 1.63.0, Chrome Headless Shell 153.0.8010.12 (build 1243), 4 cores. Baseline =
main@af8f3c2. Intermediate checkpoint = fix commitf18e627(the table rows below). Validated head =3016d07(the fix merged withmain@5e97aa3).af8f3c2--repeat-each=10, idle--repeat-each=10, 12 CPU-burning processes on 4 coresread ECONNRESET×3,connect ECONNRESET×1, each followed byServer is not running.connect ECONNRESET+Server is not running.)playwright testf18e627npm run typecheckValidated head
3016d07:npm run typecheckclean; targeted tests--repeat-each=1050/50 passed; fullplaywright test58/58 passed. That is the current test count after the merge frommain. The 47 in the report and the 53 atf18e627are older counts. CI on this head:testjob (typecheck, unit tests, full browser suite) passed; PR is mergeable.Each assertion was checked to still fail with the feature broken (each mutation applied alone, then reverted):
callsexpectation)stopping && merge503 checktoHaveValue)rememberDraft()after the action responsetoHaveValue)Not reproduced
I could not reproduce the
toBeVisible/toContainTexttimeouts in the twopreserves edits … in flighttests in any configuration: idle, heavy CPU stress, CDP CPU throttling ×20, the Node side stalled 75–94 % of the time, or right after a forced drain failure (no knock-on effect). Readingapp.jsandserver.tsfound no race in the app. Busy-gating, generation checks and draft compare-and-swap all hold. The only timing assumption in the test was editing before the submission was proven in flight, which this PR removes. If those two tests fail again, please attach the trace (trace: retain-on-failureis already on) so the concrete interleaving can be turned into a regression.Review-lesson audit
3016d07: no findings, approval recommended. Nothing to classify and noAGENTS.mdupdate needed.🤖 Generated with Claude Code
https://claude.ai/code/session_013owjkhQZhekCae7KP5rC3P