commit 39fd61588114933c4d45b3a32990b6ade0da0450
parent 1fe11dc6378937ab46cb33c85622247e0523dd3f
Author: Michael Camilleri <[email protected]>
Date: Sat, 27 Jun 2026 07:33:38 +0900
Reserve accountSeen horizons before publishing
Opening a shared puzzle could still send duplicate accountSeen pushes
when the delivered-notification dismissal and active read lease
overlapped. Both callers checked the coalescing state before either
worker request had returned, so the second path could miss the first
in-flight publish and send the same open-time horizon.
This commit records the per-game accountSeen horizon before awaiting the
worker publish, after the local push-client and author preconditions
have passed. Overlapping open-time callers now see the reserved horizon
and log the existing coalesced diagnostic instead of making a second
worker request.
Co-Authored-By: Codex GPT 5.5 <[email protected]>
Diffstat:
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/Crossmate/Services/AccountPushCoordinator.swift b/Crossmate/Services/AccountPushCoordinator.swift
@@ -325,6 +325,14 @@ final class AccountPushCoordinator {
}
func publishAccountSeenPush(gameID: UUID, readAt: Date) async {
+ guard let pushClient else {
+ syncMonitor.note("push(\(Self.accountSeenPushKind)): skipped (no pushClient)")
+ return
+ }
+ guard let authorID = identity.currentID, !authorID.isEmpty else {
+ syncMonitor.note("push(\(Self.accountSeenPushKind)): skipped (no authorID)")
+ return
+ }
if shouldCoalesceAccountSeen(gameID: gameID, readAt: readAt) {
syncMonitor.note(
"push(accountSeen): coalesced \(gameID.uuidString.prefix(8)) " +
@@ -332,9 +340,14 @@ final class AccountPushCoordinator {
)
return
}
- if await publishAccountEvent(kind: Self.accountSeenPushKind, gameID: gameID, readAt: readAt) {
- lastAccountSeenReadAt[gameID] = readAt
- }
+ let address = ensureAccountPushAddress(authorID: authorID)
+ lastAccountSeenReadAt[gameID] = readAt
+ await pushClient.publishAccountEvent(
+ kind: Self.accountSeenPushKind,
+ gameID: gameID,
+ address: address,
+ readAt: readAt
+ )
}
private func shouldCoalesceAccountSeen(gameID: UUID, readAt: Date) -> Bool {