Blast Radius Analysis in code-review-graph: How Affected Files Are Computed

Blast radius analysis in code-review-graph determines affected files by traversing the knowledge graph from modified nodes, calculating impact scores using edge weights and depth decay, and returning all reachable entities above a configurable threshold.

The code-review-graph project maps relationships between source files, functions, and modules to help developers assess the downstream risk of code changes. Its blast radius analysis feature quantifies this risk by walking the dependency graph starting from modified files and collecting every reachable node within a specified number of hops.

The Two-Layer Architecture

The blast radius implementation splits responsibilities between a user-facing API and a high-performance SQL graph engine.

Public Interface: get_impact_radius

Located in code_review_graph/tools/query.py at lines 105-122, the get_impact_radius function serves as the primary entry point. This tool accepts either an explicit list of changed files or automatically discovers them via git diff, then coordinates with the graph store to produce a human-readable summary. It returns counts of changed nodes, impacted nodes, additional affected files, and assigns a risk rating based on the blast radius size.

Graph Engine: get_impact_radius_sql

The heavy lifting occurs in code_review_graph/graph.py within the get_impact_radius_sql method (declared at lines 71-100, implemented starting at line 742). This method executes an optimized breadth-first search directly in SQLite, utilizing temporary tables to track the algorithm state and avoid Python-level iteration over large graphs.

Step-by-Step Algorithm Execution

The blast radius computation follows a six-phase process that combines seed identification, weighted traversal, and result filtration.

1. Seed Preparation

For every changed file provided, the system retrieves all nodes residing in those files using self.get_nodes_by_file. The qualified names of these nodes populate the _impact_seeds temporary table, establishing the starting points for the traversal. This phase corresponds to lines 996-1000 in graph.py.

2. Edge Weight Configuration

The algorithm applies relationship-specific weights defined in the IMPACT_EDGE_WEIGHTS map (located in code_review_graph/constants.py at lines 421-429). These weights are loaded into the _impact_weights temporary table (lines 383-390) to ensure that different dependency types—such as CALLS versus IMPORTS_FROM—contribute appropriately to the impact calculation.

3. Frontier Initialization

Two additional temporary tables are created: _impact_best tracks the highest score achieved for each node, and _impact_frontier holds nodes queued for expansion. Initially, both tables are seeded with all nodes from _impact_seeds assigned a starting score of 1.0 (lines 511-518).

4. Iterative Graph Expansion

The core traversal runs for a configurable max_depth iterations or until convergence. Each iteration performs the following:

  • Candidate Generation: Joins the current frontier with the edges table in both directions to discover neighbors
  • Score Calculation: Computes candidate scores using the formula score = parent_score × edge_weight × depth_decay, applying the IMPACT_DEPTH_DECAY constant to penalize distant relationships
  • Deduplication: Retains only candidates exceeding both the node's current best score and the global IMPACT_SCORE_FLOOR
  • Frontier Advancement: Surviving candidates replace the previous best scores and become the new frontier

This logic spans lines 585-618 for SQL candidate generation and lines 886-904 for the Python-side loop control.

5. Result Extraction

After traversal completes, the algorithm selects the top max_nodes + 1 entries from _impact_best (the extra row detects result truncation). It joins these against the main nodes table to retrieve full entity data, filters out the original seed nodes, and excludes internal "verilog-kind" nodes. This extraction occurs at lines 909-923.

6. Report Formatting

Finally, get_impact_radius in query.py (lines 124-202) converts raw GraphNode and GraphEdge objects into dictionaries, injects computed impact_score values, and assembles a structured report. When detail_level="minimal", it also generates a qualitative risk rating (low, medium, or high) based on the total count of impacted nodes.

Practical Usage Examples

Command Line Interface

Analyze changes in the current branch using the impact sub-command:


# Analyze blast radius of current changes

crg impact

This invokes get_impact_radius_tool in code_review_graph/main.py, which delegates to the get_impact_radius function.

Python API

Obtain a detailed programmatic report for specific files:

from code_review_graph.tools.query import get_impact_radius

# Analyze last commit (auto-detects changed files via git diff)

report = get_impact_radius(
    changed_files=None,
    max_depth=2,
    max_results=500,
    detail_level="standard"
)

print(report["summary"])

# Output example:

# Blast radius for 3 changed file(s):

#   - 5 nodes directly changed

#   - 27 nodes impacted (within 2 hops)

#   - 4 additional files affected

Direct Graph Store Access

For advanced use cases, interact with the SQLite backend directly:

from code_review_graph.graph import GraphStore

store = GraphStore("/tmp/crg.db")
changed_files = ["src/foo/bar.py", "src/baz/qux.ts"]

impact = store.get_impact_radius_sql(
    changed_files,
    max_depth=3,
    max_nodes=200
)

print(f"Total impacted nodes: {len(impact['impacted_nodes'])}")
print(f"Affected files: {impact['affected_files']}")

Summary

  • Blast radius analysis quantifies change impact by traversing the knowledge graph from modified files to all reachable dependencies.
  • The implementation splits between get_impact_radius in code_review_graph/tools/query.py (coordination layer) and get_impact_radius_sql in code_review_graph/graph.py (graph computation engine).
  • SQLite temporary tables (_impact_seeds, _impact_best, _impact_frontier) enable linear-time traversal even on cyclic graphs.
  • Impact scores decay with distance using IMPACT_DEPTH_DECAY and filter below IMPACT_SCORE_FLOOR.
  • The algorithm handles cyclic dependencies by keeping only the best score per node and terminates when scores fall below the floor or max_depth is reached.

Frequently Asked Questions

How does blast radius analysis handle cyclic dependencies in the graph?

The algorithm prevents infinite loops by maintaining the _impact_best table, which stores only the highest score achieved for each node. If a traversal path revisits a node with a lower score than previously recorded, the candidate is discarded. This ensures the analysis remains linear in complexity even when encountering circular import or call chains.

What determines the edge weights in the blast radius calculation?

Edge weights are controlled by the IMPACT_EDGE_WEIGHTS dictionary defined in code_review_graph/constants.py (lines 421-429). Different relationship types—such as CALLS, IMPORTS_FROM, or INHERITS_FROM—receive distinct weight values that reflect their semantic coupling strength. These weights are multiplied against the parent score during traversal to quantify how strongly a dependency propagates impact.

How does the depth decay parameter affect the results?

The IMPACT_DEPTH_DECAY constant (defined alongside edge weights) reduces the impact score multiplicatively as the algorithm moves farther from the original changes. This ensures that direct neighbors receive full weight consideration while transitive dependencies at maximum depth contribute fractionally. Combined with max_depth, this parameter constrains the blast radius to meaningful, high-probability affected regions rather than the entire codebase.

What is the difference between changed nodes and impacted nodes?

Changed nodes are entities (functions, classes, or variables) physically located within the modified files—these populate the _impact_seeds table. Impacted nodes are entities discovered during graph traversal that depend upon or are depended upon by the changed nodes, excluding the seeds themselves. The final report separately tallies these categories and lists additional files affected by impacted nodes to give reviewers a complete picture of the change surface area.

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 →