Ask the server only for the conversations that changed - #6744
Draft
AndyScherzinger wants to merge 4 commits into
Draft
AndyScherzinger wants to merge 4 commits into
AndyScherzinger wants to merge 4 commits into
Conversation
Add the modifiedSince query parameter to GET /room and return the full response so the X-Nextcloud-Talk-Modified-Before header can be read. The network data source now reports the conversations, the timestamp to use for the next delta request, and whether the response it got back was a delta at all - a server below conversation API v4 answers in full whatever it was asked, and a caller that assumed otherwise would reconcile deletions against the wrong kind of response. Assisted-by: Claude Code:claude-opus-5 Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Send the timestamp the server handed back on the last conversation list sync as modifiedSince, so a sync carries what changed rather than every room with its last message, and ask without includeStatus while doing so - with it the server returns every one-to-one room whatever modifiedSince says, which is most of the list on a typical account. The response to such a request cannot express a conversation being deleted or the user being removed from one, so the left-conversation reconcile is skipped for it: every conversation the response leaves out would otherwise look like one that was left, and deleting those cascades through the foreign key to their cached messages and chat blocks. The network layer reports whether the response really was a delta, because a server below conversation API v4 answers in full whatever it was asked. The timestamp is stored per account in arbitrary storage, and only once the response is in the database - one kept ahead of a write that then failed would permanently skip the conversations that write was carrying. A failed sync drops it, so the next one asks for everything again. Assisted-by: Claude Code:claude-opus-5 Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
A modifiedSince response cannot say that a conversation was deleted or that the user was removed from one, so the server asks clients to fetch the whole list regularly anyway. Follow that: at least every five minutes, and always when the internal signaling backend is in use, where no signaling server exists to announce the change out of band. A caller can also demand one. Pull to refresh does, so a conversation left on another device is gone by the time the indicator stops spinning rather than within the next five minutes, and so does the first sync after an account switch or a process start, which has nothing this process has seen the full picture behind to anchor a delta on. A device clock that moved backwards makes the last full sync read as being in the future; that is not a young full sync but an unusable one, and it asks for a full one too. Assisted-by: Claude Code:claude-opus-5 Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
The case worth a test here is the one that destroys data rather than the one that annoys: a delta response lists only what changed, so every conversation it leaves out looks like one the user left, and reconciling those away takes their cached messages and chat blocks with them through the foreign key cascade. The first test seeds ten conversations with cached chat, runs a delta sync that mentions one of them, and asserts the other nine still have theirs. It was checked against the mistake it guards: with the delta branch removed from the sync, it fails. The rest cover what decides the mode - the stored timestamp is sent and includeStatus is not, the internal signaling backend never gets a delta, a full response still reconciles a conversation away, and a failed sync drops the timestamp so the next one asks for everything. Assisted-by: Claude Code:claude-opus-5 Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Contributor
📱 QA build
The QA build installs alongside a released Nextcloud app, so you can keep Downloading the file requires a GitHub account, so open this link on the |
This was referenced Sep 21, 2026
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.
Every conversation list sync is a full
GET /roomtoday: every room, with its last message. This adds the server'smodifiedSincedelta so a sync carries only what changed. It is the prerequisite for the two periodic triggers stacked on top of it, which would otherwise multiply the most expensive request the client makes.What it does
modifiedSinceonGET /roomand echoes back theX-Nextcloud-Talk-Modified-Beforeresponse header on the next request — the server's own timestamp, never a client clock.includeStatuson delta syncs, which otherwise makes the server return every one-to-one room regardless and eats most of the saving.docs/conversation.md.The one thing to check in review
A delta response must never reach
determineLeftConversationIds. That function lists every previously known conversation absent from the response — on a filtered response, nearly all of them — and the delete cascades through the foreign key to cached messages and chat blocks.RoomListResult.wasDeltais reported by the network layer rather than derived from the caller's intent, because an old server silently answers a delta request in full, and the reconcile is skipped on it.Not in this PR
delete/disinvitesignaling messages, which the server also recommends. Android handles neither event today.🚧 TODO
🏁 Checklist
/backport to stable-xx.x🤖 AI (if applicable)