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.
14 KiB
P2 Design: Parity & Resilience Polish
Purpose: Defines scope, boundaries, and acceptance criteria for P2 work before implementation begins.
Owner: Development Team
Last Updated: 2025-12-22
Status: design-only (no implementation)
Baseline: v1.0.11-p0-p1.4-complete
Purpose
This document defines the scope, boundaries, and acceptance criteria for P2 work before any implementation begins. It ensures P2:
- Does not violate established invariants
- Has clear "done" criteria
- Can be executed incrementally
- Maintains the stability achieved in P0/P1.4/P1.5
P2 Scope Definition
What P2 Includes
P2.6 — Type Safety Cleanup
- Replace TypeScript
anywithunknown/generics where appropriate - Improve type safety without changing runtime behavior
- Maintain backward compatibility
P2.7 — System Invariants Documentation
- Document all enforced invariants
- Explain "why" behind policy-as-code
- Create onboarding reference for contributors
P2.x — Parity & Resilience Polish
- P2.1: Schema versioning strategy (iOS explicit versioning)
- P2.2: Combined edge case tests (iOS: DST + duplicate delivery + cold start)
- P2.3: Android combined edge case tests (achieve parity with iOS P2.2)
What P2 Excludes
- No new features — P2 is polish, not expansion
- No architectural changes — Core structure remains unchanged
- No breaking API changes — Backward compatibility required
- No new platforms — Focus on existing iOS/Android/Web
- No new dependencies — Minimize external additions
Invariants That Must Not Be Violated
1. Packaging Invariants (P0)
Enforced by: verify.sh → check_package()
npm pack --dry-runmust not contain forbidden files:xcuserdata/,*.xcuserstate,DerivedData/ios/App/,.DS_Store,*.swp,*.swo,*.orig,*.rej
package.json.fileswhitelist must remain authoritative.npmignoreis secondary (belt-and-suspenders only)
P2 Constraint: Any P2 changes must not introduce new forbidden file patterns or break packaging checks.
2. Core Module Purity (P1.4)
Enforced by: verify.sh → check_core_source() + check_core_artifacts()
src/core/must not import:- Node builtins (
fs,path,os,child_process, etc.) - Platform-specific modules (
@capacitor/*,react,capacitor)
- Node builtins (
package.json.exports['./core']must exist and point to valid artifacts- Core types must remain platform-agnostic
P2 Constraint: P2.6 type safety work must not introduce platform dependencies into core.
3. CI Authority (P0)
Enforced by: ci/README.md (policy-as-code contract)
./ci/run.shis the only supported CI entrypoint- All gates (release, merge, automation) must call
./ci/run.sh npm run buildmust not be called directly in gates
P2 Constraint: P2 work must not bypass CI or create alternative entrypoints.
4. Export Correctness (P0)
Enforced by: verify.sh → check_build()
package.json.exports["./web"]paths must match actual build artifactspackage.json.exports["./core"]paths must match actual build artifacts- All exported paths must exist after build
P2 Constraint: P2.6 type changes must not break export paths or artifact generation.
5. Documentation Structure (P1.5)
Enforced by: docs/00-INDEX.md (index-first rule)
- New docs must be linked from
docs/00-INDEX.mdor placed in_archive//_reference/ - Progress docs are authoritative (no drift)
- Archive structure standardized (
docs/_archive/)
P2 Constraint: P2.7 SYSTEM_INVARIANTS.md must be added to index and follow drift guard format.
6. Baseline Tag Integrity
Baseline: v1.0.11-p0-p1.4-complete
- This tag represents a known-good architectural baseline
- All invariants enforced in tooling
- Documentation structure established
P2 Constraint: P2 work must not invalidate the baseline or require rollback to it.
P2 Work Items (Detailed)
P2.6: Type Safety Cleanup
Goal: Replace any with unknown/generics where appropriate, improving type safety without changing runtime behavior.
Scope:
- Audit all
anyusages insrc/(excluding test files initially) - Categorize by risk:
- Low risk: Type guards with
unknown, generic constraints - Medium risk: API boundaries, error handling
- High risk: Core module types, public interfaces
- Low risk: Type guards with
- Prioritize: Core module → Public interfaces → Internal code
Constraints:
- Must not break existing TypeScript compilation
- Must not change runtime behavior
- Must maintain backward compatibility
- Must pass all existing tests
Acceptance Criteria:
- Zero
anyinsrc/core/(except where truly necessary, documented) - Public interfaces (
src/definitions.ts,src/index.ts) useunknown/generics - All changes pass
npm run buildandnpm test - No new type errors introduced
- Existing tests pass unchanged
Exit Criteria:
- Type safety improved measurably (grep
anycount reduced to zero except documented exception) - No runtime behavior changes
- All CI checks pass
- Documentation updated (changelog, status, test runs)
Status: ✅ Complete (2025-12-22)
P2.7: System Invariants Documentation
Goal: Create a single authoritative document that names, explains, and references all enforced invariants.
Scope:
- Document all invariants listed in "Invariants That Must Not Be Violated" above
- For each invariant:
- What: Clear statement of the invariant
- Why: Rationale (why it exists, what it prevents)
- How: How it's enforced (tooling, process, documentation)
- Where: References to enforcing code/docs
- Include onboarding guidance for new contributors
Constraints:
- Must reference existing policy-as-code (not duplicate it)
- Must be added to
docs/00-INDEX.mdunder "Policy & Contracts" - Must follow drift guard format (Purpose, Owner, Last Updated, Status)
Acceptance Criteria:
docs/SYSTEM_INVARIANTS.mdcreated with all invariants documented- Each invariant has: What, Why, How, Where
- Document added to
docs/00-INDEX.md - Drift guard header present
- References to enforcing code are accurate and up-to-date
Exit Criteria:
- Single source of truth for all invariants
- New contributors can understand "what not to break"
- Document is discoverable via index
P2.x: Parity & Resilience Polish
Goal: Address remaining parity gaps and add resilience tests for edge cases.
P2.1: Schema Versioning Strategy
Current State:
- Android: Room migrations (explicit versioning)
- iOS: CoreData auto-migration (implicit, may need explicit strategy)
Scope:
- Define explicit schema versioning strategy for iOS
- Document migration contract (what changes require version bumps)
- Add version tracking to CoreData model (metadata or attribute)
- Ensure Android and iOS versioning strategies are equivalent in practice
- Clarification: Schema version is a logical contract, not a forced migration trigger. CoreData auto-migration remains authoritative; version mismatches are logged, not blocked.
Constraints:
- Must not break existing data
- Must support forward compatibility
- Must be testable
- Must not interfere with CoreData auto-migration
Acceptance Criteria:
- iOS schema versioning strategy documented (with explicit "logical contract" clarification)
- Version tracking implemented in CoreData model (metadata or attribute)
- Migration contract defined (when to bump versions)
- Version check utility added (logs version on init, does not block)
- Tests verify version handling (if version tracking implemented)
- Parity matrix updated (schema versioning: ✅ Explicit)
P2.2: Combined Edge Case Tests
Current State:
- Individual edge cases tested (DST, duplicate delivery, cold start)
- Combined scenarios not explicitly tested
Scope:
- Create test scenarios that combine multiple edge cases:
- DST boundary + duplicate delivery + cold start
- Rollover + migration + recovery
- Network failure + rollover + cold start
- Ensure idempotency and correctness in combined scenarios
Constraints:
- Must not duplicate existing test coverage unnecessarily
- Must be runnable in CI (or clearly marked as manual)
- Must be deterministic
Acceptance Criteria:
- At least 3 combined edge case test scenarios
- Tests verify idempotency in combined scenarios
- Tests pass in CI or are clearly documented as manual
- Test results logged in
docs/progress/03-TEST-RUNS.md
P2.3: Android Combined Edge Case Tests
Current State:
- iOS: ✅ Automated combined edge case tests (P2.2 complete)
- Android: ⚠️ Manual emulator scripts only, no automated combined scenarios
Scope:
- Enable Android test infrastructure (currently disabled in
build.gradle) - Create test helpers (in-memory Room database, test data injection)
- Add automated combined edge case tests mirroring iOS P2.2:
- DST boundary + duplicate delivery + cold start
- Rollover + duplicate delivery + cold start
- Schema version + cold start recovery (optional)
- Use CI-compatible testing framework (JUnit + Robolectric or pure unit tests)
Constraints:
- Must be CI-compatible (JVM-compatible, no emulator required)
- Must use modern AndroidX testing framework (not deprecated APIs)
- Tests only, no production code changes
- Must not break existing functionality
Acceptance Criteria:
- Android test infrastructure enabled and CI-compatible
- Test helpers created (database factory, data injection)
- At least 2 combined test scenarios implemented (3 if time permits)
- Tests verify idempotency in combined scenarios
- Tests pass in CI (or clearly documented as manual)
- Parity matrix updated with direct test references
- Test results logged in
docs/progress/03-TEST-RUNS.md
See: docs/progress/P2.3-DESIGN.md for detailed design and execution plan.
P2 Execution Strategy
Phase Ordering
Recommended sequence (P2.6/P2.7 already complete):
-
P2.1 First (Doc-first approach)
- Write documentation first
- Then add minimal code (logging/metadata)
- Update parity matrix immediately after
- Checkpoint: Run
./ci/run.sh, update progress docs, only then proceed
-
P2.2 Second (Tests)
- Start with 2 scenarios
- Add 3rd only if time/energy allows
- Label tests explicitly as resilience/combined-scenarios
- Checkpoint: Run
./ci/run.sh, update progress docs
Previous phases (complete):
- P2.7 — Document invariants before making changes ✅
- P2.6 — Type safety cleanup ✅
Incremental Approach
- Each P2 item can be completed independently
- No dependencies between P2.6, P2.7, and P2.x
- Each item has its own acceptance criteria
- Can pause/resume at any item boundary
Testing Strategy
- P2.6: Existing tests must pass unchanged
- P2.7: Documentation review (no code changes)
- P2.x: New tests required, existing tests must pass
P2 "Done" Criteria
Overall P2 Completion
P2 is complete when:
- All P2 items completed (P2.6, P2.7, P2.x)
- All invariants preserved (verified by CI)
- All acceptance criteria met (per item)
- Documentation updated (progress docs, index, changelog)
- Baseline tag created (if desired:
v1.0.11-p2-complete)
Individual Item Completion
Each P2 item is complete when:
- Acceptance criteria met
- CI passes (
./ci/run.sh) - No invariant violations
- Documentation updated (if applicable)
- Progress docs updated
Risk Mitigation
Risk: Breaking Existing Functionality
Mitigation:
- All changes must pass existing tests
- Incremental approach (one file/feature at a time)
- CI gates prevent regressions
Risk: Violating Invariants
Mitigation:
- P2.7 documents invariants first
- CI enforces invariants automatically
- Design review before implementation
Risk: Scope Creep
Mitigation:
- Clear "what P2 excludes" section
- Acceptance criteria defined upfront
- Can pause/resume at item boundaries
Risk: Documentation Drift
Mitigation:
- P2.7 creates invariant documentation
- Progress docs updated per item
- Index updated per P1.5 rules
Success Metrics
Quantitative
- P2.6:
anyusage count reduced (target: 50%+ reduction insrc/core/and public interfaces) - P2.7: All invariants documented (target: 100% coverage)
- P2.x: Combined edge case tests added (target: 3+ scenarios)
Qualitative
- Type safety: Code is more maintainable, fewer runtime type errors possible
- Documentation: New contributors understand invariants quickly
- Resilience: Edge cases are better understood and tested
Dependencies
External Dependencies
- None — P2 is self-contained polish work
Internal Dependencies
- P2.7 → P2.6/P2.x: Invariant documentation helps validate other work
- P2.6 → P2.x: Type improvements may help P2.x implementation
Blocking Dependencies
- None — P2 can start immediately after P1.5
Timeline Estimate
P2.7: 2-4 hours (documentation only)
P2.6: 8-16 hours (incremental type cleanup)
P2.x: 16-32 hours (varies by item complexity)
Total: 26-52 hours (can be spread over multiple sessions)
Note: These are estimates. Actual time depends on codebase complexity and test coverage.
Next Steps (After Design Approval)
- Review this design — Ensure scope and constraints are correct
- Approve invariants list — Confirm nothing is missing
- Prioritize P2 items — Decide execution order
- Begin P2.7 — Document invariants first (recommended)
- Execute incrementally — One item at a time, pause/resume as needed
Last Updated: 2025-12-22
Status: Design-Only (No Implementation)
Next Action: Review and approve design before proceeding