# Blast Radius Analysis Algorithm vs BFS: How code-review-graph Calculates Code Impact

> Discover the blast radius analysis algorithm and how it improves upon BFS for code impact analysis in dense graphs. Learn about efficient pathfinding.

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

---

**The blast radius analysis algorithm is a bounded, weighted, best-score propagation method that differs from BFS by storing only the highest-scoring path per node rather than exploring all frontier paths, avoiding exponential blowup in dense cyclic graphs.**

The blast radius analysis is the core routine in [tirth8205/code-review-graph](https://github.com/tirth8205/code-review-graph) that identifies which parts of a codebase are likely affected by changed files. Unlike a standard breadth-first search, the default implementation uses a **SQLite-based best-score relaxation** that trades complete path exploration for scalability and performance.

## How the Blast Radius Analysis Algorithm Works

The primary implementation lives in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py) as `GraphStore.get_impact_radius()`. It propagates impact scores from seed nodes (changed files) through the dependency graph using edge-specific weights and directional semantics.

### Core Mechanism: Best-Score Relaxation

The algorithm executes an iterative SQL-based relaxation starting at line 1478:

1. **Seed initialization**: Changed files are inserted into `_impact_seeds`
2. **Best-score tracking**: The `_impact_best` table maintains only the highest impact score per node
3. **Frontier expansion**: Each iteration joins `_impact_frontier` with the `edges` table, applying weights from `_impact_policies`
4. **Depth decay**: `IMPACT_DEPTH_DECAY` reduces scores at each hop
5. **Early pruning**: `IMPACT_SCORE_FLOOR` drops negligible paths before they expand

The SQL loop terminates when `MAX_IMPACT_DEPTH` or `MAX_IMPACT_NODES` is reached. This bounded approach keeps memory usage flat regardless of graph density.

### Edge Semantics and Weighting

Edge types carry distinct influence weights defined in [`code_review_graph/constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/constants.py):

| Edge Type | Typical Weight | Direction |
|-----------|---------------|-----------|
| `IMPORTS_FROM` | 1.0 | Forward (dependency) |
| `IMPORTED_BY` | 0.9 | Reverse (dependents) |
| `TESTED_BY` | 0.7 | Reverse (test coverage) |

The `_impact_policies` temp table configures these per-edge behaviors, allowing fine-grained control over how different relationship types propagate impact.

## How BFS Differs in the Legacy Implementation

The `_get_impact_radius_networkx()` method (starting at line 1564 in [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py)) performs a **classic breadth-first search** on an in-memory NetworkX graph:

```python

# Simplified conceptual flow of the NetworkX BFS approach

frontier = set(changed_files)
for depth in range(max_depth):
    next_frontier = set()
    for node in frontier:
        for neighbor in graph.neighbors(node):
            score = current_score * edge_weight * (IMPACT_DEPTH_DECAY ** depth)
            # BFS keeps ALL paths, not just best scores

            next_frontier.add(neighbor)
    frontier = next_frontier

```

Key characteristics of this BFS approach:

- **Complete frontier expansion**: Maintains all reachable nodes at each depth level
- **No early pruning of inferior paths**: Multiple paths to the same node are all explored
- **Memory growth**: Frontier size can explode in dense graphs with many cycles
- **Python-side processing**: Requires full graph materialization in memory

## Critical Differences: Blast Radius vs BFS

| Aspect | Blast Radius (SQLite Best-Score) | Legacy BFS (NetworkX) |
|--------|----------------------------------|------------------------|
| **Memory model** | SQL temp tables, fixed overhead | In-memory NetworkX graph |
| **Path strategy** | Single best score per node | All frontier paths retained |
| **Time complexity** | O(d × E') where d = depth, E' = edges touched | O(b^d) worst-case in branching factor b |
| **Cycle handling** | Naturally acyclic via best-score dominance | Requires explicit visited tracking |
| **Scalability** | Tested on hundreds of thousands of edges | Struggles with large dense graphs |
| **Result precision** | Monotonic: higher score always means stronger impact | Same final scores, more work to compute |

The blast radius algorithm's **best-score dominance** property means that once a node receives a score of 0.8 from one path, a later path offering 0.3 can be discarded immediately. BFS cannot apply this optimization without modifying its fundamental structure.

## Using the Blast Radius Algorithm

### Python API

```python
from code_review_graph.graph import GraphStore

store = GraphStore(db_path="crg.db")

impact = store.get_impact_radius(
    changed_files=["src/core/engine.py", "src/api/routes.py"],
    max_depth=3,      # Maximum dependency hops

    max_nodes=500     # Hard limit on returned results

)

# Results sorted by descending impact score

for file in impact["impacted_files"][:10]:
    print(f"{file['path']}: {file['impact_score']:.3f}")

```

This invokes the SQLite relaxation at lines 1317-1360 of [`code_review_graph/graph.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/graph.py).

