CRAP
/krap/ · noun
Change Risk Anti-Patterns. A code metric that combines complexity and test coverage to identify functions that may be risky to change.

A function can pass the project's test suite and still have bugs. The tests may never reach it. They may execute its lines without exercising the decisions that matter. The function may also contain enough branches that one small change can affect several paths.

An implementation agent is usually rewarded for completing the requested behavior. Once the tests pass, another agent can inspect the risk left inside the code.

Dense network of industrial pipes crossing a dark ceiling
[ INDUSTRIAL PIPES / MIKHAIL NILOV / PEXELS ↗ ]

A Score for Change Risk

Alberto Savoia and Bob Evans introduced the metric in 2007 to combine two signals that become more useful together: cyclomatic complexity and automated test coverage.

The original formula scores a method m like this:

CRAP(m) = complexity(m)² × (1 − coverage(m)/100)³ + complexity(m)

Cyclomatic complexity counts the independent paths created by decisions in the function. Coverage estimates how much of that behavior the tests execute. A function with a complexity of 10 and 0% coverage receives a CRAP score of 110. At 50% coverage, the score falls to 22.5. At 100% coverage, it remains 10 because the underlying complexity still exists.

Savoia and Evans treated a score above 30 as a warning. The number was meant to identify code worth examining, not provide a universal definition of good code.

Give the Score to Another Agent

The AI Build Loop separates planning, implementation, and verification. If we add a cleanup pass to our agent loop, it will now look like this:

PLANQUEUEBUILDVERIFYCLEANUPVERIFYCOMMITNEXT

After the implementation agent completes the requested behavior and its tests, run coverage and complexity tools to produce a score for each function. We give a cleanup agent the changed files, the relevant tests, and the highest-scoring functions instead of asking it to improve the entire codebase.

For each flagged function, we ask the cleanup agent to take one of three actions:

  1. Add meaningful tests around behavior that is insufficiently covered.
  2. Simplify branching, separate responsibilities, or make a decision easier to inspect.
  3. Leave the function intact and explain why its complexity is appropriate.

Have the cleanup agent make one bounded change at a time and run the same tests after each change. Require its report to show the old score, the new score, the code that changed, and the evidence that behavior remained intact.

The agent works from a specific list instead of a vague request to “clean up” the code. The reviewer can see why each refactor was made.

Read the Code Too

The creators of CRAP were direct about its limitations. High coverage can come from weak tests. Some problems contain unavoidable complexity. Dividing one understandable function into several smaller functions can lower a local score while making the overall design harder to follow. CRAP also does not measure cohesion, coupling, naming, or whether the abstraction matches the problem.

An agent optimizing only for the score can game it in the same way a person can. It can add shallow tests, move branches into helpers, or break one coherent decision across several files.

[ FIELD NOTE / METRICS ]

The cleanup should make the code easier to understand and change.

Use the score to choose where to review. Run the tests and read the diff to decide if the change improved the code.

If you think your code is starting to smell like CRAP, try running the report and adding a cleanup agent to your loop.

Will your code stand up to CRAP?