crossmate

A collaborative crossword app for iOS
Log | Files | Refs | LICENSE

commit 6b410f3c6d198034088b7091d8ce14cc436765da
parent ccb56ce371b93f166195f3395b64f9937cca4d66
Author: Michael Camilleri <[email protected]>
Date:   Tue,  4 Aug 2026 00:28:41 +0900

Fix record of successful deletion

Diffstat:
MCrossmate/Sync/CloudDiagnostics.swift | 68++++++--------------------------------------------------------------
1 file changed, 6 insertions(+), 62 deletions(-)

diff --git a/Crossmate/Sync/CloudDiagnostics.swift b/Crossmate/Sync/CloudDiagnostics.swift @@ -242,9 +242,11 @@ extension SyncEngine { return environment } - /// Deletes every record this account holds in the abandoned v3 container: - /// all of its custom zones, then anything left in the default zone, which - /// cannot itself be removed. + /// Deletes every custom zone this account holds in the abandoned v3 + /// container. The private default zone is left alone: the sync engine only + /// ever wrote to custom zones, and CloudKit rejects change enumeration + /// there outright ('AppDefaultZone does not support getChanges call'), so + /// there is nothing to sweep and no cheap way to look. /// /// Abandoning a container generation does not reclaim its records — they /// consume the account's iCloud quota indefinitely — and v3 was abandoned @@ -314,8 +316,7 @@ extension SyncEngine { ) } - let defaultZoneCleared = await deleteDefaultZoneRecords(in: database, progress: progress) - let swept = failed == 0 && defaultZoneCleared + let swept = failed == 0 await progress( "legacy delete complete: zonesDeleted=\(deleted) zonesFailed=\(failed) " + "swept=\(swept)" @@ -323,63 +324,6 @@ extension SyncEngine { return swept } - /// The default zone cannot be deleted, so anything sitting in it has to be - /// removed record by record. The audit skips this zone, so its contents are - /// unmeasured rather than known-empty. - private func deleteDefaultZoneRecords( - in database: CKDatabase, - progress: @MainActor @Sendable (String) -> Void - ) async -> Bool { - var recordIDs: [CKRecord.ID] = [] - var token: CKServerChangeToken? - var moreComing = true - do { - while moreComing { - let page = try await database.recordZoneChanges( - inZoneWith: CKRecordZone.default().zoneID, - since: token - ) - token = page.changeToken - moreComing = page.moreComing - for result in page.modificationResultsByID.values { - if let record = try? result.get().record { - recordIDs.append(record.recordID) - } - } - } - } catch { - await progress("legacy delete: couldn't read the default zone — \(describe(error))") - return false - } - - guard !recordIDs.isEmpty else { - await progress("legacy delete: default zone holds no records") - return true - } - - await progress("legacy delete: \(recordIDs.count) default-zone record(s) to remove") - var deleted = 0 - for start in stride(from: 0, to: recordIDs.count, by: 100) { - let batch = Array(recordIDs[start..<min(start + 100, recordIDs.count)]) - do { - // The default zone does not support atomic changes. - let results = try await database.modifyRecords( - saving: [], - deleting: batch, - atomically: false - ) - deleted += results.deleteResults.values.filter { - if case .success = $0 { return true } - return false - }.count - } catch { - await progress("legacy delete: default-zone batch FAILED — \(describe(error))") - } - } - await progress("legacy delete: \(deleted) of \(recordIDs.count) default-zone record(s) deleted") - return deleted == recordIDs.count - } - private func auditPrivateCloudStorage( label: String, container: CKContainer,