docs(01): plan phase 1 — 7 plans across 3 waves, verified after 1 revision

Wave 1: Plan 01 (scaffold + test infra)
Wave 2: Plans 02 (eslint firewall), 03 (save layer), 04 (content pipeline),
        05 (asset provenance — autonomous:false human-curate checkpoint),
        06 (doctrine docs)
Wave 3: Plan 07 (CI workflow)

All 16 Phase-1 REQ-IDs covered. Plan-checker found 4 blockers + 6 warnings
on first pass; revision iteration 1 landed all 10 fixes; iteration 2
returned VERIFICATION PASSED. Two orchestrator judgment calls during
revision: (1) implement CORE-04 localStorage fallback in Phase 1 (the
literal requirement and ROADMAP success criterion #2 both call for it),
(2) reclassify STRY-09 as vacuously satisfied in Phase 1.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-08 23:09:08 -04:00
parent 9c9c6eddbc
commit 39563f6934
10 changed files with 3370 additions and 9 deletions
@@ -0,0 +1,136 @@
---
phase: 1
slug: foundations-and-doctrine
status: planned
nyquist_compliant: true
wave_0_complete: pending-execution
created: 2026-05-08
updated: 2026-05-08 (populated by /gsd-plan-phase)
---
# Phase 1 — Validation Strategy
> Per-phase validation contract for feedback sampling during execution.
> Source: `01-RESEARCH.md` § Validation Architecture.
---
## Test Infrastructure
| Property | Value |
|----------|-------|
| **Framework** | Vitest 4.1.5 (verified 2026-05-08) |
| **Config file** | `vitest.config.ts` (Plan 01 Task 2 deliverable; environment: happy-dom) |
| **Quick run command** | `npm test` (alias for `vitest run --passWithNoTests=false`) |
| **Full suite command** | `npm run ci` (lint + test + validate-assets + build) |
| **Estimated runtime** | ~5s quick, ~30s full |
---
## Sampling Rate
- **After every task commit:** Run `npm test`
- **After every plan wave:** Run `npm run ci`
- **Before `/gsd-verify-work`:** `npm run ci` must be green, plus manual smoke that `npm run dev` opens the Phaser scaffold
- **Max feedback latency:** ~5 seconds per commit, ~30 seconds per wave
---
## Per-Task Verification Map
> Populated by the planner during /gsd-plan-phase. Each task maps to a Wave 0 test stub or existing infrastructure.
| Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status |
|---------|------|------|-------------|------------|-----------------|-----------|-------------------|-------------|--------|
| 01-01-T1 | 01 | 1 | CORE-01 | — | Scaffold builds | smoke | `npm run build` | post-execution | ⬜ pending |
| 01-01-T2 | 01 | 1 | (infra) | — | Vitest + Playwright wired | smoke | `npm test && npx playwright --version` | post-execution | ⬜ pending |
| 01-02-T1 | 02 | 2 | CORE-10 | — | ESLint flat config + boundaries plugin in place | static-analysis | `npm run lint` | post-execution | ⬜ pending |
| 01-02-T2 | 02 | 2 | CORE-10 | — | Boundary rule fires on `sim → render` import | unit (lint) | `npx vitest run src/sim/__test_violation__/lint-firewall.test.ts` | post-execution | ⬜ pending |
| 01-03-T1 | 03 | 2 | CORE-06, CORE-07 | T-01-01 | CRC-32 envelope + canonical JSON; v0→v1 synthetic migration | unit | `npx vitest run src/save/checksum.test.ts src/save/envelope.test.ts src/save/migrations.test.ts` | post-execution | ⬜ pending |
| 01-03-T2 | 03 | 2 | CORE-04, CORE-05, CORE-08 | T-01-01 | idb DB + LocalStorageDBAdapter fallback (CORE-04) + last-3 snapshot retention + persist API | unit | `npx vitest run src/save/db.test.ts src/save/snapshots.test.ts src/save/persist.test.ts` | post-execution | ⬜ pending |
| 01-03-T3 | 03 | 2 | CORE-09, CORE-04 | T-01-02 | Base64 codec with 50MB DoS cap + full round-trip | unit + integration | `npx vitest run src/save/round-trip.test.ts && npm run build` | post-execution | ⬜ pending |
| 01-04-T1 | 04 | 2 | PIPE-01, STRY-09 | — | Vite-native loader + Zod schemas + demo fragment | smoke | `npm run build && npm run compile:ink` | post-execution | ⬜ pending |
| 01-04-T2 | 04 | 2 | PIPE-01 | — | Schema violation throws (build fails on bad content) | unit | `npx vitest run src/content/loader.test.ts` | post-execution | ⬜ pending |
| 01-05-T1 | 05 | 2 | PIPE-03, AEST-08, AEST-09 | T-01-06, T-01-07 | Validator script + sidecar schema + refused-sample fixture (test fixture isolated under os.tmpdir()) | integration | `node scripts/validate-assets.mjs && npx vitest run scripts/validate-assets.test.ts` | post-execution | ⬜ pending |
| 01-05-T2 | 05 | 2 | AEST-08, AEST-09 | T-01-06 | 1020 north-star reference images committed with sidecars | manual + smoke | `node scripts/validate-assets.mjs` (count assertion) | post-execution | ⬜ pending (checkpoint) |
| 01-06-T1 | 06 | 2 | PIPE-05, UX-13 | — | anti-FOMO doctrine consolidates 4 source documents (file exists with required H2 sections) | smoke | `test -f .planning/anti-fomo-doctrine.md && grep -q '## Banned Mechanics' .planning/anti-fomo-doctrine.md` | post-execution | ⬜ pending |
| 01-06-T2 | 06 | 2 | PIPE-05, STRY-09 | — | Season 7 end-state doctrine principle-level + doc-lint test | doc-lint | `npx vitest run scripts/doctrine.test.ts` | post-execution | ⬜ pending |
| 01-07-T1 | 07 | 3 | PIPE-06 | T-01-08 | GitHub Actions workflow runs `npm run ci` on push + PR | smoke (CI) | `npm run ci` (locally) + workflow runs on next push | post-execution | ⬜ pending |
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
**Coverage:** All 16 Phase-1 requirement IDs (CORE-01, CORE-04, CORE-05, CORE-06, CORE-07, CORE-08, CORE-09, CORE-10, PIPE-01, PIPE-03, PIPE-05, PIPE-06, AEST-08, AEST-09, STRY-09, UX-13) are covered by at least one task above.
---
## Per-Requirement Behavior Map (from RESEARCH.md)
| Req ID | Behavior Under Test | Test Type | Automated Command | Plan |
|--------|---------------------|-----------|-------------------|------|
| CORE-04 | IndexedDB save round-trips AND localStorage fallback round-trips when IDB rejects (stub-injected) | unit | `npx vitest run src/save/db.test.ts` | 03 |
| CORE-05 | `requestPersistence()` returns `{granted, apiAvailable}` shape and handles missing API | unit | `npx vitest run src/save/persist.test.ts` | 03 |
| CORE-06 | `wrap()` produces valid envelope; `unwrap()` rejects checksum mismatch | unit | `npx vitest run src/save/envelope.test.ts` | 03 |
| CORE-07 | `migrate({garden:[]}, 0)` produces v1 shape; `migrations[1]` invoked exactly once | unit | `npx vitest run src/save/migrations.test.ts` | 03 |
| CORE-08 | After 5 successive `snapshot()` calls, exactly 3 newest entries remain | unit | `npx vitest run src/save/snapshots.test.ts` | 03 |
| CORE-09 | Base64 export → import → migrate → unwrap yields original payload | unit (round-trip) | `npx vitest run src/save/round-trip.test.ts` | 03 |
| CORE-10 | `src/sim/` importing from `src/render/` produces ESLint error | static-analysis | `npx vitest run src/sim/__test_violation__/lint-firewall.test.ts` (programmatic ESLint API) | 02 |
| CORE-01 | Game scaffold `npm run build` produces a valid bundle | smoke | `npm run build` (Phase 2 PIPE-07 adds Playwright) | 01 |
| PIPE-01 | Demo content file with deliberate schema violation fails the build | unit (build-time) | `npx vitest run src/content/loader.test.ts` | 04 |
| PIPE-03 | Asset validator script exits non-zero on a fixture missing provenance (fixture isolated under os.tmpdir()) | integration | `npx vitest run scripts/validate-assets.test.ts` | 05 |
| PIPE-05 | `.planning/anti-fomo-doctrine.md` and `.planning/season-7-end-state.md` exist with required H2 sections | doc lint | `npx vitest run scripts/doctrine.test.ts` | 06 |
| PIPE-06 | All save migration tests run on every CI build | meta | `.github/workflows/ci.yml` runs `npm run ci` | 07 |
| AEST-08 / AEST-09 | All assets in `assets/` (excluding `__samples__/refused/`) have valid provenance sidecars | integration | covered by PIPE-03 test + Plan 05 north-star commit | 05 |
| STRY-09 | Vacuously satisfied: Phase 1 ships no source code containing player-visible strings; first enforcement lands in Phase 2 | n/a (Phase 1 has no code to externalize from yet) | — | 04, 06 |
| UX-13 | Doctrine doc enforced by review per CONTEXT D-07 | manual-only | — | 06 |
> **Note on STRY-09 (BLOCKER 4 fix):** STRY-09 ("All player-visible strings externalized to /content/, never hardcoded in source") is *vacuously satisfied* in Phase 1 — Phase 1 ships scaffolding, doctrine docs, and pure-function libraries (save layer, content loader, asset validator); none of these contain player-visible UI strings. The `/content/` convention is *established* by Plan 04's loader + demo fragment + README, and the `<content/>` directory tree is committed by Plans 01 and 04, but no source code yet exists that *could* hardcode a player-visible string. First enforcement (lint rule on JSX text nodes, or grep guard) lands in Phase 2 when the first UI components are authored. This row previously cited CONTEXT D-07 erroneously (D-07 is about anti-FOMO review enforcement, not about UX-string externalization) — that misattribution is corrected here.
---
## Wave 0 Requirements
Wave 0 (test infrastructure) is split across Plans 01 and the test files of Plans 0206:
- [x] `vitest.config.ts` — minimal happy-dom config (**Plan 01 Task 2**)
- [x] `playwright.config.ts` — installed only, no specs in Phase 1 (**Plan 01 Task 2**)
- [x] `eslint.config.js` — flat config with `eslint-plugin-boundaries` (**Plan 02 Task 1**)
- [x] `src/sim/__test_violation__/violator.ts` — boundary lint fixture (**Plan 02 Task 2**)
- [x] `src/sim/__test_violation__/lint-firewall.test.ts` — boundary rule assertion (**Plan 02 Task 2**)
- [x] `src/save/checksum.test.ts` — checksum determinism (**Plan 03 Task 1**)
- [x] `src/save/envelope.test.ts` — CORE-06 (**Plan 03 Task 1**)
- [x] `src/save/migrations.test.ts` — CORE-07 (**Plan 03 Task 1**)
- [x] `src/save/db.test.ts` — CORE-04 (IDB-primary + LocalStorageDBAdapter fallback paths) (**Plan 03 Task 2**)
- [x] `src/save/snapshots.test.ts` — CORE-08 (**Plan 03 Task 2**)
- [x] `src/save/persist.test.ts` — CORE-05 (**Plan 03 Task 2**)
- [x] `src/save/round-trip.test.ts` — CORE-09 (**Plan 03 Task 3**)
- [x] `src/content/loader.test.ts` — PIPE-01 (**Plan 04 Task 2**)
- [x] `scripts/validate-assets.test.ts` — PIPE-03 (**Plan 05 Task 1**, fixture isolated under os.tmpdir())
- [x] `scripts/doctrine.test.ts` — PIPE-05 (**Plan 06 Task 2**)
- [x] `.github/workflows/ci.yml` — runs `npm run ci` on PR + push (**Plan 07 Task 1**)
- [x] Framework install: `vitest`, `happy-dom`, `fake-indexeddb`, `@playwright/test` (all installed by **Plan 01 Task 1**)
`[x]` indicates the plan ships the file; actual file creation happens during execution.
---
## Manual-Only Verifications
| Behavior | Requirement | Why Manual | Test Instructions |
|----------|-------------|------------|-------------------|
| Game scaffold loads in Chrome/Firefox/Safari/Edge under 5s on 25 Mbps | CORE-01 | Multi-browser load-time + bandwidth simulation belongs in Phase 2 Playwright (PIPE-07); Phase 1 ships the bundle and verifies build succeeds | Run `npm run build && npm run preview`, open in each browser locally, confirm load. Cross-browser perf gate is Phase 2's `gsd-verify-work` deliverable. |
| Anti-FOMO doctrine review-readiness | UX-13 | Doctrine is enforced by human review per CONTEXT D-07; no lint rule | Read `.planning/anti-fomo-doctrine.md` end-to-end; confirm every banned pattern from PROJECT.md / REQUIREMENTS.md / CLAUDE.md / PITFALLS.md #9 is enumerated. |
| Season 7 end-state principle clarity | STRY-09 (related; not the formal target — see note above) | Principle-level doc; enforced by review | Read `.planning/season-7-end-state.md`; confirm it answers (a) what *rest state* means, (b) what the finite Roothold ceiling is tied to, (c) the coda's tonal register. |
| North-star reference set human-curation | AEST-09 | Curation gate is the human reviewer per CONTEXT D-03 | Manually review the 1020 generations under `assets/north-stars/`; confirm provenance sidecars present and visually consistent. (Plan 05 Task 2 is `checkpoint:human-verify`.) |
---
## Validation Sign-Off
- [x] All tasks have `<automated>` verify or Wave 0 dependencies (Plan 05 Task 2 is the sole `checkpoint:human-verify` per CONTEXT D-01 + D-03 — curation gate is human review by design)
- [x] Sampling continuity: no 3 consecutive tasks without automated verify (every plan has at least one automated test except Plan 05 T2 which is the human-curation checkpoint)
- [x] Wave 0 covers all MISSING references — see "Wave 0 Requirements" above
- [x] No watch-mode flags — `npm test` uses `vitest run` (one-shot)
- [x] Feedback latency < 30s — `npm run ci` is ~30s per RESEARCH § Validation Architecture
- [x] `nyquist_compliant: true` set in frontmatter
**Approval:** approved