How Execution Flows Are Detected and Prioritized by Criticality in code-review-graph

The code-review-graph library identifies execution entry points using framework decorators and naming conventions, performs a breadth-first search to trace call paths, and calculates a weighted criticality score from 0.0 to 1.0 based on file spread, security sensitivity, and test coverage gaps.

The tirth8205/code-review-graph repository provides a static analysis toolkit that maps execution flows through codebases to highlight high-risk paths for review. Understanding how the system detects entry points and quantifies criticality helps teams prioritize code review efforts on the most impactful logic paths.

Detecting Entry Points in code-review-graph

Entry point detection drives the entire analysis pipeline. In code_review_graph/flows.py, the detect_entry_points function (lines 64–78) identifies starting nodes by evaluating three distinct criteria.

True Root Detection

A node qualifies as a true root if it has no incoming CALLS edges. The algorithm builds a set called called_qnames containing all target qualified names from CALLS edges, then verifies whether the node's qualified name exists in this set. Nodes absent from the set represent uncalled functions that potentially serve as application entry points.

Framework Decorator Patterns

The system recognizes framework-specific decorators through _has_framework_decorator(node), which scans the node's decorators metadata against _FRAMEWORK_DECORATOR_PATTERNS. This list includes patterns for Flask, FastAPI, Click, Spring, and other common web and CLI frameworks, automatically flagging decorated functions as entry points regardless of their call graph position.

Conventional Naming Conventions

The _matches_entry_name(node) helper checks against _ENTRY_NAME_PATTERNS and _LANGUAGE_ENTRY_NAME_PATTERNS, identifying names like main, __main__, test_*, on_*, lambda_handler, and Android lifecycle methods. Any function or test node matching these patterns joins the entry_points list (lines 71–78).

Tracing Execution Flows with BFS Traversal

Once entry points are identified, trace_flows initiates path discovery by calling _trace_single_flow (lines 22–30) for each starting node.

The tracer performs a forward BFS on the CALLS adjacency structure (adj.calls_out), respecting a configurable max_depth parameter that defaults to 15 levels. During traversal, the algorithm accumulates node IDs and qualified names in path_ids and path_qnames, tracking visited nodes to prevent cycles. Single-node flows are discarded as trivial (lines 60–62).

Each resulting flow dictionary contains metadata including name, entry_point, path, depth, node_count, file_count, and an initial criticality value of 0.0 (lines 70–79).

Computing Criticality Scores for Prioritization

The compute_criticality function (lines 24–93) in code_review_graph/flows.py transforms flow metadata into a prioritized score between 0.0 and 1.0 using five weighted factors:

  • File spread (30%): Calculated as min((file_count‑1)/4, 1), rewarding flows that touch multiple files
  • External calls (20%): Computed as min(external_count/5, 1), penalizing dependencies on unanalyzed code
  • Security sensitivity (25%): Derived from constants.SECURITY_KEYWORDS matches in node names, calculated as min(security_hits/len(nodes), 1)
  • Test coverage gap (15%): Represented as 1 - coverage, where coverage measures nodes with TESTED_BY relationships
  • Depth (10%): Scored as min(depth/10, 1), favoring deeper execution paths

The final score equals the weighted sum of these components (lines 86–92), rounded to four decimal places before storage (lines 80–81).

Persisting and Querying Flow Data

After computation, store_flows persists flow records to SQLite tables flows and flow_memberships, linking nodes to their respective execution paths.

For retrieval, get_flows (lines 88–106) returns flows sorted by criticality by default, surfacing the highest-risk paths first. For CI/CD integration, incremental_trace_flows (lines 58–78) retraces only flows intersecting changed files, reducing analysis time for large repositories during incremental reviews.

Code Example: Detecting and Prioritizing Flows

from code_review_graph.graph import GraphStore
from code_review_graph.flows import trace_flows, get_flows, incremental_trace_flows

# 1️⃣ Load the graph store (assume an existing SQLite DB at `mydb.sqlite`).

store = GraphStore(sqlite_path="mydb.sqlite")

# 2️⃣ Full flow detection and scoring (default depth = 15).

all_flows = trace_flows(store)          # → list of dicts, each with a `criticality` field

print(f"Found {len(all_flows)} execution flows")
print("Top‑3 most critical flows:")
for fl in all_flows[:3]:
    print(f"- {fl['name']} (criticality={fl['criticality']})")

# 3️⃣ Query stored flows (e.g., the 10 most critical ones).

top_stored = get_flows(store, limit=10)
for f in top_stored:
    print(f"{f['name']} → criticality {f['criticality']}")

# 4️⃣ Incremental re‑trace after editing a few files.

changed = ["src/web/app.py", "src/services/payment.py"]
retracked = incremental_trace_flows(store, changed_files=changed)
print(f"Re‑traced {retracked} flows that touched changed files")

This snippet demonstrates the core API: trace_flows for full analysis, get_flows for retrieval, and incremental_trace_flows for efficient re-analysis after code changes.

Summary

  • Entry detection relies on three criteria: uncalled roots, framework decorators, and conventional naming patterns defined in code_review_graph/flows.py
  • Flow tracing uses forward BFS with a default depth limit of 15, filtering out trivial single-node paths
  • Criticality scoring weights file spread (30%), security sensitivity (25%), external calls (20%), test gaps (15%), and depth (10%) into a 0.0–1.0 scale
  • Persistence uses SQLite tables flows and flow_memberships, with incremental tracing available for optimized CI/CD workflows

Frequently Asked Questions

What defines an entry point in code-review-graph?

An entry point is any Function or Test node that satisfies at least one of three conditions: it has no incoming CALLS edges (a true root), it carries a framework decorator matching patterns in _FRAMEWORK_DECORATOR_PATTERNS, or its name matches conventional patterns like main, test_*, or lambda_handler. The detect_entry_points function evaluates these criteria against the graph's nodes to seed the flow analysis.

How is the criticality score calculated?

The criticality score ranges from 0.0 to 1.0 and combines five weighted factors computed in compute_criticality: file spread (30%), security sensitivity based on keyword matches (25%), external call density (20%), test coverage gaps (15%), and execution depth (10%). Each factor normalizes to a 0–1 scale before the weighted sum produces the final priority value.

When should I use incremental tracing versus full flow detection?

Use incremental_trace_flows when analyzing pull requests or commits that modified specific files, as it retraces only flows touching the changed files rather than the entire codebase. Full trace_flows detection remains appropriate for initial database creation or comprehensive audits where the complete call graph might have shifted.

Which security keywords affect the criticality calculation?

The security sensitivity factor references constants.SECURITY_KEYWORDS to identify sensitive operations. While the specific keyword list resides in code_review_graph/constants.py, typical entries include patterns related to authentication, authorization, encryption, and input validation that appear in node qualified names or function names.

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 →