Skip to content
Development
Skill

/crap-score

Calculates CRAP (Change Risk Anti-Patterns) for a named .NET method, class, or file. USE FOR: explicit CRAP calculation or coverage-and-complexity risk within that named target, including which tests to prioritize. DO NOT USE FOR: project-wide coverage/CRAP, plateaus, or

From plugin
managedcode-dotnet-skills
481182 skills17 agents
Install
$ npx -y skills add managedcode/dotnet-skills --skill crap-score --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/crap-score

Context preview

The summary Claude sees to decide when to auto-load this skill.

Calculates CRAP (Change Risk Anti-Patterns) for a named .NET method, class, or file. USE FOR: explicit CRAP calculation or coverage-and-complexity risk within that named target, including which tests to prioritize. DO NOT USE FOR: project-wide coverage/CRAP, plateaus, or

SKILL.md

crap-score.SKILL.md
name: crap-score
description: >
  Calculates CRAP (Change Risk Anti-Patterns) for a named .NET method, class, or
  file. USE FOR: explicit CRAP calculation or coverage-and-complexity risk
  within that named target, including which tests to prioritize. DO NOT USE
  FOR: project-wide coverage/CRAP, plateaus, or project-wide blockers/priorities
  (coverage-analysis); behavioral/pseudo-mutation gaps (test-gap-analysis);
  writing tests; test runs without CRAP context.
license: MIT

CRAP Score Analysis

Calculate CRAP (Change Risk Anti-Patterns) scores for .NET methods to identify code that is both complex and undertested.

Background

The CRAP score combines **cyclomatic complexity** and **code coverage** into a single metric:

$$\text{CRAP}(m) = \text{comp}(m)^2 \times (1 - \text{cov}(m))^3 + \text{comp}(m)$$

Where:

  • $\text{comp}(m)$ = cyclomatic complexity of method $m$
  • $\text{cov}(m)$ = code coverage ratio (0.0 to 1.0) of method $m$

| CRAP Score | Risk Level | Interpretation | |------------|------------|----------------| | < 5 | Low | Simple and well-tested | | 5 to < 15 | Moderate | Acceptable for most code | | 15 to 30 | High | Needs more tests or simplification | | > 30 | Critical | Refactor and add coverage urgently |

A method with 100% coverage has CRAP = complexity (the minimum). A method with 0% coverage has CRAP = complexity^2 + complexity.

When to Use

  • User wants to assess which methods are risky due to low coverage and high complexity
  • User asks for CRAP score of specific methods, classes, or files
  • User wants to prioritize what to test next within a named method, class, or file based on coverage-and-complexity risk
  • User wants to evaluate test quality beyond simple coverage percentages

When Not to Use

  • User just wants to run tests (use `run-tests` skill)
  • User wants to write new tests (use `code-testing-agent`)
  • User only wants a coverage percentage without complexity analysis
  • User wants project-wide coverage/CRAP analysis or priorities (use `coverage-analysis`)

Inputs

| Input | Required | Description | |-------|----------|-------------| | Target scope | Yes | Method name, class name, or file path to analyze | | Test project path | No | Path to the test project. Defaults to discovering test projects in the solution. | | Source project path | No | Path to the source project under analysis |

Workflow

Step 1: Collect code coverage data

If no coverage data exists yet, classify the test project first. For SDK-style projects, run `dotnet test` with coverage collection. For classic non-SDK projects (`ToolsVersion`, explicit compile items, or `packages.config`), use only a repository-provided coverage command that emits Cobertura. If none exists, ask for Cobertura XML and stop; do not migrate the project or inject an SDK-style coverage package. CRAP scores always require real coverage data.

Check the test project's `.csproj` for the coverage package, then run the appropriate command:

| Coverage Package | Command | Output Location | |---|---|---| | `coverlet.collector` | `dotnet test --collect:"XPlat Code Coverage" --results-directory ./TestResults` | Typically under `TestResults/<guid>/coverage.cobertura.xml`. Search recursively under the results directory (for example, `TestResults/**/coverage.cobertura.xml`) or use any explicit coverage path the user provides. | | `Microsoft.Testing.Extensions.CodeCoverage` (.NET 9) | `dotnet test -- --coverage --coverage-output-format cobertura --coverage-output ./TestResults` | `--coverage-output` path | | `Microsoft.Testing.Extensions.CodeCoverage` (.NET 10+) | `dotnet test --coverage --coverage-output-format cobertura --coverage-output ./TestResults` | `--coverage-output` path |

Never estimate coverage

**Guessed coverage produces wrong CRAP scores, which is worse than no answer.** For a classic project with no repository coverage command or existing report, stop here and request Cobertura; do not use any collection fallback below.

For SDK-style projects, if the first command yields no Cobertura XML, work down this collection list before giving up:

1. For SDK-style projects only, add a provider if none is referenced: `dotnet add <test.csproj> package coverlet.collector`, then re-run. Never use this fallback for `packages.config` or classic non-SDK projects. 2. Use the standalone collector, which works even when the test host or a shared assembly blocks the in-proc collector: `dotnet tool install --global dotnet-coverage` then `dotnet-coverage collect -f cobertura -o coverage.cobertura.xml "dotnet test <test.csproj>"`.

For any project type, if a real binary `.coverage` report already exists, convert or summarize that existing data with ReportGenerator:

3. Convert the existing report: `dotnet tool install --global dotnet-reportgenerator-globaltool` then `reportgenerator -reports:<file> -targetdir:cov -reporttypes:Cobertura`. 4. Tests fail but still run? Coverage is collected from the tests that executed — continue with that data and note the failures.

If every path fails, **report that coverage could not be collected, show the commands you tried and their errors, and stop.** Report complexity on its own if useful, but never publish a CRAP number derived from an assumed coverage percentage.

Before using a report, verify that it parses, contains at least one class and method, and contains the requested target. An empty report or a report that omits the target is failed collection or filtering, not 0% coverage. Regenerate coverage when possible; otherwise stop without publishing a CRAP score.

If the user supplies an existing report, state that it was not regenerated. Do not describe its data as current unless its provenance is established by running the repository's coverage command in this analysis.

Step 2: Compute cyclomatic complexity

Prefer a machine-produced per-method complexity from a repository-provided code metrics re

Read more
Ships withmanagedcode-dotnet-skills

Stop explaining .NET to your AI. Start building. We've all been there: asking Claude to use Entity Framework, only to get EF6 patterns in a .NET 8 project. Explaining to Copilot that Blazor Server and Blazor WebAssembly aren't the same thing.

Get the whole plugin

Other skills on managedcode-dotnet-skills.