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

443 lines
14 KiB
Markdown

# 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.sh``check_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.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`)
- `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.sh``check_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:**
- [x] Zero `any` in `src/core/` (except where truly necessary, documented)
- [x] Public interfaces (`src/definitions.ts`, `src/index.ts`) use `unknown`/generics
- [x] All changes pass `npm run build` and `npm test`
- [x] No new type errors introduced
- [x] Existing tests pass unchanged
**Exit Criteria:**
- [x] Type safety improved measurably (grep `any` count reduced to zero except documented exception)
- [x] No runtime behavior changes
- [x] All CI checks pass
- [x] 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