Files
daily-notification-plugin/docs/progress/P2.1-IMPLEMENTATION-PLAN.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

7.6 KiB

P2.1: Schema Versioning Strategy - Implementation Plan

Purpose: Step-by-step implementation plan for P2.1 schema versioning
Status: Ready for execution
Date: 2025-12-22
Estimated Effort: 4-6 hours


Overview

Add explicit schema versioning to iOS CoreData implementation to achieve parity with Android's Room database versioning. This is a documentation-first, minimal-code approach that provides observability without interfering with CoreData's automatic migration.


Implementation Steps

Step 1: Add Schema Version Constant (5 min)

File: ios/Plugin/DailyNotificationModel.swift

Location: Add near top of PersistenceController class

Code:

class PersistenceController {
    // MARK: - Schema Versioning
    
    /// Current schema version (incremented when schema changes)
    private static let SCHEMA_VERSION = 1
    
    // ... existing code ...
}

Verification:

  • Constant added
  • Compiles without errors

Step 2: Add Version Check Method (15 min)

File: ios/Plugin/DailyNotificationModel.swift

Location: Add as private method in PersistenceController class

Code:

    /**
     * Check and log schema version
     * 
     * Schema version is a logical contract, not a forced migration trigger.
     * CoreData auto-migration remains authoritative; version mismatches are
     * logged, not blocked.
     */
    private func checkSchemaVersion() {
        guard let store = container?.persistentStoreCoordinator.persistentStores.first else {
            return
        }
        
        let currentVersion = store.metadata["schema_version"] as? Int ?? 1
        let expectedVersion = PersistenceController.SCHEMA_VERSION
        
        if currentVersion != expectedVersion {
            print("DNP-PLUGIN: Schema version mismatch - current: \(currentVersion), expected: \(expectedVersion)")
            print("DNP-PLUGIN: CoreData auto-migration will handle schema changes")
            
            // Update metadata for future reference (does not trigger migration)
            var metadata = store.metadata
            metadata["schema_version"] = expectedVersion
            // Note: Metadata persists on next store save
        } else {
            print("DNP-PLUGIN: Schema version verified: \(currentVersion)")
        }
    }

Verification:

  • Method added
  • Compiles without errors
  • Follows existing code style

Step 3: Call Version Check on Initialization (5 min)

File: ios/Plugin/DailyNotificationModel.swift

Location: In init(inMemory:) method, after container is successfully loaded

Code:

                // Configure view context
                if let context = tempContainer?.viewContext {
                    context.automaticallyMergesChangesFromParent = true
                    context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
                }
                self.container = tempContainer
                
                // Check schema version (after container is initialized)
                checkSchemaVersion()
                
                // Verify all entities are available (after container is initialized)
                if let context = tempContainer?.viewContext {
                    verifyEntities(in: context)
                }

Verification:

  • Version check called after container initialization
  • Compiles without errors
  • Version logged on app launch

Step 4: Set Initial Version Metadata (10 min)

File: ios/Plugin/DailyNotificationModel.swift

Location: In init(inMemory:) method, when creating new store

Code:

            // Configure persistent store options
            let description = tempContainer?.persistentStoreDescriptions.first
            description?.shouldMigrateStoreAutomatically = true
            description?.shouldInferMappingModelAutomatically = true
            
            // Set initial schema version metadata (for new stores)
            if !inMemory {
                var metadata = description?.metadata ?? [:]
                if metadata["schema_version"] == nil {
                    metadata["schema_version"] = PersistenceController.SCHEMA_VERSION
                    description?.metadata = metadata
                }
            }

Verification:

  • Initial version metadata set for new stores
  • Compiles without errors
  • Version metadata persists across app restarts

Step 5: Add Documentation to README (30 min)

File: ios/Plugin/README.md

Location: Add new section after "Implementation Details" section

Content: Use the draft from docs/progress/P2.1-SCHEMA-VERSIONING-DRAFT.md

Steps:

  1. Copy the "Schema Versioning Strategy" section from the draft
  2. Paste into ios/Plugin/README.md after "Implementation Details"
  3. Update "Last Updated" date in README header
  4. Verify markdown formatting

Verification:

  • Documentation added
  • Markdown renders correctly
  • All links/references are valid
  • "Last Updated" date updated

Step 6: Update Parity Matrix (5 min)

File: docs/progress/04-PARITY-MATRIX.md

Location: Update "Storage & Persistence" section

Change:

| Schema versioning | ✅ Room migrations | ✅ Explicit | iOS has explicit version tracking in CoreData metadata |

Verification:

  • Parity matrix updated
  • Status changed from "⚠️ Partial" to " Explicit"
  • Notes section updated

Step 7: Update Progress Docs (10 min)

Files:

  • docs/progress/00-STATUS.md
  • docs/progress/01-CHANGELOG-WORK.md
  • docs/progress/03-TEST-RUNS.md

Updates:

  1. Mark P2.1 as complete in status
  2. Add changelog entry
  3. Add test run entry (manual verification)

Verification:

  • All progress docs updated
  • Dates are correct
  • Status reflects completion

Step 8: Run CI and Verify (10 min)

Command:

./ci/run.sh

Verification:

  • CI passes
  • No new errors introduced
  • Version logging appears in console output (manual check)

Testing Checklist

Manual Testing

  • New Store: Create new CoreData store, verify version metadata is set
  • Existing Store: Load existing store, verify version check runs
  • Version Logging: Verify version logged on app launch
  • Metadata Persistence: Verify version metadata persists across app restarts

Code Review

  • Code follows existing style
  • Comments are clear and accurate
  • No breaking changes introduced
  • CoreData auto-migration still works

Acceptance Criteria Checklist

  • iOS schema versioning strategy documented (with explicit "logical contract" clarification)
  • Version tracking implemented in CoreData model (metadata)
  • Migration contract defined (when to bump versions)
  • Version check utility added (logs version on init, does not block)
  • Parity matrix updated (schema versioning: Explicit)
  • All CI checks pass
  • Progress docs updated

Rollback Plan

If issues arise:

  1. Revert code changes: Remove version check method and calls
  2. Revert documentation: Remove schema versioning section from README
  3. Revert parity matrix: Change back to "⚠️ Partial"
  4. Update progress docs: Mark P2.1 as incomplete

Baseline tag available: v1.0.11-p0-p1.4-p1.5-p2.6-p2.7-complete


Next Steps After P2.1

  1. Checkpoint: Run ./ci/run.sh, update progress docs
  2. Proceed to P2.2: Combined edge case tests
  3. Optional: Create baseline tag v1.0.11-p2.1-complete if desired

Last Updated: 2025-12-22
Status: Ready for execution