commit 80a2bd8a09c436809578781aa2ab032693251e45
parent 154b90e09beea5f7c8671846f1ffb8a63ab983e2
Author: Michael Camilleri <[email protected]>
Date: Fri, 29 May 2026 20:32:10 +0900
Tighten debouncing gating
Diffstat:
1 file changed, 12 insertions(+), 0 deletions(-)
diff --git a/Crossmate/Services/AppServices.swift b/Crossmate/Services/AppServices.swift
@@ -140,6 +140,11 @@ final class AppServices {
private let gameListFreshenCooldown: TimeInterval = 300
private var fresheningPuzzleGridKeys: Set<String> = []
private var lastRemotePuzzleGridFreshenAt: [String: Date] = [:]
+ /// Collapses bursts of remote-push grid refreshes, but only while the
+ /// engagement websocket is live for the game (see
+ /// `shouldSkipRecentRemotePuzzleGridFreshen`). When the live channel is
+ /// down, the push path is the sole convergence mechanism and is not
+ /// debounced.
private let remotePuzzleGridFreshenDebounce: TimeInterval = 5
private var isGameListVisible = false
private var latestLocalSelections: [UUID: PlayerSelection] = [:]
@@ -1420,6 +1425,13 @@ final class AppServices {
scope: CKDatabase.Scope,
label: String
) -> Bool {
+ // The debounce only suppresses refreshes that the live channel already
+ // covers. When the engagement websocket is live for this game, grid
+ // deltas arrive over it and the push-driven fetch is redundant, so
+ // collapsing a burst of pushes is harmless. When it is not live, the
+ // CK-push path is the only thing converging the grid — never skip it,
+ // or convergence stalls exactly when the live overlay is down.
+ guard engagementStatus.isLive(gameID: gameID) else { return false }
let key = puzzleGridFreshenKey(gameID: gameID, scope: scope)
guard let last = lastRemotePuzzleGridFreshenAt[key] else { return false }
let elapsed = Date().timeIntervalSince(last)