What it does
dev-report defines the report format every other crate in the dev-*
suite emits. AI agents need machine-readable evidence of what passed,
what failed, and why. This crate provides that schema.
Why it exists
A test runner that prints colored checkmarks to a TTY is unreadable to an AI agent. The agent needs:
- A stable, versioned schema
- Verdicts separated from logs
- Enough evidence to decide accept / reject / retry / escalate
dev-report is that schema.
Quick start
Add to Cargo.toml:
[]
= "0.9.3"
Opt-in features:
[]
= { = "0.9.3", = ["terminal", "markdown"] }
Build a report:
use ;
let mut report = new
.with_producer;
report.push;
report.push;
report.push;
report.finish;
let verdict = report.overall_verdict; // Verdict::Fail
let json = report.to_json.unwrap; // ready to write to disk or stdout
Tags and evidence
Tags filter checks by category. Evidence attaches typed, decision-grade
data without forcing the consumer to parse the free-form detail string.
use ;
let mut report = new;
report.push;
// Filter by tag without parsing names.
let bench_checks: = report.checks_with_tag.collect;
assert_eq!;
The four evidence kinds are:
| Kind | Constructor | Use for |
|---|---|---|
Numeric |
Evidence::numeric(label, value) |
A single labeled number (mean_ns, ops/sec). |
KeyValue |
Evidence::kv(label, pairs) |
String->string maps (env, config). |
Snippet |
Evidence::snippet(label, text) |
Short captured text (panic, log line). |
FileRef |
Evidence::file_ref(label, path) / file_ref_lines(label, path, start, end) |
Pointer to a source location. |
Both tags and evidence are additive: v0.1.0 reports deserialize as
v0.9.x reports with empty collections, and reports with no tags or
evidence omit those keys from the JSON output.
Diffing two reports
Compare a current run against a baseline to flag regressions:
use ;
let mut baseline = new;
baseline.push;
let mut current = new;
current.push;
current.push;
let diff = current.diff_with;
assert_eq!;
assert_eq!;
assert!;
Diff exposes newly_failing, newly_passing, severity_changes,
duration_regressions, added, removed. All vectors are sorted by
check name so two diffs of the same input pair are byte-equal.
Aggregating multiple producers
A single CI run usually invokes several producers (dev-bench,
dev-fixtures, dev-async, ...). MultiReport aggregates them while
preserving each check's (producer, name) identity:
use ;
let mut bench = new.with_producer;
bench.push;
let mut chaos = new.with_producer;
chaos.push;
let mut multi = new;
multi.push;
multi.push;
multi.finish;
let json = multi.to_json.unwrap;
Output formats
Four opt-in features render a Report (and MultiReport) into other
formats. All are pure functions; JSON remains the only round-trippable
wire format.
terminal—to_terminal/to_terminal_color(ANSI). 80-column friendly. No new dependencies.markdown—to_markdownemits a CommonMark-compatible document preserving every fact (verdict, severity, tags, evidence, durations). No new dependencies.sarif—to_sarifemits a SARIF 2.1.0 document. OnlyFailandWarnchecks are included (SARIF is a defect-report format). Severity maps to SARIFlevel:Critical/Error→error,Warning→warning,Info→note.Evidence::FileRefbecomes a SARIFphysicalLocation. No new dependencies.junit—to_junit_xmlemits a Jenkins/Surefire JUnit XML document. Every check becomes a<testcase>; fails get a<failure>child, skips get a<skipped/>child, warns are emitted as passing testcases (JUnit has no native warn representation; use SARIF for warns). No new dependencies.
Verdict rules
Computed by Report::overall_verdict():
| Condition | Overall verdict |
|---|---|
Any check is Fail |
Fail |
Else any check is Warn |
Warn |
Else any check is Pass |
Pass |
Else (all Skip or empty) |
Skip |
Wire format and JSON Schema
The canonical wire format for both Report and MultiReport is JSON. A
JSON Schema document (Draft 2020-12) describing every field is shipped in
the crate at schema/report.schema.json.
The schema is the contract for cross-language consumers: a TypeScript /
Python / Go / jq user can write tooling against a Report without
touching Rust. The schema covers all of Report, MultiReport,
CheckResult, Verdict, Severity, Evidence, EvidenceData, and
FileRef, with field-level descriptions.
CI validates a generated sample against the schema on every run via
scripts/validate_schema.py and the schema_sample example.
The dev-* suite
dev-report is the foundation. The other crates produce reports in this
schema:
dev-fixtures- test environments and sample datadev-bench- performance measurement and regression detectiondev-async- async-specific validationdev-stress- high-load stress testingdev-chaos- failure injection and recovery testingdev-tools- umbrella crate with feature gates
Status
v0.9.x is the pre-1.0 stabilization line. The schema is at
schema_version = 1 and stays there through this line. Minor
additions remain possible before 1.0; the 1.0 release will pin
the schema and follow strict semver.
Minimum supported Rust version
1.85 — pinned in Cargo.toml via rust-version and verified by
the MSRV job in CI. (Bumped from 1.75 because transitive dependencies
in the suite require edition2024, stabilized in Rust 1.85.)
License
Apache-2.0. See LICENSE.