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"
Opt-in features:
[]
= { = "0.9", = ["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.0 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
Two opt-in features render a Report for human consumption. Both are
pure functions; JSON remains the only round-trippable wire format.
terminal—Report::to_terminal(monochrome) andReport::to_terminal_color(ANSI). 80-column friendly. No new dependencies.markdown—Report::to_markdownemits a CommonMark-compatible document preserving every fact (verdict, severity, tags, evidence, durations). 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 |
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.