Static, Dynamic, and Data-Flow Views of the Same Code

Code-Graph-RAG’s structural graph is powerful precisely because it is not the only view of a repository. Static analysis can map declarations and many relationships before the program runs, but some routes appear only through runtime dispatch. A separate data-flow layer asks where values travel, which is different from asking which functions are connected. This chapter shows how runtime observations and source-to-sink paths extend the graph, how their provenance is recorded, and why unobserved or uncovered behavior must never be treated as absent.

Runtime observation fills a different kind of gap

A static call graph is built from source and language rules. It can often resolve a direct call, an import, an inheritance relationship, or a reference to a callable. But a program can choose its target at runtime. A registry may store a function under a string key. A framework may invoke a callback after an event. getattr, reflection, monkey patches, interface dispatch, or a dependency-injection proxy may select a concrete implementation that is not visible from the syntax at the call site.

Those cases are not evidence that static analysis failed in general. They are evidence that the question has crossed from “what relationships can be inferred from source?” to “what relationships did a particular workload actually exercise?” Code-Graph-RAG’s dynamic tracing path is designed for that second question. It can record calls from a test or other workload, convert traces from supported runtimes and profilers, and merge the observations into the existing graph alongside static CALLS relationships.

The two paths can be read together:

sequenceDiagram participant R as Repository participant P as Static parser participant G as Graph participant W as Test or production workload participant T as Runtime tracer or profiler participant I as Trace ingestion participant A as Call or flow decision R->>P: Parse source and relationships P->>G: Write static CALLS edges W->>T: Execute a selected workload T->>I: Record observed call stacks I->>G: Merge runtime provenance and missed edges G->>A: Answer behavior or source-to-sink question

An observed edge can strengthen a static edge without changing its origin. When a trace confirms a relationship already present in the graph, Code-Graph-RAG marks it as runtime-confirmed. When the trace reveals a route for which no matching static call edge existed, the graph records it as a dynamic-only edge and marks the static miss. The result is not one blended relationship with no history. It is a relationship whose properties say whether it came from static analysis, runtime observation, or both.

The stored properties make the observation more useful. A dynamic edge can include the number of observed activations, the workloads that exercised it, the number of distinct workloads, and concrete receiver types for method dispatch. These details answer questions such as “which implementation handled this test?” or “which test ids exercised this relationship?” They also qualify the answer.