commit bf1b6f354240c7e142a3823b1ceaa0c0c68ab539
parent b34d2e41ba6e9192a8c9d505cc10889fe1a1b47f
Author: Michael Camilleri <[email protected]>
Date: Wed, 10 Jun 2026 13:07:47 +0900
Fix incorrect comment
Diffstat:
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/Crossmate/Sync/RecordApplier.swift b/Crossmate/Sync/RecordApplier.swift
@@ -242,10 +242,16 @@ extension SyncEngine {
// fresher local cursor drop the baseline and re-report the same moves as
// a duplicate catch-up banner. The etag guard above already rejects
// genuinely stale fetches. Adopting the cursor here is *not* monotonic:
- // `noteIncomingReadCursor` recomputes the account horizon as the max over
- // our devices' Player leases, so a leaving sibling's past horizon cannot
- // collapse another sibling's live presence lease, yet a clean close still
- // lowers it once no sibling leases above it.
+ // `noteIncomingReadCursor` adopts the inbound value directly under
+ // last-writer-wins, so a leaving sibling's past horizon *can* pull the
+ // account horizon back below another sibling's live presence lease.
+ // That collapse is bounded and self-healing: the still-present device
+ // re-asserts its lease as soon as it processes the inbound close
+ // (AppServices' incoming-cursor drain re-runs `publishReadCursor`
+ // ahead of the 5-min refresh floor), and a foreground device marks
+ // inbound peer moves read on arrival regardless. Keeping "A left
+ // while C is still here" representable without the dip would need
+ // per-device Player rows, which don't exist (one row per author).
let incomingReadAt = RecordSerializer.parsePlayerReadAt(from: record)
entity.readAt = incomingReadAt
let incomingReadThrough = RecordSerializer.parsePlayerReadThrough(from: record)