Skip to content

fix(mobile): merge relay recounts with locally seen thread replies - #4633

Open
brow wants to merge 1 commit into
mainfrom
mobile-thread-summary-merge
Open

fix(mobile): merge relay recounts with locally seen thread replies#4633
brow wants to merge 1 commit into
mainfrom
mobile-thread-summary-merge

Conversation

@brow

@brow brow commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Keep mobile thread reply badges current by merging relay recounts with replies observed locally.
  • Retain replies in the local channel store while continuing to filter them from the main timeline.
  • Match the thread summary behavior already used on desktop, including the reply count, latest reply time, and participant avatars.

Why

On mobile, the "N replies" badge under a channel message can stall at a stale count or remain missing after a reply arrives. This makes the badge unreliable and can cause people to miss replies.

The badge has two inputs: best-effort recounts from the relay and replies the client sees arrive. Mobile previously let any positive relay recount override the local view, while also discarding replies from its local message store. A delayed or lost recount, or a reply received after the recount, could therefore leave the badge behind.

This change combines both inputs by using the higher reply count, the later last-reply time, and a merged participant list. Relay timestamps have one-second precision, so equal timestamps do not prove that a recount included a locally observed reply. Comparing counts preserves that reply instead of trusting recency alone. Desktop already uses this merge behavior.

Validation

At commit 4e3356636f5ad62e8f07910af305c532186c6c08 with a clean worktree:

  • flutter test for mobile: 1105 passed, 1 skipped
  • flutter analyze for mobile: no issues found
  • Reverting the merge so a positive relay recount shadows local replies fails 4 of the new tests, including the same-second and reply-after-recount cases. Restoring the store-level reply drop fails both new provider tests.

Added tests:

  • timeline_message_test.dart, covering relay-only recounts, a reply newer than the recount, a reply in the same second as the recount, a lost recount, a zero recount, nested replies at the root and at the reply they answer, a deleted reply, and participant merging and capping.
  • channel_messages_provider_test.dart, covering a live reply reaching the store while staying out of the main timeline, and a reply newer than the relay recount raising the badge.

A message's "N replies" badge could stall at a stale count, or stay
missing, after a reply arrived. Once the relay sent any positive thread
recount, `_buildSummary` returned it and ignored replies this client had
already received, so a delayed or lost recount, or a reply landing after
the recount was taken, left the badge behind.

Merge the two sources instead: take the higher reply count, the later
last-reply time, and a combined participant list. Relay timestamps have
one-second precision, so an equal timestamp is no proof the recount
already included a locally observed reply, which is why the counts are
compared rather than the times alone. Desktop already merges this way
(`mergeThreadSummaries` in threadPanel.ts).

Replies also have to survive in the channel window store for the local
half of that merge to see anything, so stop dropping them in
`_mergeWindowEventIntoStore`. They are still filtered out of the main
timeline at render, and read state already ignores them.

Co-authored-by: Tom Brow <tomb@block.xyz>
Signed-off-by: Tom Brow <tomb@block.xyz>
@brow
brow marked this pull request as ready for review August 3, 2026 23:27
@brow
brow requested a review from a team as a code owner August 3, 2026 23:27
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