Metrics Reference
Comprehensive guide to all signals measured by Debtmap and how to interpret them.
Debtmap acts as a sensor, providing quantified signals about code complexity and risk. These signals are designed for consumption by AI coding tools and developers alike.
Metric Categories (Spec 118)
Debtmap distinguishes between two fundamental categories of metrics:
Measured Metrics
Definition: Metrics directly computed from the Abstract Syntax Tree (AST) through precise analysis.
These metrics are:
- Deterministic: Same code always produces the same metric value
- Precise: Exact counts from syntax analysis, not estimates
- Suitable for thresholds: Reliable for CI/CD quality gates
- Language-specific: Computed using language parsers (syn for Rust, tree-sitter for others)
Measured metrics include:
| Metric | Description | Example |
|---|---|---|
cyclomatic_complexity | Count of decision points (if, match, while, for, etc.) | Function with 3 if statements = complexity 4 |
cognitive_complexity | Weighted measure of code understandability | Nested loops increase cognitive load |
nesting_depth | Maximum levels of nested control structures | 3 nested if statements = depth 3 |
loc | Lines of code in the function | Physical line count |
parameter_count | Number of function parameters | fn foo(a: i32, b: String) = 2 |
Estimated Metrics
Definition: Heuristic approximations calculated using formulas, not direct AST measurements.
These metrics are:
- Heuristic: Based on mathematical formulas and assumptions
- Approximate: Close estimates, not exact counts
- Useful for prioritization: Help estimate effort and risk
- Not suitable for hard thresholds: Use for relative comparisons, not absolute gates
Estimated metrics include:
| Metric | Formula | Purpose | Example |
|---|---|---|---|
est_branches | max(nesting, 1) × cyclomatic ÷ 3 | Estimate test cases needed for branch coverage | Complexity 12, nesting 3 → ~12 branches |
Important: The est_branches metric was previously called branches. It was renamed in Spec 118 to make it explicit that this is an estimate, not a precise count from the AST.
Why the Distinction Matters
For Code Quality Gates
# GOOD: Use measured metrics for CI/CD thresholds
debtmap validate . --threshold-complexity 15
# AVOID: Don't use estimated metrics for hard gates
# (est_branches is not exposed as a threshold flag)
Rationale: Measured metrics are deterministic and precise, making them suitable for build-breaking quality gates.
For Prioritization
# GOOD: Use est_branches for prioritization
debtmap analyze . --top 10 # Sorts by est_branches (among other factors)
# GOOD: Estimated metrics help understand testing effort
debtmap analyze . --lcov coverage.info --verbose
Rationale: Estimated metrics provide useful heuristics for understanding where to focus testing and refactoring efforts.
For Comparison Across Codebases
- Measured metrics: Comparable across projects (cyclomatic 10 means the same everywhere)
- Estimated metrics: Project-specific heuristics (est_branches depends on nesting patterns)
Detailed Metric Descriptions
Cyclomatic Complexity (Measured)
What it measures: The number of linearly independent paths through a function’s control flow.
How it’s calculated:
- Start with a base of 1
- Add 1 for each decision point:
if,else ifmatcharmswhile,for,loop&&,||in conditions?operator (early return)
Example:
#![allow(unused)]
fn main() {
fn example(x: i32, y: i32) -> bool {
if x > 0 { // +1
if y > 0 { // +1
true
} else { // implicit in if/else
false
}
} else if x < 0 { // +1
false
} else {
y == 0 // no additional branches
}
}
// Cyclomatic complexity = 1 + 3 = 4
}
Thresholds:
- 1-5: Simple, easy to test
- 6-10: Moderate, manageable complexity
- 11-20: Complex, consider refactoring
- 21+: Very complex, high maintenance cost
Cognitive Complexity (Measured)
What it measures: How difficult the code is for humans to understand.
How it differs from cyclomatic:
- Weights nested structures more heavily (nested if is worse than sequential if)
- Ignores shorthand structures (early returns, guard clauses)
- Focuses on readability, not just logic paths
Example:
#![allow(unused)]
fn main() {
fn cyclomatic_low_cognitive_low(status: Status) -> bool {
match status { // Cyclomatic: 4, Cognitive: 1
Status::Active => true,
Status::Pending => false,
Status::Closed => false,
Status::Error => false,
}
}
fn cyclomatic_low_cognitive_high(x: i32, y: i32, z: i32) -> bool {
if x > 0 {
if y > 0 { // Nested: +2 cognitive penalty
if z > 0 { // Deeply nested: +3 cognitive penalty
return true;
}
}
}
false
}
// Cyclomatic: 4, Cognitive: 7 (nesting penalty applied)
}
Thresholds:
- 1-5: Easy to understand
- 6-10: Moderate mental load
- 11-15: Difficult to follow
- 16+: Refactor recommended
Estimated Branches (Estimated)
What it estimates: Approximate number of execution paths that would need test coverage.
Formula:
est_branches = max(nesting_depth, 1) × cyclomatic_complexity ÷ 3
Why this formula:
- Nesting multiplier: Deeper nesting creates more combinations
- Cyclomatic base: Higher complexity → more paths
- ÷ 3 adjustment: Empirical factor to align with typical branch coverage needs
Example scenarios:
| Cyclomatic | Nesting | est_branches | Interpretation |
|---|---|---|---|
| 3 | 1 | 1 | Simple linear code |
| 12 | 1 | 4 | Multiple sequential branches |
| 12 | 3 | 12 | Nested conditions, many paths |
| 20 | 5 | 33 | Complex nested logic |
Use cases:
- Estimating test case requirements
- Prioritizing untested complex code
- Understanding coverage gaps
Limitations:
- Not a precise count: This is a heuristic approximation
- Don’t use for coverage percentage calculation: Use actual coverage tools
- Varies by code style: Heavily nested code scores higher
Terminology Change (Spec 118)
Before: branches
Previously, this metric was displayed as branches=X, which was confusing because:
- Users thought it was a precise count from AST analysis
- It was mistaken for cyclomatic complexity (actual branch count)
- The estimation nature was not obvious
After: est_branches
Now displayed as est_branches=X to:
- Make estimation explicit: “est_” prefix indicates this is approximate
- Avoid confusion: Clearly different from cyclomatic complexity
- Set correct expectations: Users know this is a heuristic, not a measurement
Migration Guide
Terminal Output:
- Old:
COMPLEXITY: cyclomatic=12, branches=8, cognitive=15 - New:
COMPLEXITY: cyclomatic=12, est_branches=8, cognitive=15
Code:
- Internal variable names updated from
branchestoest_branches - Comments added explaining the estimation formula
JSON Output:
- No change: The ComplexityMetrics struct does not include this field
est_branchesis calculated on-demand for display purposes only
Practical Usage Examples
Example 1: Code Quality Gate
# Fail build if any function exceeds cyclomatic complexity 15
debtmap validate . --threshold-complexity 15 --max-high 0
# Why: Cyclomatic is measured, precise, and repeatable
Example 2: Prioritize Testing Effort
# Show top 10 functions by risk (uses est_branches in scoring)
debtmap analyze . --lcov coverage.info --top 10
# Functions with high est_branches and low coverage appear first
Example 3: Understanding Test Requirements
# Verbose output shows est_branches for each function
debtmap analyze . --verbose
# Output:
# └─ COMPLEXITY: cyclomatic=12, est_branches=8, cognitive=15, nesting=2
#
# Interpretation: ~8 test cases likely needed for good branch coverage
Example 4: Explaining Metrics to Team
# Display comprehensive metric definitions
debtmap analyze --explain-metrics
# Shows:
# - Measured vs Estimated categories
# - Formulas and thresholds
# - When to use each metric
Metric Selection Guide
When to Use Cyclomatic Complexity
✅ Use for:
- CI/CD quality gates
- Code review guidelines
- Consistent cross-project comparison
- Identifying refactoring candidates
❌ Don’t use for:
- Estimating test effort (use est_branches)
- Readability assessment (use cognitive complexity)
When to Use Cognitive Complexity
✅ Use for:
- Readability reviews
- Identifying hard-to-maintain code
- Onboarding difficulty assessment
❌ Don’t use for:
- Test coverage planning
- Strict quality gates (more subjective than cyclomatic)
When to Use est_branches
✅ Use for:
- Estimating test case requirements
- Prioritizing test coverage work
- Understanding coverage gaps
❌ Don’t use for:
- CI/CD quality gates (it’s an estimate)
- Calculating coverage percentages (use actual coverage data)
- Cross-project comparison (formula is heuristic)
Combining Metrics for Insights
High Complexity, Low Coverage
cyclomatic=18, est_branches=12, coverage=0%
Interpretation: High-risk code needing ~12 test cases for adequate coverage.
Action: Prioritize writing tests, consider refactoring.
High Cyclomatic, Low Cognitive
cyclomatic=15, cognitive=5
Interpretation: Many branches, but simple linear logic (e.g., validation checks).
Action: Acceptable pattern, tests should be straightforward.
Low Cyclomatic, High Cognitive
cyclomatic=8, cognitive=18
Interpretation: Deeply nested logic, hard to understand despite fewer branches.
Action: Refactor to reduce nesting, extract functions.
High est_branches, Low Cyclomatic
cyclomatic=9, nesting=5, est_branches=15
Interpretation: Deep nesting creates many path combinations.
Action: Flatten nesting, use early returns, extract nested logic.
Frequently Asked Questions
Q: Why is est_branches different from cyclomatic complexity?
A: Cyclomatic is the measured count of decision points. est_branches is an estimated number of execution paths, calculated using nesting depth to account for path combinations.
Q: Can I use est_branches in CI/CD thresholds?
A: No. Use measured metrics (cyclomatic_complexity, cognitive_complexity) for quality gates. est_branches is a heuristic for prioritization, not a precise measurement.
Q: Why did the metric name change from “branches” to “est_branches”?
A: To make it explicit that this is an estimate, not a measured value. Users were confused, thinking it was a precise count from the AST.
Q: How accurate is est_branches for estimating test cases?
A: It’s a rough approximation. Actual test case requirements depend on:
- Business logic complexity
- Edge cases
- Error handling paths
- Integration points
Use est_branches as a starting point, not an exact requirement.
Q: Should I refactor code with high est_branches?
A: Not necessarily. High est_branches indicates complex logic that may need thorough testing. If the logic is unavoidable (e.g., state machines, complex business rules), focus on comprehensive test coverage rather than refactoring.
Signal Categories Summary
| Category | Signals | Purpose |
|---|---|---|
| Complexity | cyclomatic, cognitive, nesting, loc | How hard code is to understand |
| Coverage | line_percent, branch_percent | How risky changes are |
| Coupling | fan_in, fan_out, call_depth | How changes ripple |
| Quality | entropy, purity, dead_code | False positive reduction |
Using Signals with AI
When piping debtmap output to an AI assistant, signals provide the context needed for intelligent fixes:
# Get structured signals for AI consumption
debtmap analyze . --format markdown --top 5 | claude "Fix the top item"
The AI uses these signals to:
- Understand code complexity before reading it
- Prioritize which files to examine first
- Decide between refactoring vs testing approaches
- Estimate the scope of changes needed
Further Reading
- Why Debtmap? - Sensor model explained
- LLM Integration - AI workflow patterns
- Configuration - Threshold customization
- Scoring Strategies - How signals combine