debtmap 0.16.6

Code complexity and technical debt analyzer
Documentation
# Profiling Audit Report

## Overview

Complete audit of all `time_span!` macro usages in debtmap to identify and validate correct timing instrumentation patterns.

**Date**: 2026-03-12
**Total spans audited**: 12 (production code)
**Issues found**: 1 (fixed in commit 0a58e595)
**Regression tests added**: Yes (commit 1f4609d1)

## Audit Results

### All Spans by File

#### src/builders/unified_analysis.rs (7 spans)

| Line | Name | Pattern | Status |
|------|------|---------|--------|
| 105 | `unified_analysis` | Unconditional, top-level | ✅ CORRECT |
| 132 | `call_graph_building` | Unconditional, in always-executed block | ✅ CORRECT |
| 185 | `typescript_call_graph` | Inside `if !js_ts_files.is_empty()` | ✅ FIXED |
| 213 | `coverage_loading` | Unconditional, in always-executed block | ✅ CORRECT |
| 251 | `purity_analysis` | Unconditional, in always-executed block | ✅ CORRECT |
| 263 | `context_loading` | Unconditional, in always-executed block | ✅ CORRECT |
| 287 | `debt_scoring` | Unconditional, in always-executed block | ✅ CORRECT |

#### src/commands/analyze/project_analysis.rs (4 spans)

| Line | Name | Pattern | Status |
|------|------|---------|--------|
| 97 | `analyze_project` | Unconditional, top-level | ✅ CORRECT |
| 162 | `file_discovery` | Unconditional, at function start | ✅ CORRECT |
| 211 | `parsing` | Unconditional, at function start | ✅ CORRECT |
| 350 | `duplication_detection` | Unconditional, at function start | ✅ CORRECT |

#### src/risk/context/git_history/function_level.rs (1 span)

| Line | Name | Pattern | Status |
|------|------|---------|--------|
| 191 | `git_function_history` | Unconditional, at function start | ✅ CORRECT |

## Issues Found & Fixed

### Issue #1: Unconditional TypeScript Timing (FIXED)

**Location**: src/builders/unified_analysis.rs:185
**Severity**: Low (0.01% performance impact)
**Fix**: Commit 0a58e595

**Problem**:
```rust
time_span!("typescript_call_graph", parent: "unified_analysis");  // ❌ WRONG
if !js_ts_files.is_empty() {
    // ... process TypeScript files
}
```

The timing span was created unconditionally, causing:
- Profiling reports to show `typescript_call_graph` entries for Rust-only codebases
- ~10ms of spurious timing in the profiling report (0.01% overhead)

**Solution**:
```rust
if !js_ts_files.is_empty() {
    time_span!("typescript_call_graph", parent: "unified_analysis");  // ✅ CORRECT
    // ... process TypeScript files
}
```

Move the timing span inside the conditional guard that protects the actual work.

## Pattern Guidelines

### ✅ CORRECT Patterns

**Unconditional Top-Level**
```rust
pub fn analyze_project() -> Result<Analysis> {
    time_span!("analyze_project");  // ✓ Always called
    // ... implementation
}
```

**Unconditional in Always-Executed Blocks**
```rust
let result = {
    time_span!("phase");  // ✓ Block always executes
    // ... work
};
```

**Conditional Timing (Pattern)**
```rust
if has_files {
    time_span!("process_files");  // ✓ Inside guard that protects work
    process_files();
}
```

### ❌ WRONG Patterns

**Unconditional Timing in Conditional Block**
```rust
time_span!("operation");  // ❌ Created unconditionally
if has_data {
    process_data();       // But work is conditional
}
```

**Timing Outside Guard**
```rust
time_span!("typescript_graph");  // ❌ WRONG
if !ts_files.is_empty() {
    build_graph();
}
```

## Regression Tests

Two tests were added to prevent regression (commit 1f4609d1):

### test_conditional_timing_not_recorded_when_guard_is_false

Validates that timing spans inside false conditionals are not recorded:

```rust
let files: Vec<String> = vec![];  // Empty
if !files.is_empty() {
    time_span!("conditional_operation");
    // ...
}
// Assertion: timing should NOT be recorded
```

### test_language_specific_timing_not_in_rust_only_codebase

Ensures language-specific timing doesn't appear for Rust-only projects:

```rust
let js_ts_files = vec![];  // No TypeScript files
if !js_ts_files.is_empty() {
    time_span!("typescript_call_graph");
}
// Assertion: typescript_call_graph should NOT appear in profiling report
```

## Risk Assessment

**Regression Risk**: LOW
- Pattern is simple and explicit
- Tests validate correct behavior
- No unconditional patterns remain

**Performance Impact**: NEGLIGIBLE
- Only affected Rust-only codebases (very common case)
- Eliminated ~10ms of spurious timing
- Zero overhead when pattern is correct

## Recommendations

1. **No immediate action needed** - All remaining 11 spans are correct
2.**Tests in place** - Regression prevention established
3. 📋 **Code review guideline** - Add to PR template:
   - "Timing spans should be placed inside conditionals that guard work"
   - "All unconditional spans must always execute"

## Related Commits

- `0a58e595` - fix(profiling): Skip TypeScript timing if no files
- `1f4609d1` - test(profiling): Add tests for conditional timing patterns

## Future Improvements

Consider these enhancements to the profiling system:

1. **Hierarchical Guards Macro** - Combine work guard + timing:
   ```rust
   time_if!("operation", !files.is_empty() => {
       process_files();
   });
   ```

2. **Parent Validation** - Warn about orphaned spans in reports

3. **Per-Phase Filtering** - Enable profiling for specific phases only

4. **Timing Assertions** - Validate operations complete within expected time ranges