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 viastryker.conf.jsonco-located at the package root, with external deps routed through the catalog (no bare versions peropenspec/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.tsxare 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
--mutatefilter 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 localTestingErrorclass, matching the existingTESTING.<DOMAIN>.<REASON>convention fromopenspec/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, andTESTING.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 astryker.conf.jsonand a CI hook. No source code changes mandated; surviving mutants drive follow-up fixes per package. - Affected catalogs: root
package.jsongains@stryker-mutator/coreand@stryker-mutator/vitest-runnerundercatalogs.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.