Incremental Scoping (--since)
Relevant source files
The following files were used as context for generating this wiki page:
Incremental Scoping is a feature in Mutineer that limits mutation testing to specific code changes. It uses the --since flag to identify modified lines relative to a Git reference, such as a branch or a commit SHA. This mechanism significantly reduces execution time by focusing only on relevant diffs, making it suitable for CI gates and developer inner loops.
The feature integrates with the reporting system to mark runs as "scoped." This distinction ensures that mutation scores calculated from partial diffs are not incorrectly compared against full-project baselines.
Scoping Logic and Validation
When you provide a Git reference to the --since flag, Mutineer calculates the diff between the current workspace and that reference. It generates mutants only for the lines identified in the diff.
Git Reference Validation
Mutineer enforces strict validation on the provided reference:
- If the Git reference is unknown or cannot be resolved, the process exits with code
2. - If the reference is blank (empty string), the process exits with code
2to prevent accidental full scans. - If the
--sincerun identifies no mutable code in the changes, it is considered a valid success and exits with code0.
Sources: test/cli_test.rb:271-275, test/cli_test.rb:281-285, skills/mutineer/SKILL.md:65
Scoping Process Flow
The following diagram illustrates how Mutineer determines which mutants to run based on the scoping configuration.
The system ensures that untracked files are mutated even in scoped runs to prevent weak test suites from passing by simply introducing new, untested files.
Sources: test/cli_test.rb:339-342, action.yml:169-175
Reporting and Denominator Discipline
Scoped runs alter the mutation score calculation. The killed / (killed + survived) formula applies only to mutants within the identified scope.
JSON Report Indicators
The JSON report includes a specific boolean key, summary.scoped, to identify these runs.
scoped: true: Indicates the score covers only changed lines.- Denominator exclusion: Mutants outside the scope do not enter the denominator, preventing score dilution.
Sources: lib/mutineer/reporter.rb:137, lib/mutineer/reporter.rb:720-724
Baseline Comparison
Because scoped scores are not comparable to full-run scores, the baseline system behaves differently:
- If
summary.scopedis true, Mutineer skips the score-drop regression check. - The system still checks for new survivors compared to the baseline, even in scoped runs.
Sources: lib/mutineer/reporter.rb:746-751
GitHub Action Integration
The Mutineer GitHub Action provides automated scoping for pull requests. It attempts to resolve the base commit automatically to streamline CI integration.
Automatic Base Resolution
- The Action checks if the event is a
pull_request. - It attempts to use the exact base SHA from the event payload.
- If the payload is unavailable, it fetches the tip of the base branch (e.g.,
origin/main). - If resolution fails, it warns the user and falls back to a full scan.
Scoping Configuration Options
| Input/Flag | Type | Description |
|---|---|---|
since | String | Git ref to scope against. Defaults to PR base in GitHub Actions. |
none | String | Pass since: none in Actions to force a full scan, overriding config. |
--no-since | Flag | CLI flag to disable scoping defined in .mutineer.yml. |
Sources: action.yml:25-41, action.yml:178-210, test/cli_test.rb:296-302
Agent Inner Loop
Incremental scoping is optimized for AI agent workflows. By using --since origin/main, an agent can iterate quickly on a branch.
- Iteration: Edit code and tests.
- Scan: Run
mutineer run --since origin/main --format json. - Analyze: Review the
survivors[]list. - Fix: Address specific survivors by strengthening tests before re-running.
Sources: skills/mutineer/SKILL.md:35-43
Incremental scoping ensures that mutation testing remains performant and focused on current development efforts without requiring a full project scan for every change.