Repository navigation
Wait out connection blips and recover as soon as the network returns - #385
Conversation
074bc22 to
06b8042
Compare
|
Hold — please don't merge yet. Changes connection/lock timing and edit replay on reconnect; a sync-focused review is in progress. I'll post the verdict here. 🤖 Generated with Claude Code |
|
Review: Changes needed The visual and Chat side is good. A blip under 1.5 s shows nothing, the footer status is calm, and the transcript does not move on desktop or phone. The draft survives a long outage, and the label fades in cleanly with opacity only. A 1 s blip replays its edits to the peer exactly once. Retrying a Chat send whose acknowledgement was lost reuses the I tested with my own headless Playwright: two users, Blocking
Should fix
Minor
Checks
|
a7f0e18 to
bb1de85
Compare
|
Thanks. All seven points are addressed, and the branch is rebased onto main.
CI: e2e and container pass. |
|
Review: Looks good I re-checked at
Non-blocking nits:
Checks: |
|
Hold lifted. |
|
CI follow-up: after my review, the
|
ed73942 to
9221187
Compare
|
Rebase re-verified: Looks good. At 9221187 the merged provider sends a rotated-epoch open through |
A socket drop now shows nothing for 1.5 s, then one calm status in the Chat composer footer (Reconnecting… then Offline) instead of a notice row that pushed the transcript. The wire reconnects at once on online, focus and visibility, the Chat draft stays editable while offline, and the locked document dims its ink. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… composer Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A document rebuilt while a client was away is now rebuilt locally too, rather than merged into, so edits made during a blip cannot fork it; the person is told when unsent edits were dropped. Focus and visibility wake the wire at most once a second and keep the backoff, and one attempt lands inside the grace period. A send during a blip waits for the connection, decision actions say when they failed for want of one, and Chat's offline status matches the document header's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ss reloads The header's offline action now reconnects in place. Reload is offered only after three reconnects fail in one outage, and Chat keeps an unsent message in sessionStorage across any reload. Stop and Resume Chopin stay usable during a blip and are sent once it is over. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… restart backoff on request The notice for edits a rebuild dropped now sits with the document status in the header, where it covers no decision card. Chat offers Reconnect when the header is out of view. Asking to reconnect starts the backoff over, so a few failed asks never leave the next automatic attempt waiting out the cap. The no-Planner mention test finds the sent message by its raw text, since the transcript drops the leading mention. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
9221187 to
3fa30fe
Compare
Why
A half-second socket blip set off three alarms at once: Chat inserted a "Connection lost · Reconnect" row that pushed the transcript up (then "Synchronizing… · Retry"), the document showed its Reconnecting pill, and decision-card actions dimmed. Then it all snapped back. During a real outage the Chat composer was locked, so you could not even draft, and recovery waited for the backoff timer (up to about 22 s) after the network was already back.
What changed
useConnectionNoticein@chopin/editor: nothing shows until a loss outlasts 1.5 s, thenreconnecting, thenoffline5 s later. The document lock and status pill, decision-card dimming, and Chat all use it. Reopening the document and sending still read the real connection. Edits typed during the grace period wait in the provider's outbox and are replayed on resume.text-xsstatus sits in the composer footer: "Reconnecting…", then "Offline" with a ghost "Reconnect" button. It fades in with--duration-fast, and there is no fade under reduced motion. Nothing moves. "Synchronizing…/Retry" is dropped.submitalso checks the live socket, so typed text is never lost or silently dropped.Wireskips the rest of its backoff ononline, windowfocus, andvisibilitychangeto visible. Only a wire waiting on its retry timer reacts, so an attempt already in flight is left alone. The listeners are removed on dispose or deletion.data-plan-offline) now start only after the grace period ends, so neither appears during a blip.packages/editor/src/status.tsxchanges minimally: an optionalonReconnectprop. When it is given, the offline alert offers Reconnect instead of Reload. The header pill from #297 receives the connection only after the grace period, so it reads Reconnecting… then Offline, matching Chat.After review
PlanProvider#openused to merge the new epoch's state into the old document. It now rebuilds from the server, the same wayplan:resetdoes. If unsent edits were dropped, the document header says "Edits not saved", with the full explanation ("Your last edits couldn't be saved because the document changed while you were offline.") in its tooltip and accessible text, and a Dismiss button. It sits in the status area, so it covers no decision card. This also closes the few-millisecond window that main had.onlineresets it.sessionStorageas it is typed, so no reload loses it. Stop and Resume Chopin no longer dim during a blip; a press waits and is sent once the connection is back.connectionShownis renamed totreatAsConnected.Chat and header now share one offline language:
Screenshots
Blip, before (main): the notice row appears and the pill shows

Blip, after: nothing changes

Long outage, before: the composer is locked and shows "Connection lost"

Long outage, after: the draft is kept, the footer says Reconnecting… then Offline, and the document ink is dimmed

Phone, before / after


Testing
bun test apps/web/src/wire.test.ts: 14 pass. New: the backoff is skipped ononline, and a wake while connected is ignored.bun test --timeout 60000 packages/editor apps/web: 1030 pass, 0 fail (after rebasing).bun run typespasses.bun scripts/check-design-record.tspasses.e2e/connection.e2e.ts(routeWebSocket): a short blip shows nothing; a long outage shows one calm state; Chat text survives and sends; theonlineevent reconnects immediately.e2e/editing.e2e.tsis updated so the lock test holds the socket down past the grace period. Local E2E is suspended for this run, so CI runs these.onlineevent the editor unlocked in about 15 ms. The 8795 reference took 0.7–6 s.Final integration
Rebased onto #379 main with the latest authored commits preserved.
bun run ci,bun run types, 224 focused Chat/provider tests, and the production build pass (247,156 B raw / 77,951 B gzip initial JavaScript). The editor design-contract review hash is renewed. Fresh hosted validation, browser E2E, and container checks all passed on final head3fa30fe3.🤖 Generated with Claude Code