Deterministic Route Extraction vs Guessing
Quick answer: Deterministic extraction proves a route exists by tracing the real framework instance and reading the AST, so a name that merely looks like a route, such as cache.get(...), is not mistaken for one. Guessing infers routes from patterns and names, which can invent paths that do not exist and miss paths that do. The scan defaults to deterministic extraction, and anything it cannot prove becomes an explicit gap rather than a guess.
Why guessing looks attractive and fails
A name-based approach is easy to build: scan for familiar method calls, assume they are routes, and emit a document quickly. The speed is real, but the result is unreliable. A helper method that shares a name with a routing call gets treated as an endpoint, while a route registered through a wrapper the pattern does not recognize is missed.
That produces two opposite errors at once: false routes that do not exist and real routes that never appear.
How deterministic extraction proves a route
The scan uses two grounded techniques instead of pattern matching.
| Technique | What it does |
|---|---|
| Framework instance tracing | Follow the actual app and router objects the framework wires together |
| AST analysis | Read the syntax tree to resolve handlers, methods, and paths |
Because the trace follows the real framework call rather than a matching word, lookalikes such as cache.get(...) are not counted as routes. A path enters the document only when the code path that mounts it is resolved.
Consider a codebase that wraps its router in a helper. A name scan sees the inner method calls and emits them as top-level routes even though the helper is never mounted, and it skips the one wrapper that is actually wired. The trace resolves the wrapper first, follows it to the mounted router, and emits only the reachable paths. The difference is visible the moment you compare the two documents: one lists routes that return 404 when called, and the other matches the running surface.
The cost and the payoff
Deterministic extraction is more work than a name scan, because it has to understand the framework wiring rather than count keywords. The payoff is a document that reflects routes the code actually mounts, with a clear boundary between what is proven and what is not.
When the trace cannot fully resolve a route or its contracts, the scan does not round the result into a confident answer. The unknown is marked as a gap, and AI can fill that specific gap later without inventing the route itself.
How this protects the generated spec
The distinction matters downstream, because a guessed route poisons everything built on the spec. A mock or a scenario test based on an invented path gives a false signal, and a missing real route leaves a flow unverified. Keeping extraction deterministic keeps the later review and scenario work grounded.
A successful scan still does not prove the implementation conforms, and dynamic loading or framework entry points can be missed. The scan does not run the app, and proven routes are not the same as verified behavior.
Powerduck keeps the extraction deterministic and shows the provenance behind each route, so the spec carries proof rather than probability.
Frequently asked questions
Can a helper method be mistaken for a route? Under deterministic extraction, no. The trace follows the framework wiring and AST, so a lookalike such as cache.get is not treated as an endpoint.
What happens when a route cannot be fully resolved? It is marked as a gap rather than guessed. AI can fill the gap, but it cannot invent the route.
Is deterministic extraction slower than guessing? It takes more work up front, but it avoids false and missing routes that would otherwise break the mocks and scenarios built on the spec.
The bottom line
Choose proven routes over probable ones. Deterministic extraction follows the real framework instance and AST to confirm a path, rejects lookalikes that a name-based scan would promote, and turns anything unresolved into an explicit gap rather than a guess. Guessing is faster but invents and misses routes in the same pass. A spec you can trust downstream has to be built on proof, and a proven route still does not certify runtime behavior. Continue in the code-to-OpenAPI guide.