How code-review-graph Calculates Blast Radius from Code Changes Using Impact Radius Analysis

TLDR: code-review-graph calculates the blast radius of code changes by traversing forward from modified files through dependency and test relationships, scoring reachable nodes by the inverse of their path length to surface the most directly impacted symbols.

The tirth8205/code-review-graph repository implements a blast radius analysis that quantifies how deeply a code change propagates through a codebase. By treating the repository as a graph of symbols and their relationships, the system computes an impact radius that identifies not just what changed, but everything that could break as a result.

The Three-Stage Impact Radius Pipeline

The core logic resides in code_review_graph/graph.py and executes in three distinct stages to transform a list of file paths into a ranked set of impacted symbols.

Step 1: Seed Creation (_impact_seed_qns)

For every file in the change set, the system collects all graph nodes belonging to that file. In _impact_seed_qns (lines 1295–1315), the code queries the graph store to find qualified names for each symbol in the changed files. For C# files, it additionally extracts declared namespace strings—these act as bridges for import relationships even though they lack dedicated node rows. This collection becomes the seed set for the traversal.

Step 2: Traversal Engine Selection (CRG_BFS_ENGINE)

Before walking the graph, the system selects a traversal backend based on the CRG_BFS_ENGINE environment variable. This logic appears in get_impact_radius (lines 1317–1348):

  • sqlite (default): Runs a bounded best-score relaxation algorithm entirely within SQLite.
  • networkx: A legacy Python-side breadth-first search using the NetworkX library.

The SQLite engine is preferred for large codebases because it avoids materializing the entire path in Python memory.

Step 3: Impact-Radius Computation (get_impact_radius_sql)

The actual blast radius calculation happens in get_impact_radius_sql (lines 1451–1488) and follows this sequence:

Seeding: Qualified names are written to a temporary table named _impact_seeds.

Iterative expansion: A series of SQL statements repeatedly join the seed table with the graph’s edge tables (including DEPENDS_ON and TESTED_BY). Each iteration propagates an impact score—calculated as the inverse of the path length—to downstream nodes. The traversal respects configurable limits defined in code_review_graph/constants.py: MAX_IMPACT_DEPTH controls the recursion depth, while MAX_IMPACT_NODES caps the total nodes visited.

Result aggregation: When the relaxation finishes, the method returns:

  • changed_nodes: Symbols residing directly in changed files.
  • impacted_nodes: Reachable symbols ordered by descending impact score.
  • impacted_files: Distinct files containing impacted symbols.
  • edges: Connections between the seed set and impacted nodes.
  • impact_scores: A mapping from qualified name to its best-path score, where higher values indicate shorter, more direct dependencies.

Why This Defines "Blast Radius"

The algorithm follows dependency-shaped edges (e.g., function calls) forward from production code toward its callers, and also tracks TESTED_BY edges linking code to its test suites. This produces a forward-reachability set representing everything that could be affected by the change. Because impact scores prioritize shorter paths, reviewers can immediately identify symbols most at risk of breakage.

Practical Usage Examples

You can invoke the blast radius calculation through the Python API or the CLI wrapper.

Python API

from code_review_graph.tools.query import get_impact_radius

# Files modified in the current commit

changed = ["/repo/auth.py", "/repo/models/user.py"]

# Calculate blast radius with depth limit of 2

radius = get_impact_radius(changed, max_depth=2)

print("Impacted nodes:")
for node in radius["impacted_nodes"]:
    print(f"- {node['qualified_name']} (score={node['impact_score']})")

Command Line Interface

The CLI wraps the same logic via get_impact_radius_tool defined in code_review_graph/main.py:

code-review-graph get-impact-radius \
    --files /repo/auth.py /repo/models/user.py \
    --max-depth 2

Both methods ultimately call GraphStore.get_impact_radius, which delegates to get_impact_radius_sql when CRG_BFS_ENGINE=sqlite.

Key Source Files for Blast Radius Analysis

File Role
code_review_graph/graph.py Core graph representation, seed generation (_impact_seed_qns), public API get_impact_radius, and the SQLite-based get_impact_radius_sql implementation.
code_review_graph/tools/query.py Convenience wrapper exposing get_impact_radius to users and the CLI.
code_review_graph/main.py Defines the CLI sub-command get-impact-radius-tool that forwards arguments to the graph store.
code_review_graph/constants.py Defines default traversal limits MAX_IMPACT_DEPTH and MAX_IMPACT_NODES.

Summary

  • Seed creation gathers all symbols from changed files (and C# namespaces) to establish the starting points for traversal.

  • Engine selection via CRG_BFS_ENGINE chooses between a high-performance SQLite relaxation algorithm or a legacy NetworkX BFS.

  • Impact scoring propagates through DEPENDS_ON and TESTED_BY edges, assigning higher scores to nodes reachable via shorter paths.

  • Configuration limits (MAX_IMPACT_DEPTH, MAX_IMPACT_NODES) prevent unbounded graph explosions in large repositories.

  • The resulting blast radius includes impacted_nodes, impacted_files, and impact_scores to prioritize code review efforts.

Frequently Asked Questions

How does the algorithm handle indirect dependencies?

The SQLite-based relaxation engine iteratively joins the _impact_seeds table with edge tables, propagating scores through each hop. It continues until reaching MAX_IMPACT_DEPTH or exhausting MAX_IMPACT_NODES, capturing indirect dependencies up to the configured limit. Each additional hop reduces the impact score because the score is the inverse of the path length.

Why does the system use SQLite for traversal instead of NetworkX?

The sqlite engine (the default) executes the best-score relaxation entirely inside the database, avoiding the memory overhead of materializing large graph paths in Python. This makes it suitable for enterprise-scale codebases where NetworkX would exhaust memory.

What edge types contribute to the blast radius calculation?

The traversal specifically follows DEPENDS_ON edges (representing calls, imports, and inheritance) and TESTED_BY edges (linking production code to its test suites). This dual focus ensures the blast radius includes both potential runtime breakages and affected test coverage.

Where are the default depth and node limits configured?

Defaults are defined as constants in code_review_graph/constants.py. MAX_IMPACT_DEPTH controls how many hops the traverser takes from the seed set, while MAX_IMPACT_NODES sets an absolute ceiling on the number of distinct symbols visited during the analysis.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →