Files
daily-notification-plugin/docs/progress/P2.1-SCHEMA-VERSIONING-DRAFT.md
Matthew Raymer 6b5b886951 feat(ios): complete P2.1 schema versioning and P2.2 combined edge case tests
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.
2025-12-22 12:59:40 +00:00

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: NSPersistentStore metadata key "schema_version"
  • Version Check: Performed during PersistenceController initialization
  • Logging: Version logged on store load; mismatches logged as warnings

Migration Contract

When to Bump Schema Version

The schema version should be incremented when:

  1. Entity changes:

    • Adding new entities
    • Removing entities (rare, requires data migration)
    • Renaming entities (requires explicit migration)
  2. 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)
  3. 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

  1. Update CoreData model in Xcode (add/remove/modify entities/attributes)
  2. Increment schema version constant in PersistenceController
  3. Update metadata on next store load
  4. Document migration in changelog
  5. 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:

  1. Unit tests: Verify version metadata is set correctly
  2. Integration tests: Verify version check runs on store load
  3. 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

  • Android Schema Versioning: android/src/main/java/com/timesafari/dailynotification/DatabaseSchema.kt (Room version = 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