---
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 `<automated>` 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
