Skip to content

date: 2026-06-14 tags: [pest, mutation, covers, testing-gate] status: graduated graduated_to: .claude/rules/testing.md

covers() scopes mutation attribution, not just coverage

Symptom — Sprint B's mutation score came in at 87.75% (below the 90 gate) with ~30 survivors in OccasionTaskBuilder and DesiredOccasionTask, even though the generator test suite exercises those classes thoroughly. The same shape appeared in Sprint A as a coverage shortfall.

Root cause — Pest's covers() narrows both coverage and mutation attribution to the named classes. GenerateOccasionTasksTest drove its scenarios through the builder/DTO but only covers()'d GenerateOccasionTasks, so the kills those tests scored against the builder/DTO weren't credited — the mutants reported as "untested" survivors.

Fix — add the collaborators to the test's covers(...): covers(GenerateOccasionTasks::class, OccasionTaskBuilder::class, DesiredOccasionTask::class, …). Score went 87.75 → 90.24 with no new tests, just correct attribution (commit 0d1aa27).

Guard.claude/rules/testing.md: when a test drives its scenario through a shared collaborator (builder, DTO, Action), name that collaborator in covers() too, or its mutants survive uncounted.