block / block/buzz

Mobile: thread-reply edits are live-only and revert after reopen because history omits include_aux

Open
#7,058 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

## 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

1. Post a reply inside a channel thread.
2. Disconnect, background, or stop the Android client.
3. Edit that reply from another client.
4. Confirm the relay contains both the original reply and its kind `40003` edit.
5. 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`:

```dart
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

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.