# How Blast Radius Analysis Works in code-review-graph: Knowledge Graph Traversal Explained

> Understand how code-review-graph's blast radius analysis works. Learn about weighted BFS and knowledge graph traversal to assess code impact and manage risk effectively.

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

---

**`code-review-graph` determines blast radius by performing a weighted breadth-first search (BFS) through the knowledge graph, starting from modified files and traversing relationships until the impact score falls below a configurable floor or the maximum hop depth is reached.**

The **blast radius analysis** feature in `tirth8205/code-review-graph` quantifies how far-reaching a code change might be by tracing dependencies through a SQLite-backed knowledge graph. Unlike simple file-based impact detection, this system accounts for semantic relationships—such as function calls, imports, and inheritance—assigning decaying weights as the distance from the change increases.

## Core Components of the Blast Radius Engine

The implementation splits responsibilities between a high-level Python API and a optimized SQL-based graph traversal.

### The Public Tool 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) (lines 105–122), the `get_impact_radius` function serves as the primary entry point. It prepares the analysis by resolving file paths—either from an explicit list or via `git diff`—and delegates the computational work to the graph store. After retrieval, it formats the raw results into a human-readable summary containing counts of changed nodes, impacted nodes, affected files, and a computed risk rating.

### The SQLite Graph Traversal (`GraphStore.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 (starting around line 742). This implementation uses temporary tables and iterative SQL queries to perform the traversal directly inside SQLite, ensuring linear performance even on cyclic graphs. It creates five temporary tables during execution: `_impact_seeds`, `_impact_weights`, `_impact_best`, `_impact_frontier`, and `_impact_next`.

## Step-by-Step Blast Radius Algorithm

The algorithm proceeds through six distinct phases, combining seed initialization with iterative frontier expansion.

### 1. Seed Preparation

