Coverage: is every part of your app really being watched
Declare what each part of an app should send and Belvador checks it against what really arrived — verified, stale, problem or unknown; manage it from CI as code.
On this page
Coverage answers one question honestly: is each part of my app actually being watched? You declare what an app should send — for example browser and server errors in production, and check-ins from the nightly job — and Belvador checks every declaration against what really arrived. No errors never counts as connected: a signal that never arrived is unknown, not fine.
Open Coverage in a workspace for every project at once, or Project → Coverage to change one project's expectations. Viewers can read coverage; members and above can change it.
Statuses#
Each declared signal gets one status, worked out in one place on Belvador's side — the page, the API and the MCP tool get_coverage show the same numbers.
| Status | Means |
|---|---|
| Verified | Real data or a verification receipt arrived from that part of the app, in that environment, within its stale after window (default 168 hours) |
| Stale | It arrived before, but not within the window — something may have stopped sending |
| Problem | An open connection problem covers it, for example the SDK reports dropped events; it wins over fresh data until it is resolved |
| Unknown | Nothing has ever arrived for it |
The rate at the top — 34 of 41 expectations verified — counts only verified signals. Stale, problem and unknown never count as covered.
What each part can send#
An expectation is one environment × one surface (a part of your app) × the signals it should send:
| Part of the app | Errors (errors) | Traces (traces) | Logs (logs) | Metrics (metrics) | Check-ins (check_ins) | Web vitals (web_vitals) | Uptime probes (probes) |
|---|---|---|---|---|---|---|---|
Browser (browser) | yes | yes | yes | — | — | later (not collected yet) | — |
Server (server) | yes | yes | yes | yes | — | — | — |
Worker (worker) | yes | yes | yes | yes | — | — | — |
Job (job) | yes | yes | yes | — | yes | — | — |
Edge function (edge_function) | yes | yes | yes | yes | — | — | — |
Database (database) | — | yes | — | yes | — | — | — |
Uptime (uptime) | — | — | — | — | — | — | yes |
Metrics count once your node runs agent 0.1.37 or later (Metrics); on an older node a metrics cell stays Unknown. Web vitals are part of the vocabulary but Belvador does not collect them yet, so they cannot be declared — coverage never promises something it cannot show.
How Belvador knows which part sent it#
Your node decides the surface of every error, span, log and check-in it stores, using the information standard SDKs already send:
Errors (Sentry SDKs): an error inside a monitored job (
contexts.monitor) → job; a browser SDK → browser; a queue task (contexts.trace.opstarting withqueue.) → worker; a serverless function (Cloudflare, Vercel Edge, AWS Lambda, Google Cloud Functions SDKs, orcloud.platform/faas.triggerof the OpenTelemetry FaaS conventions) → edge function — atimertrigger counts as a job,pubsubas a worker; everything else → server.Traces and logs (OpenTelemetry): the browser SDK (
telemetry.sdk.language = webjs) → browser; FaaS attributes as above → edge function; a consumer span withmessaging.system→ worker; a span withdb.system.namealso counts as database traces. Data withoutdeployment.environment.namecounts asproduction, like Sentry SDKs.Check-ins → job. Uptime probes come from your uptime checks.
Declare expectations#
Open Project → Coverage.
A project with nothing declared offers a suggested set for its framework — for TanStack Start, browser and server errors in its main environment. Choose Apply suggestion, or Add expectation.
Pick the environment exactly as your SDK sends it, the surface and its signals. Stale after is how long without evidence before it turns stale (1–720 hours): pick longer than the usual gap between real data — a job that runs every night needs about 26.
Verify now on a signal opens the project's connection check for that environment: run it and the signal turns verified as soon as the receipt arrives.
Seen but not declared#
Signals Belvador saw in the last 30 days that no expectation covers are listed under Seen but not declared, with Add to expectations. They do not change the rate until you declare them.
Manage it from code#
Keep the expectations next to the code and apply them from CI. A set written this way is managed in code: the app shows it read-only, so a click cannot undo the file.
config_source: codeexpectations: - environment: production surface: browser signals: [errors] - environment: production surface: server signals: [errors, traces] - environment: production surface: job signals: [check_ins] stale_after_hours: 26 note: nightly billingyq -o=json belvador-coverage.yaml | curl --fail-with-body -X PUT \ "https://api.belvador.dev/v1/projects/$BELVADOR_PROJECT_ID/coverage-expectations" \ -H "Authorization: Bearer $BELVADOR_TOKEN" \ -H "Content-Type: application/json" \ --data-binary @-The token needs the coverage:write scope (a service token from Workspace settings → Service accounts suits CI). Each call replaces the project's whole set; sending the same file again changes nothing. To hand the set back to the app, send it once with config_source: ui.
From an AI agent#
The MCP tool get_coverage returns the same report as the page — statuses, rate and what was seen but not declared — so a coding agent can check that the feature it just shipped is actually reporting. See MCP.
What leaves your node#
For coverage your node sends only keys and times: environment, surface, signal, when it was last seen and when it was last verified — never messages, names, attributes or counts of your data. It keeps at most 256 of them per project. The first time a node that reports coverage starts, it reads back the last 30 days of errors and check-ins and 7 days of traces and logs once, so existing apps do not start as unknown.
Coverage needs node 0.1.35 or later. An older node reports nothing, and the page says so instead of guessing.
Spotted something wrong or missing? Tell us: hello@belvador.dev