Skip to main content
Runtime coverage adds a runtime layer on top of fallow health. Static analysis can tell you which exports have no references and which files are not test-reachable. Runtime coverage answers a different question: which functions actually executed when your deployed app handled real traffic.
fallow license activate --trial --email [email protected]
fallow coverage setup
fallow health --runtime-coverage ./coverage

What it tells you

When runtime coverage is enabled, fallow merges runtime evidence into the existing health report and assigns each function a per-finding verdict combining the static reachability signal with observed production invocations:
VerdictMeaning
safe_to_deleteStatically unused AND V8 tracked AND zero invocations. The strongest delete signal fallow emits.
review_requiredStatically used but never invoked in production. Needs a human look: could be seasonal, error-path-only, or legitimately dead.
low_trafficInvoked in production, but below the configured --low-traffic-threshold ratio of total trace count (spec default 0.1%). Effectively dead for the observed period.
coverage_unavailableV8 could not track the function (lazy-parsed, worker-thread isolate, dynamic eval, or the source map did not resolve). Advisory, not a dead-code signal.
activeInvoked in production above the low-traffic threshold. Not dead.
unknownForward-compat sentinel returned by newer sidecars. Rare.
Fallow also surfaces:
OutputMeaning
verdictOverall report status: clean, cold-code-detected, hot-path-touched, license-expired-grace, or unknown. Promotes hot-path-touched over cold-code-detected in PR-review contexts when --diff-file (or --changed-since) is set.
signalsArray of every signal the post-processing pass detected, independent of verdict (which is the single most actionable signal under the current context). Ordered severity-descending; omitted entirely when empty. A typical PR run emits ["cold-code-detected", "hot-path-touched"] together when both apply.
summaryAggregate counts (functions_tracked, functions_hit, functions_unhit, functions_untracked, coverage_percent) plus trace_count, period_days, deployments_seen, and an optional capture_quality block (window_seconds, instances_observed, lazy_parse_warning, untracked_ratio_percent) on protocol-0.3+ sidecars that flags short-window captures where lazy-parsed scripts may not appear.
findingsCold or unresolved functions with a per-finding suppression id (fallow:prod:<hash>, hashes the current line), an optional cross-surface stable_id (fallow:fn:<hash>, hashes file + name + start line; one value per function across findings / hot-paths / blast-radius / importance and across V8/Istanbul/oxc producers), an optional content-digest source_hash (line-move-immune: a moved-but-unedited function keeps the same value, so baselines stay suppressed across a pure line shift), line, per-finding verdict, confidence, supporting evidence, machine-readable actions, and an optional discriminators block exposing the inputs behind the verdict (tracking_state of called / never_called / untracked, invocation_ratio, the low_traffic_threshold and min_observation_volume in effect, and trace_count with meets_observation_volume) so an agent can reproduce the verdict without re-deriving it.
hot_pathsThe busiest runtime functions with a stable id, an optional stable_id join key, line, invocations, and percentile rank.
actionableWhether the report carries enough evidence to act on, with actionability_reason and actionability_verdict. A capture with no tracked functions reports a first-class insufficient_evidence verdict rather than being read as cold. This is a non-action floor: it never gates a positive verdict or a confidence score.
provenanceContext block describing the data behind the report (data_source, is_production, freshness_days, untracked_ratio, unresolved_ratio, stale, stale_after_days). Context only; it never gates a verdict.
watermarkTrial/license grace marker applied when paid-feature access is in warning mode.
warningsNon-fatal merge diagnostics, for example partial source-map remapping.
Every finding carries an evidence block so the “why” behind a verdict is machine-readable without re-deriving it:
"evidence": {
  "static_status": "used",
  "test_coverage": "not_covered",
  "v8_tracking": "tracked",
  "untracked_reason": null,
  "observation_days": 30,
  "deployments_observed": 14
}

Confidence thresholds

Two flags tune how aggressively fallow applies verdicts:
FlagDefaultEffect
--min-observation-volume <N>5000Minimum total trace volume before the sidecar is allowed to emit high-confidence safe_to_delete or review_required verdicts. Below this threshold, confidence is capped at medium to protect against overconfident verdicts on new or low-traffic services.
--low-traffic-threshold <RATIO>0.001Fraction of trace_count below which an invoked function is classified low_traffic rather than active. Expressed as a decimal (0.001 = 0.1%).

