mutineer · diff

git:20261025.ba9e0ef to git:20261026.80198df

3 added, 3 removed. Audit A to A.

---
name: mutineer
description: Mutation testing for Ruby (Prism + stdlib, zero deps). Mutates source one change at a time, runs the suite against each mutant, and reports the mutants tests fail to catch, with a versioned JSON contract and CI/agent gating. Use when checking whether a Ruby test suite would catch a change, finding weak or missing tests, gating CI on a mutation score, or acting on mutineer's JSON report.
---
# Mutineer
Mutation testing for Ruby, built for CI gates and AI coding agents. Line coverage tells
you which code *ran*; mutation testing tells you whether your tests would *notice if it
broke*.
## Install
```sh
gem install mutineer
```
## Run
```sh
- mutineer run <source...> --test <test> [--test <test>...] [options]
+ mutineer run <source...> [--test <test>...] [options] # no --test: pairs each source with its test by convention; unmatched sources are skipped; --dry-run with --rails/--boot needs --test
```
Example — mutate `lib/calculator.rb`, gate CI below 90%:
```sh
mutineer run lib/calculator.rb --test test/calculator_test.rb --threshold 90
```
## Agent loop
1. Edit code and tests on a branch. Fetch `origin/main` before using it below.
2. Run diff-scoped, as JSON:
```sh
mutineer run app/ --since origin/main --threshold 90 --format json --output .mutineer/run.json
```
3. Parse `survivors[]` — each carries a `diff` and an `id`. File moves, renames,
project-root changes, and changes to repeated-name or repeated-mutation order can
- change ids; see [Mutant ids](https://github.com/davidteren/mutineer#mutant-ids). Review each change
+ change ids; see [Mutant ids](https://github.com/davidteren/mutineer/blob/main/docs/results.md#mutant-ids). Review each change
against the intended behaviour. If review finds a test gap, write or strengthen
a test that fails under that change.
4. Re-run. Accept the result only when this run exits `0`, `summary.score` is not `null`,
and `summary.score >= 90`. If every scored mutant must be killed, also require `summary.survived == 0`.
Mutineer 1.7.0 and earlier gate on the rounded score, so a run just below the threshold can
still exit `0`. On those versions, also require
`summary.killed * 100 >= 90 * (summary.killed + summary.survived)`.
Stop after a few unsuccessful attempts and ask a person to review the survivor.
Failed attempts do not prove that a mutant is equivalent. To
suppress it, `mutineer triage .mutineer/run.json --reason TEXT --id ID` prints an
`ignore:` entry for `.mutineer.yml` (Mutineer 1.7 or later reads it). See
- [Suppressing equivalent mutants](https://github.com/davidteren/mutineer#suppressing-equivalent-mutants).
+ [Suppressing equivalent mutants](https://github.com/davidteren/mutineer/blob/main/docs/results.md#suppressing-equivalent-mutants).
Keep `fail_fast` disabled (the default). If the active `.mutineer.yml` sets it to
`true`, temporarily change that value to `false` for the loop. Restore the original
value when the loop ends, before committing. A fail-fast run is partial,
and its score and exit code do not cover the full scope.
Zero survivors alone is not success: an empty or fully suppressed scope, or a run
with no usable verdicts, also has zero survivors. If the score is null, stop and
report “no score”. Check `no_coverage[]` for test gaps and `no_verdict[]` for
harness failures, and fix them before starting a new run. A positive threshold fails when nothing can be scored and something
broke, or when more than one mutant has no verdict and they exceed 10% of those
attempted; it does not require zero errors. Set the threshold to your target.
An empty run (`summary.total` is 0) exits 0 in 1.x and prints a warning on stderr. Treat it as "no score". Pass `--allow-empty` only when an empty run is expected. A `--since` run whose changes hold no mutable code says "nothing to test in the changes since REF"; that is a valid success. Warnings that start with `mutineer:` or `[mutineer]` also go to stderr: the empty-run warning, "did you mean" hints, notes about Mutineer 2.0, the count of errored mutants, and a notice that a `PARALLEL_WORKERS` value you set was replaced with 1.
## Exit codes
<!-- contract:exit-codes -->
| Code | Meaning |
|------|---------|
| `0` | Score ≥ threshold (or no gate) **and** no baseline regression. |
| `1` | Score below `--threshold`, OR nothing could be scored and something broke, or more than one mutant produced no verdict and they exceed 10% of those attempted, OR a `--baseline` regression, OR a runtime error, including a boot, source or `require:` file that raises while loading. |
| `2` | Usage / invalid-flag error, including a mistyped flag, a bad path (such as a missing `--boot` or `require:` file), or an unreadable baseline. |
<!-- /contract:exit-codes -->
## References
- Docs: https://davidteren.github.io/mutineer/
- Agent & CI guide: https://davidteren.github.io/mutineer/agentic-coding.html
- JSON schema: https://davidteren.github.io/mutineer/json-schema.html
- Ruby API: https://davidteren.github.io/mutineer/api/
- Source: https://github.com/davidteren/mutineer