During a normal sync, when the same card or note has been changed on two devices since the last sync, Anki silently keeps the version with the newer modification time and discards the other (in rslib/src/sync/collection/chunks.rs the incoming entry wins if the local one isn’t pending sync or existing.mtime < entry.mtime). Review history is safely merged, but the card’s state, fields, tags and deck are not: one side’s change is lost without any notice.
A real example
Our family uses a self-hosted sync server with a desktop and two AnkiDroid devices. On the desktop I rescheduled a set of very easy cards to 12–18 months (Set Due Date 365-545!). If my daughter reviews one of those cards on her phone before the phone has synced, her review is newer, it wins, and my rescheduling of that card is silently undone. Nobody is told, and the only way to notice is to compare the collection before and after.
Proposal: deterministic conflict detection
A conflict can be detected exactly, without heuristics: an object is in conflict when both sides modified it after the last successful sync. The client already knows its own pending changes (usn = -1) and receives the server’s changes since its last sync, so the intersection of the two sets is precisely the set of conflicting objects. It is cheap to compute and deterministic.
For each conflicting object, Anki could:
- show which fields differ between the two versions: note fields, tags, deck, and for cards the scheduling values (due, interval, ease/stability, queue);
- let the user choose per object (local / remote), with “keep newest for all” as the default, which is today’s behaviour;
- at minimum, if an interactive choice is too intrusive, write a conflict log listing the objects where the older side was discarded, with both versions, so a user can review and restore them.
The default behaviour would not change for users who don’t care, while users who make bulk edits on one device and study on another would no longer lose changes silently.
Related: #5414 (changing deck bumps the mtime of all its cards, which makes these conflicts more likely).
I’d be glad if someone more familiar with the codebase could pick this up. If not, I’m willing to work on it myself, although it would be my first contribution to Anki.