How Execution Flows Are Traced Through the Call Graph in code-review-graph
The code-review-graph package traces execution flows by detecting entry points in a SQLite-backed knowledge graph and performing a breadth-first search (BFS) over CALLS edges to generate linear execution paths with criticality scores.
The code-review-graph repository builds a static analysis toolchain that maps codebase structure into a queryable graph. Understanding how execution flows are traced through the call graph enables developers to identify critical paths, analyze test coverage, and prioritize code review efforts.
Detecting Entry Points in the Call Graph
The detect_entry_points function in code_review_graph/flows.py (lines 64-81) identifies functions that can initiate program execution. It evaluates every Function and Test node against three distinct criteria to determine if it qualifies as an entry point.
True Root Functions
Functions with no inbound CALLS edges—meaning nothing else in the codebase invokes them—are flagged as potential entry points. The implementation queries store.get_all_call_targets() at line 179 to build a set of called qualified names, then filters for nodes absent from that set.
Framework-Specific Decorators
The analyzer scans for framework decorators using regex patterns defined in _FRAMEWORK_DECORATOR_PATTERNS (lines 26-71). When a node's extra["decorators"] field matches patterns for Flask (@app.get), Click (@click.command), Spring (@GetMapping), or similar frameworks, the _has_framework_decorator helper (line 29) marks it as an entry point.
Conventional Entry Names
Functions matching naming conventions in _ENTRY_NAME_PATTERNS (lines 73-84) are automatically classified as entry points. These patterns include common names like main, handle_*, and lambda_handler, evaluated by the _matches_entry_name function (line 44).
Loading the Flow Adjacency Structure
To avoid expensive SQLite lookups during traversal, GraphStore.load_flow_adjacency in code_review_graph/graph.py (lines 1493-1527) materializes the graph into a FlowAdjacency dataclass. This in-memory structure contains:
nodes_by_qn: Maps qualified names toGraphNodeobjectsnodes_by_id: Maps node IDs toGraphNodeobjectscalls_out: Dictionary mapping source qualified names to lists of target qualified names for CALLS edgeshas_tested_by: Set of qualified names with TESTED_BY edges for criticality calculations
BFS Traversal of Execution Flows
With entry points identified and the adjacency structure loaded, the system traces execution flows using breadth-first search.
Tracing Individual Execution Paths
The _trace_single_flow function (lines 222-260 in flows.py) implements a forward BFS starting from each entry point. It initializes a queue with the entry point's qualified name at depth 0, then iteratively processes each node by recording its ID and enqueueing unvisited callees from calls_out. The traversal respects a configurable max_depth parameter (default 15) and discards trivial flows containing fewer than two nodes.
Criticality Scoring and Flow Assembly
For each valid flow, the system calculates a criticality score based on factors including test coverage (using the has_tested_by set) and flow depth. The resulting dictionary contains the ordered path of node IDs, distinct files touched, depth metrics, and the computed criticality value.
Complete Execution Flow Pipeline
The trace_flows function (lines 284-316) orchestrates the complete process:
def trace_flows(
store: GraphStore,
max_depth: int = 15,
include_tests: bool = False,
) -> list[dict]:
entry_points = detect_entry_points(store, include_tests=include_tests)
adj = store.load_flow_adjacency()
flows = []
for ep in entry_points:
flow = _trace_single_flow(adj, ep, max_depth)
if flow:
flows.append(flow)
flows.sort(key=lambda f: f["criticality"], reverse=True)
return flows
This pipeline first identifies entry points, loads the adjacency structure once, traces each entry point via BFS, and returns flows sorted by criticality.
Practical Code Examples
Tracing Production Flows
To analyze all production execution flows while excluding test-only entry points:
from code_review_graph.graph import GraphStore
from code_review_graph.flows import trace_flows
store = GraphStore("my-repo-graph.db")
all_flows = trace_flows(store, max_depth=20, include_tests=False)
for flow in all_flows[:5]:
print(f"Flow {flow['entry_point']} → depth {flow['depth']}")
print(" nodes:", flow["path"])
print(" criticality:", flow["criticality"])
Incremental Re-tracing After Changes
When specific files change, incremental_trace_flows updates only affected flows without rebuilding the entire graph:
from code_review_graph.flows import incremental_trace_flows
changed_files = ["src/services.py", "src/api/routes.py"]
re_traced = incremental_trace_flows(store, changed_files, max_depth=15)
print(f"Re-traced {re_traced} flows after modifications")
Retrieving Detailed Flow Information
To access step-by-step details for a specific flow:
from code_review_graph.flows import get_flow_by_id
flow_detail = get_flow_by_id(store, flow_id=42)
print("Flow name:", flow_detail["name"])
for step in flow_detail["steps"]:
print(f"{step['qualified_name']} ({step['file']}:{step['line_start']}-{step['line_end']})")
Summary
- Entry point detection combines static analysis of call targets, framework decorators, and naming conventions to identify flow origins in
code_review_graph/flows.py. - Flow adjacency loading materializes the SQLite graph into RAM via
load_flow_adjacencyincode_review_graph/graph.pyto enable fast traversal. - BFS traversal in
_trace_single_flowexplores call relationships up to a configurable depth, filtering trivial flows and calculating criticality scores. - The complete
trace_flowspipeline returns execution paths sorted by criticality, enabling targeted code review and analysis.
Frequently Asked Questions
What constitutes an entry point in the code-review-graph system?
An entry point is any function identified by detect_entry_points that has no inbound CALLS edges, uses recognized framework decorators like @app.get or @click.command, or matches conventional naming patterns such as main or lambda_handler. These functions represent potential starting points for program execution.
How does the system handle large codebases efficiently?
The system loads all nodes and CALLS edges into a FlowAdjacency structure in memory using load_flow_adjacency, eliminating repeated database queries during BFS traversal. This approach reduces the tracing of execution flows through the call graph to simple dictionary lookups.
What is the default maximum depth for flow tracing and why?
The default max_depth is 15 levels, configured in the trace_flows and _trace_single_flow functions. This limit prevents infinite loops in recursive call patterns and ensures analysis completes in bounded time while still capturing meaningful execution contexts.
How are execution flows prioritized in the output?
Flows are sorted by a criticality score computed during tracing. This score incorporates factors such as whether the flow includes tested code (via TESTED_BY edges) and the complexity of the call chain, with higher criticality flows appearing first in the returned list.
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 →