mutation_test
Verify assertions by applying an explicit code mutant, confirming it compiles, and running a scoped test set. Distinguishes real checks (KILLED) from vacuous ones (SURVIVED) without false kills, then restores the original file.
Instructions
Mutation-test your own assertions: apply an explicit mutant, prove it still COMPILES, run a scoped test set, classify the result, and restore the file — the check that tells a real assertion from a vacuous one. Takes explicit mutants only (file_path + exact-once old_string/new_string, like edit_file); it does not generate them. Three outcomes: KILLED (mutant compiled and a test failed — the assertion is real), SURVIVED (mutant compiled and every test still passed — the assertion is VACUOUS, the finding that matters), and INVALID (the mutant did not apply, did not compile, could not be started, or timed out — it proves nothing and is NEVER reported as a kill; that false kill is why the compile gate exists). Scope the run with test_target, which fills the stored test command's {target} placeholder (topology_affected says which tests to name) — the shipped go/python/rust test defaults carry one, so scoping works out of the box. Commands are the stored, trust-gated [tasks.] slots run_task uses; you cannot pass a command line. Restoration is guaranteed on every exit path (pass, fail, compile error, timeout, panic, cancellation): the pre-mutation bytes are snapshotted in memory, rewritten under the same per-path lock, and SHA-256-verified before the run is reported clean. It REFUSES to touch a file with uncommitted changes (untracked included), no override — a clean file means git checkout recovers it if the daemon dies mid-run; that is the recovery story. It also refuses to start unless the workspace BUILDS and its tests PASS unmutated: a kill means "green before, red after", so against an already-red suite every mutant reads as killed for a reason unrelated to it. The refusal says which happened — suite red, command timed out, or could not start — because only the first is about your code. One mutation run at a time per daemon; a second call is refused rather than queued.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| mutants | No | The mutants to test, applied and restored ONE AT A TIME. Each is an exact-once str_replace in the style of edit_file. | |
| test_task | No | Which stored [tasks.<lang>] slot runs the tests. Default "test". The built-ins are build, lint, test, e2e and verify; a project-defined slot works here too. | |
| test_target | No | Optional value for the test command's {target} placeholder — THE way to scope the run to the affected package or test instead of the whole suite (ask topology_affected which). The shipped go/python/rust test defaults carry a defaulted placeholder, so this works with no config edit; a hand-written test command needs a {target} token of its own or the target is refused. Scoping matters: each mutant costs a full compile+test cycle, so the whole suite per mutant is the difference between minutes and tens of minutes. One shell-safe argument ([A-Za-z0-9._/:@-]). | |
| compile_task | No | Which stored slot proves the mutant COMPILES before its tests are trusted. Default "build". It always runs unscoped (no {target}) — a whole-module compile catches breakage a scoped test never reaches. Cannot be disabled: without it a non-compiling mutant looks exactly like a kill. The built-ins are build, lint, test, e2e and verify; a project-defined slot works here too. | |
| timeout_seconds | No | Per-step timeout for the compile and test commands. Default 600. |