Repository navigation
Conversation
Clear a previous live retry control error after that control succeeds, while preserving a newer failure reported by the live stream. Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Show one persistent toast and a community-scoped issue dialog. Reuse read owners, sequence manual retries, disable the queue, and shake each failed row as its attempt finishes. Preserve drafts, partial data, dialog history and source-specific failures. Include production-read regression journeys; omit the temporary Developer harness. Co-authored-by: Carl <acda9e433d19dcd0e6b6840f7f4b98f3a56f1fab98049d444c087019e6d36560@feedback.communities.buzz.xyz> Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
kalvinnchau
left a comment
There was a problem hiding this comment.
🤖 Three actionable findings: the persistent recovery toast obstructs Send, live/connection retries do not track settlement, and the recovery test can mask an automatic-recovery regression.
| <ToastNotice | ||
| title="Buzz is having issues" | ||
| tone="warning" | ||
| navigation={{ label: "Open Buzz Doctor", open: show }} |
There was a problem hiding this comment.
🤖 [P2] Keep the persistent Doctor toast clear of Send
A background visibility-read refusal places this persistent toast over the healthy conversation composer. In the production frontend/broker harness, Chromium and WebKit at 1440×600 and 390×600 with 16px and 20px root text both resolve Send’s center to Open Buzz Doctor. A real mouse click opens Doctor and publishes no message; Send becomes pointer-accessible after recovery removes the toast. An unrelated finite-read failure can therefore obstruct messaging indefinitely. Reserve composer clearance or move persistent recovery outside its controls, and restore Send pointer-actionability assertions in live-status.spec.mjs and relay-recovery.spec.mjs; the replacement focus checks pass despite this obstruction.
| } | ||
| }; | ||
| try { | ||
| // Sources are dependency ordered: connection/live, catalog, workspaces, |
There was a problem hiding this comment.
🤖 [P3] Track live/connection retry settlement and selectable work
relay.retry() and session.live.retry() return void, so awaiting source.retry() does not wait for reconnection. The loop advances to finite reads, and the immediate finally check observes connecting/pending rather than the eventual failure, losing per-row failure feedback for these sources. Separately, when the only retained issue is busy live/connection, the toast Retry remains enabled but selection excludes it and returns without feedback. Either wait for bounded source settlement to provide the stated dependency ordering/results, or make the weaker contract explicit and disable Retry when no work is selectable. Add live/connection-specific retry coverage. Whether early finite reads themselves fail again was not runtime-verified.
| await expect( | ||
| page.getByText("Missed while asleep", { exact: true }), | ||
| ).toBeVisible({ timeout: 45_000 }); | ||
| if (await notice.isVisible()) { |
There was a problem hiding this comment.
🤖 [P3] Separate automatic recovery from manual Retry coverage
The notice.isVisible() branch races notice removal and permits manual Retry all to repair reads that previously had to recover automatically. An automatic finite-read recovery regression can therefore pass through the manual branch, while other runs never exercise Retry all. Use deterministic separate cases: assert automatic recovery clears all issues without clicking Retry, then force a persistent finite-read failure and assert manual Retry clears it.
|
🤖 Closing in favor of #2968, which takes the "consolidate even harder" direction: one quiet, buttonless reconnect toast after 30 s on every page, replacing the separate LiveStatus, timeline and agent-banner notices. Automatic recovery already retries on its own, so it drops the per-source Retry / Retry all / View issues controls. The one piece of this PR we're keeping is the Thanks @tellaho for pushing on this. The video and the whack-a-mole framing are what set the direction. |
A failed stream-retry POST left its error on the live snapshot until the next stream status, so the reconnect notice could stay stuck after a later retry succeeded. Clear only that control error, leaving any newer failure in place. Taken from #3000. Co-authored-by: Taylor Ho <taylorkmho@gmail.com> Co-authored-by: mbot <3754f8729004d95654c46dbab3129e4ab9ef05cc2534e2a3fbfc155983bd637b@buzz.block.builderlab.xyz>
…oser (#2968) ## Summary The "Reconnecting to relay…" notice showed up too often and too loudly. It appeared 3 s after any background read failed, as a warning strip with **Retry now** above the composer, and the same failure was often repeated in the timeline and the agents banner. Most of those moments were a slow background read, not a real disconnect, and the app already retries on its own (1, 2, 4, 8, 16 s, then every 30 s forever, plus immediately on wake, focus and network-online). Now: - **One quiet notice on every page.** Relay recovery shows a single bottom-right toast reading "Buzz is having trouble connecting" with the description "Retrying automatically." It has no button and the calm `info` tone. - **It waits 30 s** (`RECOVERY_NOTICE_DELAY_MS`, up from 3 s). Blips, laptop wake and failures that the first retries fix stay silent. - **No duplicates.** The inline strip in `LiveStatus` is gone. While recovery is running, the timeline's history-edge error text stays hidden; it comes back if the failure outlasts recovery. **Retry older messages** stays either way, because recovery does not retry older history and paging stops on a failed read. - **Toasts never cover Send.** The composer and the preview's Join notice register with a new `useToastClearance(ref)` in `Toast.tsx`, and a CSS rule lifts the toast stack above them. This applies to every toast, not only this one. Pages with no composer keep the usual bottom-right spot. - **A retry that works clears its old error.** A failed `stream-retry` request used to leave its error on the live snapshot until the next stream status, so the notice could stay stuck after a later retry succeeded. `broker-live.ts` now clears only that request's own error, and leaves a newer failure in place. Taken from Taylor's #3000. Unchanged: the recovery backoff, the retry signals, `retryNow` wiring (wake/focus/online still call it), and "Live updates limited" with its Retry for failures that recovery does not retry (denials, partial roster). Decided in the Buzz thread with baxen: toast on every page, a longer grace period, simple states, no button, and a toast that keeps the composer clear. Related: #2958 (wake ping) is independent and touches different files. ## Screenshots Taken at 1440 px (light and dark) and 390 px, with a draft typed and Send clickable. They're posted in the Buzz thread where this was decided. ## Tests - Vitest: - `RecoveryNotice`: quiet until exactly 30 s, then one buttonless notice that clears once recovery settles. - `LiveStatus`: empty while recovery runs or shows; focus hands off when the notice replaces a focused Retry. - `ChannelTimeline`: the edge error text is hidden while recovering, and Retry older messages stays, in button and scroll modes. Fails without the fix. - `broker-live`: a successful retry clears its earlier control error, and keeps a newer stream failure. The case without the newer failure fails without the fix. - Browser journeys, migrated from the inline strip + Retry now to the toast. Controlled clocks jump the 30 s delay. - `relay-recovery`: quiet, then one notice, with no Retry buttons and no "Relay request failed" anywhere. Recovers with no click. - `live-status`: the notice sits above the composer and Send stays clickable at 390/800/1440 px. A long relay reason at enlarged text stays out of the notice. The notice sits above the preview's Join button. An empty preview recovers with no Retry. These layout cases **fail without the clearance CSS** (checked by removing it). - `live`: quota catch-up and the empty-roster recovery stay quiet inside the delay and recover with no click. - `focus-navigation`: the covered-composer F6 case pins clearance to 0 so that path stays exercised. - `history-loading`, `presence`, `navigation-groups`, `websocket-actions.profile`: locator updates. - Run in Chromium and WebKit: `relay-recovery`, `live-status`, `live`, `history-loading`, `presence`, `navigation-groups`, plus the toast-touching specs (`focus-navigation`, `message-actions`, `composer-attachments`, `profiles`, `reactions`, `updates`, `startup`, …). Browser cases removed: the Retry-now keyboard and focus cases in `live-status`, because the control no longer exists. The layout contract they guarded (notice never blocks the composer) is kept as the toast-above-composer assertions. ## Deferred - No human test yet in the desktop app with a real network drop. - Composers inside dialogs also lift the stack while mounted. That's harmless but untested. - `relay-recovery` failed 2 of about 60 local Chromium runs. Both times the notice cleared before its entrance finished, which suggests recovery settled while the fixture's HTTP outage was still on. I couldn't reproduce it with debug logging on a heavily loaded machine. Watch it in CI. --------- Signed-off-by: Bradley Axen <baxen@squareup.com> Co-authored-by: mbot <3754f8729004d95654c46dbab3129e4ab9ef05cc2534e2a3fbfc155983bd637b@buzz.block.builderlab.xyz> Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Demo
Human walkthrough with temporary, labeled simulated issues. The Developer simulation controls shown in this recording are excluded from this PR. Captions describe the actions; the original app footage plays at normal speed.
doctor-walkthrough.mp4
Fresh production-build captures below use controlled read failures and neutral fixture data. The failure image pauses a native app-generated shake frame while the next read remains pending.
Overview
Category: new-feature
User Impact: Buzz now shows background-read problems in one persistent notice, with a single place to review and retry them.
Problem: A shared outage can produce separate errors across the sidebar, workspaces and conversation, and their Retry actions do not all recover the same reads.
Solution: Buzz Doctor collects current read failures in one toast and a community-scoped dialog. Retry all runs affected reads in dependency order, disables the queue, shows the active attempt and shakes each failed row as it finishes; drafts, partial data and local write recovery stay intact.
File changes
docs/buzz-help.md
Explain the Doctor toast, issue dialog, sequential retries and failure feedback.
docs/design-system-adoption.md
Record Doctor as the shared home for background-read recovery.
docs/navigation-history.md
Document the community-scoped Doctor visit and its retained workspace.
src/app/App.tsx
Mount one Doctor for the active app session and restore focus to the current workspace.
src/app/navigation.test.tsx
Cover workspace retention, Back/Forward and explicit dialog dismissal.
src/app/navigation.ts
Treat Doctor as a global dialog while retaining the workspace presentation.
src/app/shell/PrimarySidebar.tsx
Remove the superseded sidebar recovery notice.
src/bundled/channels/LiveStatus.tsx
Suppress only live failures represented in Doctor; preserve diagnostics and local behavior.
src/bundled/channels/SoloWorkspaces.tsx
Suppress the workspace read error only when Doctor represents that source.
src/features/channel-navigation/ChannelInventory.tsx
Route represented catalog, sidebar, roster and visibility errors to Doctor without duplicate controls.
src/features/channel-navigation/SoloInventory.tsx
Suppress represented roster errors while keeping unrelated local feedback.
src/features/navigation/controller.ts
Preserve history return paths for global dialogs.
src/features/navigation/service.ts
Retain underlying page work while Doctor is open.
src/features/navigation/targets.test.ts
Validate Doctor targets, scope and distinct history keys.
src/features/navigation/targets.ts
Add the community-scoped Doctor target and shared dialog classification.
src/features/relay/BuzzDoctor.test.tsx
Exercise mounted toast/dialog recovery, disabled controls, history, failure replay and reduced motion.
src/features/relay/BuzzDoctor.tsx
Render the toast and issue dialog with shared controls, source-specific suppression and action results.
src/features/relay/DoctorRetryButton.tsx
Animate failed attempts using shared motion tokens, including disabled rows, and honor reduced motion.
src/features/relay/broker-live.test.ts
Verify successful retry control clears its own old error without hiding a newer stream error.
src/features/relay/broker-live.ts
Clear a recovered retry-control error at its owner.
src/features/relay/doctor-testing.ts
Provide isolated real-session read fixtures and explicit request gates for regression tests.
src/features/relay/doctor.test.ts
Cover dependency ordering, sequential admission, source-local results, session replacement and recovery.
src/features/relay/doctor.ts
Collect current read issues and sequence explicit retries through their existing owners without replaying writes.
src/shared/design-system/DESIGN.md
Align feedback guidance with Doctor and document explicit disabled appearance during loading.
src/shared/design-system/styles/components.css
Apply shared disabled colors when a loading control is explicitly disabled.
src/shared/design-system/ui/Button.tsx
Expose explicit disabled appearance separately from the internal loading lock.
src/shared/design-system/ui/Toast.tsx
Keep the toast body navigation action keyboard reachable.
src/shared/design-system/ui/registry.ts
Document combined loading and explicit-disabled behavior.
tests/browser/hidden-conversation-retry.spec.mjs
Exercise the production app and read owners through exhausted reads, history, sequential retries and native per-row failure animation.
tests/browser/history-loading.spec.mjs
Observe Doctor instead of the superseded inline recovery notice.
tests/browser/live-status.spec.mjs
Keep live-recovery keyboard and focus expectations aligned with the toast.
tests/browser/live.spec.mjs
Verify the shared notice, cooldown and healthy subscriptions with controlled recovery timing.
tests/browser/navigation-groups.spec.mjs
Observe grouped read recovery through Doctor.
tests/browser/presence.spec.mjs
Observe live presence recovery through the shared notice.
tests/browser/relay-recovery.spec.mjs
Verify automatic live recovery plus manual recovery of remaining finite reads.
tests/fixtures/design-system/ui/ButtonSpecimens.tsx
Show the real Button with loading and explicit disabled state together.
Reproduction steps
bin/pnpm test:browser hidden-conversation-retry.spec.mjs --project chromium --project webkit --no-deps.Validation
a2ab54fb5, including the newer partial-inventory reconnect behavior and Solo composer contract.hidden-conversation-retry.spec.mjspassed in Chromium/WebKit (19.7s). One browser case was added and the existing history/exhaustion case was retained. It covers the production read-owner integration and native Web Animations that DOM tests cannot establish; request gates prove a row fails before the later source completes. Retry matrices remain in model tests.b7d949ed3. History cleanup preserved the full source tree; the final rebase only adds main’s unrelated agent-prompt wording change (f293f0418). Range-diff confirms the feature patches are unchanged. Mandatory commit hooks and final-head push checks passed: TypeScript/related unit tests (206.58s) and design types/guards (5.97s). Hosted checks provide the remaining broad coverage.Not yet tested
This remains a draft; independent agent review is deferred.