crap-analysis
- Repo stars 1,012
- Forks 98
- Author updated Apr 16, 2026, 02:05 AM
- Author repo dotnet-skills
- Domain
- Documentation
- Compatible agents
-
- Claude Code
- Cursor
- Cline
- Codex
- Windsurf
- Gemini CLI
- +20
- Trust score
- 88 / 100 · community maintained
- Author / version / license
- @Aaronontheweb · no license declared
- Token usage
- Lean
- Setup complexity
- Guided setup
- External API key
- Not required
- Operating systems
- macOS · Linux · Windows
- Runtime requirements
- No special requirements
- Permissions
-
- Read-only
- Write / modify
- Shell exec
- Network behavior
- Local-only
- Install commands
- 26 variants
Profile is derived at build time from SKILL.md and install vectors. Subject to drift from author intent.
Heads up: 未限定 allowed-tools,默认拥有全部工具权限。
---
name: crap-analysis
description: Analyze code coverage and CRAP (Change Risk Anti-Patterns) scores to identify high-risk code. Us…
category: documentation
runtime: no special runtime
---
# crap-analysis output preview
## PART A: Task fit
- Use case: Analyze code coverage and CRAP (Change Risk Anti-Patterns) scores to identify high-risk code. Use OpenCover format with ReportGenerator for Risk Hotspots showing cyclomatic complexity and untested code paths..
- Inputs: target material, constraints, expected output, and acceptance criteria.
- Evidence boundary: follow “When to Use This Skill / What is CRAP? / Why CRAP Matters” and do not present inference as author intent.
## PART B: Execution result
- **01** The card summarizes the use case; runtime output centers on “Analyze code coverage and CRAP (Change Risk Anti-Patterns) scores to identify high-risk code. Use OpenCover format with ReportGenerator for Risk Hotspots showing cyclomatic complexity and untested code paths.”.
- **02** When the source has headings, the agent prioritizes “When to Use This Skill / What is CRAP? / Why CRAP Matters” so the result follows the author’s structure.
- **03** Typical output includes task judgment, concrete steps, required commands or file edits, validation, and follow-up options.
- **04** Risk context follows the fingerprint: read files, write/modify files, run shell commands; mostly runs locally; usually needs no extra API key.
## Running Rules
- read files, write/modify files, run shell commands; mostly runs locally; usually needs no extra API key.
- Validate with a small sample before expanding scope.
- Return the result, validation criteria, and next iteration options. The source does not require a stable slash command. After installation, invoke the skill by name and describe the task.
Name target files or source material, expected output, forbidden changes, and whether network or shell access is allowed. Permission fingerprint: read files, write/modify files, run shell commands.
Start with a small task and check whether the result follows “When to Use This Skill / What is CRAP? / Why CRAP Matters”. Inspect diffs, logs, previews, or tests before expanding scope.
Confirm the final output includes a concrete result, evidence, and next action. If it stays generic, tighten inputs, boundaries, and acceptance criteria.
---
name: crap-analysis
description: Analyze code coverage and CRAP (Change Risk Anti-Patterns) scores to identify high-risk code. Us…
category: documentation
source: Aaronontheweb/dotnet-skills
---
# crap-analysis
## When to use
- Analyze code coverage and CRAP (Change Risk Anti-Patterns) scores to identify high-risk code. Use OpenCover format wit…
- Use it when the task has clear inputs, repeatable steps, and validation criteria.
## What to provide
- Target material, scope, expected result, and forbidden changes.
- Whether network, commands, file writes, or external services are allowed.
## Execution rules
- Organize steps around “When to Use This Skill / What is CRAP? / Why CRAP Matters” and keep inference separate from source facts.
- read files, write/modify files, run shell commands; mostly runs locally; usually needs no extra API key.
- Validate with a small sample before expanding the task.
## Output requirements
- Return the deliverable, key evidence, validation method, and next action.
- Mark missing information as unknown; do not invent commands, platforms, or dependencies. The author source anchors workflow facts; repository files anchor sources and commands; Fluxly only adds fit, limitations, and quality judgment.
skill "crap-analysis" {
input -> user goal + target files + boundaries + acceptance criteria
context -> When to Use This Skill / What is CRAP? / Why CRAP Matters
rules -> SKILL.md triggers / order / output contract
runtime -> no special runtime | read files, write/modify files, run shell commands | mostly runs locally
guardrails -> usually needs no extra API key + small-sample validation + diff/log review
output -> copyable result + checklist + next iteration
} CRAP Score Analysis
When to Use This Skill
Use this skill when:
- Evaluating code quality and test coverage before changes
- Identifying high-risk code that needs refactoring or testing
- Setting up coverage collection for a .NET project
- Prioritizing which code to test based on risk
- Establishing coverage thresholds for CI/CD pipelines
What is CRAP?
CRAP Score = Complexity x (1 - Coverage)^2
The CRAP (Change Risk Anti-Patterns) score combines cyclomatic complexity with test coverage to identify risky code.
| CRAP Score | Risk Level | Action Required |
|---|---|---|
| < 5 | Low | Well-tested, maintainable code |
| 5-30 | Medium | Acceptable but watch complexity |
| > 30 | High | Needs tests or refactoring |
Why CRAP Matters
- High complexity + low coverage = danger: Code that's hard to understand AND untested is risky to modify
- Complexity alone isn't enough: A complex method with 100% coverage is safer than a simple method with 0%
- Focuses effort: Prioritize testing on complex code, not simple getters/setters
CRAP Score Examples
| Method | Complexity | Coverage | Calculation | CRAP |
|---|---|---|---|---|
GetUserId() |
1 | 0% | 1 x (1 - 0)^2 | 1 |
ParseToken() |
54 | 52% | 54 x (1 - 0.52)^2 | 12.4 |
ValidateForm() |
20 | 0% | 20 x (1 - 0)^2 | 20 |
ProcessOrder() |
45 | 20% | 45 x (1 - 0.20)^2 | 28.8 |
ImportData() |
80 | 10% | 80 x (1 - 0.10)^2 | 64.8 |
Coverage Collection Setup
coverage.runsettings
Create a coverage.runsettings file in your repository root. The OpenCover format is required for CRAP score calculation because it includes cyclomatic complexity metrics.
<?xml version="1.0" encoding="utf-8" ?>
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName="XPlat code coverage">
<Configuration>
<!-- OpenCover format includes cyclomatic complexity for CRAP scores -->
<Format>cobertura,opencover</Format>
<!-- Exclude test and benchmark assemblies -->
<Exclude>[*.Tests]*,[*.Benchmark]*,[*.Migrations]*</Exclude>
<!-- Exclude generated code, obsolete members, and explicit exclusions -->
<ExcludeByAttribute>Obsolete,GeneratedCodeAttribute,CompilerGeneratedAttribute,ExcludeFromCodeCoverageAttribute</ExcludeByAttribute>
<!-- Exclude source-generated files, Blazor generated code, and migrations -->
<ExcludeByFile>**/obj/**/*,**/*.g.cs,**/*.designer.cs,**/*.razor.g.cs,**/*.razor.css.g.cs,**/Migrations/**/*</ExcludeByFile>
<!-- Exclude test projects -->
<IncludeTestAssembly>false</IncludeTestAssembly>
<!-- Optimization flags -->
<SingleHit>false</SingleHit>
<UseSourceLink>true</UseSourceLink>
<SkipAutoProps>true</SkipAutoProps>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
</RunSettings>
Key Configuration Options
| Option | Purpose |
|---|---|
Format |
Must include opencover for complexity metrics |
Exclude |
Exclude test/benchmark assemblies by pattern |
ExcludeByAttribute |
Skip generated, obsolete, and explicitly excluded code (includes ExcludeFromCodeCoverageAttribute) |
ExcludeByFile |
Skip source-generated files, Blazor components, and migrations |
SkipAutoProps |
Don't count auto-properties as branches |
ReportGenerator Installation
Install ReportGenerator as a local tool for generating HTML reports with Risk Hotspots.
Add to .config/dotnet-tools.json
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-reportgenerator-globaltool": {
"version": "5.4.5",
"commands": ["reportgenerator"],
"rollForward": false
}
}
}
Then restore:
dotnet tool restore
Or Install Globally
dotnet tool install --global dotnet-reportgenerator-globaltool
Collecting Coverage
Run Tests with Coverage Collection
# Clean previous results
rm -rf coverage/ TestResults/
# Run unit tests with coverage
dotnet test tests/MyApp.Tests.Unit \
--settings coverage.runsettings \
--collect:"XPlat Code Coverage" \
--results-directory ./TestResults
# Run integration tests (optional, adds to coverage)
dotnet test tests/MyApp.Tests.Integration \
--settings coverage.runsettings \
--collect:"XPlat Code Coverage" \
--results-directory ./TestResults
Generate HTML Report
dotnet reportgenerator \
-reports:"TestResults/**/coverage.opencover.xml" \
-targetdir:"coverage" \
-reporttypes:"Html;TextSummary;MarkdownSummaryGithub"
Report Types
| Type | Description | Output |
|---|---|---|
Html |
Full interactive report | coverage/index.html |
TextSummary |
Plain text summary | coverage/Summary.txt |
MarkdownSummaryGithub |
GitHub-compatible markdown | coverage/SummaryGithub.md |
Badges |
SVG badges for README | coverage/badge_*.svg |
Cobertura |
Merged Cobertura XML | coverage/Cobertura.xml |
Reading the Report
Risk Hotspots Section
The HTML report includes a Risk Hotspots section showing methods sorted by complexity:
- Cyclomatic Complexity: Number of independent paths through code (if/else, switch cases, loops)
- NPath Complexity: Number of acyclic execution paths (exponential growth with nesting)
- Crap Score: Calculated from complexity and coverage
Interpreting Results
Risk Hotspots
─────────────
Method Complexity Coverage Crap Score
──────────────────────────────────────────────────────────────────
DataImporter.ParseRecord() 54 52% 12.4
AuthService.ValidateToken() 32 0% 32.0 ← HIGH RISK
OrderProcessor.Calculate() 28 85% 1.3
UserService.CreateUser() 15 100% 0.0
Action items:
ValidateToken()has CRAP > 30 with 0% coverage - test immediately or refactorParseRecord()is complex but has decent coverage - acceptableCreateUser()andCalculate()are well-tested - safe to modify
Coverage Thresholds
Recommended Standards
| Coverage Type | Target | Action |
|---|---|---|
| Line Coverage | > 80% | Good for most projects |
| Branch Coverage | > 60% | Catches conditional logic |
| CRAP Score | < 30 | Maximum for new code |
Configuring Thresholds
Create coverage.props in your repository:
<Project>
<PropertyGroup>
<!-- Coverage thresholds for CI enforcement -->
<CoverageThresholdLine>80</CoverageThresholdLine>
<CoverageThresholdBranch>60</CoverageThresholdBranch>
</PropertyGroup>
</Project>
CI/CD Integration
GitHub Actions
name: Coverage
on:
pull_request:
branches: [main, dev]
jobs:
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Restore tools
run: dotnet tool restore
- name: Run tests with coverage
run: |
dotnet test \
--settings coverage.runsettings \
--collect:"XPlat Code Coverage" \
--results-directory ./TestResults
- name: Generate report
run: |
dotnet reportgenerator \
-reports:"TestResults/**/coverage.opencover.xml" \
-targetdir:"coverage" \
-reporttypes:"Html;MarkdownSummaryGithub;Cobertura"
- name: Upload coverage report
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage/
- name: Add coverage to PR
uses: marocchino/sticky-pull-request-comment@v2
with:
path: coverage/SummaryGithub.md
Azure Pipelines
- task: DotNetCoreCLI@2
displayName: 'Run tests with coverage'
inputs:
command: 'test'
arguments: '--settings coverage.runsettings --collect:"XPlat Code Coverage" --results-directory $(Build.SourcesDirectory)/TestResults'
- task: DotNetCoreCLI@2
displayName: 'Generate coverage report'
inputs:
command: 'custom'
custom: 'reportgenerator'
arguments: '-reports:"$(Build.SourcesDirectory)/TestResults/**/coverage.opencover.xml" -targetdir:"$(Build.SourcesDirectory)/coverage" -reporttypes:"HtmlInline_AzurePipelines;Cobertura"'
- task: PublishCodeCoverageResults@2
displayName: 'Publish coverage'
inputs:
codeCoverageTool: 'Cobertura'
summaryFileLocation: '$(Build.SourcesDirectory)/coverage/Cobertura.xml'
Quick Reference
One-Liner Commands
# Full analysis workflow
rm -rf coverage/ TestResults/ && \
dotnet test --settings coverage.runsettings \
--collect:"XPlat Code Coverage" \
--results-directory ./TestResults && \
dotnet reportgenerator \
-reports:"TestResults/**/coverage.opencover.xml" \
-targetdir:"coverage" \
-reporttypes:"Html;TextSummary"
# View summary
cat coverage/Summary.txt
# Open HTML report (Linux)
xdg-open coverage/index.html
# Open HTML report (macOS)
open coverage/index.html
# Open HTML report (Windows)
start coverage/index.html
Project Standards
| Metric | New Code | Legacy Code |
|---|---|---|
| Line Coverage | 80%+ | 60%+ (improve gradually) |
| Branch Coverage | 60%+ | 40%+ (improve gradually) |
| Maximum CRAP | 30 | Document exceptions |
| High-risk methods | Must have tests | Add tests before modifying |
What Gets Excluded
The recommended coverage.runsettings excludes:
| Pattern | Reason |
|---|---|
[*.Tests]* |
Test assemblies aren't production code |
[*.Benchmark]* |
Benchmark projects |
[*.Migrations]* |
Database migrations (generated) |
GeneratedCodeAttribute |
Source generators |
CompilerGeneratedAttribute |
Compiler-generated code |
ExcludeFromCodeCoverageAttribute |
Explicit developer opt-out |
*.g.cs, *.designer.cs |
Generated files |
*.razor.g.cs |
Blazor component generated code |
*.razor.css.g.cs |
Blazor CSS isolation generated code |
**/Migrations/**/* |
EF Core migrations (auto-generated) |
SkipAutoProps |
Auto-properties (trivial branches) |
When to Update Thresholds
Lower thresholds temporarily for:
- Legacy codebases being modernized (document in README)
- Generated code that can't be modified
- Third-party wrapper code
Never lower thresholds for:
- "It's too hard to test" - refactor instead
- "We'll add tests later" - add them now
- New features - should meet standards from the start
Additional Resources
- Coverlet Documentation: https://github.com/coverlet-coverage/coverlet
- ReportGenerator: https://github.com/danielpalme/ReportGenerator
- CRAP Score Original Paper: http://www.artima.com/weblogs/viewpost.jsp?thread=215899
Decide Fit First
Design Intent
How To Use It
Boundaries And Review