# How code-review-graph Performs Blast-Radius Analysis for Code Changes

> Learn how code-review-graph performs blast-radius analysis on code changes. Discover affected code entities and impact severity using a SQLite-based algorithm.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: how-to-guide
- Published: 2026-08-13

---

**Blast-radius analysis in code-review-graph identifies all potentially affected code entities by traversing the program graph from modified files using a SQLite-based best-score relaxation algorithm that applies depth-decay multipliers to rank impact severity.**

The `code-review-graph` open-source tool helps developers understand the potential impact of code changes before they merge. Its **blast-radius analysis** feature calculates how far a modification ripples through the codebase by walking relationships between functions, classes, and their dependents. This analysis lives primarily in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py) and exposes both a Python API and CLI for integration into review workflows.

## How the Blast-Radius Algorithm Works

The core logic resides in `Graph.get_impact_radius` within [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py). The system accepts a list of changed file paths and returns every logical code entity that could be affected, weighted by a calculated impact score.

### Entry Point and Engine Dispatch

Analysis begins when the CLI command `crg impact …` or the Python tool `get_impact_radius_tool` forwards changed file paths to `store.get_impact_radius`. According to the source in [`code_review_graph/main.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/main.py) around line 220, the implementation routes to `Graph.get_impact_radius`, which selects between two engines:

- **SQLite engine** (default): Uses temporary tables and SQL-based traversal for high performance
- **NetworkX engine** (legacy): Activated by setting the environment variable `CRG_BFS_ENGINE=networkx`

The dispatch logic at line 1317 in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py) automatically chooses the fast SQLite path unless explicitly overridden.

### Seed Preparation and Initialization

Before traversal begins, the system identifies **seed nodes** representing the changed files. The algorithm creates a temporary table named `_impact_seeds` populated with the qualified names of modified nodes, each assigned an initial score of `1.0`. This initialization occurs between lines 1392 and 1402 in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py), establishing the starting frontier for the graph walk.

### Best-Score Relaxation in SQL

The SQLite implementation uses an iterative **best-score relaxation** technique expressed through temporary tables `_impact_frontier`, `_impact_next`, and `_impact_best`. For each iteration:

1. The algorithm expands the current frontier to neighboring nodes
2. It multiplies the current score by the edge weight (retrieved from the `extra` column or defaulted to `1.0`) and the `IMPACT_DEPTH_DECAY` factor (approximately `0.5`)
3. It keeps only the highest score per node, discarding lower-scoring paths to the same entity

This logic appears between lines 1439 and 1464 in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py). The depth-decay mechanism ensures that transitive dependencies receive exponentially lower impact scores than direct callers.

### Termination Criteria and Results

Expansion continues until the frontier becomes empty or all scores fall below `IMPACT_SCORE_FLOOR`. The termination check and final result assembly happen between lines 1464 and 1556. During assembly:

- Nodes are sorted by descending impact score
- File-type nodes are intentionally omitted, returning only logical code entities (functions, classes, etc.)
- The method returns both the list of impacted nodes and a mapping of `impact_scores[qualified_name] → score`

### NetworkX Fallback Implementation

When `CRG_BFS_ENGINE=networkx` is set, the system falls back to a straightforward breadth-first search on a NetworkX `DiGraph` built from the same edge table. This implementation, found between lines 1564 and 1580 in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py), functionally mirrors the SQL approach but executes much slower due to Python-level traversal overhead.

## Configuring Impact Scoring

The blast-radius calculation exposes several parameters to balance precision against performance:

- **`IMPACT_DEPTH_DECAY`** – Each hop away from the modified code multiplies the score by approximately `0.5`, ensuring distant dependencies receive lower priority
- **`IMPACT_SCORE_FLOOR`** – The minimum score threshold for continued traversal; nodes scoring below this value terminate expansion along that path
- **`max_depth`** – Limits the traversal depth (CLI flag `--depth` or environment variable `CRG_MAX_IMPACT_DEPTH`). The default value of `2` captures direct callers and immediate dependents, covering over 90% of real-world regressions while maintaining fast query execution

Edge weights are extracted from the `extra` column of the edge table when available, defaulting to `1.0` for unweighted relationships.

## Usage Examples

### Querying Blast Radius via Python API

```python
from code_review_graph.main import GraphStore

store = GraphStore(repo_path="/my/project")
changed = ["/my/project/src/auth.py"]

# Analyze with default depth of 2

impact = store.get_impact_radius(changed, max_depth=2)

print("Impacted nodes:")
for node in impact["impacted_nodes"]:
    score = impact["impact_scores"][node.qualified_name]
    print(f"- {node.kind}: {node.qualified_name} (score={score:.2f})")

```

### Command Line Interface

```bash

# Analyze specific files with custom depth

$ crg impact src/auth.py --depth 3
Wide blast radius: 27 impacted symbols
  1. function login (score 1.00)
  2. function check_credentials (score 0.50)
  3. function validate_token (score 0.25)

```

### Integration in Review Workflows

```python
from code_review_graph.tools.review import review_pr

# Automatically add blast-radius warnings to PR reviews

summary = review_pr(
    repo_path="/my/project",
    pr_number=42,
    max_depth=2,
)

# summary contains: "Wide blast radius: 27 impacted nodes"

print(summary)

```

## Summary

- **Blast-radius analysis** walks the program graph from modified files to identify affected logical entities using `Graph.get_impact_radius` in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py)
- The default **SQLite engine** uses temporary tables (`_impact_seeds`, `_impact_frontier`, `_impact_best`) and iterative best-score relaxation with depth decay
- **NetworkX fallback** provides a slower but equivalent BFS implementation when `CRG_BFS_ENGINE=networkx` is set
- Impact scores decay exponentially via `IMPACT_DEPTH_DECAY` (≈0.5 per hop) and terminate below `IMPACT_SCORE_FLOOR`
- **File nodes are excluded** from final results, returning only logical code symbols like functions and classes
- The API supports **`max_depth`** configuration (default 2) via the `get_impact_radius` parameter or `--depth` CLI flag

## Frequently Asked Questions

### How does the algorithm handle circular dependencies?

The best-score relaxation mechanism naturally handles cycles by keeping only the highest score per node in the `_impact_best` temporary table. If a cycle is encountered, subsequent visits to an already-processed node with lower scores are discarded, preventing infinite loops while preserving the strongest impact path through the cycle.

### What is the performance difference between the SQLite and NetworkX engines?

The **SQLite engine** performs traversal entirely within the database engine using set-based SQL operations, making it significantly faster for large codebases. The **NetworkX fallback** builds a `DiGraph` in memory and executes Python-level BFS, which incurs substantial overhead according to the implementation in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py) lines 1564-1580. The SQLite path is preferred for production use.

### Can I adjust how quickly the impact score decays with depth?

While the internal `IMPACT_DEPTH_DECAY` is hardcoded to approximately `0.5`, you can effectively control sensitivity through the **`max_depth`** parameter. Increase `--depth` via CLI or `max_depth` via the Python API to analyze deeper transitive dependencies. Limiting depth to the default of `2` captures direct callers and immediate dependents while keeping queries fast.

### Why are file nodes excluded from the blast-radius results?

The algorithm intentionally filters out file-type nodes during result assembly in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py) (lines 1529-1556) because **logical code entities** (functions, classes, methods) provide more actionable review feedback than entire files. This filtering ensures reviewers focus on specific callable units rather than being overwhelmed by broad file-level notifications.