$npx -y skills add ThibautBaissac/rails_ai_agents --skill mutation-testingRun mutant, read mutation reports, fix alive mutations, and verify coverage. Use when running mutation testing, responding to alive mutations, or improving test quality. Triggers: "mutation testing", "mutant", "alive mutation", "mutation coverage". WHEN NOT: Writing tests from sc
| 1 | # Mutation Testing with Mutant |
| 2 | |
| 3 | ## When to Activate |
| 4 | |
| 5 | - The user asks to run mutation testing. |
| 6 | - The user has alive mutations to fix. |
| 7 | - The user asks to verify mutation coverage on a subject. |
| 8 | |
| 9 | ## When Not to Use |
| 10 | |
| 11 | - The task does not involve mutation testing. |
| 12 | |
| 13 | ## Inputs |
| 14 | |
| 15 | - Alive mutation output to act on (paste the `evil:` block). |
| 16 | - Optional: subject expression to scope the run. |
| 17 | |
| 18 | ## Outputs (Fixed Order) |
| 19 | |
| 20 | 1. Mutation results (alive count, coverage percentage). |
| 21 | 2. Clear action for each alive mutation: add test or simplify code. |
| 22 | |
| 23 | --- |
| 24 | |
| 25 | ## Reading Mutation Output |
| 26 | |
| 27 | An alive mutation looks like: |
| 28 | |
| 29 | ```text |
| 30 | evil:YourClass#method:YourClass#method:lib/your_class.rb:42:abc12 |
| 31 | @@ -1,3 +1,3 @@ |
| 32 | def method |
| 33 | - @value >= threshold |
| 34 | + @value > threshold |
| 35 | end |
| 36 | ``` |
| 37 | |
| 38 | - `evil` means no test killed this mutation. |
| 39 | - The diff shows original (`-`) and mutated (`+`) code. |
| 40 | |
| 41 | --- |
| 42 | |
| 43 | ## Reporting Format (BLUF) |
| 44 | |
| 45 | Lead with the verdict — bottom line up front: |
| 46 | |
| 47 | **If unkillable:** |
| 48 | |
| 49 | > **Unkillable.** Both forms are equivalent because \[reason\]. |
| 50 | > Add to ignore list. |
| 51 | |
| 52 | **If killable:** |
| 53 | |
| 54 | > **Killable.** |
| 55 | > |
| 56 | > **Option A — add test:** |
| 57 | > |
| 58 | > ```diff |
| 59 | > (test diff) |
| 60 | > ``` |
| 61 | > |
| 62 | > **Option B — simplify code:** |
| 63 | > |
| 64 | > ```diff |
| 65 | > (source diff) |
| 66 | > ``` |
| 67 | |
| 68 | Always present both options so the user can choose. Include evidence: if |
| 69 | you cannot think of a test that would kill the mutation, say so — that is |
| 70 | valuable signal toward unkillable. |
| 71 | |
| 72 | --- |
| 73 | |
| 74 | ## Usage |
| 75 | |
| 76 | ### 1. Run Mutant |
| 77 | |
| 78 | ```bash |
| 79 | bundle exec mutant run --fail-fast |
| 80 | ``` |
| 81 | |
| 82 | When the subject is known, scope the run to avoid testing unrelated subjects: |
| 83 | |
| 84 | ```bash |
| 85 | bundle exec mutant run --fail-fast 'Entities::CreateService#call' |
| 86 | ``` |
| 87 | |
| 88 | If the command succeeds, coverage is 100% — done. |
| 89 | If it fails, find the `evil:` line in the output — it has the subject |
| 90 | name, file path, and line number. The diff block immediately after shows |
| 91 | the original and mutated code. |
| 92 | |
| 93 | ### 2. Investigate |
| 94 | |
| 95 | Read the source file and existing spec file for the subject. |
| 96 | Ask: **"Is the mutated code acceptable for all valid inputs?"** |
| 97 | |
| 98 | ### 3. Decide and Act |
| 99 | |
| 100 | - **Add a test** when the mutated code is wrong but tests do not prove it. |
| 101 | - **Simplify the code** when the mutated code is correct for all valid inputs. |
| 102 | |
| 103 | Do not change both code and tests in the same commit. If both need |
| 104 | changing, commit the test first, then simplify the code in a second commit. |
| 105 | |
| 106 | ### 4. Re-run and Verify |
| 107 | |
| 108 | Re-run mutant (step 1) until 100%. If the same mutation survives after |
| 109 | 2 attempts, evaluate whether it is unkillable. |
| 110 | |
| 111 | ```bash |
| 112 | bundle exec rspec # full suite must pass |
| 113 | ``` |
| 114 | |
| 115 | ### 5. Commit |
| 116 | |
| 117 | Follow the project's conventional commits format. The commit body must |
| 118 | explain which mutation survived, why the test kills it or why the |
| 119 | simplification is correct. |
| 120 | |
| 121 | --- |
| 122 | |
| 123 | ## Fixing Alive Mutations |
| 124 | |
| 125 | ### When to Add a Test |
| 126 | |
| 127 | Add a test when the mutated code is wrong but the existing tests do not |
| 128 | prove it. The test must pass with the original code and fail with the |
| 129 | mutated code. Common reasons a test is missing: |
| 130 | |
| 131 | - Only one value of a boolean/flag is tested — add the other. |
| 132 | - A collection has one element, so `next` and `break` behave the same — |
| 133 | add a test with multiple elements. |
| 134 | - Two objects return the same value in test data, hiding which one the |
| 135 | code actually uses — add test data where they differ. |
| 136 | - A method has a default parameter, and all tests pass the argument |
| 137 | explicitly — add a test that omits the argument. |
| 138 | |
| 139 | ### When to Simplify Code |
| 140 | |
| 141 | Simplify when the mutated code is correct for all valid inputs. Apply the |
| 142 | mutation's change directly to the source code — do not restructure or |
| 143 | rewrite, just accept the mutated form. |
| 144 | |
| 145 | Mutant encodes the **principle of least power**: use the most constrained |
| 146 | primitive that satisfies the requirement. When Ruby offers multiple methods |
| 147 | that overlap in behavior but differ in power, mutant replaces the more |
| 148 | powerful one with the less powerful one. If tests still pass, you did not |
| 149 | need the extra power — accept the simpler form. |
| 150 | |
| 151 | Before accepting a simplification, verify the mutation preserves behavior |
| 152 | across the method's full input domain and all call sites. |
| 153 | |
| 154 | ### Simplification Trap: Syntax Rewriting |
| 155 | |
| 156 | Do not rewrite code to eliminate a mutation axis without first ensuring the |
| 157 | expression has test coverage. Changing syntax may make the mutation |
| 158 | disappear without proving the code is correct. The correct sequence: |
| 159 | |
| 160 | 1. Add test coverage for the expression. |
| 161 | 2. Apply the simplification mutant suggests. |