Static coverage vs runtime coverage

These three surfaces live side by side inside fallow health, but they answer different questions:
SurfaceFlagInputAnswersPaid
Static reachability gaps--coverage-gapsnoneWhich runtime files and exports have no transitive test path?no
Exact CRAP scoring--coverageIstanbul JSONHow covered is each function for CRAP calculation?no
Runtime runtime coverage--runtime-coverageV8 directory, V8 JSON file, or Istanbul JSONWhich functions actually ran, which stayed cold, and which hot paths changed?yes
Use --coverage-gaps when you want to find untested code. Use --coverage when you want better CRAP scores. Use --runtime-coverage when you want runtime evidence about real execution paths.

Accepted input

fallow health --runtime-coverage <path> accepts:
InputExample
V8 dump directory./coverage created with NODE_V8_COVERAGE=./coverage
Single V8 JSON file./coverage/12345.json
Single Istanbul coverage map JSON file./coverage/coverage-final.json
If a V8 dump includes Node’s source-map-cache, fallow remaps supported source-map URLs before analysis, including file paths, relative paths, webpack://..., and vite://.... Unsupported virtual schemes fall back safely to raw V8 handling instead of failing the whole run.

Production coverage: getting source attribution

Production runtime coverage is collected against your built bundle (a Next.js .next/server/chunks/*.js, an Electron out/main/index.js, a NestJS dist/, a minified browser bundle). Those positions cannot map back to your TypeScript or JSX source on their own, so unless you take one of the two steps below the cloud records every function as unresolved and fallow coverage analyze --cloud surfaces no attributable findings (a coverage_unresolved warning explains why). Pick one:
  • Upload source maps (for V8 coverage). After the build, upload the .map files as a CI step so the cloud can map bundle positions back to source:
    fallow coverage upload-source-maps --dir <build-dir>   # e.g. dist, .next, out
    
    The maps must be uploaded for the same commit the coverage was collected on. See fallow coverage for the flags, per-commit SHA matching, and CI snippets. When fallow coverage analyze --cloud finds built .map files locally that have not been uploaded, it prints the exact command to run.
  • Instrument at build time with Istanbul (no maps needed). oxc-coverage-instrument rewrites your source so the original file and line positions are embedded in the coverage itself, so nothing has to be remapped afterward. This is the path the fallow project dogfoods.

First-run workflow

The intended first-run path is:
  1. Start a trial or activate a license with fallow license.
  2. Run fallow coverage setup.
  3. Follow the generated recipe in docs/collect-coverage.md.
  4. Re-run fallow coverage setup or fallow health --runtime-coverage <path> once coverage exists.
fallow coverage setup is resumable. It checks license state, installs or locates fallow-cov, writes a framework-specific collection recipe, detects an existing coverage artifact when present, and then hands off into fallow health --runtime-coverage.

Review changed code

Runtime coverage becomes especially useful during change review:
fallow health --changed-since main --runtime-coverage ./coverage
When changed files touch hot runtime code, fallow can upgrade the overall verdict to hot-path-touched. That gives PR review a stronger signal than static complexity alone. For tighter line-level scoping, pass a pre-computed unified diff:
git diff --unified=0 main...HEAD > /tmp/pr.diff
fallow health --runtime-coverage ./coverage --diff-file /tmp/pr.diff
A hot function is then flagged only when the diff modifies a line inside its [start_line, end_line] range, instead of matching the whole file. The bundled GitHub Action and GitLab CI template already pre-compute the diff and pass it through, so PR comments only highlight hot paths the change actually touches. Hot-path matching needs protocol 0.5 or newer in the sidecar (older sidecars only report a start line, so fallow falls back to file-level scoping).

Trial and watermark behavior

Runtime coverage is a paid feature with a trial flow. Verification is offline against a compiled-in Ed25519 public key; only fallow license activate --trial and fallow license refresh require network access. If a license is expired but still inside the grace window, fallow keeps the analysis available but annotates the output with a watermark. Once the hard-fail window is exceeded, paid features are blocked until the license is refreshed.

See also

fallow health

Runtime coverage merges into the standard health report and output formats.

License commands

Start a trial, inspect license status, refresh, or deactivate a local token.