P2.1: iOS Schema Versioning Strategy
- Added SCHEMA_VERSION constant and checkSchemaVersion() method in PersistenceController
- Version stored in NSPersistentStore metadata (observability contract, not migration gate)
- CoreData auto-migration remains authoritative; version mismatches logged, not blocked
- Documentation added to ios/Plugin/README.md with migration contract
P2.2: Combined Edge Case Tests
- Added 3 resilience test scenarios to DailyNotificationRecoveryTests.swift:
- test_combined_dst_boundary_duplicate_delivery_cold_start()
- test_combined_rollover_duplicate_delivery_cold_start()
- test_combined_schema_version_cold_start_recovery()
- All tests labeled with @resilience @combined-scenarios comments
- Tests verify idempotency and correctness under combined stressors
P2.3: Android Combined Tests Design
- Created P2.3-DESIGN.md with scope, invariants, and acceptance criteria
- Created P2.3-IMPLEMENTATION-CHECKLIST.md with step-by-step execution plan
- Design ready for implementation to achieve parity with iOS P2.2
Documentation Updates
- Fixed parity matrix: iOS invalid data handling now correctly shows "✅ Recovery tested" with test references
- Updated progress docs (00-STATUS.md, 01-CHANGELOG-WORK.md, 03-TEST-RUNS.md, 04-PARITY-MATRIX.md)
- Updated P2-DESIGN.md to reflect P2.3 scope (Android combined tests)
- Updated SYSTEM_INVARIANTS.md baseline tag references
Baseline Tag
- Created and pushed v1.0.11-p2-complete tag
- Tag represents P2.x completion (schema versioning + combined resilience tests)
All invariants preserved. CI passes. Tests runnable via xcodebuild on macOS.
5.2 KiB
P2.1: Schema Versioning Strategy - Documentation Draft
Purpose: Draft documentation for iOS schema versioning strategy (ready to integrate into ios/Plugin/README.md)
Status: Draft for review
Date: 2025-12-22
Section to Add to ios/Plugin/README.md
Schema Versioning Strategy
Current Schema Version: 1 (initial schema)
The iOS implementation uses explicit schema versioning to achieve parity with Android's Room database versioning approach. This provides observability and migration tracking without interfering with CoreData's automatic migration capabilities.
Versioning Approach
CoreData Auto-Migration Remains Authoritative
The schema version is a logical contract, not a forced migration trigger. CoreData auto-migration (shouldMigrateStoreAutomatically = true) remains the authoritative mechanism for schema changes. Version mismatches are logged, not blocked.
Version Tracking
Schema version is stored in CoreData persistent store metadata using NSPersistentStore metadata dictionary. This approach:
- ✅ Non-intrusive (does not require schema changes)
- ✅ Observable (version can be read at any time)
- ✅ Compatible with CoreData auto-migration
- ✅ Matches Android's explicit versioning pattern
Current Implementation
- Schema Version:
1(initial schema, established 2025-09-22) - Version Storage:
NSPersistentStoremetadata key"schema_version" - Version Check: Performed during
PersistenceControllerinitialization - Logging: Version logged on store load; mismatches logged as warnings
Migration Contract
When to Bump Schema Version
The schema version should be incremented when:
-
Entity changes:
- Adding new entities
- Removing entities (rare, requires data migration)
- Renaming entities (requires explicit migration)
-
Attribute changes:
- Adding new required attributes (requires default values or migration)
- Removing attributes (requires data cleanup)
- Changing attribute types (requires type conversion)
- Renaming attributes (requires explicit migration)
-
Relationship changes:
- Adding/removing relationships
- Changing relationship cardinality
- Renaming relationships
When NOT to Bump
- Adding optional attributes (CoreData handles automatically)
- Adding optional relationships (CoreData handles automatically)
- Changing default values (no schema change required)
- Adding indexes (metadata change, not schema change)
Version Bump Process
- Update CoreData model in Xcode (add/remove/modify entities/attributes)
- Increment schema version constant in
PersistenceController - Update metadata on next store load
- Document migration in changelog
- Update parity matrix if versioning strategy changes
Android Parity
Android: Room database with explicit version = 2 and Migration objects
iOS: CoreData with explicit schema version 1 in metadata + auto-migration
Both platforms now have:
- ✅ Explicit version tracking
- ✅ Migration documentation
- ✅ Version observability
- ✅ Migration contract defined
Parity Status: ✅ Explicit versioning (P2.1 complete)
Implementation Notes
Version Check Utility
A simple version check is performed during PersistenceController initialization:
// In PersistenceController.init()
private func checkSchemaVersion() {
guard let store = container?.persistentStoreCoordinator.persistentStores.first else {
return
}
let currentVersion = store.metadata["schema_version"] as? Int ?? 1
let expectedVersion = SCHEMA_VERSION
if currentVersion != expectedVersion {
print("DNP-PLUGIN: Schema version mismatch - current: \(currentVersion), expected: \(expectedVersion)")
// Log warning, but do not block (CoreData auto-migration handles actual migration)
} else {
print("DNP-PLUGIN: Schema version verified: \(currentVersion)")
}
// Update metadata if needed
if currentVersion != expectedVersion {
var metadata = store.metadata
metadata["schema_version"] = expectedVersion
// Note: Metadata update happens on next store save
}
}
Constants
// In PersistenceController
private static let SCHEMA_VERSION = 1 // Current schema version
Testing
Version handling is verified through:
- Unit tests: Verify version metadata is set correctly
- Integration tests: Verify version check runs on store load
- Migration tests: Verify version tracking survives migrations
Test Coverage:
- ✅ Version metadata is set on initial store creation
- ✅ Version check runs during initialization
- ✅ Version mismatches are logged (not blocked)
- ✅ Version metadata persists across app restarts
Related Documentation
- Android Schema Versioning:
android/src/main/java/com/timesafari/dailynotification/DatabaseSchema.kt(Roomversion = 2) - CoreData Model:
ios/Plugin/DailyNotificationModel.xcdatamodeld - PersistenceController:
ios/Plugin/DailyNotificationModel.swift - Parity Matrix:
docs/progress/04-PARITY-MATRIX.md
Last Updated: 2025-12-22
Status: Draft for integration