Skip to content

Commit b7c4dcb

Browse files
katipallyCopilot
andcommitted
fix: clear stale Development CloudKit state on first Production run
Mac (CloudKitPusher): - On first launch with icloud-container-environment=Production, wipe ServerRecordCache and engine state persisted from v2.4.3 which used Development CloudKit. Development recordChangeTags embedded as base records caused 'server record changed' errors in Production, silently preventing MacStatus/AgentConfig from ever reaching the server. - Keyed by 'doomcoder.ckpusher.environment.v1' — future env changes also trigger the wipe automatically. iOS (CompanionSyncEngine): - Same migration: clear engine state, serverRecords, and MacStatusStore (cached entries from Development fetches) on first Production run. Keyed by 'ck.ios.environment.v1'. - After the wipe, the engine does a fresh fetch from the Production zone and properly receives the Mac's MacStatus record. iOS version: 2.4.1 → 2.4.2 (build 3) — TestFlight submission. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 23da213 commit b7c4dcb

3 files changed

Lines changed: 37 additions & 4 deletions

File tree

DoomCoder/AgentTracking/CloudKitPusher.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,24 @@ final class CloudKitPusher {
142142
return
143143
}
144144

145+
// ── Environment migration guard ──────────────────────────────────
146+
// v2.4.3 used the Development CloudKit environment (no explicit
147+
// icloud-container-environment entitlement). v2.4.4 adds Production.
148+
// Any CKSyncEngine state serialisation and ServerRecordCache blobs
149+
// written under Development are incompatible with Production (different
150+
// server-side record-change tags, sync tokens, etc.).
151+
// On the first launch in Production we wipe both so the engine starts
152+
// fresh: records are saved without a stale base changeTag, meaning
153+
// CloudKit creates them from scratch in the Production database.
154+
let environmentKey = "doomcoder.ckpusher.environment.v1"
155+
let currentEnv = "production"
156+
if UserDefaults.standard.string(forKey: environmentKey) != currentEnv {
157+
logger.notice("ckpusher: environment changed → wiping stale engine state and server-record cache")
158+
serverRecords.clear()
159+
UserDefaults.standard.removeObject(forKey: "doomcoder.ckpusher.engineState.v1")
160+
UserDefaults.standard.set(currentEnv, forKey: environmentKey)
161+
}
162+
145163
let stateKey = "doomcoder.ckpusher.engineState.v1"
146164
let state: CKSyncEngine.State.Serialization?
147165
if let data = UserDefaults.standard.data(forKey: stateKey),

DoomCoderCompanion/DoomCoderCompanion.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@
424424
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
425425
CODE_SIGN_STYLE = Automatic;
426426
COPY_PHASE_STRIP = NO;
427-
CURRENT_PROJECT_VERSION = 2;
427+
CURRENT_PROJECT_VERSION = 3;
428428
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
429429
DEVELOPMENT_TEAM = A9P2388PHM;
430430
ENABLE_NS_ASSERTIONS = NO;
@@ -439,7 +439,7 @@
439439
GCC_WARN_UNUSED_FUNCTION = YES;
440440
GCC_WARN_UNUSED_VARIABLE = YES;
441441
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
442-
MARKETING_VERSION = 2.4.1;
442+
MARKETING_VERSION = 2.4.2;
443443
MTL_ENABLE_DEBUG_INFO = NO;
444444
MTL_FAST_MATH = YES;
445445
OTHER_LDFLAGS = "$(inherited) -ObjC";
@@ -505,7 +505,7 @@
505505
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
506506
CODE_SIGN_STYLE = Automatic;
507507
COPY_PHASE_STRIP = NO;
508-
CURRENT_PROJECT_VERSION = 2;
508+
CURRENT_PROJECT_VERSION = 3;
509509
DEBUG_INFORMATION_FORMAT = dwarf;
510510
DEVELOPMENT_TEAM = A9P2388PHM;
511511
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -526,7 +526,7 @@
526526
GCC_WARN_UNUSED_FUNCTION = YES;
527527
GCC_WARN_UNUSED_VARIABLE = YES;
528528
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
529-
MARKETING_VERSION = 2.4.1;
529+
MARKETING_VERSION = 2.4.2;
530530
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
531531
MTL_FAST_MATH = YES;
532532
ONLY_ACTIVE_ARCH = YES;

DoomCoderCompanion/DoomCoderCompanion/Sync/CompanionSyncEngine.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,21 @@ final class CompanionSyncEngine: NSObject {
125125

126126
if syncEngine != nil { syncEngine = nil }
127127

128+
// ── Engine state migration ───────────────────────────────────────
129+
// Prior to v2.4.1 the engine state may have been written when the Mac
130+
// was using Development CloudKit (before we added the explicit
131+
// icloud-container-environment: Production entitlement). Stale sync
132+
// tokens from Development will cause the Production engine to skip
133+
// records that were never fetched from Production. Clear once.
134+
let envKey = "ck.ios.environment.v1"
135+
if sharedDefaults.string(forKey: envKey) != "production" {
136+
print("[CompanionSyncEngine] env migration: wiping stale engine state & server-record cache")
137+
sharedDefaults.removeObject(forKey: Self.engineStateKey)
138+
serverRecords.clear()
139+
MacStatusStore.shared.clear()
140+
sharedDefaults.set("production", forKey: envKey)
141+
}
142+
128143
// Restore persisted engine state
129144
let serialization: CKSyncEngine.State.Serialization? = {
130145
guard let data = sharedDefaults.data(forKey: Self.engineStateKey),

0 commit comments

Comments
 (0)