Files
2026-05-27 23:29:53 +01:00

3.9 KiB

Why

The 2026-04-25 test-suite audit (/mnt/s/web/genesis/docs/superpowers/specs/2026-04-25-test-suite-audit.md §2) identifies mutation testing as a critical missing tier of the genesis test pyramid. The canonical openspec/specs/testing/spec.md enforces 100% Istanbul line/branch/function/statement coverage and a mitata 10% benchmark regression gate, but neither catches a whole class of defects: tests that execute a code path without actually asserting its behaviour. A mutated implementation that still passes the test suite is a silent gap in the contract.

CLAUDE.md (/mnt/s/web/genesis/CLAUDE.md §Critical and §Quality) mandates enterprise-grade quality on every package and explicitly forbids skipping or disabling tests. Foundation packages (crypto-*, error, validation, serialize, datetime, timing, retry, pagination, env, config, mime, templates, i18n, idempotency, slsa, diff) are the substrate for every downstream consumer; a surviving mutant in one of those packages is a latent defect propagated everywhere. Layering a mutation-score gate on top of the existing 100% line-coverage gate closes the assertion-quality hole without diluting either signal.

What Changes

This change adds mutation testing as a quality gate on top of (not in place of) 100% Istanbul line coverage. 100% line coverage remains a precondition; mutation score is an additional, independent gate. Neither substitutes for the other.

New requirements

  • Stryker (@stryker-mutator/core + @stryker-mutator/vitest-runner) configured per-package via stryker.conf.json co-located at the package root, with external deps routed through the catalog (no bare versions per openspec/AGENTS.md §1).
  • Mutation score gate — foundation packages SHALL achieve ≥ 85% mutants killed; all other @suaveplan/* packages SHALL achieve ≥ 70% mutants killed. Surviving mutants MUST be triaged (killed, equivalent-marked with justification, or covered by a follow-up issue) before the change lands.
  • Excluded paths — barrel index.ts, *.schemas.ts, *.bench.ts, __benchmarks__/, and *.stories.tsx are excluded from mutation analysis (no behavioural assertions to mutate).
  • CI integration — nightly per-package mutation runs publish HTML + JSON reports as artefacts; on-PR runs use Stryker's --mutate filter to score only changed files, keeping wall-clock under budget.
  • Reporter contract — surviving mutants are enumerated in a structured PR comment (path, line, mutator, status) so reviewers can act without opening artefact links.
  • Error-code prefix — any custom Stryker mutator or runner adapter Suaveplan ships throws TESTING.MUTATION.* codes via the local TestingError class, matching the existing TESTING.<DOMAIN>.<REASON> convention from openspec/specs/testing/spec.md.
  • Self-coverage — any custom Suaveplan mutator or adapter SHALL itself meet 100% Istanbul coverage; mutation tooling does not exempt itself.

Capabilities

Modified Capabilities

  • testing — adds normative requirements for the mutation-score gate, excluded paths, CI cadence, reporter contract, and TESTING.MUTATION.* error codes. Does not modify or relax the existing 100% line-coverage requirement or the mitata benchmark gate.

Impact

  • Affected code: every @suaveplan/* package gains a stryker.conf.json and a CI hook. No source code changes mandated; surviving mutants drive follow-up fixes per package.
  • Affected catalogs: root package.json gains @stryker-mutator/core and @stryker-mutator/vitest-runner under catalogs.testing.
  • Pre-publish gate: the existing pre-publish gate is unchanged. Mutation score is enforced by a separate bunx turbo test:mutation --filter=@suaveplan/<pkg> step that MUST also pass before publish.
  • Wall-clock budget: PR runs scoped to changed files keep mutation analysis within the existing PR CI envelope; full runs move to nightly to absorb the higher cost.