This document describes the comprehensive formal verification framework now implemented for the Block It Out shadow sync algorithm.
Location: /TLAPlus/
NoDuplicates ==
\A destID \in DestCalendarIDs :
\A s1, s2 \in shadowsPerDest[destID] :
s1.sourceID = s2.sourceID => s1 = s2
StoreConsistency ==
\A destID \in DestCalendarIDs :
\A shadow \in shadowsPerDest[destID] :
HasShadowInDest(shadow.sourceID, destID)
NoFalseOrphans ==
\A destID \in DestCalendarIDs :
\A s \in orphans :
s.sourceID \notin currentSources \/
~HasShadowInDest(s.sourceID, destID)
ShadowSyncPhaseB_Correct.cfg - Tests fixed implementation (should PASS)ShadowSyncPhaseB_Buggy.cfg - Tests buggy implementation (should FAIL)Location: /BlockItOut/Services/ShadowLifecycleState.swift
enum ShadowLifecycleState {
case none
case created(shadowID: String, timestamp: Date)
case synced(shadowID: String, inputHash: Int)
case stale(shadowID: String, oldHash: Int, newHash: Int)
case orphaned(shadowID: String, reason: OrphanReason)
case deleted(timestamp: Date)
func canTransition(to newState: ShadowLifecycleState) -> Bool
}
Valid Transitions:
none → created: First sync creates shadowcreated → synced: Store record savedsynced → synced: No change (idempotent)synced → stale: Source inputs changedstale → synced: Shadow updatedsynced → orphaned: Source removedorphaned → deleted: Cleanup runsLocation: /BlockItOut/Services/SyncInvariants.swift
Implements TLA+ invariants as runtime checks:
static func verifyNoDuplicates(
sourceID: String,
ruleID: UUID,
destCalendar: EKCalendar,
eventStore: EventStoreProtocol,
logManager: LogManager
) throws
Verifies at most one shadow per (sourceID, destID) pair.
static func verifyStoreConsistency(
shadow: EKEvent,
ruleID: UUID,
destID: String,
logManager: LogManager
) throws
Verifies every shadow has corresponding store record with destination.
static func verifyNoFalseOrphans(
orphanedShadows: [(shadow: EKEvent, sourceID: String)],
currentSources: [EKEvent],
ruleID: UUID,
destID: String,
logManager: LogManager
) throws
Verifies orphaned shadows truly have no source OR no store entry for destination.
static func verifyPerDestinationFiltering(
storeRecords: [String: SourceEventRecord],
filteredRecords: [String: SourceEventRecord],
destID: String,
logManager: LogManager
) throws
Verifies store records are correctly filtered by destination before orphan detection.
Location: /BlockItOut/SyncEngine/SyncService.swift
Invariant checks integrated at critical points:
NoDuplicates after each insertionPerDestinationFilteringLocation: /BlockItOutTests/SyncPropertyTests.swift
Tests verify invariants hold across different scenarios:
func testSyncIdempotence()
Running sync twice with no changes produces zero insertions/deletions.
func testNoDuplicatesInvariant()
func testMultipleSyncsNeverCreateDuplicates()
Each source has at most one shadow per destination, always.
func testOrphanDetectionCorrectness()
When source deleted, shadow detected as orphan and removed.
func testStoreConsistency()
Every shadow has corresponding store record with destination state.
func testPerDestinationOrphanDetection()
Store records filtered correctly per destination (the bug we fixed).
cd TLAPlus
# Verify correct implementation (should PASS all invariants)
java -jar tla2tools.jar -config ShadowSyncPhaseB_Correct.cfg ShadowSyncPhaseB.tla
# Verify buggy implementation FAILS (should find invariant violation)
java -jar tla2tools.jar -config ShadowSyncPhaseB_Buggy.cfg ShadowSyncPhaseB.tla
# Run all property-based tests
xcodebuild test -project "Block It Out.xcodeproj" \
-scheme "Block It Out" \
-destination 'platform=iOS Simulator,name=iPhone 15' \
-only-testing:BlockItOutTests/SyncPropertyTests
Invariant checks are enabled in DEBUG builds:
#if DEBUG
do {
try SyncInvariants.verifyNoDuplicates(...)
} catch {
// Logs violation but doesn't crash
logManager.addAuditLog("INVARIANT VIOLATION: \(error)")
}
#endif
Production builds skip checks for performance.
| TLA+ Concept | Swift Implementation |
|---|---|
ShadowLifecycleState |
ShadowLifecycleState.swift enum |
NoDuplicates |
SyncInvariants.verifyNoDuplicates() |
StoreConsistency |
SyncInvariants.verifyStoreConsistency() |
NoFalseOrphans |
SyncInvariants.verifyNoFalseOrphans() |
PerDestinationFiltering |
recordsForThisDest filter in SyncService.swift |
OrphanDetectionPhaseB |
deleteOrphans() with filtered store records |
HasShadowInDest(sid, destID) |
record.shadows[destID] != nil |
currentSources |
allSources from EventKit query |
shadowsPerDest[destID] |
existing shadows fetched per destination |
✓ TLA+ specs prove algorithm correctness under all scenarios ✓ Model checker verifies invariants hold across state space ✓ Specs document WHY design decisions were made
✓ State machine prevents invalid transitions ✓ Invariant checks catch violations immediately in debug ✓ Clear error messages identify violation type and location
✓ Property tests run on every build ✓ Removing protections causes test failures ✓ New bugs caught before production
✓ TLA+ models document design formally ✓ Code comments reference TLA+ specs ✓ New developers can understand correctness properties
/TLAPlus//BlockItOut/Services/ShadowLifecycleState.swift/BlockItOut/Services/SyncInvariants.swift/BlockItOutTests/SyncPropertyTests.swift/BlockItOut/SyncEngine/SyncService.swiftStatus: ✅ COMPREHENSIVE FORMAL VERIFICATION FRAMEWORK COMPLETE
All components implemented, tested, and integrated.