Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

Inconsistent conflict resolution between production and tests

Abierto
#356 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
4/5
Tiempo estimado
3-5 días
Aptitud para principiantes
35/100
Tipo de issue
Error
Claridad
Bastante claro
Estado de actividad
Estancado
Stack tecnológico
sqlite, swift

Línea de trabajo

Start with SyncEngine.refreshLastKnownServerRecord(_:) and compare how saved records are represented by the mock server. Then read MergeConflictTests, especially clientRecordUpdatedBeforeServerRecord() and serverRecordEditedAfterClientAndProcessedAfterClient(), alongside PR #411. Done means production and test conflict-resolution behavior agree without relying on a polluted last-known server record.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

bug
Description

I’ve been trying to wrap my head around the implementation of the built-in “field-wise last edit wins” strategy, and I’m honestly having a hard time. To better understand what’s going on, I started documenting the current behavior in this document. While I still don’t have all the answers, I ran into some unexpected behavior that felt worth reporting, as it might help clarify the intended design.

It traces back to the purpose of the didSet flag in CKRecord.update(with:row:columnNames:parentForeignKey:), which is used during upserts. As I understand it, this logic attempts to restore values from the last-known server record onto an incoming server record. In my mental model, this should be superfluous (and really a no-op), as I was assuming the last-known server record represents the most recent record that was either accepted by or fetched from the server. In the three-way merge terms, this would be the ancestor.

However, while digging deeper, I found two spots in the codebase where a record is saved as the last-known server record before it has been accepted by the server. I went into more detail on these in the warning sections of the linked document. In particular, the premature save during send looked worrying to me, as it seems to break the mental model of the last-known server record.

When testing this with the sample apps, I noticed that the record was not actually being saved during send. Inspecting SyncEngine.refreshLastKnownServerRecord(_:) revealed that this was due to the check of the modificationDate between the saved last-known server record and the given record, which happened to be equal, as the given record was based off of the last-known server record.

In tests, however, the record is being saved. The reason appears to be that the mock server does not populate modificationDate on records it reports back to the sync engine. While CKRecord.modificationDate can’t be set directly, I was able to swizzle it and have the mock server simulate a save timestamp. With that change in place, behavior became closer to production but two MergeConflictTests started producing different results, as they had previously been operating on a polluted last-known server record:

  • clientRecordUpdatedBeforeServerRecord(): the final assertion changed from isCompleted = 1 @ t=30 to isCompleted = 1 @ t=60
  • serverRecordEditedAfterClientAndProcessedAfterClient() (added in #353): the title changed from “Buy milk” to “Get milk”, which is incorrect, but at least aligned with the other test preferring local edits regardless of timestamps (as described in #354)

I might be wrong, but I don’t think the reconciliation from the last-known server record that doesn’t reflect the actual server state is an intended behavior specifically built for tests. Having different results between the production and test environment feels wrong, even though the broader question of the desired semantics still stands.

The most straightforward way to align both environments seems to be to have the mock server populate modificationDate on “saved” records. From there, we could iterate further. Is this how things are meant to work? Do you want me to submit a PR that allows the mock server to set the modification date? PR #411 submitted.

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.
SQLiteData version information

1.4.1

Sharing version information

2.7.4

GRDB version information

7.8.0

Destination operating system

No response

Xcode version information

Version 26.2 (17C52)

Swift Compiler version information
swift-driver version: 1.127.14.1 Apple Swift version 6.2.3 (swiftlang-6.2.3.3.21 clang-1700.6.3.2)
Target: arm64-apple-macosx15.0
Lenguaje dominante
Swift
Estrellas
1.9k
Forks
154
Merge medio
2 d 18 h
PR fusionados (30 d)
1

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de pointfreeco/sqlite-data

Todos los issues de pointfreeco/sqlite-data

Issues similares

Más issues de Swift

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.