Commit Graph

3 Commits

Author SHA1 Message Date
fc27eef6eb docs(coverage): sync docs to shipped state + wire sandcastle prompts
Closes the staleness gap after the 10-commit coverage epic shipped.

Doc sync (item 1 from the user's choice):
  - CLAUDE.md Quick Start: adds pnpm coverage:aggregate / coverage:diff
    / mutate to the command listing
  - CLAUDE.md: new "Sibling architecture: coverage (ADR-020)" section
    after the conformance gate table — captures the 4-layer table +
    points at docs/guides/coverage.md + ADR-020 + says agents must run
    coverage:diff before reporting complete
  - AGENTS.md preamble: now lists coverage as a parallel multi-latency
    quality system alongside conformance, with the same gate / latency
    framing
  - PRD frontmatter: status draft -> shipped + shipped date +
    shipping-commits list (all 10 SHAs anchoring the trace)
  - PRD findings table: each row gets a Resolution column citing the
    commit that closed it; conclusion text updated to past tense
  - ADR-020 implementation phasing: rewritten as a status table with
    each step linked to the commit that shipped it + Boot-time
    assertFeatureConformance explicitly marked Deferred with rationale
  - docs/guides/coverage.md: removed "Boot wiring lands in the next
    story" line; replaced with the deferral rationale + clarified
    that two readers (vitest, coverage:diff) consume the manifest

Sandcastle prompts (item 2 from the user's choice):
  - .sandcastle/implementer.prompt.md: new "Coverage gates" section
    after the conformance-gates list, requiring `pnpm test --coverage`,
    `pnpm coverage:aggregate`, and `pnpm coverage:diff` to all pass
    before reporting `complete`. Machine-readable JSON shape of
    coverage:diff documented (status / uncovered[] / kind enum), with
    explicit instructions on how to interpret each kind. Allowlist
    expansion requires justification + test.
  - .sandcastle/reviewer.prompt.md: AC coverage relabeled to "AC
    coverage (acceptance criteria, not test coverage)" to disambiguate;
    new check #7 "Coverage gates (ADR-020)" requiring CI's
    Coverage — diff (L1) step green + per-layer thresholds met +
    no silent allowlist expansion + manifest band drift detection.

Effect: future agent runs through sandcastle now treat coverage as a
first-class blocking gate, parallel to conformance. PRs no longer
discover coverage failures only via CI; the implementer is required
to check before reporting done, and the reviewer is required to
verify.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 16:47:16 +02:00
6428f10b82 feat(coverage): pnpm mutate (Stryker) + L3 implementation
Lands L3 of the agent-first coverage architecture (ADR-020) — the
mutation-testing layer. Stryker on entities + use-cases (the pure
business-logic surface) catches the third dimension of test quality:
tests that exist + execute the code but assert nothing.

Deps (root devDependencies):
  - @stryker-mutator/core ^8.7.0
  - @stryker-mutator/vitest-runner ^8.7.0

Shared base: packages/core-testing/stryker.base.json
  - testRunner: vitest (uses each feature's vitest.config.ts)
  - mutate: src/entities/** + src/application/use-cases/** (excludes
    tests, factories, contracts)
  - thresholds: high 90 / low 80 / break 80
  - reporters: progress + html + json (reports/mutation/{index.html,
    mutation.json})
  - incremental mode enabled, concurrency 4, timeout 10s
  - exposed via @repo/core-testing/stryker.base.json subpath export

Per-feature config: packages/auth/stryker.config.json
  - 4-line file that extends the shared base
  - Proof-of-concept; other features get a config when L0 unification
    closes their existing test gaps

Driver: scripts/coverage/mutate.mjs (zero-dep Node ESM)
  - discoverStrykerConfigs: walks packages/* and apps/* for
    stryker.config.json
  - Supports --filter <name>, --since <ref> (incremental), --json
  - Runs Stryker per-feature via node_modules/.bin/stryker run
  - Surfaces per-package pass/fail summary; exits 1 on any failure
  - Tests: scripts/coverage/mutate.test.mjs (3 tests, all green)

CI: .github/workflows/mutation-nightly.yml
  - Cron at 02:30 UTC + workflow_dispatch with filter input
  - Uploads reports/mutation/** as artifact (30-day retention)
  - On failure, opens a tracking issue labelled mutation-testing
  - permissions: contents: read, issues: write
  - 60-min timeout (Stryker is slow by design)

Generator: turbo gen feature now scaffolds stryker.config.json from
turbo/generators/templates/feature/stryker.config.json.hbs — new
features ship mutation-ready out of the box.

Guide: docs/guides/coverage.md L3 section fleshed out with run
syntax, config shape, base config inventory, CI behavior, and a
"what you're looking for" primer on mutation scores.

Lockfile churn: pnpm regenerated the lockfile for the new deps;
~5K-line net reduction is collateral (pnpm version drift) but
mechanical.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 16:31:30 +02:00
f4254aae48 docs(coverage): cookbook guide + feature generator scaffolds coverage:
Adds the day-to-day cookbook for the 4-layer coverage architecture
(ADR-020) and threads it into the discovery path:

docs/guides/coverage.md (new):
  - 4 layers at a glance + when each fires
  - Single-source-of-truth pattern (feature.manifest.ts coverage:
    section) and the three readers (vitest, assertFeatureConformance,
    coverage:diff)
  - Daily workflow: pnpm test --coverage -> aggregate -> diff
  - How to read a failure (stderr human + stdout JSON examples)
  - How to fix uncovered slices (TDD walkthrough)
  - The full allowlist (test files, configs, docs, scripts, dev
    tooling, per-feature excludes)
  - Adjusting bands (manifest-first, when to override vitest)
  - CI behavior (two workflows: validate + coverage-snapshot)
  - Reading the committed trend via git log -- coverage/summary.json
  - Mutation testing primer (L3, opt-in, scope, lands in next story)
  - Troubleshooting

CLAUDE.md Read First gets the new guide pinned between audit and
template-tiers, with the L0-L3 layer summary inline so agents see the
shape at a glance.

Feature generator updates (turbo/generators/templates/feature/):
  - feature.manifest.ts.hbs: new `coverage:` block at <gen:coverage>
    anchor scaffolded with the documented defaults + mutationTargets
  - vitest.config.ts.hbs: now uses vitestThresholdsFromBands(
    DEFAULT_COVERAGE_BANDS) instead of the duplicated literal — new
    features ship conformance-compliant by default

Next features generated via `pnpm turbo gen feature` are coverage-
aware from the first commit: bands declared in manifest, vitest
config consumes the helper, no duplication to drift.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 14:15:01 +02:00