Skip to content

Ask the server only for the conversations that changed - #6744

Draft
AndyScherzinger wants to merge 4 commits into
masterfrom
feat/noid/conversation-list-delta-sync
Draft

AndyScherzinger wants to merge 4 commits into
masterfrom
feat/noid/conversation-list-delta-sync

Conversation

@AndyScherzinger

@AndyScherzinger AndyScherzinger commented Sep 21, 2026

Copy link
Copy Markdown
Member

Every conversation list sync is a full GET /room today: every room, with its last message. This adds the server's modifiedSince delta 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

  • Sends modifiedSince on GET /room and echoes back the X-Nextcloud-Talk-Modified-Before response header on the next request — the server's own timestamp, never a client clock.
  • Drops includeStatus on delta syncs, which otherwise makes the server return every one-to-one room regardless and eats most of the saving.
  • Still forces a full sync every 5 minutes, on internal signaling, on pull-to-refresh, on account switch and after a failed sync, per the server's guidance in docs/conversation.md.
  • Sends nothing on servers below conversation API v4, which answer in full.

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.wasDelta is 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

  • Periodic background refresh, and the foreground refresh loop while the list is open — stacked on top of this branch.
  • A full refresh on delete / disinvite signaling messages, which the server also recommends. Android handles neither event today.

🚧 TODO

  • Manual check against a real server: federated conversations are not skipped by delta syncs

🏁 Checklist

  • ⛑️ Tests (unit and/or integration) are included or not needed
  • 🔖 Capability is checked or not needed
  • 🔙 Backport requests are created or not needed: /backport to stable-xx.x
  • 📅 Milestone is set
  • 🌸 PR title is meaningful (if it should be in the changelog: is it meaningful to users?)

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI

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>
@github-actions

Copy link
Copy Markdown
Contributor

📱 QA build

Download app-qa-debug.apk
QR code Open the QR code for this download
Commit bb53fe7
Version 6744
Available until 7 days after this build

The QA build installs alongside a released Nextcloud app, so you can keep
using your existing install while testing.

Downloading the file requires a GitHub account, so open this link on the
device you want to test on, or transfer the APK to it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant