Skip to content

fix(chat): keep a preview on the row after a delete - #727

Merged
bmc08gt merged 1 commit into
mainfrom
fix/chat-deleted-message-preview
Sep 3, 2026
Merged

fix(chat): keep a preview on the row after a delete#727
bmc08gt merged 1 commit into
mainfrom
fix/chat-deleted-message-preview

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Deleting the newest message left the conversation list blank until the chat was opened and closed again.

Server metadata reports the newest message whatever its state, so the delete arrives as a tombstone last_message. Both seats for it wrote that to the feed row verbatim — setFeed on every feed load, and upsert on a .metadataRefresh — and nothing draws for a tombstone, so the row went blank with an unread splat beside it. refreshFeedPreview already repaired the row from the database, but it ran on the transcript paths, which is why opening the chat and coming back fixed it.

ConversationStore now refuses a tombstone as a preview at both seats: it keeps the visible message the row already carries, unless that is the message the tombstone replaces, in which case the row clears rather than showing deleted content. loadFeed(type:) then runs the existing database repair for the conversations the server previewed with a tombstone, so the fallback lands where the blank was seated.

markRead was already correct — it takes the newest id from the database, tombstones included, so the read pointer does not park below a deleted message.

This is the behaviour code-payments/code-android-app#1396 brought Android to: preview the newest message that still has content, and let the splat clear with it.

Also here: the two on-demand hydrates persist the server's Conversation rather than the store's. The store no longer carries the tombstone, and the database needs that row for the repair to tell the newest message was deleted.

Deleting the newest message left the conversation list blank until the chat was
opened and closed again. Server metadata reports the newest message whatever its
state, so the delete arrives as a tombstone `last_message`, and both seats for it
— the feed load and a metadata refresh — wrote it to the row verbatim. Nothing
draws for a tombstone, so the row went blank with an unread splat beside it.

The store now refuses a tombstone as a preview. It keeps the visible message the
row already carries, unless that is the message the tombstone replaces, and the
feed load fills the gap from the newest visible message in the database — the
path that already repaired the row on open, now run where the blank was seated.

That is the fallback code-payments/code-android-app#1396 brought Android to; iOS
only did it on the paths that already went through `refreshFeedPreview`.

The two on-demand hydrates persist the server's copy rather than the store's, so
the database still gets the tombstone row the repair reads to tell that the
newest message was deleted.
@bmc08gt bmc08gt self-assigned this Sep 3, 2026
@bmc08gt
bmc08gt merged commit 932ac47 into main Sep 3, 2026
1 check passed
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