Luigit
repositories / pi-ext

pi-ext

bugabingas pi extensions

owned by admin

.system/plans/PX-PLAN-IRCFFLM3-test-quality-tooling/index.md

Raw
Rendered preview

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

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/<name>: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/<name>:mutate <file|range> 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/<name>:fuzz <target> 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

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.
---
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/<name>: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/<name>:mutate <file|range>` 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/<name>:fuzz <target>` 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.