commit 0d4e8935682582fde2e1b7756c76ca07d0936ee1
parent 6b48596d330cf485ab9ab1209bef0104fff20374
Author: triesap <tyson@radroots.org>
Date: Sat, 6 Jun 2026 20:17:17 -0700
bench: capture release evidence artifacts
- add a benchmark report binary and source-local script wrapper
- write summary JSON plus listing and search query-plan artifacts
- record deterministic benchmark smoke and restore proof fields
- update benchmark guards for the artifact shape
Diffstat:
5 files changed, 248 insertions(+), 2 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,4 +1,5 @@
/target/
+/.local/
# Local environment files
.env
diff --git a/Cargo.lock b/Cargo.lock
@@ -4130,6 +4130,7 @@ dependencies = [
"sha2",
"tangle_nips",
"tangle_protocol",
+ "tangle_runtime",
"tangle_store",
"tangle_store_surreal",
"tangle_test_support",
diff --git a/crates/tangle_bench/Cargo.toml b/crates/tangle_bench/Cargo.toml
@@ -7,16 +7,19 @@ rust-version.workspace = true
license.workspace = true
description = "Deterministic benchmark and proof-gate harnesses for tangle"
+[[bin]]
+name = "tangle-benchmark-report"
+path = "src/bin/tangle_benchmark_report.rs"
+
[dependencies]
serde_json = "1"
sha2 = "0.10"
tangle_nips = { path = "../tangle_nips" }
tangle_protocol = { path = "../tangle_protocol" }
+tangle_runtime = { path = "../tangle_runtime" }
tangle_store = { path = "../tangle_store" }
tangle_store_surreal = { path = "../tangle_store_surreal" }
tangle_test_support = { path = "../tangle_test_support" }
-
-[dev-dependencies]
tokio = { version = "1", features = ["macros", "rt"] }
[lints]
diff --git a/crates/tangle_bench/src/bin/tangle_benchmark_report.rs b/crates/tangle_bench/src/bin/tangle_benchmark_report.rs
@@ -0,0 +1,237 @@
+#![forbid(unsafe_code)]
+
+use serde_json::json;
+use std::env;
+use std::fs;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+use std::time::{SystemTime, UNIX_EPOCH};
+use tangle_bench::{
+ BenchDatasetConfig, capture_query_plans, run_ingest_benchmark, run_listing_query_benchmark,
+ run_rebuild_benchmark, run_restore_drill_smoke, run_search_benchmark,
+};
+use tangle_runtime::TANGLE_SUPPORTED_NIPS;
+
+struct BenchmarkReportArgs {
+ output_root: PathBuf,
+ run_id: String,
+ listing_count: usize,
+ note_count: usize,
+}
+
+fn main() {
+ let result = tokio::runtime::Builder::new_current_thread()
+ .enable_all()
+ .build()
+ .map_err(|error| error.to_string())
+ .and_then(|runtime| runtime.block_on(run()));
+ if let Err(error) = result {
+ eprintln!("{error}");
+ std::process::exit(1);
+ }
+}
+
+async fn run() -> Result<(), String> {
+ let args = BenchmarkReportArgs::parse(env::args().skip(1))?;
+ let artifact_dir = args.output_root.join(&args.run_id);
+ fs::create_dir_all(&artifact_dir).map_err(|error| error.to_string())?;
+ let config = BenchDatasetConfig::new(args.listing_count, args.note_count);
+
+ let ingest = run_ingest_benchmark(config).await?;
+ let listing = run_listing_query_benchmark(config).await?;
+ let search = run_search_benchmark(config).await?;
+ let query_plans = capture_query_plans(config).await?;
+ let rebuild = run_rebuild_benchmark(config).await?;
+ let restore = run_restore_drill_smoke(config).await?;
+
+ let listing_plan_path = artifact_dir.join("listing-query-plan.txt");
+ let search_plan_path = artifact_dir.join("search-query-plan.txt");
+ fs::write(&listing_plan_path, &query_plans.listing_plan_text)
+ .map_err(|error| error.to_string())?;
+ fs::write(&search_plan_path, &query_plans.search_plan_text)
+ .map_err(|error| error.to_string())?;
+
+ let expected_events = (args.listing_count + args.note_count) as u64;
+ let benchmark_smoke = ingest.attempted == expected_events
+ && ingest.inserted == expected_events
+ && listing.listing_rows == args.listing_count as u64
+ && listing.limited_rows <= listing.listing_rows
+ && search.indexed == args.listing_count as u64
+ && search.text_results > 0
+ && search.browse_results > 0
+ && rebuild.scanned == args.listing_count as u64
+ && rebuild.rebuilt == rebuild.scanned
+ && rebuild.projected == rebuild.scanned
+ && rebuild.listing_rows == args.listing_count as u64
+ && rebuild.checksum.len() == 64;
+ let query_plan_capture =
+ query_plans.listing_plan_steps > 0 && query_plans.search_plan_steps > 0;
+ let restore_drill_smoke = restore.exported == args.listing_count as u64
+ && restore.restored == restore.exported
+ && restore.checksum_matches;
+
+ let summary = json!({
+ "schema": 1,
+ "run_id": args.run_id,
+ "artifact_directory": path_string(&artifact_dir),
+ "surrealdb_mode": "memory",
+ "dataset": {
+ "listing_count": args.listing_count,
+ "note_count": args.note_count,
+ "fixture_builder_family": "tangle_test_support canonical event builders"
+ },
+ "artifacts": {
+ "summary_json": "summary.json",
+ "listing_query_plan": "listing-query-plan.txt",
+ "search_query_plan": "search-query-plan.txt"
+ },
+ "ingest": {
+ "attempted": ingest.attempted,
+ "inserted": ingest.inserted,
+ "elapsed_micros": elapsed(ingest.elapsed_micros)
+ },
+ "listing_query": {
+ "listing_rows": listing.listing_rows,
+ "limited_rows": listing.limited_rows,
+ "elapsed_micros": elapsed(listing.elapsed_micros)
+ },
+ "search": {
+ "indexed": search.indexed,
+ "text_results": search.text_results,
+ "browse_results": search.browse_results,
+ "elapsed_micros": elapsed(search.elapsed_micros)
+ },
+ "query_plan_capture": {
+ "listing_plan_steps": query_plans.listing_plan_steps,
+ "search_plan_steps": query_plans.search_plan_steps,
+ "listing_plan_text": "listing-query-plan.txt",
+ "search_plan_text": "search-query-plan.txt"
+ },
+ "rebuild": {
+ "scanned": rebuild.scanned,
+ "rebuilt": rebuild.rebuilt,
+ "projected": rebuild.projected,
+ "listing_rows": rebuild.listing_rows,
+ "checksum": rebuild.checksum,
+ "elapsed_micros": elapsed(rebuild.elapsed_micros)
+ },
+ "restore_drill": {
+ "exported": restore.exported,
+ "restored": restore.restored,
+ "source_checksum": restore.source_checksum,
+ "restored_checksum": restore.restored_checksum,
+ "checksum_matches": restore.checksum_matches
+ },
+ "supported_nips_audit": {
+ "supported_nips": TANGLE_SUPPORTED_NIPS,
+ "count": TANGLE_SUPPORTED_NIPS.len()
+ },
+ "validation_summary": {
+ "benchmark_smoke": status(benchmark_smoke),
+ "restore_drill_smoke": status(restore_drill_smoke),
+ "query_plan_capture": status(query_plan_capture),
+ "coverage_diagnostic": "not_run_by_release_acceptance"
+ }
+ });
+ let summary_path = artifact_dir.join("summary.json");
+ let raw = serde_json::to_string_pretty(&summary).map_err(|error| error.to_string())?;
+ fs::write(&summary_path, format!("{raw}\n")).map_err(|error| error.to_string())?;
+ println!("{}", path_string(&artifact_dir));
+ Ok(())
+}
+
+impl BenchmarkReportArgs {
+ fn parse(args: impl IntoIterator<Item = String>) -> Result<Self, String> {
+ let mut output_root = PathBuf::from(".local/tangle/benchmarks");
+ let mut run_id = None;
+ let mut listing_count = 12;
+ let mut note_count = 4;
+ let mut args = args.into_iter();
+ while let Some(arg) = args.next() {
+ match arg.as_str() {
+ "--output-root" => {
+ output_root = PathBuf::from(require_value("--output-root", args.next())?);
+ }
+ "--run-id" => {
+ run_id = Some(require_value("--run-id", args.next())?);
+ }
+ "--listing-count" => {
+ listing_count = parse_count("--listing-count", args.next())?;
+ }
+ "--note-count" => {
+ note_count = parse_count("--note-count", args.next())?;
+ }
+ "--help" => return Err(help_text()),
+ other => return Err(format!("unsupported argument `{other}`")),
+ }
+ }
+ let run_id = run_id.unwrap_or_else(default_run_id);
+ validate_run_id(&run_id)?;
+ Ok(Self {
+ output_root,
+ run_id,
+ listing_count,
+ note_count,
+ })
+ }
+}
+
+fn require_value(name: &'static str, value: Option<String>) -> Result<String, String> {
+ value.ok_or_else(|| format!("{name} requires a value"))
+}
+
+fn parse_count(name: &'static str, value: Option<String>) -> Result<usize, String> {
+ let raw = require_value(name, value)?;
+ raw.parse::<usize>()
+ .map_err(|error| format!("{name} must be a non-negative integer: {error}"))
+}
+
+fn validate_run_id(run_id: &str) -> Result<(), String> {
+ if run_id.is_empty() || run_id.contains('/') || run_id.contains('\\') || run_id.contains("..") {
+ return Err("run id must be a single relative path segment".to_owned());
+ }
+ Ok(())
+}
+
+fn default_run_id() -> String {
+ format!("local-{}-{}", unix_seconds(), git_short_commit())
+}
+
+fn unix_seconds() -> u64 {
+ SystemTime::now()
+ .duration_since(UNIX_EPOCH)
+ .map(|duration| duration.as_secs())
+ .unwrap_or(0)
+}
+
+fn git_short_commit() -> String {
+ Command::new("git")
+ .args(["rev-parse", "--short", "HEAD"])
+ .output()
+ .ok()
+ .filter(|output| output.status.success())
+ .and_then(|output| String::from_utf8(output.stdout).ok())
+ .map(|value| value.trim().to_owned())
+ .filter(|value| !value.is_empty())
+ .unwrap_or_else(|| "unknown".to_owned())
+}
+
+fn status(value: bool) -> &'static str {
+ if value { "pass" } else { "fail" }
+}
+
+fn elapsed(value: u128) -> u64 {
+ u64::try_from(value).unwrap_or(u64::MAX)
+}
+
+fn path_string(path: &Path) -> String {
+ path.to_string_lossy().into_owned()
+}
+
+fn help_text() -> String {
+ [
+ "usage: tangle-benchmark-report [--output-root PATH] [--run-id ID]",
+ " [--listing-count COUNT] [--note-count COUNT]",
+ ]
+ .join("\n")
+}
diff --git a/scripts/benchmark_report.sh b/scripts/benchmark_report.sh
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+cargo run -p tangle_bench --bin tangle-benchmark-report -- "$@"