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

> Learn blast radius analysis in code-review-graph. Discover how affected files are computed by traversing the knowledge graph and calculating impact scores for effective code review.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: deep-dive
- Published: 2026-07-26

---

**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`](https://github.com/tirth8205/code-review-graph/blob/main/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`](https://github.com/tirth8205/code-review-graph/blob/main/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`](https://github.com/tirth8205/code-review-graph/blob/main/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`](https://github.com/tirth8205/code-review-graph/blob/main/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`](https://github.com/tirth8205/code-review-graph/blob/main/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:

```bash

# Analyze blast radius of current changes

crg impact

```

This invokes `get_impact_radius_tool` in [`code_review_graph/main.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/main.py), which delegates to the `get_impact_radius` function.

### Python API

Obtain a detailed programmatic report for specific files:

```python
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:

```python
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`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/tools/query.py) (coordination layer) and `get_impact_radius_sql` in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/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`](https://github.com/tirth8205/code-review-graph/blob/main/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.