commit 93b8097d8ec51d9b38bac1cb8b3998285fe6e7f3
parent ee646a58690d30804aee98782ec632e1f85e721c
Author: Michael Camilleri <[email protected]>
Date: Tue, 14 Apr 2026 23:03:23 +0900
Add telemetry for iCloud debugging
Diffstat:
1 file changed, 26 insertions(+), 2 deletions(-)
diff --git a/Crossmate/Sync/SyncEngine.swift b/Crossmate/Sync/SyncEngine.swift
@@ -61,6 +61,14 @@ actor SyncEngine {
let userRecordID = try await container.userRecordID()
zoneID = CKRecordZone.ID(zoneName: zoneID.zoneName, ownerName: userRecordID.recordName)
ownerResolved = true
+ await trace("resolveOwner: zoneID now \(zoneID.zoneName)/\(shortOwner(zoneID.ownerName))")
+ }
+
+ private nonisolated func shortOwner(_ name: String) -> String {
+ // Shorten long owner record IDs so diagnostics stay readable.
+ // Keeps the last 8 characters so both devices can be compared visually.
+ guard name.count > 10 else { return name }
+ return "…" + String(name.suffix(8))
}
// MARK: - Bootstrap
@@ -76,7 +84,11 @@ actor SyncEngine {
SyncStateEntity.current(in: context).zoneCreated
}
- guard !alreadyCreated else { return }
+ guard !alreadyCreated else {
+ await trace("bootstrap: zone already created, skipping")
+ return
+ }
+ await trace("bootstrap: creating zone \(zoneID.zoneName)")
let zone = RecordSerializer.zone()
let operation = CKModifyRecordZonesOperation(
@@ -346,11 +358,18 @@ actor SyncEngine {
}
let changedZoneIDs = try await fetchDatabaseChanges(token: databaseToken, context: context)
+ let zoneDescriptions = changedZoneIDs
+ .map { "\($0.zoneName)/\(shortOwner($0.ownerName))" }
+ .joined(separator: ", ")
+ await trace("fetch: changedZoneIDs count=\(changedZoneIDs.count) [\(zoneDescriptions)]")
// Only proceed if our zone has changes. Equality works here because
// `resolveOwnerIfNeeded()` has rebuilt `zoneID` with the real owner
// record ID, matching what the server returns.
- guard changedZoneIDs.contains(zoneID) else { return }
+ guard changedZoneIDs.contains(zoneID) else {
+ await trace("fetch: our zone \(zoneID.zoneName)/\(shortOwner(zoneID.ownerName)) not in changed set, skipping zone fetch")
+ return
+ }
// Step 2: Fetch zone-level changes
let zoneToken: CKServerChangeToken? = context.performAndWait {
@@ -358,6 +377,10 @@ actor SyncEngine {
}
let incomingRecords = try await fetchZoneChanges(token: zoneToken, context: context)
+ await trace("fetch: incomingRecords count=\(incomingRecords.count)")
+ for record in incomingRecords {
+ await trace("fetch: record \(record.recordType) name=\(record.recordID.recordName)")
+ }
guard !incomingRecords.isEmpty else { return }
@@ -369,6 +392,7 @@ actor SyncEngine {
self.applyIncomingRecords(incomingRecords, in: context)
try? context.save()
}
+ await trace("fetch: applied \(incomingRecords.count) record(s) to Core Data")
// Step 4: Route cell changes through the single inbox
if let onRemoteCellChanges, !cellChanges.isEmpty {