Skip to content

Commit f0aa9d3

Browse files
authored
AGENTS: document cargo-mutants as a periodic package-owner tool (#298)
## Summary Add a rust-style entry covering `cargo-mutants` as a package-owner audit, not a CI gate. Lands next to the `cargo-careful` paragraph so the two behavior-validation tools sit together. Source fragment edited in `agents-md/sections/06-rust-style.md`; `AGENTS.md` and `CLAUDE.md` regenerated via `nix run .#agents-md -- --write`. ## Trial results Ran on `code-tokenizer` (37 tests, all-pure tokenizer, no async, no FFI): ```sh nix shell nixpkgs#cargo-mutants -c cargo mutants --package code-tokenizer --in-place --no-shuffle ``` 31 mutants tested in 2 min: 19 caught, 3 timeouts (also caught), 6 unviable (compile errors), **3 missed**. The three survivors are real gaps: - `packages/code-tokenizer/src/lib.rs:113` `self.position += 1` → `*= 1` (EOF early-return). - `packages/code-tokenizer/src/lib.rs:144` `self.position += 1` → `*= 1` (normal token-boundary return). - `packages/code-tokenizer/src/lib.rs:140` `current_offset += ch.len_utf8()` → `*=` (separator branch). `packages/code-tokenizer/src/tests/helpers.rs` only collects `token.text`, so `Token::position`, `offset_from`, and `offset_to` are never asserted. Tracked separately in #297 so this PR stays focused on the trial decision. ## Recommendation Keep cargo-mutants a periodic package-owner tool rather than a CI gate: - Runtime scales linearly with mutant count; even 31 mutants on a tiny pure crate ran 2 min, the same workload across the workspace would dominate CI. - Equivalent mutants need human judgment: the survivor on line 113 is reachable but inert for any caller that ignores `Token::position`, which is a real call-site question, not a binary pass/fail. - A surviving mutant is a prompt to look, not a regression to block. CI gating would push the team toward writing assertions just to kill mutants instead of asking whether the behavior is worth pinning. ## Test plan - [x] `nix run .#lint` - [x] `nix run .#agents-md -- --write` produces no further diff - [x] cargo-mutants trial captured above Closes #252 Refs #297
1 parent 0bccf43 commit f0aa9d3

3 files changed

Lines changed: 33 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,17 @@ against a debug-assertion standard library and surfaces some unsafe-precondition
304304
and stdlib-invariant breakage, but it does not model aliasing, uninitialized
305305
reads, or data races, so it complements Miri rather than replacing it.
306306

307+
When auditing a crate with deterministic, fast tests, run
308+
[`cargo-mutants`](https://mutants.rs/) with
309+
`nix shell nixpkgs#cargo-mutants -c cargo mutants --package <name>` to surface
310+
behavior that coverage cannot prove protected. Let the default copy-to-`target`
311+
mode hold; `--in-place` is faster but leaves the source tree dirty on interrupt
312+
or panic, so reserve it for disposable checkouts. Treat surviving mutants as
313+
candidates for tighter assertions, equivalent-mutant write-offs, or
314+
unreachable-by-test code, and keep cargo-mutants a package-owner tool rather
315+
than a CI gate: equivalent mutants need human judgment, runtime scales with
316+
mutant count, and a survivor is a prompt to look, not a regression to block.
317+
307318
## Python style
308319

309320
Default repo-owned Python apps to uv: `pyproject.toml`, committed `uv.lock`,

CLAUDE.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,17 @@ against a debug-assertion standard library and surfaces some unsafe-precondition
304304
and stdlib-invariant breakage, but it does not model aliasing, uninitialized
305305
reads, or data races, so it complements Miri rather than replacing it.
306306

307+
When auditing a crate with deterministic, fast tests, run
308+
[`cargo-mutants`](https://mutants.rs/) with
309+
`nix shell nixpkgs#cargo-mutants -c cargo mutants --package <name>` to surface
310+
behavior that coverage cannot prove protected. Let the default copy-to-`target`
311+
mode hold; `--in-place` is faster but leaves the source tree dirty on interrupt
312+
or panic, so reserve it for disposable checkouts. Treat surviving mutants as
313+
candidates for tighter assertions, equivalent-mutant write-offs, or
314+
unreachable-by-test code, and keep cargo-mutants a package-owner tool rather
315+
than a CI gate: equivalent mutants need human judgment, runtime scales with
316+
mutant count, and a survivor is a prompt to look, not a regression to block.
317+
307318
## Python style
308319

309320
Default repo-owned Python apps to uv: `pyproject.toml`, committed `uv.lock`,

agents-md/sections/06-rust-style.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,14 @@ against a debug-assertion standard library and surfaces some unsafe-precondition
3333
and stdlib-invariant breakage, but it does not model aliasing, uninitialized
3434
reads, or data races, so it complements Miri rather than replacing it.
3535

36+
When auditing a crate with deterministic, fast tests, run
37+
[`cargo-mutants`](https://mutants.rs/) with
38+
`nix shell nixpkgs#cargo-mutants -c cargo mutants --package <name>` to surface
39+
behavior that coverage cannot prove protected. Let the default copy-to-`target`
40+
mode hold; `--in-place` is faster but leaves the source tree dirty on interrupt
41+
or panic, so reserve it for disposable checkouts. Treat surviving mutants as
42+
candidates for tighter assertions, equivalent-mutant write-offs, or
43+
unreachable-by-test code, and keep cargo-mutants a package-owner tool rather
44+
than a CI gate: equivalent mutants need human judgment, runtime scales with
45+
mutant count, and a survivor is a prompt to look, not a regression to block.
46+

0 commit comments

Comments
 (0)