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.
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:| Verdict | Meaning |
|---|---|
safe_to_delete | Statically unused AND V8 tracked AND zero invocations. The strongest delete signal fallow emits. |
review_required | Statically used but never invoked in production. Needs a human look: could be seasonal, error-path-only, or legitimately dead. |
low_traffic | Invoked 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_unavailable | V8 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. |
active | Invoked in production above the low-traffic threshold. Not dead. |
unknown | Forward-compat sentinel returned by newer sidecars. Rare. |
| Output | Meaning |
|---|---|
verdict | Overall 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. |
signals | Array 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. |
summary | Aggregate 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. |
findings | Cold 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_paths | The busiest runtime functions with a stable id, an optional stable_id join key, line, invocations, and percentile rank. |
actionable | Whether 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. |
provenance | Context 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. |
watermark | Trial/license grace marker applied when paid-feature access is in warning mode. |
warnings | Non-fatal merge diagnostics, for example partial source-map remapping. |
Confidence thresholds
Two flags tune how aggressively fallow applies verdicts:| Flag | Default | Effect |
|---|---|---|
--min-observation-volume <N> | 5000 | Minimum 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.001 | Fraction 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 insidefallow health, but they answer different questions:
| Surface | Flag | Input | Answers | Paid |
|---|---|---|---|---|
| Static reachability gaps | --coverage-gaps | none | Which runtime files and exports have no transitive test path? | no |
| Exact CRAP scoring | --coverage | Istanbul JSON | How covered is each function for CRAP calculation? | no |
| Runtime runtime coverage | --runtime-coverage | V8 directory, V8 JSON file, or Istanbul JSON | Which functions actually ran, which stayed cold, and which hot paths changed? | yes |
--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:
| Input | Example |
|---|---|
| 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 |
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
.mapfiles as a CI step so the cloud can map bundle positions back to source:The maps must be uploaded for the same commit the coverage was collected on. Seefallow coveragefor the flags, per-commit SHA matching, and CI snippets. Whenfallow coverage analyze --cloudfinds built.mapfiles locally that have not been uploaded, it prints the exact command to run. -
Instrument at build time with Istanbul (no maps needed).
oxc-coverage-instrumentrewrites 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:- Start a trial or activate a license with
fallow license. - Run
fallow coverage setup. - Follow the generated recipe in
docs/collect-coverage.md. - Re-run
fallow coverage setuporfallow 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: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:
[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; onlyfallow 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.