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

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 any with unknown/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.shcheck_package()

  • npm pack --dry-run must not contain forbidden files:
    • xcuserdata/, *.xcuserstate, DerivedData/
    • ios/App/, .DS_Store, *.swp, *.swo, *.orig, *.rej
  • package.json.files whitelist must remain authoritative
  • .npmignore is 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.shcheck_core_source() + check_core_artifacts()

  • src/core/ must not import:
    • Node builtins (fs, path, os, child_process, etc.)
    • Platform-specific modules (@capacitor/*, react, capacitor)
  • 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.sh is the only supported CI entrypoint
  • All gates (release, merge, automation) must call ./ci/run.sh
  • npm run build must 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.shcheck_build()

  • package.json.exports["./web"] paths must match actual build artifacts
  • package.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.md or 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 any usages in src/ (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
  • 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 any in src/core/ (except where truly necessary, documented)
  • Public interfaces (src/definitions.ts, src/index.ts) use unknown/generics
  • All changes pass npm run build and npm test
  • No new type errors introduced
  • Existing tests pass unchanged

Exit Criteria:

  • Type safety improved measurably (grep any count 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.md under "Policy & Contracts"
  • Must follow drift guard format (Purpose, Owner, Last Updated, Status)

Acceptance Criteria:

  • docs/SYSTEM_INVARIANTS.md created 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):

  1. 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
  2. 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:

  1. All P2 items completed (P2.6, P2.7, P2.x)
  2. All invariants preserved (verified by CI)
  3. All acceptance criteria met (per item)
  4. Documentation updated (progress docs, index, changelog)
  5. 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: any usage count reduced (target: 50%+ reduction in src/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)

  1. Review this design — Ensure scope and constraints are correct
  2. Approve invariants list — Confirm nothing is missing
  3. Prioritize P2 items — Decide execution order
  4. Begin P2.7 — Document invariants first (recommended)
  5. 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