For every modified file, the system retrieves all contained nodes using `self.get_nodes_by_file` and inserts their qualified names into the `_impact_seeds` temporary table (lines 996–1000 in [`graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/graph.py)). These seeds represent the ground truth of what changed, receiving an initial impact score of 1.0.

### 2. Edge Weight Configuration

The algorithm loads relationship weights from the `IMPACT_EDGE_WEIGHTS` mapping defined in [`code_review_graph/constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/constants.py) (lines 421–429) into the `_impact_weights` table (lines 383–390). This allows different edge types—such as `CALLS` or `IMPORTS_FROM`—to contribute varying levels of impact to the traversal.

### 3. Frontier Initialization

Two additional temporary tables are initialized (lines 511–518):
- `_impact_best` tracks the highest score achieved for any visited node
- `_impact_frontier` contains the nodes to expand during the current iteration

Both tables are seeded with the initial nodes from `_impact_seeds` at score 1.0.

### 4. Iterative Expansion and Scoring

For each depth iteration up to `max_depth`, the algorithm performs the following operations (lines 585–618 and the control loop at 886–904):

- Joins the current frontier with the `edges` table in both directions to discover neighbors
- Calculates candidate scores using the formula: `score = parent_score × edge_weight × depth_decay`
- Applies the `IMPACT_DEPTH_DECAY` factor to reduce influence as distance increases
- Filters candidates against `IMPACT_SCORE_FLOOR` to eliminate negligible impacts
- Updates `_impact_best` only when a candidate exceeds the current best score for that node, preventing cycles from inflating scores

### 5. Result Extraction

Once the BFS terminates, the query selects the top `max_nodes + 1` rows from `_impact_best` (lines 909–923). The extra row serves solely to detect truncation. The algorithm joins these results back to the `nodes` table to retrieve full metadata, filtering out seed nodes and internal "verilog-kind" nodes.

### 6. Risk Assessment and Formatting

The `get_impact_radius` wrapper in [`query.py`](https://github.com/tirth8205/code-review-graph/blob/main/query.py) (lines 124–202) converts the raw `GraphNode` and `GraphEdge` objects into dictionaries. When `detail_level="minimal"`, it assigns a risk rating—low, medium, or high—based on the total count of impacted nodes, providing immediate triage guidance for code reviewers.

## Practical Usage Examples

### Analyzing Changes via CLI

The command-line interface exposes blast radius analysis through the `impact` sub-command defined in [`code_review_graph/main.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/main.py):

```bash

# Analyze the blast radius of uncommitted changes

crg impact

# Analyze a specific commit range

crg impact --base HEAD~3 --head HEAD

```

### Python API Integration

For programmatic access, import the query tool directly:

```python
from code_review_graph.tools.query import get_impact_radius

report = get_impact_radius(
    changed_files=None,      # Auto-detect via git diff

    max_depth=2,
    max_results=500,
    detail_level="standard"
)

print(report["summary"])

# Output: 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

Advanced users can bypass the wrapper to interact with the database layer:

```python
from code_review_graph.graph import GraphStore

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

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

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

```

## Configuration and Tuning Constants

The behavior of the blast radius analysis is governed by constants in [`code_review_graph/constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/constants.py):

- **`IMPACT_EDGE_WEIGHTS`**: Dictionary mapping relationship types (e.g., `CALLS`, `INHERITS_FROM`) to numerical weights
- **`IMPACT_DEPTH_DECAY`**: Float value (typically < 1.0) multiplied at each hop to attenuate distant impacts
- **`IMPACT_SCORE_FLOOR`**: Minimum score threshold; nodes scoring below this value are excluded from results

Modifying these constants allows customization for different codebase densities and review strictness requirements.

## Summary

- **Blast radius analysis** in `code-review-graph` performs a weighted BFS through a SQLite knowledge graph to measure change impact.
- The **`get_impact_radius`** function in [`code_review_graph/tools/query.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/tools/query.py) provides the public API, handling input resolution and output formatting.
- **`GraphStore.get_impact_radius_sql`** in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py) implements the core algorithm using temporary tables and iterative SQL to achieve linear time complexity.
- Impact scores decay multiplicatively based on **edge weights** and **depth decay**, ensuring distant relationships contribute less than immediate dependencies.
- The system supports both **CLI usage** (`crg impact`) and **programmatic access**, with configurable thresholds for depth, score floors, and result limits.

## Frequently Asked Questions

### How does code-review-graph prevent infinite loops in cyclic graphs?

The algorithm stores the best-known score for each node in the `_impact_best` temporary table. During each iteration, a candidate node only updates the frontier if its newly calculated score exceeds the existing best score for that node. As scores monotonically decrease due to `IMPACT_DEPTH_DECAY`, cycles cannot propagate indefinitely, ensuring the query terminates in linear time relative to the number of edges traversed.

### What determines the risk rating in the blast radius report?

When `detail_level="minimal"` is specified, the `get_impact_radius` function assigns a risk rating based on the cardinality of impacted nodes. Low risk indicates minimal downstream effects, medium risk suggests moderate dependency chains, and high risk signals extensive potential breakage. The specific thresholds are calculated dynamically based on the total nodes discovered within the configured `max_depth` and `max_results` constraints.

### Can I customize which relationship types affect the blast radius calculation?

Yes. The `IMPACT_EDGE_WEIGHTS` dictionary in [`code_review_graph/constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/constants.py) (around lines 421–429) defines how much each edge type contributes to the impact score. You can modify these weights before database initialization or extend the mapping to include custom relationship types defined in your knowledge graph schema. Setting a weight to 0.0 effectively excludes that relationship from the traversal.

### Why does the algorithm use temporary SQLite tables instead of Python data structures?

Temporary tables leverage SQLite's query optimizer and index structures to handle large graphs efficiently. By performing the frontier expansion, score comparison, and cycle detection within the database engine, the system avoids loading the entire graph into memory. This approach maintains consistent performance even when analyzing repositories with millions of nodes and edges, as the working set remains bounded by the current frontier rather than the full dataset.