[Claude-drafted]
SyncRepository.UpdateSyncDate stamps a SyncDate onto every local commit whose SyncDate is null — regardless of whether it actually reached the server (SyncRepository.cs:13-24):
UPDATE Commits SET metadata = json_set(metadata, '$.ExtraMetadata.SyncDate', <now>)
WHERE json_extract(Metadata, '$.ExtraMetadata.SyncDate') IS NULL;
So a commit that was never pushed (e.g. one silently dropped from the push set) is marked synced on the next sync: the pending-commits count drops to 0 and no UI or telemetry signal ever appears.
Impact: a real single-commit loss on project blj-flex — a stranded CreateExampleSentenceChange that left an orphaned jsonPatch:ExampleSentence edit, which throws NotSupportedException in SnapshotWorker and has wedged FwHeadless since 2026-07-10 — was invisible for weeks because of this. It will mask any future drop too.
Fix: only stamp SyncDate for commits confirmed present on the server (derive from the acknowledged push / the server's returned sync state), not "all local commits with null SyncDate".
Related: the drop itself comes from the lossy (ClientId → millisecond-timestamp) SyncState watermark — see sillsdev/harmony#79 (duplicated-ClientId variant of the same watermark weakness); server-side commit-PK hardening in #2365.
[Claude-drafted]
SyncRepository.UpdateSyncDatestamps a SyncDate onto every local commit whose SyncDate is null — regardless of whether it actually reached the server (SyncRepository.cs:13-24):So a commit that was never pushed (e.g. one silently dropped from the push set) is marked synced on the next sync: the pending-commits count drops to 0 and no UI or telemetry signal ever appears.
Impact: a real single-commit loss on project blj-flex — a stranded
CreateExampleSentenceChangethat left an orphanedjsonPatch:ExampleSentenceedit, which throwsNotSupportedExceptioninSnapshotWorkerand has wedged FwHeadless since 2026-07-10 — was invisible for weeks because of this. It will mask any future drop too.Fix: only stamp SyncDate for commits confirmed present on the server (derive from the acknowledged push / the server's returned sync state), not "all local commits with null SyncDate".
Related: the drop itself comes from the lossy
(ClientId → millisecond-timestamp)SyncStatewatermark — see sillsdev/harmony#79 (duplicated-ClientId variant of the same watermark weakness); server-side commit-PK hardening in #2365.