### Command Line Interface

```bash
code-review-graph impact \
  --depth 2 \
  --max-results 300 \
  --base HEAD~1 \
  src/core/engine.py src/api/routes.py

```

The CLI handler is defined at line 1068 in [`code_review_graph/cli.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/cli.py), with result formatting handled by [`code_review_graph/tools/query.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/tools/query.py).

### MCP Tool Integration

```python
await get_impact_radius_tool(
    changed_files=["src/core/engine.py"],
    max_depth=2,
    max_results=200,
    repo_root="/path/to/repo",
    base="main"
)

```

The tool wrapper is defined at line 220 in [`code_review_graph/main.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/main.py), exposing the algorithm to MCP clients.

## Key Configuration Constants

The algorithm behavior is controlled 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`: Base multipliers per relationship type
- `IMPACT_EDGE_DIRECTIONS`: Which direction to traverse (`"outgoing"`, `"incoming"`, `"both"`)
- `IMPACT_DEPTH_DECAY`: Score multiplier per hop (default typically 0.9)
- `IMPACT_SCORE_FLOOR`: Minimum score to continue propagation
- `MAX_IMPACT_DEPTH`: Hard depth limit
- `MAX_IMPACT_NODES`: Result set size limit

## Summary

- **Blast radius analysis** uses **best-score relaxation** in SQLite, keeping only the highest-impact path to each node
- **BFS explores all paths**, causing exponential work in dense graphs while producing identical final scores
- The SQLite implementation scales to **hundreds of thousands of edges** with fixed memory overhead
- Edge-specific **weights and directions** allow semantic control over how different relationship types propagate impact
- Both modes respect `max_depth` and `max_nodes` limits, but the SQL engine enforces them more efficiently

## Frequently Asked Questions

### What makes the blast radius algorithm faster than BFS on large codebases?

The blast radius algorithm avoids materializing the full graph in Python and discards inferior paths immediately via best-score tracking. The SQL-based implementation processes edges in set-oriented batches rather than iterating Python objects, and temporary tables provide O(1) lookup for current best scores per node.

### When should I use the legacy NetworkX BFS implementation?

The NetworkX BFS in `_get_impact_radius_networkx()` exists primarily for verification and debugging. It may be useful when you need to audit all possible impact paths rather than just the strongest ones, or when diagnosing discrepancies in the SQL relaxation results. For production use on real codebases, the SQLite method is strongly preferred.

### How does the depth decay factor affect results?

`IMPACT_DEPTH_DECAY` (typically 0.9) multiplies the impact score at each hop away from changed files. A file three dependencies away receives approximately 0.9³ = 0.729 of its direct edge weight. Combined with `IMPACT_SCORE_FLOOR`, this ensures distant, weakly-connected nodes don't clutter results while preserving high-impact transitive dependencies.

### Can the algorithm handle circular dependencies?

Yes. The best-score relaxation naturally handles cycles because a node's score only updates when a strictly better path is found. In a cycle, scores converge to fixed points or are pruned by the floor threshold. The BFS implementation requires explicit cycle detection via visited sets to prevent infinite loops.