Report format¶
Every run writes report.json and, beside it, report.html (-out and -html choose the paths). -junit PATH also writes JUnit XML. Reading a report explains how to use them; this page lists the fields.
report.json¶
{
"schemaVersion": 2,
"name": "cashier-charge-must-survive",
"startedAt": "2026-10-29T13:58:34.98+05:30",
"elapsed_ns": 15200000000,
"passed": false,
"recovery_ns": 199250833,
"phases": [ ... ],
"hypotheses": [ ... ],
"faultLog": [ ... ],
"probes": [ ... ],
"timeseries": [ ... ],
"observedVsInjected": [ ... ],
"warnings": [ ... ]
}
| Field | Meaning |
|---|---|
schemaVersion |
the report format version, currently 2 |
name |
metadata.name of the scenario |
startedAt, elapsed_ns |
when the run started, and how long it took (nanoseconds) |
passed |
true when every hypothesis held |
recovery_ns |
time from the end of the faults to healthy again |
phases |
one summary per phase: steady, inject, recover |
hypotheses |
each hypothesis with its verdict |
faultLog |
each fault: name, kind, start, end, intensity, rollback (ok or fail: ...) and its parameters as written (tunables) |
probes |
every probe sample |
timeseries |
per-second buckets for the charts |
observedVsInjected |
whether each fault visibly landed |
warnings |
everything the run warned about |
load, loadGenerator |
the load generator's output, when load is set |
prometheus |
the Prometheus series, when observability.prometheus is set |
Durations whose key ends in _ns are nanoseconds.
A phase¶
{
"name": "inject",
"from": "2026-10-29T13:58:37.98+05:30",
"to": "2026-10-29T13:58:45.98+05:30",
"errorRate": 0.9756,
"availability": 0.0244,
"p50_ns": 279000,
"p95_ns": 353875,
"p99_ns": 421834,
"rps": 5.12,
"samples": 41,
"failed": 40
}
errorRate and availability are fractions (0 to 1) here; hypotheses state them as percentages.
A hypothesis¶
{
"name": "charge survives its own outage",
"metric": "error_rate",
"operator": "<",
"limit": "5%",
"observed": "97.56%",
"passed": false
}
observed is "no data" with "noData": true when the window had no samples, and "not recovered" for a recovery hypothesis whose service never came back. allowNoData is copied from the scenario.
Versions¶
A report without schemaVersion was written by an older litmus-lite and is read as version 1. Later versions only add fields. litmus-lite refuses to read a report newer than it knows, and says so.
| Version | Change |
|---|---|
| 1 | no schemaVersion |
| 2 | adds schemaVersion, and noData and allowNoData on each hypothesis |
report.html¶
One self-contained file with no external requests: open it from disk or attach it to a CI run. Sections: the verdict, fault against impact (a chart of the injected intensity, p95 and error rate over time, with the inject window shaded), hypotheses, a phase comparison table, observed against injected, the fault log and a probe summary.
JUnit XML¶
One testcase per hypothesis (class litmus-lite.hypothesis), with a failure that carries the metric, operator, limit and observed value. A scenario with no hypotheses is one test case for the whole run.
<testsuite name="cashier-charge-must-survive" tests="2" failures="1">
<testcase name="charge survives its own outage" classname="litmus-lite.hypothesis">
<failure message="error_rate < 5%">observed 97.56%</failure>
</testcase>
<testcase name="recovers" classname="litmus-lite.hypothesis"></testcase>
</testsuite>