Files
TheLastGarden/.planning/phases/01-foundations-and-doctrine/01-VALIDATION.md
T
josh 39563f6934 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>
2026-05-08 23:09:08 -04:00

137 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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