Skip to content

fix(desktop): dedupe replayed thread reply notifications#2189

Open
Areson wants to merge 1 commit into
block:mainfrom
Areson:Areson/thread-reply-notification-dedupe
Open

fix(desktop): dedupe replayed thread reply notifications#2189
Areson wants to merge 1 commit into
block:mainfrom
Areson:Areson/thread-reply-notification-dedupe

Conversation

@Areson

@Areson Areson commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Why

Reconnect catch-up re-delivers already-seen thread replies through the live handler, causing macOS notifications to replay after laptop sleep, network changes, or retryable subscription recovery.

What

  • Persist every observed external non-DM thread-reply ID per user/channel before mutable mute, follow, participation, or active-channel eligibility checks
  • Reconcile persisted records and replay floors to active and provisionally pending broad subscriptions before cap eviction; narrow to successful subscriptions after setup so same-second boundary IDs survive remounts
  • Recreate broad subscriptions when notification-dedupe ownership changes, preventing retryable CLOSED recovery callbacks from remaining bound to a retired identity
  • Assign each broad-subscription sync a monotonic generation and guard post-await insertion/reconciliation, preventing canceled syncs from overwriting replacement state
  • Coalesce durable storage during replay while keeping in-memory dedupe immediate; flush one pruned/capped snapshot on replay completion or lifecycle handoff, and stop repeat serialization after a storage failure
  • Keep the five-second watermark floor on finite HTTP catch-up while preserving each original long-lived live filter across reconnect and retryable CLOSED
  • Track retryable CLOSED recovery per live subscription from scheduling through recovered EOSE buffer drain, suspending cap eviction and persistence until every overlapping socket/subscription replay completes
  • Acquire socket replay ownership at stalled before reset releases subscription recovery, eliminating a cap/flush gap before reconnect begins
  • Give standalone retryable-CLOSED recovery one non-extendable eight-second EOSE deadline that resets into socket reconnect while recovery ownership is still held
  • Reset CLOSED retry backoff when recovery is released into a new socket, so each connection generation starts with the base one-second retry inside its fresh eight-second deadline
  • Retain notification IDs for each channel subscription's actual session-start replay window, with a 2,000-item oldest-first safety cap
  • Cover persisted remount boundaries, superseding pending sync, identity handoff before/during recovery, CLOSED-to-stalled transfer, missing standalone EOSE, socket-generation retry reset, full-cap newest-first CLOSED replay, overlapping socket/subscription recovery, newest-first HTTP/live replay, delayed old-timestamp events, mutable eligibility changes, active-channel navigation, departed-channel cleanup, startup cap pressure, canceled-sync ordering, replay write coalescing, final persisted cap, and storage quota failure

Risk Assessment

Medium-low — notification dedupe remains isolated to thread replies. Shared desktop recovery preserves long-lived filter semantics, bounds socket and standalone subscription EOSE waits, and exposes an idempotent recovery lifecycle only to broad channel subscriptions. Identity handoff recreates those subscriptions; subscription removal, terminal CLOSED, stalled/socket reset, and timeout all settle recovery state. The global cap remains a bounded-storage tradeoff among currently active subscriptions.

References

  • Focused reconnect/recovery/dedupe tests: 37 passed
  • Complete desktop unit suite: 3,265 passed
  • TypeScript, Biome/static checks, file-size guard, commit hooks, and full repository pre-push gate passed

Generated with Codex

@Areson
Areson force-pushed the Areson/thread-reply-notification-dedupe branch 7 times, most recently from 5e386ee to 47be921 Compare July 21, 2026 02:00
Persist notified reply IDs per channel and retain replay-boundary entries until reconnect catch-up completes.

Co-authored-by: Ian Oberst <ioberst@squareup.com>
Signed-off-by: Ian Oberst <ioberst@squareup.com>
Co-authored-by: Codex <noreply@openai.com>
Ai-assisted: true
@Areson
Areson force-pushed the Areson/thread-reply-notification-dedupe branch from 47be921 to 9e07d18 Compare July 21, 2026 02:30
@Areson
Areson marked this pull request as ready for review July 21, 2026 14:03
@Areson
Areson requested a review from a team as a code owner July 21, 2026 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant