fix(automation): kill uncatchable run_cargo mutants - #58
Merged
martin-kolinek merged 1 commit intoJul 20, 2026
Conversation
`run_cargo` used `duct::cmd(...).run()`, which already returns an `Err` on a non-zero exit status. That made the `if !output.status.success()` block unreachable dead code (and its `output.stdout`/`stderr` reads were always empty, since stdio is inherited). cargo-mutants` scheduled exhaustive run flagged two uncatchable mutants there: "delete !" and "replace body with Ok(())". Add `.unchecked()` so duct no longer short-circuits on failure, making the status check the single observable success/failure decision, and simplify the now-correct bail message. Add unit tests covering both the success and failure paths, which kill both mutants. These lines predate the mutation-testing infra (added 3 months before cargo-mutants CI) and were never in a PR diff since, so the diff-scoped per-PR check never mutated them; the scheduled full sweep did. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5e5f60bf-ad77-4786-b8cf-79ee116be1db
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #58 +/- ##
=======================================
Coverage 100.0% 100.0%
=======================================
Files 50 50
Lines 2652 2652
=======================================
Hits 2652 2652
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes automation::run_cargo so that mutation testing can reliably observe (and therefore kill) mutants related to the command’s success/failure decision, and adds focused tests to prevent regressions.
Changes:
- Make
run_cargouseduct::cmd(...).unchecked().run()?so non-zero exits don’t short-circuit into an error before the explicitstatus.success()check. - Simplify the failure path to avoid reporting stdout/stderr that aren’t captured when running with inherited output.
- Add unit tests covering both a known-success invocation and a known-failure invocation to kill the previously missed mutants.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Sergey Galkin (sgalkin)
approved these changes
Jul 20, 2026
martintmk
approved these changes
Jul 20, 2026
martin-kolinek
deleted the
martin-kolinek/fix-automation-run-cargo-mutants
branch
July 20, 2026 12:59
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The scheduled-exhaustive CI leg (
anvil-mutants-full) failed with 2 missed mutants incrates/automation/src/lib.rs(run_cargo):crates/automation/src/lib.rs:76— replacerun_cargo -> Result<(), AppError>withOk(())crates/automation/src/lib.rs:83— delete!inrun_cargoRoot cause
duct::cmd(...).run()already returnsErron a non-zero exit status (duct's default). That made theif !output.status.success()block effectively unreachable dead code — so flipping!or stubbing the body withOk(())was unobservable, hence uncatchable. As a bonus bug,output.stdout/stderrwere read in the bail message but are always empty because stdio is inherited (piped live).Fix
.unchecked()so duct no longer short-circuits, making the status check the single observable success/failure decision.test_run_cargo_successandtest_run_cargo_reports_failure; the failure test kills both mutants.Why the diff-scoped PR check never caught this
anvil-mutants-diffonly mutates lines in the PR diff (--in-diff).run_cargowas added 2026-03-18, ~3 months before cargo-mutants CI landed (#33, 2026-06-16), and no PR has touched those lines since — so they never appeared in a mutation diff. The scheduled full sweep is the safety net that surfaced it.Verification
cargo mutants --file crates/automation/src/lib.rs: 4 caught, 1 unviable, 0 missed.cargo mutants --workspacerun in progress; 0 missed at ~50% at time of opening. (Change is isolated to one file, so it cannot affect other crates.)cargo test -p automation, nightlyfmt, andjust spellcheckall clean.