diff --git a/.planning/phases/09-faster-write-back/09-VALIDATION.md b/.planning/phases/09-faster-write-back/09-VALIDATION.md new file mode 100644 index 0000000..dc65a96 --- /dev/null +++ b/.planning/phases/09-faster-write-back/09-VALIDATION.md @@ -0,0 +1,84 @@ +--- +phase: 9 +slug: faster-write-back +status: draft +nyquist_compliant: false +wave_0_complete: false +created: 2026-06-12 +--- + +# Phase 9 — Validation Strategy + +> Per-phase validation contract for feedback sampling during execution. + +--- + +## Test Infrastructure + +| Property | Value | +|----------|-------| +| **Framework** | Vitest (existing) | +| **Config file** | `apps/api/vitest.config.ts` | +| **Quick run command** | `cd apps/api && npx vitest run tests/broker/outboxWorker.test.ts` | +| **Full suite command** | `cd apps/api && npm test` (→ `vitest run`) | +| **Estimated runtime** | ~5–20 seconds (existing broker suite + new signal cases; no live Fastmail) | + +--- + +## Sampling Rate + +- **After every task commit:** Run quick command (`vitest run tests/broker/outboxWorker.test.ts`) +- **After every plan wave:** Run full suite (`npm test`) + `npm run typecheck` (`tsc --noEmit` — esbuild/Vitest does not catch type errors; see [[vitest-passes-tsc-fails]]) +- **Before `/gsd-verify-work`:** Full suite + typecheck must be green +- **Max feedback latency:** ~20 seconds + +--- + +## Per-Task Verification Map + +> Task IDs are assigned by the planner; rows below map each Success Criterion + CAL-15 to its +> concrete automated assertion (Nyquist coverage). The signal-path tests need no fake timers — +> a `setImmediate`/microtask flush is sufficient to observe the synchronous emit → drain wiring +> (per RESEARCH.md). The 15s `setInterval` fallback is exercised with Vitest fake timers as today. + +| Item | Wave | Requirement | Threat Ref | Expected Behavior | Test Type | Automated Command | File Exists | Status | +|------|------|-------------|------------|-------------------|-----------|-------------------|-------------|--------| +| SC-1 signal → prompt drain | 1 | CAL-15 | — | Enqueuing a pending row publishes the trigger and `runOutboxDrain` runs without waiting for the 15s interval (CalDAV dispatch stubbed) | unit/integration | `vitest run tests/broker/outboxWorker.test.ts` | ✅ extends existing | ⬜ pending | +| SC-2 fire-and-forget 202 | 1 | CAL-15 | — | Publishing the signal is non-blocking; route enqueue path makes no inline CalDAV call (signal is fire-and-forget) | unit | `vitest run tests/broker/outboxWorker.test.ts` | ✅ extends existing | ⬜ pending | +| SC-3 create-before-delete under move | 1 | CAL-15 | — | Edit-as-move publishes once after the transaction commits; CREATE row precedes DELETE; no signal fires between the two inserts | unit | `vitest run tests/broker/outboxWorker.test.ts` | ✅ extends existing | ⬜ pending | +| SC-4 exactly-once overlap | 1 | CAL-15 | — | Concurrent `scheduleOutboxDrain` calls + 15s fallback overlap produce no duplicate CalDAV PUT for the same uid (`isDraining` guard + `pending AND next_attempt_at <= NOW()` selection unchanged) | unit | `vitest run tests/broker/outboxWorker.test.ts` | ✅ extends existing | ⬜ pending | +| SC-5 / D-05 trailing re-drain | 1 | CAL-15 | — | A signal arriving during an in-flight drain sets `drainRequested` and triggers exactly one follow-up drain after the current one finishes; the 15s `setInterval` fallback still runs and recovers missed rows | unit | `vitest run tests/broker/outboxWorker.test.ts` | ✅ extends existing | ⬜ pending | + +*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky* + +--- + +## Wave 0 Requirements + +- Existing infrastructure covers all phase requirements. `apps/api/tests/broker/outboxWorker.test.ts` + already provides the DB / write / sync mock scaffold (`isDraining`, drain, edit-as-move ordering). + New cases are added to that file (or a sibling `tests/broker/outboxTrigger.test.ts`); no new + framework, config, or fixtures are installed. + +--- + +## Manual-Only Verifications + +| Behavior | Requirement | Why Manual | Test Instructions | +|----------|-------------|------------|-------------------| +| — | — | — | — | + +*All phase behaviors have automated verification. No operator-stopwatch checkpoint (D-10): the dev-bypass user (id 1) has no CalDAV credential/calendars, so a live event-create 422s in the dev stack ([[dev-data-user1-no-calendars]]); the automated wiring test is the durable, CI-guarded evidence.* + +--- + +## Validation Sign-Off + +- [ ] All tasks have `` verify or Wave 0 dependencies +- [ ] Sampling continuity: no 3 consecutive tasks without automated verify +- [ ] Wave 0 covers all MISSING references +- [ ] No watch-mode flags (`vitest run`, not `vitest`) +- [ ] Feedback latency < 20s +- [ ] `nyquist_compliant: true` set in frontmatter + +**Approval:** pending