Release SPEC — declarative contract (znippy constellation)
This file is the source of truth from which release/bench Rust drivers are generated/driven. A human or LLM reads this plus the per-repo entry in release/nornir.toml and drives the nornir APIs. Generated files carry the header // GENERATED FROM workspace_znippy/release/SPEC.md — DO NOT EDIT.
Principles
- Rust only. No shell, no Make, no Just. Each step is one call into
nornir. - Append-only history.
bench_history.jsonllines are never edited or reordered. New runs append one JSON object per line. - Same-machine comparison. Regression checks compare only entries with the same
machinefield. First run on a new machine establishes the baseline. - Fail closed. Any gate failure aborts the release. No "warn and continue".
- One bench suite. znippy benches go through nornir's
Benchertrait inznippy/xtask/examples/nornir-bench.rs— nevercargo bench/criterion for the gate. See.nornir/benching.mdin the znippy repo.
Gates (executed in order)
| # | Name | nornir API | Aborts on |
| 1 | no-path-patches |
release::gate::no_path_patches(repo) |
any [patch.crates-io] znippy entry (znippy: off) |
| 2 | bench-run |
bench::run(repo_spec) |
any bench panics or exits non-zero |
| 3 | no-regression |
release::gate::no_regression(run, history, max_drop=0.10) |
any metric drops >10% vs last same-machine entry |
| 4 | history-appended |
bench::history::append(path, run) |
write/lock failure |
| 5 | docs-updated |
docs::assemble_and_check(repo) |
README/CLAUDE.md out of date |
Only after all gates pass: release::publish::tag_and_publish(repo_spec) walks publish_order from the repo TOML (bottom-up, per crate).
Bench history schema
One JSON object per line. Required keys:
{
"date": "2026-06-09", // ISO date
"version": "0.9.1", // semver of the repo being released
"machine": "oden", // stable identifier, kebab-case
"cores": 32,
"results": [ /* repo-specific result objects */ ]
}
Result object shape (znippy):
- archive throughput:
{ "name": "archive_small_10k", "compress_mbs": F, "decompress_mbs": F, "ratio_x": F, "files": N, "in_mb": F, "cores": N }. - decompressor vs legacy:
{ "name": "ljar_guava", "<ours>_mbs": F, "<legacy>_mbs": F, "speedup_x": F, "bytes": N }.
nornir::bench::history exposes typed structs; append serialises one line and fsyncs.
Maven asset fixtures
Bench inputs that download real JARs/wheels live in nornir::bench::assets (BENCH_JARS). Cached under the default cache dir; downloaded via pure-Rust HTTPS. The archive_real_{jars,crates,wheels} benches additionally want a staged corpus under ~/work/holger_tests/{jars,crates,wheels}/ and skip gracefully (recorded red, not fatal) when absent.
Bench fixtures live on local disk only — never on T9. T9 is an external USB drive and its throughput would skew every measurement; copy to /home/rickard/work/ first.
Documentation assembly (gate #5)
nornir::docs owns documentation generation. The znippy README has <!-- nornir:gen:start:* --> / <!-- nornir:gen:end:* --> markers for the benches/tests tables and the dependency graph; those regions are rewritten from the warehouse, never by hand. See .nornir/docs-generation.md in the nornir repo for the marker grammar.