---
phase: 2
slug: client-engine-documentation
status: draft
nyquist_compliant: false
wave_0_complete: false
created: 2026-05-02
---

# Phase 2 — Validation Strategy

> Per-phase validation contract for feedback sampling during execution.
> Detailed validation architecture (assertions, fixtures, exit codes, MATRIX/ADR linters) lives in `02-RESEARCH.md` § "Validation Architecture (Nyquist)". This file is the executor-facing checklist.

---

## Test Infrastructure

| Property | Value |
|----------|-------|
| **Framework** | vitest 4.1.5 (mirror `tools/extract-gmd/`) |
| **Config file** | `tools/asset-catalog/vitest.config.ts` (created Wave 0) |
| **Quick run command** | `pnpm --filter ./tools/asset-catalog test` |
| **Full suite command** | `pnpm --filter ./tools/asset-catalog test && pnpm --filter ./tools/asset-catalog typecheck && node tools/asset-catalog/scripts/lint-docs.mjs` |
| **Estimated runtime** | ~30 seconds (catalog tests + typecheck + doc linter) |

Doc-side validation (markdown linters) runs as plain Node scripts in `tools/asset-catalog/scripts/`:
- `lint-docs.mjs` — verifies subsystem MD presence, autogen-block round-trip, README jump-table coverage
- `lint-matrix.mjs` — parses `docs/extracted-engine/MATRIX.md` weights table; asserts schema + numeric coherence
- `lint-adr.mjs` — verifies `docs/adr/0001-client-engine.md` cites at least N MATRIX rows

---

## Sampling Rate

- **After every task commit:** Run quick command (catalog vitest only) — < 10 s
- **After every plan wave:** Run full suite (vitest + typecheck + doc linters)
- **Before `/gsd-verify-work`:** Full suite must be green AND determinism check (run catalog twice, diff outputs, must be empty)
- **Max feedback latency:** 30 seconds

---

## Per-Task Verification Map

To be filled during plan generation. Pattern (every task slot below MUST resolve to either an `<automated>` block or a Wave 0 file dependency):

| Task ID | Plan | Wave | Requirement | Test Type | Automated Command | File Exists | Status |
|---------|------|------|-------------|-----------|-------------------|-------------|--------|
| 2-01-01 | 01-tool-scaffold | 0 | CDOC-02 | structural | `pnpm --filter ./tools/asset-catalog typecheck` | ❌ W0 | ⬜ pending |
| 2-01-02 | 01-tool-scaffold | 0 | CDOC-02 | unit | `pnpm --filter ./tools/asset-catalog test src/load.test.ts` | ❌ W0 | ⬜ pending |
| 2-01-03 | 01-tool-scaffold | 0 | CDOC-02 | unit (fixture) | `pnpm --filter ./tools/asset-catalog test src/crossref.fixture.test.ts` | ❌ W0 | ⬜ pending |
| 2-02-* | 02-d08-resolution | 0 | CDOC-01 | structural | `test ! -s extracted/client-5-8/UNKNOWN-ACTIONS.md` (file empty or absent after re-extract) | ✅ | ⬜ pending |
| 2-03-* | 03-aggregator-derived | 1 | CDOC-02 | unit | `pnpm --filter ./tools/asset-catalog test src/derive.test.ts` | ❌ W0 | ⬜ pending |
| 2-04-* | 04-crossref-emit | 1 | CDOC-02 | integration | `pnpm --filter ./tools/asset-catalog test src/emit.test.ts` + determinism diff | ❌ W0 | ⬜ pending |
| 2-05-* | 05-subsystem-mds | 2 | CDOC-01 | doc-lint | `node tools/asset-catalog/scripts/lint-docs.mjs` | ❌ W0 | ⬜ pending |
| 2-06-* | 06-matrix | 3 | CDOC-03 | doc-lint | `node tools/asset-catalog/scripts/lint-matrix.mjs` | ❌ W0 | ⬜ pending |
| 2-07-* | 07-adr | 3 | CDOC-04 | doc-lint | `node tools/asset-catalog/scripts/lint-adr.mjs` | ❌ W0 | ⬜ pending |

*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*

Planner is responsible for splitting `2-XX-*` rows into individual task IDs and pinning each to a concrete `<automated>` invocation per `02-RESEARCH.md` § "Validation Architecture > Per-Subsystem Test Map".

---

## Wave 0 Requirements

- [ ] `tools/asset-catalog/package.json` — pin TS 5.6.3 / tsx 4.21.0 / vitest 4.1.5 (mirror Phase 1)
- [ ] `tools/asset-catalog/tsconfig.json` — strict mode, target ES2022
- [ ] `tools/asset-catalog/vitest.config.ts` — `maxWorkers: 1` (mirror Phase 1 determinism rule)
- [ ] `tools/asset-catalog/src/types.ts` — re-export from `tools/extract-gmd/src/types.ts`
- [ ] `tools/asset-catalog/test/fixtures/mini-extract/` — synthetic 4-sprite / 2-script / 1-room fixture for cross-ref tests including the `Hexport*` substring-collision case (RESEARCH §Pitfall 1)
- [ ] `tools/asset-catalog/scripts/lint-docs.mjs` — autogen-block round-trip linter
- [ ] `tools/asset-catalog/scripts/lint-matrix.mjs` — MATRIX schema linter (3 engine columns: Phaser 3.90, Phaser 4.1, PixiJS 8.18)
- [ ] `tools/asset-catalog/scripts/lint-adr.mjs` — ADR rationale-coverage linter
- [ ] `tools/extract-gmd/data/action-ids.json` — extend with action 523 + 525 (LateralGM "Set font" / "Set font (combined)")
- [ ] Re-run `tools/extract-gmd` so `extracted/client-5-8/UNKNOWN-ACTIONS.md` resolves to empty (D-08 path (a))

---

## Manual-Only Verifications

| Behavior | Requirement | Why Manual | Test Instructions |
|----------|-------------|------------|-------------------|
| Subsystem MD prose quality | CDOC-01 | Hand-judged interpretation per D-10 — no machine can score "is this a good narrative" | Reviewer reads every subsystem MD end-to-end; confirms each cites at least one extracted script and links to `decomp/wiki/` |
| MATRIX scoring fairness | CDOC-03 | Per-row Phaser-vs-Pixi-vs-Phaser-4 scoring is judgment, not lint | Reviewer spot-checks 5 random rows against Phaser/Pixi docs cited in source column |
| ADR rationale soundness | CDOC-04 | "Decision tied to matrix" is satisfied structurally by lint-adr; reasoning quality is human | Reviewer confirms ADR Decision section follows logically from highest-weighted MATRIX rows |
| `mvp: yes` tag accuracy | CDOC-01 + Phase 6 | Mapping a feature to MVP requires reading FEATURES.md context | Reviewer audits 100% of `mvp: yes` tags vs `.planning/research/FEATURES.md` §"MVP-Critical (Stage 6 gate)" |
| Hard-knockout call (D-13) | CDOC-04 | Engineering judgment whether a Phaser limitation is "invasive" | Reviewer reads MATRIX rows where Phaser score < PixiJS score and confirms no overlooked knockouts |

---

## 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 (vitest config, fixtures, doc linters, action-ids extension)
- [ ] No watch-mode flags
- [ ] Feedback latency < 30s
- [ ] Determinism check wired (run catalog twice → byte-identical)
- [ ] `nyquist_compliant: true` set in frontmatter

**Approval:** pending
