Coverage & the honest ceiling
DACIP is deterministic: it only reports what it can prove from the code. The flip side is that its view has a ceiling — some paths are built at runtime, some files can't be parsed, some client wrappers aren't recognized. DACIP's rule for all of these is the same: list the gap, never guess across it. A short report from DACIP doesn't mean "nothing is wrong"; it means "here is what I saw, and here is exactly what I couldn't."
The coverage block
Every run writes a coverage.json next to the findings, and every report embeds the same block under a ## Coverage heading:
{
"files": { "total": 412 },
"symbols": { "total": 3180 },
"routes": { "total": 307, "resolved": 301, "partial": 6 },
"calls": { "literal": 118, "template": 64, "dynamic": 9, "total": 191 },
"links": { "matched": 168, "no_backend_route": 5, "uncomparable": 9 },
"frontend_base_urls": ["/api/v1"]
}
What the fields mean:
| Field | Meaning |
|---|---|
routes.resolved |
Backend routes whose full URL prefix was statically resolved |
routes.partial |
Routes with an unresolved prefix — matched to frontend calls by suffix only |
calls.literal / calls.template |
Frontend calls whose path is a string literal, or a template with static segments (/users/{param}) |
calls.dynamic |
Calls whose path is fully runtime-computed — listed, never compared |
links |
Match status of each comparable call against the extracted routes |
Gaps also surface as warning diagnostics in diagnostics.json and the report's "Analysis notes" section — codes like PARTIAL_ROUTES, DYNAMIC_CALLS, UNMATCHED_CALLS, LOW_MATCH_RATE, and NO_BACKEND_ROUTES. These are notes, not findings: only error-grade evidence becomes a finding. If fewer than 85% of comparable calls match a route, LOW_MATCH_RATE tells you route extraction may be incomplete for your repo — treat cross-stack results accordingly.
Dynamic paths: listed, never guessed
A frontend call like client.get(buildUrl(entity)) has no statically knowable path. DACIP marks it dynamic, links it as uncomparable ("Frontend path is fully dynamic; cannot compare."), and moves on. It will not pattern-match or infer what the URL "probably" is — a guessed match is how false positives happen.
Teaching DACIP your HTTP client
The TypeScript analyzer recognizes fetch, axios, and method calls (.get/.post/.put/.patch/.delete) on common client names such as api, http, client, apiClient, fetcher, and $api. If your codebase wraps requests in something it doesn't know — say _data.get(...) — those calls are invisible until you name the wrapper:
dacip scan --client _data --client legacyApi
The flag is repeatable and works on scan, investigate, diff, and the other analysis commands.
The TypeScript analyzer needs Node
Frontend extraction runs the repo's own typescript package via Node. If neither the repo (checked in node_modules/, including frontend/, web/, client/ subdirectories) nor DACIP's toolchain cache has a usable typescript, the analyzer emits TS_ANALYZER_UNAVAILABLE — and because losing the whole frontend side must never look like "no findings", the CLI prints a loud stderr notice telling you frontend calls were NOT extracted and cross-stack findings are incomplete. The one-time fix:
dacip toolchain install-ts
This provisions a DACIP-managed typescript in the user cache, so it also covers repos with no node_modules at all.
Unparseable files
A file DACIP can't parse is DACIP's reading ceiling, not evidence of a defect in your code. Python files that fail to parse — for example, syntax newer than the interpreter this DACIP build ships with — are excluded from analysis and reported as a PYTHON_PARSE_ERROR warning naming the file and line. They never become findings.
Reading a thin report
When a report looks sparse, check the coverage block first. routes.total: 0 alongside real frontend calls means contract checking never ran, not that your contracts are clean. That distinction is the point: DACIP tells you what it can't see, so you know exactly how much weight the rest of the report carries.
Next: Quickstart to run your first scan, Troubleshooting for analyzer setup issues, or the proof dashboard for how this plays out on real repos.

