Skip to content

Data divergence between devices after concurrent offline edits #274

@lukaskubanek

Description

@lukaskubanek

Description

While experimenting with the library in preparation for #272, I ran into a case where a concurrently edited field diverged between devices.

Let’s consider a single TEXT column of a table (I was using Reminder.title in the Reminders example app) and two devices, A and B, editing the field of the same row concurrently. To simulate a real-world scenario, device A is put offline during the editing phase.

Scenario 1

In the first scenario, device B makes its edit before device A. Everything works as expected. When device A comes online, it’s prevented from sending its value until it downloads device B’s update. Since device A’s change is considered the last write, it’s then correctly propagated to device B.

Device A Device B
foo foo
offline
fooB
send
fooA
online
send 💥
fetch
send
fetch
fooA

Scenario 2

In the second scenario, the steps are similar, only the order of edits is swapped. When device A comes online, it also fetches device B’s value. But this time, since device B’s edit is the last write, device A should adopt that value and drop its local change. However, this doesn’t happen. Device A keeps its local value, which causes the SQLite database to diverge from the CloudKit record, as the local value correctly isn’t synced with CloudKit anymore.

Device A Device B
foo foo
offline
fooA
fooB
send
online
send 💥
fetch ⚠️
send ⚠️
fetch

It seems that device A’s local value is still considered a modification during the fetch. The expected behavior would be for the logic to recognize that the local change is outdated and let it be overwritten by the server value.

This might be better addressed with an abstraction built as part of #272, but I think it’s better to tackle it in piecemeal steps.

Checklist

  • I have determined whether this bug is also reproducible in a vanilla SwiftUI project.
  • I have determined whether this bug is also reproducible in a vanilla GRDB project.
  • If possible, I've reproduced the issue using the main branch of this package.
  • This issue hasn't been addressed in an existing GitHub issue or discussion.

Expected behavior

No response

Actual behavior

No response

Reproducing project

No response

SQLiteData version information

main

Sharing version information

No response

GRDB version information

No response

Destination operating system

iOS 18

Xcode version information

26.1 β3

Swift Compiler version information

swift-driver version: 1.127.14.1 Apple Swift version 6.2 (swiftlang-6.2.0.19.9 clang-1700.3.19.1) Target: arm64-apple-macosx15.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions