Skip to content

Desktop reconnect replay re-alerts old thread replies and plays false notification sound #3215

Description

@billerickson

Describe the bug

Buzz Desktop plays the configured thread-reply notification sound after a
relay reconnect even when no new message has arrived. The visible timeline
does not show a duplicate, but an already-delivered thread reply appears to
pass through the desktop-notification callback again during reconnect replay.

The relay connection card itself is silent; the sound coincides with
ReconnectingConnected because live channel subscriptions are replayed
at that point.

Steps to reproduce

  1. In Buzz Desktop, enable desktop notifications and the Thread replies
    alert row under Settings → Notifications.
  2. Receive a reply in a thread the current user authored, participated in, or
    follows.
  3. Leave Buzz open without receiving any newer messages.
  4. Interrupt the relay connection, or reproduce while the relay/load balancer
    is temporarily unavailable, and allow Buzz to reconnect.
  5. Observe that Buzz plays the configured notification sound after reconnect,
    despite there being no new visible message.
  6. Repeat the disconnect/reconnect. The same chirp can occur on every cycle.

Turning off only the Thread replies alert row suppresses the false chirp
while leaving the other alert classes enabled.

Expected behavior

Reconnect replay may redeliver an event to restore client state, but an event
ID that has already passed through the desktop-notification path must not
create another notification or play another sound.

Version and platform

  • Buzz version: 0.4.26 (xyz.block.buzz.app)
  • OS: macOS 15.1 (24B2082), Apple Silicon

Logs / additional context

This was observed during a relay incident in which other clients reported
503 Service Unavailable. A separate authenticated WebSocket probe connected
to the same relay recorded:

  • 2026-07-27T21:19:20.826Z: abnormal close 1006, empty reason,
    wasClean: false
  • 2026-07-27T21:19:26.652Z: reconnect opened; authentication accepted at
    21:19:26.957Z
  • 2026-07-27T21:19:29Z: Buzz Desktop visibly reconnected and chirped
  • 2026-07-27T21:19:42.490Z: probe closed with 1006 again

The transport outage is only the trigger for this report. The client bug is
that reconnecting re-alerts an already-delivered event.

Source-level findings in the v0.4.26 release:

  1. desktop/src/features/sidebar/ui/SidebarRelayConnectionCard.tsx and
    useSidebarRelayConnectionCard.ts contain no sound call.
  2. desktop/src/shared/api/relayReconnectReplay.ts replays each live
    subscription from five seconds before lastSeenCreatedAt.
  3. That watermark is the latest event timestamp, not wall-clock time, so it
    remains fixed during a quiet period and the same latest event can be
    returned on every reconnect.
  4. prepareSubscriptionEvent() in
    desktop/src/shared/api/relayClosedRecovery.ts advances the timestamp but
    does not deduplicate by event ID.
  5. desktop/src/features/channels/useLiveChannelUpdates.ts has bounded
    event-ID gates for DM and mention paths, but the qualifying thread-reply
    path can call onThreadReplyDesktopNotification without an equivalent
    gate.
  6. desktop/src/app/useAppShellDesktopNotifications.ts plays the configured
    thread_reply sound whenever that callback successfully sends the desktop
    notification.

This establishes a source path that matches the one-chirp-per-reconnect
behavior. The exact replayed event ID is not available because the release
build does not log notification attempts or the event ID passed to the sound
call.

Suggested fix:

  • Add bounded event-ID deduplication before invoking thread-reply desktop
    notifications, retaining the set across reconnect replay.
  • Add a regression test that delivers a thread reply, reconnects with the same
    event in the replay window, and asserts that the notification/sound callback
    runs exactly once.
  • Consider adding a reconnect watermark for live subscriptions that have no
    lastSeenCreatedAt, rather than resending the original subscription window.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions