Understanding Results
After novetest test returns you have a result to interpret — a scannable text block (human) or a novetest/v1 JSON envelope (agent). This page covers:
- The six exit codes and what they mean.
- The
errors[].codecatalog (failure paths). - Reading the output (glyphs / the envelope frame).
data.stage_eligibility.data.recommendations[]and the closed seven-category taxonomy.- The follow-up verbs
statusandinspect. - The sub-report verbs (
coverage,regression,localization,replay,compare,memory). - A worked example: green → bug → fix.
warnings[].
Every output below is a real capture from the calc example (see Quick Start). Run ids are 26-character ULIDs; yours will differ.
Exit codes
Nove Test uses six exit codes. Read it with echo $? (POSIX) or $LASTEXITCODE (PowerShell).
| Code | Constant | ok | Meaning |
|---|---|---|---|
0 | EXIT_OK | true | CLI succeeded; tests passed. Data-level unavailable outcomes also land here. |
1 | EXIT_GENERIC | false | Unexpected CLI exception. Report as a bug. |
2 | EXIT_USAGE | false | Bad input (missing Project Store, unknown run_id, invalid flag, malformed test target, reset without --confirm). |
3 | EXIT_USER_TESTS_FAILED | true | CLI succeeded; your tests failed (or errored before producing results). Product data, not a tooling error. |
4 | EXIT_ENGINE_MISSING | false | Native engine not ready (missing on PATH) or adapter invocation error. |
5 | EXIT_STORAGE | false | Project Store corrupt or unreadable. |
Two invariants that trip people up:
- Exit 3 is normal. Your tests failed — or a suite errored before producing results (
run_record.status == "errored", onrun); either way the CLI did its job.okstaystrue— failing/errored tests are data. (Sook: truedoes not imply exit 0; always read both.) - An
unavailableoutcome is exit 0. When coverage / regression / localization can't produce facts for a structural reason (no baseline, no failing tests, ran without--coverage), that is reported as data on a successful command — never an error. - Exit 0 doesn't prove tests ran. An explicit target that matches nothing (a typo, a non-anchor-relative path) collects zero tests and still reports success (
total: 0,status: "passed"). Before trusting a targeted green run, check the counts — see Troubleshooting.
errors[].code catalog
When ok: false, errors[] carries at least one {code, message, details} object. Pin against code (not the message text).
errors[].code | Exit | Triggered when | Recovery |
|---|---|---|---|
uninitialized | 2 | A non-init verb run where no .novetest/ exists in any ancestor. | novetest init, or cd into a store tree. |
not-found | 2 | A run_id matches no Memory Entry. Message: No Memory Entry for run_id='<id>'. | List ids with novetest memory list. |
invalid-flag | 2 | Flag value outside the allowed set (bad --formula, --top-n < 1). Message lists allowed values. | Re-issue with a valid flag. |
confirm-required | 2 | novetest reset without --confirm. | Pass --confirm. |
adapter-invalid-target | 2 | A test target was rejected at the adapter boundary before any spawn — a dash-/flag-leading expression a native engine would consume as its own flag (e.g. novetest run -- --pdb). A caller usage error, not an engine problem. | Correct the target expression (drop or quote the leading dash). |
engine-ambiguous | 2 | ≥ 2 viable engines (marker present AND toolchain ready) at the init directory. Nothing is created; data.candidates[] lists the choices. | Re-issue novetest init --engine <name> with a value from data.candidates[]. |
engine-missing | 4 | Readiness state is engine-missing. data.engine_readiness is present. A misconfigured engine reports engine-misconfigured. | Install/configure the engine. |
no-engine-detected | 4 | init found no supported engine marker (nothing created; data.candidates[] lists discovered sub-projects, data.scan_refused: true at / and $HOME) — or run/test hit a marker-less anchor (payload: data.engine_readiness, not candidates). | cd into the right project and novetest init (or novetest init --engine <name>). |
adapter-<kind> | 4 | A native adapter invocation failed (e.g. adapter-unparseable-output). details.install_hint may carry a fix. | Apply the hint. |
store-corrupt / store-wipe-failed | 5 | .novetest/store.json unreadable/malformed (store-corrupt); a filesystem error interrupted reset (store-wipe-failed); or the record.json of the exact run you addressed by run_id is unreadable (memory show / memory delete / coverage show / coverage diff / regression compare / compare / localization / replay / inspect) — the message names the corrupt file's path. NOT not-found: the run exists but cannot be read. | Surface; don't auto-recover. store.json: worst case rm -rf .novetest && novetest init (loses ALL history). record.json: with operator approval, delete just that run_<id>/ dir and re-run the tests. |
The error code is the readiness state verbatim — engine-missing or engine-misconfigured (the code IS the state; there is no extra engine- prefix, and no engine-not-ready code/state exists).
Reading the output
Every novetest test invocation prints the same shape:
<count> recommendation(s) · <count> category/categories · run_id=<ULID>
<glyph> [<category>] <human-readable sentence>
↳ <citation>Glyph palette (no ANSI color at MVP — meaning is carried by glyphs + words):
| Glyph | Means |
|---|---|
✓ | Good / informational; no action. |
✗ | Bad news — look here. |
— | Unavailable for a structural reason; not an error. |
! | An action recommendation needs attention. |
? | "Can't tell" (e.g. replay not yet attempted). |
⚠ | Advisory warning. |
· | Separator. |
↳ | Citation pointer (the evidence behind a line). |
The all-green block:
1 recommendation · 1 category · run_id=01KVYRJJJ75ZRHC05GNKYRK99S
✓ [all_green] All tests green; no action recommended (passed 3, skipped 0, total 3).
↳ run_reference 01KVYRJJJ75ZRHC05GNKYRK99SEvery command emits the same frame, keys sorted alphabetically:
{ "command": "test", "data": { }, "errors": [], "ok": true,
"schema": "novetest/v1", "warnings": [] }Exactly six top-level keys: schema (always "novetest/v1"), command, ok, data, errors, warnings. There is no top-level version, verb, or exit_code field — the exit code is the process status. errors/warnings are arrays of {code, message, details}.
Routing skeleton:
if code == 0: handle_success(env) # ok: true
elif code == 3: handle_test_failures(env) # ok: true — read recommendations
elif code == 2: handle_usage_error(env) # ok: false — fix the call
elif code == 4: handle_engine_missing(env) # ok: false — install/configure engine
elif code == 5: handle_storage_error(env) # ok: false — store damaged
elif code == 1: handle_generic_error(env) # ok: false — report as bugdata.stage_eligibility
The test envelope's data has exactly four keys: run_reference, stage_eligibility, recommendation_schema_version (currently 1), and recommendations. The stage-eligibility block (real calc failing-run capture):
"stage_eligibility": {
"coverage": "available",
"localization": "sbfl_per_test",
"regression": "available",
"replay": "not_run"
}| Slot | Values | Notes |
|---|---|---|
coverage | available ∣ unavailable ∣ not_applicable | test always collects coverage, so usually available. |
regression | available ∣ unavailable ∣ not_applicable | unavailable on the first run for a target (no baseline). |
localization | the SBFL mode string (sbfl_per_test ∣ sbfl_aggregate ∣ failure_proximity) when a finding exists; else unavailable | NOT the word "available". A passing run is unavailable (no failing tests). |
replay | always not_run | test never invokes replay. |
A stage that is unavailable simply contributes no recommendations — it is not an error signal.
data.recommendations[]
Each recommendation has exactly these keys: recommendation_id, category, priority, summary, slots, evidence_citations. There is no severity field — priority (int, 1 = most urgent … 7 = all green) is the only ranking.
Closed taxonomy (seven categories)
priority | category | Fires when |
|---|---|---|
| 1 | regression_with_localization | A newly-failing test overlaps a top SBFL location — the strongest signal. |
| 2 | investigate_location | A localization finding, confidence ∈ {high, medium}, rank ≤ 3. |
| 3 | investigate_regression | A regressed (newly-failing vs baseline) transition. |
| 4 | coverage_gap | Uncovered lines overlap a suspicious location's span. |
| 5 | flaky_suspected | A replay classified the run inconsistent. Fires from novetest test --reruns N (N ≥ 1): a failed run is replayed whole N times; divergence produces this recommendation (empty test_id when several tests diverge). Default 0 = never replays. |
| 6 | unavailable_analysis | A downstream stage was unavailable AND either tests failed or the suite never executed. Informational. |
| 7 | all_green | The run's own status is passed AND zero failures AND zero regressed. A suite that never executed has zero failures by construction and is NOT all_green — it routes to unavailable_analysis. Mutually exclusive — never coexists with another category. |
(Category names are pinned to the code constants; the authoritative list lives with the engineering docs.)
Behavioural notes:
regression_with_localizationandinvestigate_regressionrequire a newly-failing transition (passing in the baseline, failing now). Re-running an already-failing suite does not re-emit them.flaky_suspectednever appears in realtestoutput.all_greennever coexists with another category.
Routing decision tree
On the happy path there is nothing to do — [all_green]. Otherwise read the top line (lowest priority number); its bracketed [category] and sentence tell you what to look at, and the ↳ citation tells you where the evidence lives. Then act, and re-run novetest test.
recs = sorted(env["data"]["recommendations"], key=lambda r: r["priority"])
if not recs:
return
top = recs[0]
cat = top["category"]
if cat == "all_green":
return # nothing to do
elif cat in {"investigate_location", "regression_with_localization"}:
# rank-bearing slots: file, primary_line, line_range, rank, symbol, formula, mode.
# Up to and including v0.2.1 this array is NOT score-ordered; from v0.3.0
# it IS: rank (asc) then score_normalized (desc). Ties still share a
# priority either way — select on the fields below, not on position:
key = lambda r: (r["slots"]["rank"], -r["slots"]["score_normalized"])
locs = [r for r in recs if r["category"] == cat]
best = min(locs, key=key)
# A tie on BOTH rank and score means the analysis could not separate those
# locations; what is left of the order is decided by file path. Every tied
# entry is a co-equal suspect — carry them all, not just the first.
tied = [r for r in locs if key(r) == key(best)]
targets = [(r["slots"]["file"], r["slots"]["primary_line"]) for r in tied]
elif cat == "coverage_gap":
# NOT rank-bearing: slots are file, lines (a list), mode, and
# related_finding_id ("entry_index_<i>" into the finding's entries) —
# no rank, primary_line, symbol or score_normalized. No in-category
# selector exists; treat every coverage_gap entry as a peer.
gaps = [(r["slots"]["file"], r["slots"]["lines"])
for r in recs if r["category"] == "coverage_gap"]
elif cat == "investigate_regression":
test_id = top["slots"]["test_id"] # newly-failing test; no rank slots
elif cat == "unavailable_analysis":
stages = top["slots"]["unavailable_stages"]
reasons = top["slots"]["reason_per_stage"] # informationalInvariant: route on category, sort by priority ascending; within a rank-bearing category (investigate_location, regression_with_localization), rank findings by slots.rank (then score_normalized) rather than by assuming array position. coverage_gap and investigate_regression carry no slots.rank at all — route them by slots.file + slots.lines and by slots.test_id respectively, never through the rank sort. Up to and including v0.2.1, array position carries no ranking information at all; from v0.3.0 it generally follows slots.rank/score_normalized too, but ties still fall through to the file path (see below) — so selecting on the fields, never on position alone, is correct on every version. Read slots / walk evidence_citations[]; never parse summary.
Ties are co-equal suspects, on every version. Ranking can genuinely fail to separate two locations — identical coverage spectra produce an identical slots.rank and an identical slots.score_normalized. Once that happens no ordering can help, and whatever order you observe is decided by the file path, so a location can move in or out of the first position on a rename alone. The rule that survives this: consider every recommendation sharing recommendations[0].slots.rank, not recommendations[0] alone. Ranks are dense, so entries that share a rank also share a score_normalized — collecting on the (slots.rank, slots.score_normalized) pair, as the snippet above does, is the same set. Prefer a non-test source file inside that set; otherwise investigate each member rather than acting on a single winner.
evidence_citations[].kind is a closed set: localization_finding, coverage_fact, regression_fact, replay_result, test_result, run_reference — each carries a selector pointing back into a persisted artifact you can drill into:
kind | Selector (real examples) | Drill in with |
|---|---|---|
run_reference | {} | novetest inspect <run_id> |
test_result | {"test_id": "…::test_subtract"} (+ outcome) | novetest inspect <run_id> |
localization_finding | {"file": "…", "primary_line": 6, "rank": 1} (+ related_finding_id on coverage_gap) | novetest localization <run_id> |
coverage_fact | {"file": "…", "lines": […]} | novetest coverage show <run_id> |
On a coverage_gap recommendation the localization_finding selector additionally carries related_finding_id: a positional "entry_index_<i>" handle — resolve it as entries[i] (0-based) of the novetest localization <run_id> output; it is distinct from the 1-based rank. Every other category keeps the bare three-field selector.
A worked example: green → bug → fix
(The human-tab and agent-tab outputs below come from two separate captures of the same scenario, so run ids differ between the tabs — yours will differ anyway.)
1. Green run
novetest test1 recommendation · 1 category · run_id=01KXMCE6R96GJSAKGNZTF5D7ET
✓ [all_green] All tests green; no action recommended (passed 3, skipped 0, total 3).
↳ run_reference 01KXMCE6R96GJSAKGNZTF5D7ETExit 0.
recommendations[0].category == "all_green", priority 7, exit 0, ok: true. stage_eligibility.localization == "unavailable" (nothing to localize on a green run).
2. Introduce the bug
Change calc/arithmetic.py line 6 so subtract adds instead of subtracts (return a + b), then novetest test:
2 recommendations · 1 category · run_id=01KXMCEGNYDJDCJCVTPMZ0GQ3J
! [regression_with_localization] Test `tests/test_arithmetic.py::test_subtract` newly failing in this run; suspected location `subtract`@6 in `calc/arithmetic.py` (rank 1, ochiai=1.000, sbfl_per_test).
↳ localization_finding calc/arithmetic.py:6 (rank 1)
! [regression_with_localization] Test `tests/test_arithmetic.py::test_subtract` newly failing in this run; suspected location `test_subtract`@13 in `tests/test_arithmetic.py` (rank 1, ochiai=1.000, sbfl_per_test).
↳ localization_finding tests/test_arithmetic.py:13 (rank 1)Exit 3 (ok: true). Because the green run left a baseline, the regression and localization signals combine into the strongest category — regression_with_localization, priority 1. SBFL ties two locations at rank 1, ochiai=1.000: the broken source line (subtract@6) and the test that exercises it (test_subtract@13). A failing test and the code it covers share a coverage signature, so such ties are normal — start at the production-source location, subtract@6 — the line you broke.
{
"command": "test",
"data": {
"recommendations": [
{ "category": "regression_with_localization", "priority": 1,
"summary": "Test `tests/test_arithmetic.py::test_subtract` newly failing in this run; suspected location `subtract`@6 in `calc/arithmetic.py` (rank 1, ochiai=1.000, sbfl_per_test).",
"slots": { "file": "calc/arithmetic.py", "formula": "ochiai",
"line_range": [5, 6], "mode": "sbfl_per_test", "primary_line": 6,
"rank": 1, "regression_kind": "newly_failing",
"run_reference_from": "01KXMCG7BTVNR0HKJAC33J23BB",
"run_reference_to": "01KXMCGQC43CBKJG5KQXTPW1S6",
"score_normalized": 1.0, "symbol": "subtract",
"test_id": "tests/test_arithmetic.py::test_subtract" } },
{ "category": "regression_with_localization", "priority": 1,
"summary": "Test `tests/test_arithmetic.py::test_subtract` newly failing in this run; suspected location `test_subtract`@13 in `tests/test_arithmetic.py` (rank 1, ochiai=1.000, sbfl_per_test).",
"slots": { "file": "tests/test_arithmetic.py", "formula": "ochiai",
"line_range": [12, 13], "mode": "sbfl_per_test", "primary_line": 13,
"rank": 1, "regression_kind": "newly_failing",
"run_reference_from": "01KXMCG7BTVNR0HKJAC33J23BB",
"run_reference_to": "01KXMCGQC43CBKJG5KQXTPW1S6",
"score_normalized": 1.0, "symbol": "test_subtract",
"test_id": "tests/test_arithmetic.py::test_subtract" } }
],
"run_reference": { "run_id": "01KXMCGQC43CBKJG5KQXTPW1S6", "...": "..." },
"stage_eligibility": { "coverage": "available", "localization": "sbfl_per_test",
"regression": "available", "replay": "not_run" }
},
"errors": [], "ok": true, "schema": "novetest/v1", "warnings": []
}(Each recommendation also carries a recommendation_id and three evidence_citations — kinds localization_finding, regression_fact, test_result — elided here.)
Exit 3, ok: true. Both recommendations are priority: 1, tied at rank: 1, score_normalized: 1.0 — a full tie, so neither position carries information in this particular capture: what decides the order you observe here is the file-path tiebreak. Ordering guarantee: up to and including v0.2.1 this array is not score-ordered at all (position is emission order); from v0.3.0 it is ordered by slots.rank ascending then slots.score_normalized descending within a priority/category group — except on a full tie like this one, where no ordering can help and the tiebreak falls through to file path. Either way, select by slots.rank (ascending), then slots.score_normalized (descending); on a full tie — as here — prefer the non-test source location, subtract@6 in calc/arithmetic.py, then route on its slots.file + slots.primary_line. Note the slots also carry the regression evidence: regression_kind: "newly_failing", the baseline/target run pair (run_reference_from / run_reference_to), and the regressed test_id.
3. Fix and re-run
Restore line 6 to return a - b, then novetest test → back to the green block, exit 0. The loop is: read the top recommendation, act, re-run.
Follow-up verbs: status and inspect
novetest status — the project's latest-run availability at a glance (read-only, derives nothing):
latest run · 01KW0PATQMBP2GXMFRX3J5EEX3 · history: 2 runs
✓ coverage available
✓ regression available
— localization unavailable
— replay unavailable(— marks a sub-report that is unavailable for a structural reason — here the latest run had no failing tests to localize, and replay only runs when you call novetest replay.) novetest status reflects the latest run.
novetest inspect <run_id> — everything known about one run (a pure read; works on tombstoned runs too):
✗ 01KXMCEGNYDJDCJCVTPMZ0GQ3J · failed · pytest (python) · target=<workspace>
coverage ✓ per-test · 11/11 statements (100.0%)
regression ✗ regressions · regressed=1 fixed=0 still_failing=0
localization sbfl_per_test · ochiai · 2 entries · confidence=high
replay ? unavailable (missing-derived-facts)target=<workspace> means the whole project. replay stays unavailable until you run novetest replay <run_id>.
status data: latest_run_reference (null after a fresh init), run_history_size, sub_reports (available/unavailable per stage).
inspect data: run_reference, run_summary, sub_reports, and four discriminated-union outcome blocks — switch on kind:
| Field | kind ∈ |
|---|---|
coverage_outcome | "fact-set" ∣ "unavailable" |
regression_outcome | "fact-set" ∣ "unavailable" |
localization_outcome | "fact-set" ∣ "unavailable" |
replay_outcome | "replay-result" ∣ "unavailable" |
"coverage_outcome": { "kind": "fact-set", "mapping_granularity": "per-test",
"summary": { "percent_covered": 100.0, "num_statements": 11, "covered_statements": 11, "...": "..." } },
"regression_outcome": { "kind": "fact-set",
"summary": { "regressed": 1, "still_passing": 2, "total_target_tests": 3, "...": "..." }, "...": "..." },
"localization_outcome": { "kind": "fact-set", "mode": "sbfl_per_test", "confidence": "high",
"formula": "ochiai", "top_n": 10, "entries": [ "...2 ranked entries..." ] },
"replay_outcome": { "kind": "unavailable", "reason": "missing-derived-facts",
"detail": "no replay attempt has been made for this run" }inspect is cache-only — it never runs replay. A stale/unknown run_id → errors[].code == "not-found", exit 2.
Sub-report verbs
All take a run_id (copy from memory list / inspect / the run_id= header). Each returns one data.<outcome> block discriminated on kind.
| Verb | data key(s) | kind values |
|---|---|---|
memory list | count, entries[] | — |
memory show <run_id> / delete | memory_entry | — |
coverage show <run_id> | coverage_outcome | fact-set ∣ unavailable |
coverage diff <base> <target> | coverage_delta | delta ∣ unavailable |
regression compare <base> <target> | regression_outcome | fact-set ∣ unavailable |
regression latest | regression_outcome | fact-set ∣ unavailable |
compare <base> <target> | regression_outcome and coverage_delta | as above |
localization <run_id> / latest | localization_outcome | fact-set ∣ unavailable |
replay <run_id> | replay_outcome (+ original_run_reference) | replay-result ∣ unavailable |
Confirm the regression against the green baseline (baseline first, target second — order matters):
novetest regression compare 01KVYRRR9ZNAM1PBA9JTR4QXC6 01KVYRRRN9FWVNQWVHNE1QHAQ4✗ regressions · regressed=1 fixed=0 still_failing=0
baseline=01KVYRRR9ZNAM1PBA9JTR4QXC6 target=01KVYRRRN9FWVNQWVHNE1QHAQ4novetest compare shows both signals at once (here coverage is unavailable because the baseline run was stored without coverage):
regression: ✗ regressions · regressed=1 fixed=0 still_failing=0
coverage: — unavailable (missing-derived-facts)novetest replay re-executes and classifies; the reruns become new runs in memory list:
✓ reproducible · 1/1 · run_id=01KVYRRRN9FWVNQWVHNE1QHAQ4regression compare → regression_outcome.kind == "fact-set", exit 0:
"summary": { "regressed": 1, "fixed": 0, "still_passing": 2, "still_failing": 0,
"total_baseline_tests": 3, "total_target_tests": 3, "added": 0, "removed": 0,
"newly_active": 0, "newly_skipped": 0, "still_skipped": 0 }The regressed test surfaces in test_transitions[] with category: "regressed" and a target_failure_reference. Top-level compare adds a coverage_delta block (here kind: "unavailable").
replay → replay_outcome.kind == "replay-result", exit 0:
"replay_outcome": {
"classification": "reproducible",
"consistency_summary": { "original_passed": 0, "original_failed": 1,
"replay_passed": 0, "replay_failed": 1, "replay_errored": 0 },
"per_rerun_outcomes": ["failed"], "reruns_total": 1, "reruns_failed": 0,
"replayed_run_reference": { "run_id": "01KVYRRVYB6K156ABEDFQTMQCG", "...": "..." },
"test_id": null, "reason": null, "attempted_at": 1782370299982, "kind": "replay-result"
}classification ∈ reproducible ∣ inconsistent ∣ unable_to_replay (all exit 0). --reruns defaults 1, --timeout 600.0. STRICT policy: one differing rerun → inconsistent. localization flags: --formula (default ochiai; values ochiai/op2/dstar2/tarantula) and --top-n (default 10); a bad value is invalid-flag, exit 2.
warnings[]
Independent of errors[]. Advisory — the command still succeeded; warnings never change the exit code or ok. Same {code, message, details} shape. The current catalog — twelve codes: one from orchestration, one from the run layer, three from localization, six from the JUnit / xUnit engine adapters, and one from the memory verbs (engine context: Supported Languages):
code | Source | Meaning |
|---|---|---|
suite-did-not-execute | orchestration | The suite never ran: the Run Record's status is outside passed/failed AND it produced zero test outcomes (e.g. a collection-time syntax error or a failing module-scope import). Zero failures here means nothing was tested, not that anything passed — the run exits 3 and routes to unavailable_analysis, never all_green. details: run_status, executed_tests, engine_name, ecosystem. Emitted by the test verb only. |
zero-tests-collected | run | The engine ran to completion, exited clean (status: "passed") and collected zero tests — e.g. an explicit target matching nothing (exit 0). Rides on both test and run. NOT suite-did-not-execute: these two are "ran, found nothing" vs. "never ran", and the code is the only wire surface that separates them. details: engine_name. |
localization-cache-rederived | localization | The cache was invalidated and re-derived because the resolved --formula/--top-n differed from the cached ones. An omitted flag resolves to its default (ochiai / 10), so a bare call can trigger this too; details.requested.formula_explicit / .top_n_explicit disclose whether you typed the flag. details: previous, requested, cache_path. |
localization-stale-build-rederived | localization | The cached SBFL finding predates this binary (an sbfl_per_test/sbfl_aggregate finding with no test_file_exclusion_basis in its metadata), so it was invalidated and re-derived; the ranking may move — the old one was the buggy one. failure_proximity findings are exempt, and inspect remains a silent cache read. details: run_id, mode, missing_metadata_key, requested, cache_path. |
localization-formula-noop-in-mode | localization | You passed --formula, but the run's SBFL mode (failure_proximity) does not consume a formula — nothing changed. |
ambiguous-build-tool | junit | Both pom.xml and build.gradle present; Maven chosen. |
missing-jacoco | junit | --coverage requested but JaCoCo not declared; coverage degraded. |
xunit-v3-coverage-deferred | xunit | xUnit v3 detected; coverage deferred. |
ambiguous-project-layout | xunit | Multiple candidate test projects. |
coverlet-below-floor | xunit | Coverlet below the 6.0.2 floor; coverage degraded to aggregate mode. |
coverlet-absent | xunit | --coverage requested but coverlet.collector not in the package graph; coverage not collected. |
corrupt-run-record-skipped | memory | A list-scan (memory list) skipped a corrupt record.json (emitted once per skipped record). The message carries the corrupt file's absolute path; details.path carries it machine-readable. Addressing that run directly by run_id (memory show / memory delete, …) does NOT skip — it fails with exit 5 store-corrupt. |
Every warning code is a dedicated token, disjoint from the readiness-state names — engine-misconfigured only ever names the readiness state and its same-named error code, never a warning.
What to read next
- Advanced Usage —
coverage diff, non-defaultlocalizationformulas,replay --reruns,memorylifecycle. - Supported Languages — engine-specific behaviour (e.g. go-test produces no coverage facts).
- Troubleshooting — every error code, its cause, and the fix.