How far static analysis sees, and where it stops - how to handle dynamic patterns

Static analysis confirms only the connections it can prove from code structure. Dynamic patterns that are resolved at runtime cannot be fully recovered by any static analyzer. Platty does not hide this boundary; it handles it with three principles: never confirm arbitrarily, link where the possibilities are finite, and mark inferences and promote them on confirmation.

If we had to name the best question in a technical review, it is this: "What can't static analysis see?" If a vendor answers "it sees everything," you should be suspicious. Our answer is a list.

What static analysis confirms

Connections proven by code structure can be confirmed without running anything. Function calls, type references, inheritance and implementation, routes and handlers, SQL target tables (where they are statically fixed), schedule and event declarations. These connections always yield the same result for the same code. They are the skeleton of the Platty graph.

Where static analysis stops. Five kinds of dynamic pattern

  • SQL determined at runtime. When a table name is assembled from variables, there is no way to know which table it is before execution.
  • Reflection. When classes and methods are called by string, the target changes depending on where that string comes from.
  • Dynamic lookup in a container. Code that pulls an implementation out of a dependency injection container by name points at different targets depending on configuration and profile.
  • Connections through configuration strings. Services linked not by imports but by URLs and topic names inside configuration files.
  • Proxies and dynamic dispatch. Patterns where the call target is wrapped or swapped at runtime.

These five types are not blind spots unique to Platty. No tool that does not execute the code can see them. The difference is in what you do next.

Principle 1. Never confirm arbitrarily

We do not link a screen to an API just because the path strings look alike. We do not pick one plausible candidate and call it confirmed either. Instead we preserve the original expression, the candidate list, and the reason it could not be confirmed. The moment you draw a road that is not there, the whole map becomes untrustworthy.

Principle 2. If it is finite, connect it

We do not give up on every dynamic pattern. Reflection where the string is a fixed constant, lookups where the branches are finite and every candidate can be enumerated. Patterns like these, where candidates can be bounded statically, are covered by extending the analysis rules. For common wrapper patterns that recur at a given customer, we take representative cases during rollout and add rules and regression tests.

Principle 3. Mark inference, promote it on confirmation

Some gaps still remain. From there on, we link with the source stated. Connections proven by static analysis are marked confirmed; connections the LLM linked by inference are marked separately as inferred. An inferred connection is promoted to confirmed when a person links it by hand or confirms it. Every answer shows whether its evidence is confirmed or inferred.

The result is a map that knows its coverage

What these three principles produce is not a map that "knows everything" but a map that knows how far it knows. Which connections are proven, which are candidates, and where the gaps are all show up on the map. An organization that bets its systems on this does not need an omniscient map. It needs an honest one.

Next : Will better models make Platty unnecessary?