Files
mokosh/.planning/phases/01-stabilize-video-pipeline/01-VALIDATION.md

7.6 KiB

phase, slug, status, nyquist_compliant, wave_0_complete, created
phase slug status nyquist_compliant wave_0_complete created
1 stabilize-video-pipeline draft false false 2026-05-15

Phase 1 — Validation Strategy

Per-phase validation contract for feedback sampling during execution. Derived from 01-RESEARCH.md §"Validation Architecture".


Test Infrastructure

Property Value
Framework Vitest (Node mode) — recommended, NOT currently installed. Vite already in devDependencies, so Vitest is a zero-config-mismatch add.
Config file NONE — Wave 0 creates vitest.config.ts.
Quick run command npx vitest run --reporter=dot
Full suite command npx vitest run && npx tsc --noEmit (+ grep guards)
Estimated runtime ~10 s quick, ~30 s full

Why not Jest: Vite is already the build tool; Vitest is the zero-config-mismatch choice. No transformer dance for TS.

Why not Playwright: MediaRecorder + getDisplayMedia ARE driveable in Chromium via Playwright with permissions auto-granted, but the acceptance gate (ffprobe on a real exported file) requires actually running the extension. Manual smoke + ffprobe is sufficient for Phase 1. Playwright-driven smoke tests are Phase 4/5 territory.


Sampling Rate

  • After every task commit: Run npx vitest run --reporter=dot && npx tsc --noEmit (≤ 10 s).
  • After every plan wave: Run npx vitest run && npx tsc --noEmit && npm run build (≤ 30 s).
  • Before /gsd-verify-work: Full suite + ffprobe gate (D-12) must be green.
  • Max feedback latency: 30 s.

Per-Task Verification Map

The exact task IDs are owned by PLAN.md. This map enumerates the behaviors and tests; the planner wires task IDs in once plans are written. Rows are sorted by acceptance-criterion order from CONTEXT.md.

Behavior Plan area Wave Requirement Threat Ref Secure Behavior Test Type Automated Command File Exists Status
Ring buffer adds chunk; first chunk gets isHeader: true (D-10) offscreen/recorder 1 REQ-video-ring-buffer N/A unit npx vitest run tests/offscreen/ring-buffer.test.ts -t "first chunk is header" Wave 0 pending
Ring buffer trims chunks older than 30 s; keeps header (D-11) offscreen/recorder 1 REQ-video-ring-buffer N/A unit npx vitest run tests/offscreen/ring-buffer.test.ts -t "trim 30s" Wave 0 pending
Codec strict-mode throws when vp9 unsupported (D-20) offscreen/recorder 1 REQ-video-ring-buffer T-1-01 (codec downgrade) Fail loud; no silent fallback to vp8/h264 unit npx vitest run tests/offscreen/codec-check.test.ts Wave 0 pending
OFFSCREEN_READY handshake sent before SW emits START_RECORDING (Pattern 4) offscreen + SW 1 REQ-video-ring-buffer N/A unit npx vitest run tests/offscreen/handshake.test.ts Wave 0 pending
Port reconnect on onDisconnect within 1 s (Pattern 5) offscreen ↔ SW 1 REQ-video-ring-buffer N/A unit npx vitest run tests/offscreen/port.test.ts -t "reconnects" Wave 0 pending
chrome.alarms keepalive deleted (D-18) SW 1 REQ-video-ring-buffer N/A grep ! grep -RIn "chrome.alarms" src/background/ NO CODE NEEDED pending
IndexedDB SW path deleted (D-19) SW 1 REQ-video-ring-buffer N/A grep ! grep -RIn "VideoRecorderDB|openIndexedDB" src/ NO CODE NEEDED pending
vite.config.ts:11-184 inline plugin deleted (D-08) build 1 REQ-video-ring-buffer N/A grep ! grep -RIn "copy-offscreen|chromeMediaSource" vite.config.ts NO CODE NEEDED pending
last_30sec.webm plays ffprobe-clean (D-12 acceptance gate) manual smoke last REQ-video-ring-buffer N/A integration ffprobe -v error -f matroska -i sample/last_30sec.webm; test $? -eq 0 Sample produced during manual smoke; in CI a known-good fixture verifies the gate itself works pending
Zero as any / @ts-ignore regressions in Phase 1 surface static each REQ-video-ring-buffer N/A static npx tsc --noEmit && ! grep -RIn "as any|@ts-ignore" src/offscreen/ src/background/index.ts EXISTS (build script) pending
Manifest permission swap (D-A6 / D-05) manifest doc-cascade REQ-video-ring-buffer T-1-02 (excess permissions) Drop tabCapture; add desktopCapture exactly grep ! grep "tabCapture" manifest.json && grep "desktopCapture" manifest.json NO CODE NEEDED pending
Build produces a loadable extension build last REQ-video-ring-buffer N/A manual npm run build && ls dist/manifest.json dist/src/offscreen/index.html dist/assets/*.js NO TEST FILE; shell check pending

Status: pending · green · red · ⚠️ flaky


Wave 0 Requirements

  • Install Vitest: npm install -D vitest @vitest/ui (verify current major via npm view vitest version at install time).
  • vitest.config.ts — pull in path aliases from tsconfig.json (if any); enable Node test env by default.
  • tests/offscreen/ directory with at minimum:
    • tests/offscreen/ring-buffer.test.ts — D-10, D-11 (header pinning + 30 s trim).
    • tests/offscreen/codec-check.test.ts — D-20 strict-mode error path.
    • tests/offscreen/handshake.test.ts — Pattern 4 OFFSCREEN_READY.
    • tests/offscreen/port.test.ts — Pattern 5 reconnect.
  • tests/fixtures/ — keep a known-good WebM for ffprobe sanity (committed once; used by CI to verify the ffprobe gate runs at all).
  • npm test script in package.json: "test": "vitest run".
  • chrome runtime stub for Vitest — light hand-rolled mock or vitest-chrome dependency (decide at install time).

Manual-Only Verifications

Behavior Requirement Why Manual Test Instructions
getDisplayMedia picker dialog appears and grants stream on operator click REQ-video-ring-buffer Browser picker UX cannot be driven in Vitest; auto-grant via Playwright is Phase 4 territory Load dist/ unpacked; click extension; observe picker; pick "Entire screen"; confirm "Sharing" indicator appears; SW console shows [Offscreen] Stream created.
last_30sec.webm actually plays in a browser (SPEC §10 #7) REQ-video-ring-buffer Decoder behavior depends on real Chromium media stack Open the exported last_30sec.webm in Chrome; confirm video plays from start to end; no playback freezes.
SW idle survival (D-16, D-17) REQ-video-ring-buffer Requires real MV3 SW lifecycle DevTools → Extensions → Service Worker → "Force stop"; wait 60 s; click extension save; confirm exported archive contains video chunks from before "Force stop".
"Stop sharing" recovery (D-03) REQ-video-ring-buffer Requires real browser stream lifecycle Click "Stop sharing" in Chrome's screen-share banner; click extension save; expect graceful "no recording — re-prompt" UX (Phase 3 owns the popup state; Phase 1 owns the offscreen-side error signal).

Validation Sign-Off

  • All tasks have <automated> verify or Wave 0 dependencies (planner enforces)
  • Sampling continuity: no 3 consecutive tasks without automated verify
  • Wave 0 covers all MISSING references (Vitest install + 4 test files + fixtures)
  • No watch-mode flags (Vitest run mode only)
  • Feedback latency < 30 s per wave
  • nyquist_compliant: true set in frontmatter (planner flips this once PLAN.md tasks reference these test commands)

Approval: pending