# How Execution Flow Detection Traces Call Chains in code-review-graph

> Discover how execution flow detection traces call chains in code review graphs. Learn about entry point discovery and breadth-first search for detailed call chain construction.

- Repository: [Tirth Kanani/code-review-graph](https://github.com/tirth8205/code-review-graph)
- Tags: how-to-guide
- Published: 2026-07-19

---

**The execution flow detection subsystem discovers entry points using multiple heuristics and then follows outgoing CALLS edges with a breadth-first search to construct complete call chains.**

The **code-review-graph** repository implements a sophisticated static analysis pipeline that maps execution flows through Python codebases. This article examines how the system located in `tirth8205/code-review-graph` identifies program entry points and traces call chains using graph traversal algorithms.

## How Entry Points Are Identified

The `detect_entry_points` function (lines 64-88 of [`code_review_graph/flows.py`](https://github.com/tirth8205/code-review-graph/blob/main/code_review_graph/flows.py)) serves as the foundation of the execution flow detection system. It scans every `Function` and `Test` node in the graph, applying three distinct heuristics to identify where code execution begins.

### Root Functions Without Incoming Calls

The system first identifies **true root** functions—those with no incoming CALLS edges. This check relies on `store.get_all_call_targets` (line 78) to build a comprehensive set of all qualified names that serve as call targets. Any function not present in this set qualifies as an entry point since no other code invokes it.

### Framework Decorator Detection

Modern Python frameworks use decorators to mark entry points. The `_has_framework_decorator` function (lines 29-40) checks nodes against regex patterns stored in `_FRAMEWORK_DECORATOR_PATTERNS`. When a function carries a decorator matching patterns for Flask, Django, FastAPI, or similar frameworks, the system flags it as an entry point regardless of its call graph position.

### Conventional Naming Patterns

The `_matches_entry_name` function (lines 44-50) implements pattern matching against `_ENTRY_NAME_PATTERNS`. Functions named `main`, `cli`, or following common CLI framework conventions trigger automatic entry point classification.

### Test File Filtering

By default, the system excludes test files from entry point detection unless `include_tests=True` is specified. The `_is_test_file` helper (lines 54-61) filters out nodes residing in test directories or files matching test naming conventions.

## Tracing Call Chains with BFS

Once entry points are established, the system employs breadth-first search to follow execution paths through the codebase.

### Flow Adjacency Structure

The `FlowAdjacency` object provides the `calls_out` mapping—a dictionary connecting each qualified name to its set of callee qualified names. This adjacency structure is populated by `store.load_flow_adjacency` and enables efficient forward traversal without repeated database queries.

### The BFS Traversal Algorithm

The `_trace_single_flow` function (lines 22-64) implements the core tracing logic. Starting from a single entry point, it initializes a queue containing the root node's qualified name. The algorithm then enters a loop (lines 41-58) that:

1. Dequeues the current node
2. Retrieves its outgoing CALLS edges from `calls_out`
3. Enqueues any unvisited callees
4. Records traversal order in `path_ids` and `path_qnames`

The process tracks `actual_depth` to respect the `max_depth` parameter, preventing infinite loops in recursive codebases. When the traversal completes with more than one node, the function assembles a flow dictionary (lines 69-79) containing the complete call chain.

## Orchestrating Flow Detection and Criticality Scoring

The `trace_flows` function (lines 84-100) orchestrates the complete pipeline. It first obtains the entry point list, loads the adjacency structure once for efficiency, then invokes `_trace_single_flow` for each entry point. 

After construction, flows undergo criticality analysis via `compute_criticality` (lines 24-93). This scoring algorithm evaluates five weighted factors:

- **File spread**: How many distinct files the flow touches
- **External calls**: Interactions with libraries or system calls
- **Security keywords**: Presence of sensitive operations defined in [`constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/constants.py)
- **Test coverage gap**: Execution paths lacking test coverage
- **Depth**: The length of the call chain

The resulting 0.0-1.0 score determines flow importance, with `trace_flows` sorting results by criticality (line 115) before returning them.

## Code Example: Tracing Execution Flows

The following example demonstrates how to trace execution flows using the public API:

```python
from code_review_graph.graph import GraphStore
from code_review_graph.flows import trace_flows, get_flows

# Initialize a populated graph store after parsing a repository

store = GraphStore(db_path=":memory:")

# Trace all execution flows excluding test entry points

all_flows = trace_flows(store, max_depth=15, include_tests=False)

# Retrieve the top 5 most critical flows

top_five = get_flows(store, sort_by="criticality", limit=5)
for flow in top_five:
    print(f"Flow {flow['name']} – criticality {flow['criticality']:.2f}")

```

For incremental analysis after code changes, use `incremental_trace_flows(store, changed_files)` to re-trace only flows intersecting modified files rather than rebuilding the entire graph.

## Summary

- **Entry point detection** in [`flows.py`](https://github.com/tirth8205/code-review-graph/blob/main/flows.py) (lines 64-88) uses three heuristics: missing incoming CALLS edges, framework decorators, and conventional naming patterns.
- **Breadth-first search** in `_trace_single_flow` (lines 22-64) follows outgoing CALLS edges through the `FlowAdjacency` structure to build complete call chains.
- **Flow orchestration** via `trace_flows` (lines 84-100) processes all entry points and loads adjacency data once for performance.
- **Criticality scoring** weighs file spread, external dependencies, security keywords, test coverage, and call depth to rank flows by importance.
- **Incremental tracing** supports efficient updates when only specific files change.

## Frequently Asked Questions

### How does the system identify entry points without manual configuration?

The system automatically discovers entry points through static analysis heuristics implemented in `detect_entry_points`. It identifies functions with no incoming CALLS edges as roots, detects framework decorators like `@app.route` using regex patterns in `_FRAMEWORK_DECORATOR_PATTERNS`, and recognizes conventional names such as `main` or `cli` via `_ENTRY_NAME_PATTERNS`.

### What is the maximum depth for call chain tracing?

The `max_depth` parameter in `trace_flows` controls traversal limits, with the BFS algorithm tracking `actual_depth` during execution. While configurable per invocation, the default prevents excessive recursion in deep call graphs while ensuring complete coverage of shallow execution paths.

### How is flow criticality calculated?

The `compute_criticality` function (lines 24-93) calculates a 0.0-1.0 score based on weighted factors including cross-file dependencies, external library usage, security-sensitive keywords defined in [`constants.py`](https://github.com/tirth8205/code-review-graph/blob/main/constants.py), gaps in test coverage, and the maximum BFS depth reached during tracing.

### Can the system trace flows incrementally after code changes?

Yes. The `incremental_trace_flows` function accepts a list of changed files and re-traces only flows intersecting those modifications. This avoids rebuilding the entire call graph when updating the analysis after small commits or pull request changes.