Clean Code Gauntlet
Effort: heavy — real compute: coverage and complexity runs plus a bounded mutation pass, then one taste model; spend it on changes that ship. Removes: line-by-line human review of whole diffs, and the fake-green tests a regression hides behind.
Why this exists
Messy code makes agents thrash, and rules buried in a long prompt fade
mid-context — deterministic checks never fade. So run Clean Code as a
gauntlet the code must pass, not prose the model must remember.
Measure, do not review. Gate on numbers a tool computes: coverage,
cyclomatic complexity (a count of independent paths through a function), module
size, mutation kills. Humans and models audit samples — never whole diffs.
The chain (run in order; each stage stops loud on failure)
- Sniper tests green. Run only the test files covering what the diff
touched — see sniper-testing. A red baseline
means stop and fix; never mutate or grade on red.
- CRAP under threshold on real coverage data (see the gate below).
Breach → refactor the function down, or cover it fully. Never lower the bar.
- Mutation testing: zero survivors in scope. A survivor convicts the
TESTS, not the code — strengthen the test that should have caught it.
- Light taste review — a model judges only what numbers cannot.
Tools that compute this
| Stack |
Tools |
| Python |
coverage.py + radon + mutmut |
| JS/TS |
c8 (or istanbul) + Stryker |
| Go |
go test -cover + gocyclo + go-mutesting |
| Rust |
cargo-tarpaulin + cargo-mutants |
| Java |
JaCoCo + PIT |
| Other |
any coverage % + any cyclomatic-complexity counter |
One command shape per stage:
- Coverage:
coverage run -m pytest <sniper files> && coverage report (JS/TS: npx c8 vitest run <files>)
- Complexity:
radon cc -s <changed files>
- Mutation:
mutmut run --paths-to-mutate <changed files> (JS/TS: npx stryker run --mutate "<glob>")
The CRAP gate
CRAP(m) = comp(m)^2 * (1 - cov(m)/100)^3 + comp(m)
- At 100% coverage the score collapses to the complexity itself.
- 30 is the classic "crappy" line (complexity 5 with zero coverage hits it).
- Humans hold roughly 4–5 complexity per function. An agent may carry 6–8
ONLY at near-100% coverage — the coverage pays for the slack.
- A high-CRAP function has exactly two exits: refactor it down, or cover it
fully. Never lower the threshold to pass.
Whose debt is it — AUTHORED / WORSENED / UNCHANGED
An absolute score hides whose debt it is. Split every complexity and CRAP
delta against the pre-change baseline:
- AUTHORED — functions this change created. The full bar applies.
- WORSENED — pre-existing functions this change made worse. The delta is
charged to this change; it must come back to baseline or better.
- UNCHANGED — pre-existing debt the change never touched. Report it, file
it, never charge it to this change — and never use it as cover to skip
the gauntlet.
Mutation rules (bounded, never reckless)
- Never the shared working tree. Mutate in a scratch checkout cut from
committed HEAD. Dirty target or test files = refuse; commit first.
- Cost is measured, never assumed. Time the scoped suite once, report
ETA = baseline x mutant count BEFORE spending anything. Offer a dry run.
- Bounded and resumable. Cap mutants and minutes. A budget stop is a
pause with a checkpoint, not a failure — resume to finish.
- Coverage-first. Mutate only covered lines; an uncovered line is a
coverage gap the CRAP gate already caught.
- Scoped only. Mutate what the diff touched, never the whole repo.
- A genuinely equivalent mutant may be refuted instead of killed — with the
refutation written down, never silently skipped.
- No mutation tool exists for your stack? Record that in the landing
report and rely on the CRAP gate — never silently skip.
The taste review (last, and light)
Deterministic gates go first; spend a model only where reasoning is the only
tool. The reviewer is a model from a different family than the builder — the
builder never grades its own work. It judges only design and taste: naming,
mixed concerns, interface width, and the six smells — rigidity, fragility,
immobility, needless complexity, needless repetition, opacity. The arithmetic
was already settled by the gates.
Craft floor the review holds: functions small, doing one thing, few arguments,
no flag arguments, honest names; deep modules — a small interface hiding real
logic; tests fast, independent, repeatable, one behavior asserted each.
Hard rules (any one broken fails the skill)
- Never lower a threshold or weaken the mutation set to force a pass.
- Never mutate the shared working tree; never run unbounded.
- Never charge UNCHANGED debt to the current change.
- A test that cannot fail is theater — mutation testing is how you prove
which tests are real.
- Say the real cost — machine time is cheap, regressions are not. Never
fake green to save the hour.
Works well with
Scaffold credit: Robert C. Martin, Clean Code (2008); Alberto Savoia &
Bob Evans, the CRAP metric (2007); John Ousterhout, deep modules
(A Philosophy of Software Design, 2018); Pocock, M., & Martin, R. C.
(2026, Aug 19). LIVE: Uncle Bob on Software Fundamentals in the Age of AI
[Video]. YouTube. https://www.youtube.com/watch?v=zcLPGC-tvgk — source of
the agent CRAP band and coverage-first mutation. The composition and hard
rules here are BACKS AIOS.
1---2name: clean-code-gauntlet3description: Use when hardening or landing any build (an agent, a service, a library) and you want a deterministic quality bar instead of a line-by-line review. Runs sniper tests, the CRAP score (complexity x coverage), and bounded mutation testing, then a light taste review. Trigger words: clean code, gauntlet, unc, uncle bob, crap score, crap, mutation testing, harden, complexity, coverage, quality bar.4license: MIT5---67# Clean Code Gauntlet8**Effort:** heavy — real compute: coverage and complexity runs plus a bounded mutation pass, then one taste model; spend it on changes that ship. Removes: line-by-line human review of whole diffs, and the fake-green tests a regression hides behind.910## Why this exists1112Messy code makes agents thrash, and rules buried in a long prompt fade13mid-context — deterministic checks never fade. So run Clean Code as a14**gauntlet the code must pass**, not prose the model must remember.1516**Measure, do not review.** Gate on numbers a tool computes: coverage,17cyclomatic complexity (a count of independent paths through a function), module18size, mutation kills. Humans and models audit samples — never whole diffs.1920## The chain (run in order; each stage stops loud on failure)21221. **Sniper tests green.** Run only the test files covering what the diff23 touched — see [sniper-testing](../sniper-testing/SKILL.md). A red baseline24 means stop and fix; never mutate or grade on red.252. **CRAP under threshold** on real coverage data (see the gate below).26 Breach → refactor the function down, or cover it fully. Never lower the bar.273. **Mutation testing: zero survivors in scope.** A survivor convicts the28 TESTS, not the code — strengthen the test that should have caught it.294. **Light taste review** — a model judges only what numbers cannot.3031## Tools that compute this3233| Stack | Tools |34| --- | --- |35| Python | coverage.py + radon + mutmut |36| JS/TS | c8 (or istanbul) + Stryker |37| Go | go test -cover + gocyclo + go-mutesting |38| Rust | cargo-tarpaulin + cargo-mutants |39| Java | JaCoCo + PIT |40| Other | any coverage % + any cyclomatic-complexity counter |4142One command shape per stage:43- Coverage: `coverage run -m pytest <sniper files> && coverage report` (JS/TS: `npx c8 vitest run <files>`)44- Complexity: `radon cc -s <changed files>`45- Mutation: `mutmut run --paths-to-mutate <changed files>` (JS/TS: `npx stryker run --mutate "<glob>"`)4647## The CRAP gate4849```50CRAP(m) = comp(m)^2 * (1 - cov(m)/100)^3 + comp(m)51```5253- At 100% coverage the score collapses to the complexity itself.54- 30 is the classic "crappy" line (complexity 5 with zero coverage hits it).55- Humans hold roughly 4–5 complexity per function. An agent may carry 6–856 ONLY at near-100% coverage — the coverage pays for the slack.57- A high-CRAP function has exactly two exits: refactor it down, or cover it58 fully. **Never lower the threshold to pass.**5960## Whose debt is it — AUTHORED / WORSENED / UNCHANGED6162An absolute score hides whose debt it is. Split every complexity and CRAP63delta against the pre-change baseline:6465- **AUTHORED** — functions this change created. The full bar applies.66- **WORSENED** — pre-existing functions this change made worse. The delta is67 charged to this change; it must come back to baseline or better.68- **UNCHANGED** — pre-existing debt the change never touched. Report it, file69 it, never charge it to this change — and never use it as cover to skip70 the gauntlet.7172## Mutation rules (bounded, never reckless)7374- **Never the shared working tree.** Mutate in a scratch checkout cut from75 committed HEAD. Dirty target or test files = refuse; commit first.76- **Cost is measured, never assumed.** Time the scoped suite once, report77 ETA = baseline x mutant count BEFORE spending anything. Offer a dry run.78- **Bounded and resumable.** Cap mutants and minutes. A budget stop is a79 pause with a checkpoint, not a failure — resume to finish.80- **Coverage-first.** Mutate only covered lines; an uncovered line is a81 coverage gap the CRAP gate already caught.82- **Scoped only.** Mutate what the diff touched, never the whole repo.83- A genuinely equivalent mutant may be refuted instead of killed — with the84 refutation written down, never silently skipped.85- **No mutation tool exists for your stack?** Record that in the landing86 report and rely on the CRAP gate — never silently skip.8788## The taste review (last, and light)8990Deterministic gates go first; spend a model only where reasoning is the only91tool. The reviewer is a model from a different family than the builder — the92builder never grades its own work. It judges only design and taste: naming,93mixed concerns, interface width, and the six smells — rigidity, fragility,94immobility, needless complexity, needless repetition, opacity. The arithmetic95was already settled by the gates.9697Craft floor the review holds: functions small, doing one thing, few arguments,98no flag arguments, honest names; deep modules — a small interface hiding real99logic; tests fast, independent, repeatable, one behavior asserted each.100101## Hard rules (any one broken fails the skill)102103- Never lower a threshold or weaken the mutation set to force a pass.104- Never mutate the shared working tree; never run unbounded.105- Never charge UNCHANGED debt to the current change.106- A test that cannot fail is theater — mutation testing is how you prove107 which tests are real.108- Say the real cost — machine time is cheap, regressions are not. Never109 fake green to save the hour.110111## Works well with112113- [sniper-testing](../sniper-testing/SKILL.md) — picks the test scope for stage 1114- [red-first](../red-first/SKILL.md) — the failing contract that precedes any build115- [blind-eval](../blind-eval/SKILL.md) — keep-or-revert when taste is the question116- [blind-tribunal](../blind-tribunal/SKILL.md) — a fuller graded verdict before landing117118> Scaffold credit: Robert C. Martin, *Clean Code* (2008); Alberto Savoia &119> Bob Evans, the CRAP metric (2007); John Ousterhout, deep modules120> (*A Philosophy of Software Design*, 2018); Pocock, M., & Martin, R. C.121> (2026, Aug 19). LIVE: Uncle Bob on Software Fundamentals in the Age of AI122> [Video]. YouTube. https://www.youtube.com/watch?v=zcLPGC-tvgk — source of123> the agent CRAP band and coverage-first mutation. The composition and hard124> rules here are BACKS AIOS.