Skip to main content
Background Image
  1. Blog/

Debtmap 0.16.7: Faster Code Debt Analysis for Real Repositories

Author
Glen Baker
Building tech startups and open source tooling
Table of Contents

Static analysis tools usually get judged by what they find. That is fair, but incomplete.

If a tool takes too long to run, it stops being part of the development loop. Developers stop using it locally. Teams stop running it on every pull request. Eventually it becomes a scheduled report that people read only when something is already painful.

Debtmap is built for a different workflow: run it while you are deciding what to refactor, while you are reviewing risk, and before a pull request makes technical debt worse.

The 0.16.7 release makes that workflow faster.

cargo install debtmap
debtmap analyze . --profile

Version 0.16.7 focuses on three hot paths:

  • Call graph construction from extracted data
  • File line counting during debt scoring
  • Function-level git history used by context-aware risk analysis

The theme is simple: do expensive work once, index the result, then make the scoring pass cheap.

Why Speed Matters for Technical Debt Tools
#

Technical debt analysis is only useful when it changes behavior.

That means the tool needs to fit into common engineering moments:

  • Before starting a refactor: “Where is the real risk?”
  • During code review: “Did this change add debt?”
  • Before release: “What untested complexity are we shipping?”
  • During cleanup planning: “Which files are worth touching first?”

Those questions do not tolerate a slow feedback loop. If the analyzer takes minutes on a normal repository, people stop asking it questions.

Debtmap does more than count lines and branches. It builds call graphs, correlates complexity with coverage, detects architectural issues, analyzes god objects, and can include contextual risk signals such as dependency importance and git history.

That richer analysis has to stay fast enough to use. Debtmap 0.16.7 is about tightening the parts of the pipeline where richer analysis was doing repeated work.

1. Indexed Call Graph Resolution
#

Debtmap has a unified extraction pipeline for Rust, Python, JavaScript, and TypeScript. That extraction phase records functions and call sites. The call graph builder then connects callers to callees.

Before 0.16.7, extracted callee resolution repeatedly searched through extracted file data while processing call sites. That approach is straightforward, but it has a bad shape on larger repositories:

for each file:
  for each function:
    for each call:
      search same file
      maybe search all files
      maybe search method names

That means the same function lists get walked over and over.

In 0.16.7, debtmap builds a callee resolution index once:

  • Same-file function lookup by qualified name and short name
  • Global qualified-function lookup
  • Method-name lookup with deterministic first-match behavior

The result is a cheaper lookup path during call graph construction. Direct calls first check the caller file index, then fall back to the qualified function index. Method calls use a method index that preserves deterministic behavior.

This matters because the call graph is not just a report artifact. It feeds downstream scoring:

  • Entry point detection
  • Caller and callee counts
  • Test-only function filtering
  • Dependency-aware prioritization
  • Contextual recommendations

Making call graph construction faster makes the rest of the analyzer feel faster.

2. Reused Line Count Cache During Debt Scoring
#

Line counts sound trivial until they happen in the wrong place.

Debtmap uses line counts in file-level debt scoring and recommendations. The correct pattern is to count each file once at the I/O boundary, keep that data in memory, and pass it into the pure scoring pipeline.

That is what the sequential path already did. The 0.16.7 change brings the same behavior into the parallel unified analysis path.

Before the change, part of the parallel scoring path could fall back to an empty cache, which meant scoring code had to recover by reading line counts again. That is exactly the kind of hidden repeated I/O that makes a fast analyzer feel inconsistent.

The fix is small but important:

  • Build a shared file line count cache from enriched metrics
  • Store it on the parallel analysis builder
  • Pass it into metric-to-debt-item conversion
  • Keep file reading at the boundary instead of inside scoring

This follows debtmap’s core architecture: pure computation in the center, I/O at the edge.

It also makes the performance model easier to reason about. File size metadata is collected once, then reused wherever scoring needs it.

3. Function-Level Git History Preloading
#

Context-aware analysis is one of debtmap’s most useful features.

Raw complexity is not enough. A complex function that changes every week and has three authors is different from a complex function that has been stable for two years. A function with low test coverage and high churn deserves attention sooner.

That is why debtmap can use git history as a context provider:

debtmap analyze . --context

The expensive version of this idea is obvious: ask git about each function independently.

That does not scale. Function-level history can require introduction detection, modification detection, and author attribution. If each function triggers its own history walk, a large repository pays the same repository traversal cost again and again.

Debtmap 0.16.7 changes that flow.

The git history provider now preloads function histories through the git2 provider. It groups function targets by file, performs repository-wide scanning once, computes file history from the same commit scan, and uses per-file blame data for author attribution.

The preloaded data then becomes an O(1) lookup during scoring:

load context:
  scan repository history once
  group function history by file and name
  cache author data by file

score functions:
  lookup function history from cache

This is the right tradeoff for an analysis tool. Pay the unavoidable git cost once, expose progress while it runs, then keep the scoring pass moving.

The TUI and analysis progress reporting were updated too. When context analysis is enabled, debtmap now reports git history preload progress in terms of commit scanning and author attribution. That is useful for large repositories where the most expensive work should be visible, not mysterious.

Built With Profiling in Mind
#

Debtmap includes a profiling flag because performance work should be measured, not guessed:

debtmap analyze . --profile

You can also write timing data to JSON:

debtmap analyze . --profile --profile-output timing.json

The profiling report breaks down analysis phases such as parsing, call graph building, unified analysis, and debt scoring. That is how these 0.16.7 improvements were targeted: identify repeated work, move it out of hot loops, and make the optimized path explicit.

There is a broader lesson here for static analysis tools. Performance problems often come from reasonable local decisions:

  • “Just search the extracted files here.”
  • “Just read the line count if the cache is empty.”
  • “Just ask git for this function.”

Each decision is fine once. It becomes expensive when multiplied by every function, every call site, or every file in a repository.

The fix is not cleverness. It is data flow:

  • Extract once
  • Index once
  • Cache boundary data once
  • Pass immutable context into parallel scoring

Why This Helps Real Repositories
#

Real repositories are messy in ways benchmarks often hide.

They have many files. They have generated code. They have tests, examples, framework glue, and old modules that are still important. They have functions that look similar by name but live in different modules. They have git histories long enough to make naive history analysis painful.

Debtmap 0.16.7 improves the parts of the analyzer that hit those realities:

  • More call sites means indexing matters more
  • More files means line-count caching matters more
  • More history means batched git analysis matters more

The goal is not to make a toy benchmark look good. The goal is to keep debtmap usable on the kind of repository where technical debt analysis is actually needed.

Try Debtmap
#

Debtmap is open source and available on crates.io:

cargo install debtmap
debtmap analyze .

For context-aware risk analysis:

debtmap analyze . --context

For performance profiling:

debtmap analyze . --profile

Repository: github.com/iepathos/debtmap

Debtmap 0.16.7 is a performance release in the most practical sense: fewer repeated searches, fewer repeated reads, fewer repeated git history queries. The analyzer does the same deeper work, but it spends less time rediscovering facts it already knows.

Related

Debtmap Re-adds JavaScript and TypeScript Support
Refactoring a God Object Detector That Was Itself a God Object
Automating Documentation Maintenance with Prodigy: A Real-World Case Study
Debtmap - Rust Technical Debt Analyzer
Pure Core, Imperative Shell in Rust with Stillwater
Stillwater 1.0: Pragmatic Effect Composition and Validation for Rust