pub mod iceberg;
pub mod iceberg_schema;
pub mod ragnar;
pub mod sql;
pub mod maintenance;
pub mod dep_graph;
pub mod funnel;
pub mod release_events;
pub mod release_changes;
pub mod clone_events;
pub mod workspace_events;
pub mod airgap_events;
pub mod test_results;
pub mod build_provenance;
pub mod test_inventory;
pub mod saga_events;
pub mod surface_coverage;
pub mod ui_snapshots;
pub mod coverage;
pub mod viz_actions;
pub mod agent_model_runs;
pub mod codegen_judge;
pub mod blob_store;
pub mod access_scan;
pub mod warehouse_access;
pub mod generator;
use std::path::Path;
use anyhow::{Context, Result};
use arrow::array::RecordBatch;
use uuid::Uuid;
use crate::bench::BenchRun;
use crate::config::Storage;
pub use skade::{Scalar, ScanFilter};
pub trait Warehouse: Send + Sync {
fn append_arrow(&self, table: &str, batch: RecordBatch) -> Result<()>;
fn scan_arrow(&self, table: &str) -> Result<Vec<RecordBatch>>;
fn scan_filtered(
&self,
table: &str,
filter: &ScanFilter,
columns: &[&str],
) -> Result<Vec<RecordBatch>>;
fn scan_limited(&self, table: &str, max_rows: usize) -> Result<Vec<RecordBatch>>;
fn ensure_table(
&self,
table: &str,
schema: ::iceberg::spec::Schema,
partition_cols: &[&str],
) -> Result<()>;
fn ensure_columns(&self, table: &str, canonical: &::iceberg::spec::Schema) -> Result<()>;
fn table_names(&self) -> Result<Vec<String>>;
fn append_bench_run(&self, repo: &str, run: &BenchRun) -> Result<Uuid>;
fn query_bench_runs(&self, filter: &BenchFilter) -> Result<Vec<BenchRun>>;
}
#[derive(Debug, Default, Clone)]
pub struct BenchFilter {
pub repo: Option<String>,
pub machine: Option<String>,
pub limit: Option<usize>,
}
impl BenchFilter {
pub fn for_repo(repo: impl Into<String>) -> Self {
Self { repo: Some(repo.into()), machine: None, limit: None }
}
}
pub fn open(storage: &Storage, workspace_root: &Path) -> Result<Box<dyn Warehouse>> {
match storage.kind.as_str() {
"" | "local" | "iceberg" => {
let root = warehouse_root(storage, workspace_root);
Ok(Box::new(iceberg::IcebergWarehouse::open(&root)?))
}
"remote" => {
let root = remote_warehouse_mirror(&storage.remote_url)?;
Ok(Box::new(iceberg::IcebergWarehouse::open(&root)?))
}
other => anyhow::bail!("unknown storage.kind: {other}"),
}
}
pub fn open_read_only(storage: &Storage, workspace_root: &Path) -> Result<Box<dyn Warehouse>> {
match storage.kind.as_str() {
"" | "local" | "iceberg" => {
let root = warehouse_root(storage, workspace_root);
Ok(Box::new(iceberg::IcebergWarehouse::open_read_only(&root)?))
}
"remote" => {
let root = remote_warehouse_mirror(&storage.remote_url)?;
Ok(Box::new(iceberg::IcebergWarehouse::open_read_only(&root)?))
}
other => anyhow::bail!("unknown storage.kind: {other}"),
}
}
fn remote_warehouse_mirror(remote_url: &str) -> Result<std::path::PathBuf> {
let url = remote_url.trim();
if url.is_empty() {
anyhow::bail!(
"storage.kind = \"remote\" needs a [storage].remote_url (the warehouse git remote)"
);
}
let dest = remote_mirror_path(url);
let ssh_key = if crate::gitio::is_ssh_url(url) {
crate::gitio::nornir_ssh_key_path()
} else {
None
};
crate::gitio::clone_or_fetch(url, &dest, ssh_key.as_deref())
.with_context(|| format!("materialize remote warehouse from `{url}`"))?;
Ok(dest)
}
fn remote_mirror_path(remote_url: &str) -> std::path::PathBuf {
let url = remote_url.trim();
let base = std::env::var_os("NORNIR_REMOTE_WAREHOUSE_CACHE")
.map(std::path::PathBuf::from)
.unwrap_or_else(|| crate::config::nornir_home().join("remote-warehouses"));
base.join(remote_cache_key(url))
}
pub fn republish_remote(storage: &Storage) -> Result<crate::gitio::LocalPushReport> {
if storage.kind != "remote" {
anyhow::bail!("republish_remote: storage.kind is `{}`, not `remote`", storage.kind);
}
let url = storage.remote_url.trim();
if url.is_empty() {
anyhow::bail!("storage.kind = \"remote\" needs a [storage].remote_url");
}
let mirror = remote_mirror_path(url);
if !mirror.join(".git").exists() {
anyhow::bail!(
"no local mirror at {} — open the remote warehouse before republishing",
mirror.display()
);
}
if crate::gitio::worktree_freshness(&mirror)?.dirty {
let msg = format!("nornir: warehouse republish {}", chrono::Utc::now().to_rfc3339());
crate::gitio::commit_all(&mirror, &msg)
.context("commit warehouse mirror before push")?;
}
crate::gitio::push_to_local_remote(&mirror, url)
.context("push warehouse mirror back to remote")
}
fn remote_cache_key(url: &str) -> String {
use sha2::{Digest, Sha256};
let mut h = Sha256::new();
h.update(url.as_bytes());
let digest = h.finalize();
let mut hex = String::with_capacity(8);
for b in digest.iter().take(4) {
use std::fmt::Write as _;
let _ = write!(hex, "{b:02x}");
}
let sanitized: String = url
.chars()
.map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
.collect();
let trimmed = sanitized.trim_matches('_');
let start = trimmed.len().saturating_sub(40);
let tail = &trimmed[start..];
format!("{hex}-{tail}")
}
fn warehouse_root(storage: &Storage, workspace_root: &Path) -> std::path::PathBuf {
if storage.local_path.is_empty() {
crate::config::warehouse_default_root()
} else {
workspace_root.join(&storage.local_path).join("warehouse")
}
}
#[cfg(test)]
mod remote_warehouse_tests {
use super::*;
use crate::bench::{BenchResult, BenchRun};
use crate::config::Storage;
fn demo_run() -> BenchRun {
BenchRun {
date: "2026-07-08".into(),
timestamp: Some("2026-07-08T00:00:00Z".into()),
version: "0.1.0".into(),
machine: "ci".into(),
cores: 4,
results: vec![BenchResult {
name: "demo".into(),
metrics: {
let mut m = serde_json::Map::new();
m.insert("x_mbs".into(), serde_json::json!(123.0));
m
},
..Default::default()
}],
tests: Vec::new(),
}
}
fn env_lock() -> std::sync::MutexGuard<'static, ()> {
static L: std::sync::Mutex<()> = std::sync::Mutex::new(());
L.lock().unwrap_or_else(|e| e.into_inner())
}
#[test]
fn remote_kind_without_url_bails_helpfully() {
let st = Storage { kind: "remote".into(), local_path: String::new(), remote_url: String::new() };
let e = open(&st, Path::new("/tmp")).map(|_| ()).unwrap_err().to_string();
assert!(e.contains("remote_url"), "names the missing config: {e}");
assert!(!e.contains("Phase 5"), "the old stub bail is gone: {e}");
}
#[test]
fn remote_read_path_clones_git_warehouse_and_reads_it_back() {
let _g = env_lock();
let dir = tempfile::tempdir().unwrap();
let cache = dir.path().join("cache");
unsafe { std::env::set_var("NORNIR_REMOTE_WAREHOUSE_CACHE", &cache); }
let src = dir.path().join("src_wh");
{
let wh = iceberg::IcebergWarehouse::open(&src).unwrap();
wh.append_bench_run("demo", &demo_run()).unwrap();
} crate::gitio::init(&src).unwrap();
crate::gitio::commit_all(&src, "seed warehouse").unwrap();
let url = src.to_string_lossy().to_string();
let st = Storage { kind: "remote".into(), local_path: String::new(), remote_url: url.clone() };
let wh = open_read_only(&st, dir.path()).unwrap();
let key = remote_cache_key(&url);
assert!(cache.join(&key).join(".git").exists(), "mirror was cloned into the cache");
let runs = wh.query_bench_runs(&BenchFilter::for_repo("demo")).unwrap();
assert!(
runs.iter().any(|r| r.find("demo").is_some()),
"the bench run persisted in the remote warehouse reads back over the mirror: {runs:?}",
);
unsafe { std::env::remove_var("NORNIR_REMOTE_WAREHOUSE_CACHE"); }
}
#[test]
fn remote_write_back_republish_pushes_mutation_visible_to_a_fresh_clone() {
let _g = env_lock();
let dir = tempfile::tempdir().unwrap();
let src = dir.path().join("src_wh");
{
let wh = iceberg::IcebergWarehouse::open(&src).unwrap();
wh.append_bench_run("demo", &demo_run()).unwrap();
}
crate::gitio::init(&src).unwrap();
crate::gitio::commit_all(&src, "seed warehouse").unwrap();
let url = src.to_string_lossy().to_string();
let st =
Storage { kind: "remote".into(), local_path: String::new(), remote_url: url.clone() };
let cache1 = dir.path().join("cache1");
unsafe { std::env::set_var("NORNIR_REMOTE_WAREHOUSE_CACHE", &cache1); }
{
let wh = open(&st, dir.path()).unwrap();
wh.append_bench_run("demo2", &demo_run()).unwrap();
}
let report = republish_remote(&st).unwrap();
assert!(!report.created, "the remote branch existed → fast-forward, not create");
let cache2 = dir.path().join("cache2");
unsafe { std::env::set_var("NORNIR_REMOTE_WAREHOUSE_CACHE", &cache2); }
let wh2 = open_read_only(&st, dir.path()).unwrap();
let demo2 = wh2.query_bench_runs(&BenchFilter::for_repo("demo2")).unwrap();
assert!(
!demo2.is_empty(),
"the pushed-back mutation (repo `demo2`) is present in a fresh remote clone: {demo2:?}",
);
let demo = wh2.query_bench_runs(&BenchFilter::for_repo("demo")).unwrap();
assert!(!demo.is_empty(), "the original run is still present after republish");
unsafe { std::env::remove_var("NORNIR_REMOTE_WAREHOUSE_CACHE"); }
}
}