The Convex doctor distinguishes established context/runtime mistakes from performance, validation and maintenance review candidates. All checks require shared analysis; unavailable analysis is reported as unexercised coverage.
| Severity | Check | Observation |
|---|---|---|
| warning | filter-table-scan |
A Convex filter without an index; review candidate reads |
| warning/info | index-without-range |
Indexed collect with no established returned range; unresolved flow is explicit |
| warning | unbounded-collect |
Collect without a supported bound; review growth and completeness |
| info | index-filter-combo |
Indexed query plus filter; potential optimization, not measured cost |
| warning | query-clock-reactivity |
Direct query clock read; review subscription and expiration behavior |
| warning | transaction-clock-duration |
Subtraction of two fixed transaction-clock readings |
| info | presence-patch-on-shared-document |
Presence field patch without a known dedicated-table target |
| warning/info | missing-args-validator |
Public function without validators; internal omission is an optional contract review |
| warning | write-in-query |
Resolved query context invokes a write, scheduler, mutation or action |
| warning | db-in-action |
Resolved action context invokes a database method |
| warning | unawaited-convex-call |
A known promise-returning context call discards its immediate result |
| warning | node-runtime-transaction |
Query or mutation registration in a true "use node" directive file |
| info | public-api-in-server-call |
Public or explicitly unresolved api-shaped server reference; audience review |
| info | sequential-run-in-loop |
Directly awaited run call in a loop; preserve retries and dependent work |
| info | spread-into-patch |
Top-level patch object spread; field ownership requires separate evidence |
Checks use semantic revision 2 or 3. Old review decisions need reassessment.
What establishes identity
Named/namespace registration imports, renamed imports and parameters, immutable
aliases, local handler/config variables and direct handlers are supported.
Database/context aliases and destructuring retain their binding identity. Typed
helpers can use imported Convex context contracts, local aliases and Pick;
consistent observed local calls can also establish helper argument provenance.
Unrelated objects named ctx or db and shadowed bindings remain ordinary objects.
Validator order, shorthand and formatting do not change the result. Returned index ranges are distinct from incidental range calls; unreachable branches do not establish bounds. Unknown returned paths produce an explicitly uncertain candidate for that chain. Node directives are parsed structurally, including semicolon-free forms and leading comments.
Read recommendations as well as locations
An index does not prove small cardinality. Use pagination or resumable batches when all billing or migration records must be processed; an arbitrary result cap can silently omit work. Measure workload before changing an indexed filter.
Keep server-authoritative expiration checks. A client timestamp is not a safe substitute for authorization time. Public API calls may be required by frontend consumers; server use or absence of discovered client calls does not establish server-only intent. Do not make an endpoint internal without checking its callers.
Object spread can be validated or server-selected. Nested object and array
spreads do not imply arbitrary top-level field writes. Dedicated heartbeats and
presence table targets are spared when explicit arguments or validators identify
them. Other naming/segmentation schemes need human review.
Awaited loops may implement retries, backoff or cursor-dependent incremental work. Keep that behavior; batching or concurrency is appropriate only when operations are independent and transaction limits and completeness permit it. Transaction semantics differ between actions and queries/mutations.
Coverage limits
The doctor follows current Convex 1.x contracts, checked against official validation guidance, runtime boundaries, and best practices, with retained framework evidence from 1.32.0. Future major APIs need re-evaluation.
Custom registration wrappers, arbitrary type/return flow, cross-file helper implementations, split query builders and search-index bounds are not inferred. A type annotation is a declared contract, not runtime proof. Stored or passed promises are outside direct-discard detection, not certified settled. Nested helper clocks and stored-then-awaited loop calls can remain undetected.
Diagnostic suffixes remain .ts, .tsx, .js, .jsx, .mjs, respecting normal
authored/test/generated scope. .mts, .cts, .cjs and fixture-named target files
are not diagnosed. No production cardinality, latency, authorization exploit or
complete frontend consumer graph is measured. Passing fixtures is not independent
acceptance; evaluate the exact package and source findings before applying fixes.