Summary
Buzz Mobile applies a kind 40003 edit to a thread reply when the edit arrives through the live channel subscription. If Mobile misses that live event, or refetches the thread after reconnecting or reopening it, the reply renders its original pre-edit content.
Top-level message edits survive reload because the channel-window request uses include_aux: true. Historical thread-reply requests do not.
Confirmed by source inspection on current main at eed74bde2.
Steps to reproduce
- Post a reply inside a channel thread.
- Disconnect, background, or stop the Android client.
- Edit that reply from another client.
- Confirm the relay contains both the original reply and its kind
40003 edit.
- Reconnect Android and reopen the thread.
Actual: Mobile shows the original reply.
Control: if Android remains connected while the edit is published, the updated content may appear live. A later refetch can replace that live state with the original content.
Expected behavior
A cold thread load, reopen, or reconnect should apply the latest valid edit and show the (edited) label, exactly as the live path does.
Root cause
mobile/lib/features/channels/thread_replies_provider.dart::_threadRepliesFilter() requests only EventKind.channelTimelineContentKinds:
extensions: {
'depth_limit': 64,
if (cursor != null) 'thread_cursor': cursor.createdAt,
if (cursor != null) 'thread_cursor_id': cursor.eventId,
},
It does not request include_aux.
The relay already supports include_aux on thread queries and returns the auxiliary closure for the root and fetched replies, including edits, reactions, and deletions. formatTimeline() already applies kind 40003 correctly when the edit is present in its event array.
The main channel-window request uses include_aux: true, but that closure targets the returned top-level rows; it does not backfill edits for replies loaded separately by the thread query.
This is the mobile equivalent of the desktop bug fixed in #1610. That PR explicitly identified the server-side thread include_aux path as the follow-up that would fix mobile clients. The relay path now exists; Mobile does not request it.
Fix boundary
Add include_aux: true to the historical thread filter.
Because auxiliary events are appended to the response, pagination must count and choose its cursor from content reply events—not events.length or events.last. Otherwise a page containing auxiliary events can falsely appear full or use an edit/reaction as the next reply cursor.
Regression coverage
Extend mobile/test/features/channels/thread_replies_provider_test.dart to verify:
- thread queries send
include_aux: true;
- a cold load containing a reply plus its edit renders the edited body;
- reconnect/refetch does not revert a live edit;
- the latest valid edit wins;
- pagination derives exhaustion and the next cursor from content replies when auxiliary events are also returned.
Version and platform
- Buzz Mobile: current upstream source at
eed74bde2
- Platform: Android
- Relay: self-hosted, with the kind
40003 edit confirmed stored
Summary
Buzz Mobile applies a kind
40003edit to a thread reply when the edit arrives through the live channel subscription. If Mobile misses that live event, or refetches the thread after reconnecting or reopening it, the reply renders its original pre-edit content.Top-level message edits survive reload because the channel-window request uses
include_aux: true. Historical thread-reply requests do not.Confirmed by source inspection on current
mainateed74bde2.Steps to reproduce
40003edit.Actual: Mobile shows the original reply.
Control: if Android remains connected while the edit is published, the updated content may appear live. A later refetch can replace that live state with the original content.
Expected behavior
A cold thread load, reopen, or reconnect should apply the latest valid edit and show the
(edited)label, exactly as the live path does.Root cause
mobile/lib/features/channels/thread_replies_provider.dart::_threadRepliesFilter()requests onlyEventKind.channelTimelineContentKinds:It does not request
include_aux.The relay already supports
include_auxon thread queries and returns the auxiliary closure for the root and fetched replies, including edits, reactions, and deletions.formatTimeline()already applies kind40003correctly when the edit is present in its event array.The main channel-window request uses
include_aux: true, but that closure targets the returned top-level rows; it does not backfill edits for replies loaded separately by the thread query.This is the mobile equivalent of the desktop bug fixed in #1610. That PR explicitly identified the server-side thread
include_auxpath as the follow-up that would fix mobile clients. The relay path now exists; Mobile does not request it.Fix boundary
Add
include_aux: trueto the historical thread filter.Because auxiliary events are appended to the response, pagination must count and choose its cursor from content reply events—not
events.lengthorevents.last. Otherwise a page containing auxiliary events can falsely appear full or use an edit/reaction as the next reply cursor.Regression coverage
Extend
mobile/test/features/channels/thread_replies_provider_test.dartto verify:include_aux: true;Version and platform
eed74bde240003edit confirmed stored