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

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

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) performs a classic breadth-first search on an in-memory NetworkX graph:


# 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

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.

Command Line Interface

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, with result formatting handled by code_review_graph/tools/query.py.

MCP Tool Integration

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, exposing the algorithm to MCP clients.

Key Configuration Constants

The algorithm behavior is controlled by constants in 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.

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 →