skill: /mutation-check — verify the tests for a change actually fail without it
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 0
- Forks
- 1
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 7
Description
Problem
standards/CLAUDE.md already says "Tests that pass regardless of whether the feature works are worthless". Nothing operationalizes it, so it stays an aspiration.
On TimZander/AudioClassifier #195 I hand-rolled the same loop three times — back up the file, apply a perl -0pi -e mutation, run the suite, count failures, restore, verify — and got it wrong twice:
- A stale pattern silently applied no mutation. The regex still targeted a code shape that had been edited away, so
sedmatched nothing, the suite passed, and my script reportedSURVIVED — GAP. A false gap, indistinguishable from real uncovered behaviour. - A restore wiped real work. The script restored from a backup a subagent had captured earlier, silently reverting ~15 lines.
git statuslooked clean afterwards.
When it worked, it was decisive and repeatedly changed decisions:
- 7 of 8 mutants surviving condemned a suite that looked like coverage — including deletion of the very line the PR added.
- 13 of 13 caught validated the rewrite.
- A survivor exposed a test that claimed to pin a guard it could never reach (
ok: falseshort-circuited before the check). - It disproved my own "13 of 13" claim on a later pass by testing a mutant I hadn't thought of.
Why a skill rather than documentation
The loop is mechanical, error-prone, and stateful in a dangerous way — it edits tracked source and must restore it. Those properties argue for scripted tooling over a prose rule:
- Restore must be guaranteed, via
trap ... EXIT, not left to a happy path. My hand-rolled version lost work exactly here. - Mutation patterns must be re-derived from the current diff. Hand-written patterns go stale the moment the code is edited — which is guaranteed, since you edit code in response to what mutation testing tells you.
- "Not applied" must be distinguishable from "survived." Conflating them produces false gaps that send you chasing coverage you already have. This is the single highest-value thing a script gets right and a human gets wrong.
A prose rule can say "revert the fix and check the test fails". It cannot prevent any of the three failures above.
Proposed behaviour
/mutation-check [path...] [--base <branch>]
- Refuse to run on a dirty working tree — the whole thing hinges on a trustworthy restore.
- Derive candidate mutations from the branch diff vs base: revert changed arguments to their base value, invert conditionals, delete added calls, empty added collections, drop added guards.
- For each mutant: apply → assert it actually changed the file → run the relevant suite → record caught (with which tests) / survived / not-applied.
- Restore unconditionally via
trap ... EXIT; verify againstgit diffand fail loudly if the tree does not match. - Report a table. Call out survivors as uncovered behaviour, list not-applied separately as a tool defect, not a finding, and state plainly that the mutant set bounds the claim.
Acceptance criteria
- Refuses to run on a dirty working tree
- Derives mutants from the diff vs base rather than hardcoded patterns
- Guarantees restore on success, failure, and interrupt (
trap ... EXIT), then verifies it againstgit diff - Distinguishes "survived" from "mutation not applied" and reports them separately
- Reports which tests caught each mutant
- Output states that results are bounded by the mutant set generated
Notes
Pairs with the standards rule proposed in the test-validity issue (assert the outcome, not the call; mutation-verify bug-fix tests) — that issue defines the practice, this makes it cheap enough to actually do.
Prior art worth checking before building: Stryker (JS/.NET), mutmut/cosmic-ray (Python). A thin wrapper over an existing mutator may beat a bespoke implementation — but the diff-scoped mutant generation and the not-applied detection are the parts that mattered here, and general-purpose mutators are usually whole-file and slow.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read standards/CLAUDE.md and inspect the proposed /mutation-check entry point, then compare Stryker, mutmut, and cosmic-ray before choosing an approach. Done means the command meets every acceptance criterion: safe dirty-tree handling and restoration, diff-scoped mutations, separate caught/survived/not-applied results, caught-test reporting, and bounded-result wording.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- testing, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100