How Impact Radius Analysis Works in CRG: BFS Graph Traversal Explained
Impact radius analysis in CRG (Code-Review-Graph) uses a bidirectional breadth-first search (BFS) over a SQLite graph database to find all code entities affected by file changes, with a default depth of 2 hops.
The impact radius feature—also called blast radius in the codebase—determines which parts of your codebase are at risk when specific files change. This article explains the complete implementation in the tirth8205/code-review-graph repository, from graph storage to the VS Code user interface.
Graph Storage Architecture
The foundation of impact radius analysis is a SQLite database populated by the Python backend. This database contains two core tables:
nodes– code entities (files, classes, functions, methods) with uniquequalified_nameidentifiers and source file referencesedges– relationships includingCALLS,IMPORTS_FROM,DEPENDS_ON, and others
Each node's qualified_name serves as the canonical identifier used throughout the traversal algorithm.
The SqliteReader Class: Database Access Layer
The VS Code extension accesses this database through SqliteReader in src/backend/sqlite.ts. This TypeScript class wraps the better-sqlite3 library and provides typed query helpers for graph operations.
The impact radius implementation lives in SqliteReader.getImpactRadius (lines 40–81 in src/backend/sqlite.ts).
Impact Radius Algorithm: Step-by-Step
The algorithm follows three distinct phases:
Seed Collection
The method receives an array of changed file paths. For each file, it gathers all nodes belonging to that file and builds a seed set of their qualified_name values.
const seeds = new Set<string>();
for (const f of changedFiles) {
for (const node of this.getNodesByFile(f)) {
seeds.add(node.qualifiedName);
}
}
BFS Traversal
Starting from the seed set, the algorithm performs a bidirectional BFS up to a configurable maxDepth (default: 2). For each node in the current frontier:
- Forward traversal: fetches outgoing edges via
getEdgesBySourceto find "who does this node affect?" - Backward traversal: fetches incoming edges via
getEdgesByTargetto find "who depends on this node?"
const visited = new Set<string>();
let frontier = new Set(seeds);
const impacted = new Set<string>();
let depth = 0;
while (frontier.size > 0 && depth < maxDepth) {
const nextFrontier = new Set<string>();
for (const qn of frontier) {
visited.add(qn);
// forward edges
for (const e of this.getEdgesBySource(qn)) {
if (!visited.has(e.targetQualified)) {
nextFrontier.add(e.targetQualified);
impacted.add(e.targetQualified);
}
}
// reverse edges
for (const e of this.getEdgesByTarget(qn)) {
if (!visited.has(e.sourceQualified)) {
nextFrontier.add(e.sourceQualified);
impacted.add(e.sourceQualified);
}
}
}
frontier = nextFrontier;
depth++;
}
The bidirectional approach ensures both downstream and upstream dependencies are captured.
Result Materialization
After BFS completion, the method:
- Resolves seed and impacted
qualified_namevalues to fullGraphNodeobjects - Gathers distinct impacted file paths
- Extracts all edges connecting involved nodes via
getEdgesAmong
The final ImpactRadius object contains:
changedNodes– entities directly in changed filesimpactedNodes– entities reached via the BFSimpactedFiles– distinct files containing impacted nodesedges– all relationships among involved nodes
This mirrors the Python implementation GraphStore.get_impact_radius for cross-language consistency.
User-Facing Command Integration
The codeReviewGraph.showBlastRadius command in src/features/blastRadius.ts (lines 17–68) provides the UI entry point:
// src/features/blastRadius.ts – command registration
vscode.commands.registerCommand('codeReviewGraph.showBlastRadius', async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) return;
// Resolve innermost node at cursor, fallback to file
let targetNode = await reader.getNodeAtCursor(editor.document, position);
const targetFiles = targetNode
? [targetNode.filePath]
: [editor.document.fileName];
// Read user-configured depth
const depth = config.get<number>('blastRadiusDepth', 2);
// Execute impact radius analysis
const radius = reader.getImpactRadius(targetFiles, depth);
// Populate tree view
treeProvider.setImpactRadius(radius);
});
The command:
- Obtains the active editor's file and cursor position
- Resolves the innermost node via
reader.getNodeAtCursor - Falls back to file-level analysis if no specific node is found
- Reads
codeReviewGraph.blastRadiusDepthfrom user configuration - Feeds results into
BlastRadiusTreeProviderfor visualization
Programmatic Usage Examples
From Another Extension Feature
import { SqliteReader } from '../backend/sqlite';
const reader = await SqliteReader.create(dbPath);
const changed = ['/src/utils/fileHelper.ts', '/src/api/userService.ts'];
const radius = reader.getImpactRadius(changed, 3);
console.log('Changed nodes:', radius.changedNodes.length);
console.log('Impacted nodes:', radius.impactedNodes.length);
console.log('Impacted files:', radius.impactedFiles);
Invoking the VS Code Command
vscode.commands.executeCommand('codeReviewGraph.showBlastRadius');
Key Files Reference
| File | Purpose | URL |
|---|---|---|
src/backend/sqlite.ts |
SqliteReader class with getImpactRadius BFS implementation |
source |
src/features/blastRadius.ts |
Command registration and cursor-to-target resolution | source |
src/views/treeView.ts |
BlastRadiusTreeProvider UI component |
source |
src/features/cursorResolver.ts |
Helper for finding nodes at cursor position | source |
Summary
- Impact radius analysis uses bidirectional BFS with configurable depth (default: 2) to find affected code
- The algorithm operates on SQLite graph data with
nodesandedgestables SqliteReader.getImpactRadiusinsrc/backend/sqlite.tscontains the core traversal logic- Both forward and reverse edges are traversed to capture complete dependency chains
- The VS Code command integrates cursor resolution, user configuration, and tree view visualization
Frequently Asked Questions
What is impact radius in CRG?
Impact radius—also called blast radius—is a code analysis feature that identifies which parts of a codebase are affected when specific files change. It answers "what else might break?" by traversing dependency relationships in both directions through a graph representation of your code.
How does the BFS traversal handle cycles in the dependency graph?
The algorithm uses a visited Set to track already-processed qualified_name values. Before adding any node to the next frontier, it checks visited.has() to prevent infinite loops and redundant processing. This ensures termination even with circular dependencies.
Can I configure how far the impact radius search travels?
Yes. The maxDepth parameter controls BFS iterations (default: 2). Users can set codeReviewGraph.blastRadiusDepth in VS Code settings. Deeper searches find more distant relationships but increase computation time and result noise.
Why does the algorithm traverse edges in both directions?
Bidirectional traversal captures both "this node calls/uses others" (outgoing edges) and "other nodes call/depend on this" (incoming edges). This is essential for complete impact analysis—outgoing edges show what your changes might break; incoming edges show what external code depends on your changes.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →