--- id: PX-PLAN-IRCFFLM3 type: plan title: Test Quality Tooling spec: PX-SPEC-DZLVGRW4 status: draft depends_on: - PX-PLAN-XQFSKHHG --- ## Outcome Coverage, property testing, mutation testing, snapshot discipline, and fuzzing are available as non-gating, author-driven tools with per-extension reporting. Verified current state: `@vitest/coverage-istanbul` installed but no coverage task; no property, mutation, or fuzz tooling. ## Behaviors ```mermaid flowchart TB q1["1. Per-extension coverage report with unimported files"] --> q2["2. Seeded property tests in unit layer"] q2 --> q3["3. Selective mutation runs with cache"] q1 --> q4["4. Snapshot policy enforced"] q2 --> q5["5. Fuzz harness for hostile-input boundaries"] ``` 1. `//:coverage` and `//extensions/:coverage` run the `unit` and `contract` projects with `all: true` scoped to owned production files, reporting line, branch, function per extension; provider chosen after timing V8 vs Istanbul on the full suite and recorded in the task description. 2. Add `fast-check` as devDependency; `test/property.ts` supplies a seeded runner that records seed and counterexample on failure and stores minimal cases under `__tests__/regressions/`. First targets: `the-system` frontmatter and Markdown normalization, `nushell` argument rendering, `web` URL and path safety, `strata` state machine. 3. `//extensions/:mutate ` via Stryker with Vitest runner, incremental cache per extension invalidated by source and test hashes; `//:mutate-all` optional report; never in hooks or CI. 4. Snapshot rules: inline or file snapshots only for normalized rendered output; a lint test rejects snapshots containing absolute paths, timestamps, IDs, or bundle content; updates require an explicit `--update` task. 5. `//extensions/:fuzz ` wraps a coverage-guided runner for parsers exposed to hostile input (`web` fetch parsing, `the-system` document parsing); findings minimized into deterministic regression tests. ## Structure ```mermaid flowchart LR unit["unit project"] --> cov["coverage per extension"] prop["test/property seeded runner"] --> unit prop --> reg["__tests__/regressions"] mut["Stryker per-extension cache"] --> unit fuzz["fuzz runner"] --> reg snap["snapshot lint"] --> unit ``` Touched: `package.json` (fast-check, Stryker, fuzz runner devDependencies), `vitest.config.ts` coverage block, `test/property.ts`, `test/snapshot-lint.test.ts`, `mise.toml` and `extensions/*/mise.toml` (`coverage`, `mutate`, `fuzz`, `snapshot-update`), `stryker.config.*` per extension template. ## Constraints - No percentage gate; coverage guides investigation. - Mutation targets pure unit-testable code only. - Long fuzz campaigns run manually or on a schedule, never in hooks or normal CI. ## Verification - [ ] Coverage report lists unimported owned files and per-extension line, branch, function numbers. - [ ] A failing property test prints a replay seed and yields a stored minimal regression case. - [ ] Repeated mutation run on unchanged code uses the cache; a source change invalidates it. - [ ] Snapshot lint fails on a snapshot containing an absolute path. - [ ] Fuzz run on a target completes and any finding lands as a normal test.