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

3.8 KiB

0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in each)
  • 0.2 If any worktrees exist under .claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against.
  • 0.3 Confirm the package set in MANIFEST.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Catalog and tooling setup

  • 1.1 Add @stryker-mutator/core and @stryker-mutator/vitest-runner to root package.json catalogs.testing (no bare versions per openspec/AGENTS.md §1)
  • 1.2 Run bun install; confirm lockfile updates cleanly
  • 1.3 Add test:mutation task to root turbo.json with dependsOn: ["test:coverage"] so 100% line coverage is a precondition
  • 1.4 Document the foundation-package set in openspec/specs/testing/spec.md once this change is folded; the same enumeration appears in the spec delta in this folder

2. Per-package Stryker configuration

  • 2.1 Author a reusable stryker.base.conf.cjs template under tooling/stryker/ (path TBD) that every package extends — testRunner: vitest, reporters: html, json, clear-text, mutate exclusions per design D4
  • 2.2 For every @suaveplan/* package, create stryker.conf.json at the package root extending the base template, declaring mutate: ["src/**/*.ts"] and the package-specific exclusions
  • 2.3 For every package, add a test:mutation script in package.json invoking Stryker against the package's vitest.config.ts

3. Threshold enforcement

  • 3.1 Encode the foundation-package list in the base config via a tiered thresholds block (≥ 85% for foundation, ≥ 70% otherwise)
  • 3.2 Wire a CI step that fails the build on mutationScore below the package's tier threshold
  • 3.3 Wire the PR-scoped mutation run via --mutate filtered to files changed in the PR (resolved through git diff --name-only origin/main...HEAD)

4. Reporter and artefacts

  • 4.1 Configure HTML + JSON reporters; archive both as CI artefacts per nightly run
  • 4.2 Author a scripts/report-mutants.ts that reads the JSON report and emits a Markdown table (path, line, mutator, status) for the PR comment
  • 4.3 Wire the PR-comment step to post the table via gh pr comment (or workflow equivalent)

5. Custom-mutator hook (extension point)

  • 5.1 If a custom Stryker mutator or runner adapter is required (e.g. once a bun-test runner exists), package it as @suaveplan/testing-mutation under packages/testing/
  • 5.2 Errors thrown by the adapter MUST extend TestingError with codes prefixed TESTING.MUTATION.* (e.g. TESTING.MUTATION.RUNNER_FAILED, TESTING.MUTATION.CONFIG_INVALID)
  • 5.3 The adapter package itself MUST meet 100% Istanbul coverage and pass the same mutation-score tier it advertises

6. Spec delta and validation

  • 6.1 openspec validate enterprise-testing-mutation --type change passes
  • 6.2 Fold specs/testing/spec.md ADDED Requirements into openspec/specs/testing/spec.md
  • 6.3 Move this change folder to openspec/archive/<yyyy-mm-dd>-enterprise-testing-mutation/

7. Rollout

  • 7.1 Run baseline mutation analysis across every existing genesis package; record current scores
  • 7.2 For each package below its tier threshold, file a triage issue listing surviving mutants by mutator class
  • 7.3 Land assertion-strengthening fixes per package until every existing package meets its tier threshold
  • 7.4 Flip the CI gate from advisory to enforcing once every package is green