fix(web): unify network recovery - #985
Merged
SamSaffron merged 1 commit intoAug 2, 2026
Merged
Conversation
Centralize fetch retry policy, connectivity state, resumable streams, and WebRTC fallback. Wake established and pre-response retries immediately when a 20-second outage ends instead of leaving the initial POST in its 60-second slow-retry sleep.
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.
What
Centralize browser network handling and make chat recovery predictable across HTTPS and WebRTC failures.
apiFetchlayer with explicit safe-read, idempotent-mutation, non-retryable-mutation, and stream policiesWhy
The durable response stream already replayed missed events safely once a response ID existed, but failure handling around it was fragmented across feature modules.
The worst path was an initial message POST during a 20-second outage: five fast failures put it into a 60-second sleep at about 13.2 seconds, so connectivity returning at 20 seconds could still leave the message waiting roughly another 53 seconds. The initial POST now uses the same wakeable recovery mechanism as established streams and resumes immediately after coordinated health and transcript reconciliation.
The shared layer also makes the retry contract explicit: reads may retry, mutations retry only with an idempotency guarantee, and ambiguous unsafe WebRTC mutations surface an unknown outcome instead of being duplicated.
Recovery behavior
For an active response:
For a pre-response POST, the message body, attachments, client message ID, request ID, and idempotency key remain stable across retries. Session switches cancel the parked retry.
Review fixes
A Claude Opus review found and the final commit fixes:
dataChannel.send()synchronously proved no frame was sentRegression tests cover each path.
Tests
internal/serveui/static/*_test.jssuitesgo test ./internal/serveuigo build ./...go test ./...go vet ./...git diff --checkThe 20-second outage tests cover an established response, the initial POST before
x-response-id, and WebRTC HTTPS fallback/recovery. They assert immediate wake after restoration, stable idempotency, no duplicated turn, and terminal replay where applicable.