For AI agentsA Markdown index of these docs is at /llms.txt. Every page is also Markdown: add .md to its address.

Guides

What static analysis can't see, and why your agent should know

Static analysis can't follow calls decided at run time, calls on values of unknown type, or files it doesn't read. Your agent should be told where.

Static analysis reads code without running it, so it can't follow calls that are decided at run time (dynamic calls, functions passed around as values, values of unknown type) or code in files it doesn't read. Your agent should know where those blind spots are, because otherwise it treats a partial list of callers as the whole list and edits accordingly.

No tool sees everything. The difference is whether it tells you where it stopped looking.

What static analysis can't see

Calls decided at run time. If code looks up a function by a string or a key, as in handlers[key](), getattr(obj, name)() or a plugin registry, which function runs depends on data that only exists when the program runs.

Functions passed around as values. When a function is stored in a variable, a dictionary or an argument and called later, the call site doesn't spell its name. A text search can't find it, and analysis can only say "something is called here".

Values of unknown type. x.close() calls whichever close belongs to x. If the analysis can't work out x's type (untyped code, a value returned from a library, a dynamic factory), it can't say which close runs. In the open-source requests library (v2.32.3, LLMGRAPH 0.4.3), 443 of the 617 blind spots it reported were values of unknown type: the largest single kind there.

Files it doesn't read. Every tool reads some languages, not all. A Python-only tool doesn't see the shell script, the template or the other-language service that calls into your code.

Code that changes code. Monkey-patching, decorators that swap functions, and generated code can all change what a name means at run time.

Why your agent needs to be told

An agent asking "who calls this?" gets a list. If the list doesn't say it's incomplete, the agent does the reasonable thing: it updates everything on the list and stops. The broken caller is the one that was never on it.

So the useful answer to "who calls this?" has three parts: the calls that are proven, the calls that might be (with the candidates), and where the analysis couldn't see, with the reason. The third part is what tells an agent to check by hand, run a test, or ask you.

What it looks like when a tool tells you

LLMGRAPH labels every answer line by how far it's proven, and names what it can't see. Here's a real answer from the open-source requests library, asking what it can't see in the whole repo:

llmgraph · what_is_unknown (whole repo): 617 blind spots ⚠ dynamic call 174: tests/test_requests.py (161), tests/test_utils.py (6), +6 files w11 ⚠ type unknown 443: tests/test_requests.py (286), src/requests/cookies.py (21), +17 files w12

And inside an ordinary answer, the blind spots sit next to the proven lines instead of being dropped:

llmgraph · what_breaks_if_changed super_len (depth 3): 22 places depend on it ✓ certain src/requests/models.py:526 PreparedRequest.prepare_body w3 ✓ certain src/requests/models.py:575 PreparedRequest.prepare_content_length w4 ... ⚠ plus 9 dynamic calls nearby that could reach anything w6 ⚠ 7 more deeper calls we can't see: not followed w9 (lines trimmed)

The five labels, strongest first:

LabelMeans
certainWe can prove it is exactly one function.
exactly_theseA known set, and every member really can run here.
within_theseOne of a known list; some listed may never happen here.
maybe_moreThere are candidates, but the door is open.
cannot_seeNothing to go on.

A label says what is ruled out. It is never a number about chance. Each one has an entry in the glossary.

What to do with a blind spot

  • Dynamic calls near your change: search for the string or key that selects the function, or add a test that exercises that path.
  • Unknown types: a type hint on the receiver can help the checker work out which function runs.
  • Files in other languages: check them by hand; no single tool reads everything.
  • Tell the agent the rule: "if an answer names a blind spot near your edit, check it or ask before you finish."

The question that lists them for a repo is what_is_unknown, and the languages and limits are on what it can't see.

See real answers, unedited · Windows x64; Python and TypeScript/JavaScript.

For agentsthis page as Markdown/guides/what-static-analysis-cant-see.mdllms.txt