feat(chat): backfill transcripts after a feed sync - #628
Open
bmc08gt wants to merge 2 commits into
Open
Conversation
Chat history was only ever fetched by opening a chat, so a fresh login — switching accounts included — started from a per-owner database with no messages in it, and every conversation in the feed showed an empty transcript until it was opened by hand. Port Android's `FeedSyncDelegate` pass: after each feed load, bring every conversation it reported level with the server's head, four at a time. Branch order matches Android's — a local cursor that lags the feed's `latest_event_sequence` is streamed forward with `GetDelta` from where it sits, and only a conversation holding nothing at all falls back to the newest page. Reversing that would spend a `GetDelta(after: 0)` re-pulling whole histories and prepending them. `Conversation` now carries the server's `latestEventSequence`. It is server truth valid only at fetch time, so it is deliberately not cached: a conversation restored from the local database reports 0, meaning "unknown", not "empty".
The feed writes each conversation's last-message preview as a message row before the backfill plans its work, so "holds any message" was true for nearly every chat in a feed the client had otherwise never fetched. With a fresh database the cursor is also 0, which blocks the delta branch — so the pass queued nothing at all on exactly the fresh-login case it exists for. Ask instead whether a transcript was ever pulled: only a newest page or an applied delta seats a catch-up cursor. Zero cursor means fetch the newest page; a seated cursor behind the server's head means resume via GetDelta. Verified on the simulator against a wiped database: 47 conversations, 47 newest-page fetches, no duplicates, and the following reconnects queue nothing once the cursors are seated.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Chat history was only ever fetched by opening a chat:
loadMessages(for:)had exactly one caller (ConversationScreen, on open) andcatchUpfired only for the visible chat or a detected live gap. A fresh login — switching accounts included — starts from a per-owner database with no messages in it, so every conversation in the feed sat empty until it was opened by hand.What changed
ConversationController.loadFeed()now backfills the conversations the feed reported, four at a time, outside the loading flag — the feed is on screen the moment the conversations apply and the transcripts fill behind it.latest_event_sequenceresumes withGetDeltafrom where it sits. Choosing on "does this chat hold any message" does not work — the feed persists each conversation's last-message preview as a message row before the backfill plans, so that test is true for nearly every chat in a feed the client has otherwise never fetched. Order matters too: aGetDelta(after: 0)would re-pull whole histories and prepend them, knocking an open transcript off the bottom, so delta only runs on a cursor that is already seated.Conversationcarries the server'slatestEventSequencefrom the feed payload. It is server truth valid only at fetch time, so it is deliberately not cached — a conversation restored from the local database reports0, meaning "unknown", not "empty". No schema change: the local cursor is already persisted asConversationTable.catchupCursor.Tests
Four new cases in
ConversationControllerTestscover the empty-conversation backfill, the cached no-op, the lagging-cursor delta path, and the regression above — a chat holding only the feed's preview row still gets its transcript fetched. Two existing cases were updated for the new premise:RESET_REQUIRED…now forgets the pagestart()'s backfill fetched, and the old "a reconnect with no conversation open fetches no transcript" is now "a reconnect backfills a chat it surfaces" — that behavior is the point of the change.