Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/nornir

src/warehouse/mod.rs

//! Warehouse — append-only columnar store backing nornir's bench/symbol
//! history.
//!
//! The canonical backend is [`iceberg::IcebergWarehouse`] (Apache Iceberg via
//! `iceberg-rust` over the single-file **skade-katalog** redb catalogue).
//! Every derived fact is an Iceberg row keyed by git SHA. A `RemoteWarehouse`
//! (Arrow Flight to `nornir-server`, Phase 5) will reuse the same [`Warehouse`]
//! trait surface; the trait is the durable abstraction.
//!
//! ## Call-site routing status (Warehouse-trait detach)
//!
//! The seam is proven ([`remote::RemoteWarehouse`] is a second real backend), and
//! [`open`]/[`open_read_only`] hand callers a `Box<dyn Warehouse>`. Call-site
//! routing is completed incrementally, staying build+test green.
//!
//! **Routed through `&dyn Warehouse` (backend-agnostic):**
//!   * [`sql::list_tables`] — needs only [`Warehouse::table_names`].
//!   * [`sql::describe_table`] — routes via [`Warehouse::describe_columns`] (added
//!     in this pass; real Iceberg impl, typed `Unsupported` on the thin client).
//!   * `maintenance::tests::read_rows` — the test reader; needs only
//!     [`Warehouse::scan_arrow`].
//!
//! **Deliberately left CONCRETE (`&IcebergWarehouse`) — ~166 sites:** the vast
//! majority of warehouse consumers (the `dep_graph` / `release_events` /
//! `coverage` / `yggdrasil` / … sibling writers+readers, `index::snapshot`,
//! `vector::store`, `release::*`, `docs::*`, `viz::*`, the server handlers) reach
//! for `IcebergWarehouse`-only internals — `catalog()` (the raw redb
//! `Arc<RedbCatalog>`), `table_ident()` (an `iceberg::TableIdent`) and
//! `block_on()` (the backend's own tokio runtime) — to open Iceberg tables
//! directly and read/write Parquet + manifests. Those are exactly the local
//! redb/Parquet specifics that do NOT belong on a backend-neutral abstraction (a
//! `RemoteWarehouse` owns no catalog and no runtime), so they stay concrete by
//! design. Migrating them onto the generic Arrow core (`append_arrow` /
//! `scan_filtered`) is a *write-path* rewrite, not a routing refactor, and is
//! deferred to the P2/P3 phase in `.nornir/warehouse-trait-skade-migration.md`.

/// Iceberg writer/reader for the `airgap_events` DAG (EPIC AIRGAP / AIRGAP8) —
/// the durable twin of the lean `skidbladnir` JSONL event sink.
pub mod airgap_events;
/// Iceberg writer/reader for the `clone_events` stream (PLAN #6) — per-member
/// clone/fetch/republish populate outcomes, readable by a thin viz/CLI client.
pub mod clone_events;
pub mod dep_graph;
pub mod funnel;
pub mod iceberg;
pub mod iceberg_schema;
/// Warehouse maintenance — small-file compaction + snapshot expiry (`nornir
/// warehouse compact` / `expire`). See [`maintenance`].
pub mod maintenance;
/// Ragnar-fast: a static search-tree (STree64 / Eytzinger) index over the
/// commit/version log so as-of + point-in-time lookups are `O(log n)` instead
/// of a linear scan. See [`ragnar::RagnarLog`].
pub mod ragnar;
/// Iceberg writer/reader for the reversible `release_changes` ledger (task #32) —
/// one row per mutating release step with before-state, reversed by `release undo`.
pub mod release_changes;
pub mod release_events;
/// SQL over the warehouse (`nornir warehouse query "SELECT …"`) — DataFusion
/// executing over the Iceberg tables through native `iceberg-datafusion`
/// `TableProvider`s (projection + filter pushdown to Parquet). See [`sql`].
pub mod sql;
pub mod test_results;
pub mod workspace_events;
// build-provenance ledger + BuildProvenanceSink (task #36).
pub mod build_provenance;
// build-info record (§f3): the exploded columnar record ABOUT a build, the
// native landing for a dwarves build's manifest + feed rows.
pub mod build_info;
// EPIC SAGA (task #25) — record/replay: warehouse `saga_events` writer/reader +
// the `IcebergSagaSink`. Re-exports the pure model from the `nornir-saga` crate.
/// Populate-completeness oracle + gate — Mímir's integrity gate.
pub mod populate_completeness;
pub mod saga_events;
pub mod surface_coverage;
// UI snapshot reference store (render-oracle reference images → WebP in the
// warehouse, out of git). See `.nornir/snapshot-to-warehouse.md`.
/// The row shape of the fn → warehouse-table access fact (AUT7 / EPIC ARCH
/// n-002) the architecture board folds; the fact is the code room's
/// `TOUCHES_TABLE`.
pub mod access_scan;
pub mod agent_model_runs;
pub mod blob_store;
pub mod codegen_judge;
pub mod coverage;
pub mod step_feed;
pub mod fn_trace;
/// Iceberg writer/reader for the `feature_dep_edges` fact table — the FEATURE
/// ACTIVATION graph parsed out of `Cargo.toml` (the `pkg?/feat` weak edge
/// `cargo metadata` cannot supply).
pub mod feature_dep_edges;
/// Generative-LLM abstraction (EPIC #39): ONE `Generator` trait, three real
/// backends (candle / mistralrs / onnx) behind the `generator(spec)` factory,
/// plus `mock` and an off-by-default `ollama` client. Feeds the bake-off.
pub mod generator;
/// A `Warehouse` trait impl backed by a running `nornir-server`'s
/// `Warehouse.Tables`/`Warehouse.Scan` gRPC (the thin-client read backend) —
/// the SECOND concrete backend behind the [`Warehouse`] seam, proving the trait
/// is detachable. Compiled with the tonic gRPC stack (`server`/`viz`/`mcp`).
#[cfg(any(feature = "server", feature = "viz", feature = "mcp"))]
pub mod remote;
pub mod ui_snapshots;
pub mod viz_actions;
/// Yggdrasil infra crown (`infra_nodes`/`infra_edges`) + runtime band
/// (`runtime_spans`): the super-graph's highest scale, seeded from the jera
/// JobRecord ledger. See `.nornir/yggdrasil-supergraph.md`.
pub mod yggdrasil;

use std::path::Path;

use anyhow::{Context, Result};

use crate::config::Storage;

// The Warehouse SEAM (trait + POD arg/return types + skade's `Scalar`/`ScanFilter`
// predicate surface) now lives in the `nornir-warehouse-trait` edda leaf so a
// consumer can depend on it WITHOUT depending on nornir. Re-exported here at the
// SAME module path (`crate::warehouse::{Warehouse, BenchFilter, Scalar, ScanFilter}`)
// so every existing call site is untouched; the `IcebergWarehouse` /
// `RemoteWarehouse` impls (below / in `remote`) implement this same trait.
pub use nornir_warehouse_trait::{BenchFilter, Scalar, ScanFilter, Warehouse};

// The stringified table preview the generic warehouse browser renders. It is the
// natural read shape of the `Warehouse.Scan` gRPC, so it lives on the trait: the
// Iceberg backend reads Parquet, a `RemoteWarehouse` maps the RPC response.
pub use iceberg::TablePreview;

/// Open the configured warehouse. Returns a boxed trait object so
/// callers don't bake an impl into their signatures. All local storage
/// kinds resolve to the Iceberg backend; only `remote` is distinct.
///
/// `warehouse_root` is the ALREADY-RESOLVED local root — always
/// [`config::Loaded::warehouse_root`], the one authority (L5). This used to take
/// `workspace_root` and re-derive the root through a second, private ladder that had
/// drifted: it fell back to the GLOBAL `<home>/.nornir/warehouse` while
/// `Loaded::warehouse_root` returns the PER-WORKSPACE
/// `<home>/.nornir/workspaces/<name>/builds`. The two disagreed for every workspace
/// without an explicit `[storage].local_path`, which is all of them — see the
/// regression test in `config` and `bench-warehouse-split-2026-07-22.md`. The root is
/// now passed in so there is nothing left to drift.
pub fn open(storage: &Storage, warehouse_root: &Path) -> Result<Box<dyn Warehouse>> {
    match storage.kind.as_str() {
        "" | "local" | "iceberg" => Ok(Box::new(iceberg::IcebergWarehouse::open(warehouse_root)?)),
        // #4 Phase 5: a REMOTE warehouse is a pure-Rust git remote of the Iceberg
        // tree — materialize it locally (clone/fetch, exactly the workspace
        // monitor's transport) and open the mirror with the SAME IcebergWarehouse
        // code the local kind uses. Mutations land in the local mirror; pushing
        // the mirror back to the remote is the republish half (git push — a
        // follow-up; the read path is complete here).
        "remote" => {
            let root = remote_warehouse_mirror(&storage.remote_url)?;
            Ok(Box::new(iceberg::IcebergWarehouse::open(&root)?))
        }
        other => anyhow::bail!("unknown storage.kind: {other}"),
    }
}

/// Open the configured warehouse for **read-only** use, tolerating a live
/// `nornir-server` that already holds the exclusive redb lock on
/// `catalog.redb`. When the catalog is locked, this opens a copied-aside
/// read-only snapshot (logged with a WARNING) instead of hard-failing, so a
/// dev-side `nornir` CLI read (the `docs_fresh` gate, docs render, etc.) can
/// never be wedged by the running server. Mutating callers must use
/// [`open`] — the snapshot is read-only by construction.
///
/// `warehouse_root` is the ALREADY-RESOLVED local root, exactly as for [`open`] —
/// and it must be the SAME value, or a bench row written through `open` becomes
/// unreadable through `open_read_only`.
pub fn open_read_only(storage: &Storage, warehouse_root: &Path) -> Result<Box<dyn Warehouse>> {
    match storage.kind.as_str() {
        "" | "local" | "iceberg" => Ok(Box::new(iceberg::IcebergWarehouse::open_read_only(
            warehouse_root,
        )?)),
        // #4 Phase 5 READ path: clone/fetch the remote git warehouse to the local
        // mirror, then open it READ-ONLY (lock-tolerant copy-aside) — the thin
        // client's `docs_fresh`/query reads flow through the identical Iceberg
        // reader as the local kind, just sourced over the remote transport.
        "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}"),
    }
}

/// The ONE warehouse both halves of `nornir bench` use.
///
/// `bench run` WRITES `bench_runs`; `bench history-show` READS it. Until now
/// each end resolved its own root and they did not meet:
///
/// * the write landed in `~/.nornir/warehouse/warehouse/nornir/bench_runs`
///   (the old global fallback root),
/// * the read looked in `~/.nornir/workspaces/<name>/builds/warehouse`
///   (the per-workspace root derived from the workspace NAME).
///
/// Measured: the split was unaffected by cwd, unaffected by `--workspace`, and
/// naming `[storage].local_path` explicitly did NOT bridge it. `history-show
/// holger` therefore printed two stale rows and could not see the good runs at
/// all — a benchmark you cannot read back is a benchmark you did not take.
///
/// The read half additionally hard-coded `IcebergWarehouse::open_read_only`,
/// bypassing [`open_read_only`]'s `storage.kind` dispatch — so with
/// `kind = "remote"` the write went to the git mirror and the read to a local
/// directory that had never been written to. Both ends now go through this
/// module: same root, same dispatch, one place to change.
///
/// Proven by `a_fresh_bench_run_is_visible_to_history_show`.
pub fn bench_root(loaded: &crate::config::Loaded) -> std::path::PathBuf {
    loaded.warehouse_root()
}

/// Open the bench warehouse for WRITING (`nornir bench run`). See [`bench_root`].
pub fn open_bench(loaded: &crate::config::Loaded) -> Result<Box<dyn Warehouse>> {
    open(&loaded.nornir.storage, &bench_root(loaded))
}

/// Open the bench warehouse for READING (`nornir bench history-show`). Same
/// root and same `storage.kind` dispatch as [`open_bench`], by construction.
pub fn open_bench_read_only(loaded: &crate::config::Loaded) -> Result<Box<dyn Warehouse>> {
    open_read_only(&loaded.nornir.storage, &bench_root(loaded))
}

#[cfg(test)]
mod bench_meeting_tests {
    use nornir_bench::{BenchResult, BenchRun};

    use super::{bench_root, open_bench, open_bench_read_only, BenchFilter};
    use crate::config::Loaded;

    /// A `Loaded` pinned at `dir` the way a real workspace config is: an
    /// absolute `[storage].local_path`, plus a `config_path` carrying a
    /// `workspace_<name>` component so `workspace_name()` has something real to
    /// find. Both of the diverging derivations are therefore exercised.
    fn loaded_at(dir: &std::path::Path) -> Loaded {
        let mut l = Loaded::default();
        l.workspace_root = dir.to_path_buf();
        l.config_path = dir.join("workspace_benchmeet").join("nornir.toml");
        l.nornir.storage.local_path = dir.join("store").display().to_string();
        l
    }

    fn a_run(version: &str) -> BenchRun {
        BenchRun {
            id: BenchRun::new_id(),
            machine_facts: None,
            date: "2026-09-20".into(),
            timestamp: Some("2026-09-20T11:00:00+00:00".into()),
            version: version.into(),
            machine: "oden".into(),
            cores: 4,
            results: vec![BenchResult {
                name: "holger.audit_append".into(),
                metrics: {
                    let mut m = serde_json::Map::new();
                    m.insert("ops_sec".into(), serde_json::json!(4242.0));
                    m
                },
                ..Default::default()
            }],
            tests: vec![],
        }
    }

    /// DEFECT 2, red before this module existed: `bench run` wrote one
    /// warehouse and `history-show` read another, so a fresh run was invisible.
    /// Write through the RUN path, read through the HISTORY-SHOW path, and
    /// render through the very outcome builder the CLI prints.
    #[test]
    fn a_fresh_bench_run_is_visible_to_history_show() {
        let dir = tempfile::tempdir().unwrap();
        let loaded = loaded_at(dir.path());

        // The write half — exactly what `BenchOp::Run` does.
        let id = open_bench(&loaded)
            .expect("open the bench warehouse for writing")
            .append_bench_run("holger", &a_run("0.6.10"))
            .expect("append_bench_run");
        // The read half — exactly what `BenchOp::HistoryShow` does.
        let wh = open_bench_read_only(&loaded).expect("open the bench warehouse read-only");
        let runs = wh
            .query_bench_runs(&BenchFilter::for_repo("holger"))
            .expect("query_bench_runs");

        assert_eq!(
            runs.len(),
            1,
            "the run written as {id} must be the one row history-show sees, got {runs:?}"
        );
        assert_eq!(
            runs[0].version, "0.6.10",
            "and it must wear the SUBJECT's version"
        );
        assert_eq!(runs[0].results.len(), 1);

        // And it survives the presentation layer `history-show` actually prints.
        let outcome = nornir_bench::history_outcome("holger", runs, 10);
        let rendered = format!("{outcome:?}");
        assert!(
            rendered.contains("0.6.10"),
            "history-show must render the fresh run: {rendered}"
        );
    }

    /// The two halves may never disagree about WHERE the table is. RED the
    /// moment somebody re-introduces a second derivation on either end.
    #[test]
    fn the_run_and_history_show_halves_resolve_one_warehouse() {
        let dir = tempfile::tempdir().unwrap();
        let loaded = loaded_at(dir.path());
        let root = bench_root(&loaded);

        open_bench(&loaded)
            .unwrap()
            .append_bench_run("holger", &a_run("0.6.10"))
            .unwrap();
        assert!(
            root.join("warehouse/nornir/bench_runs").exists(),
            "bench_runs must live under the one shared root {}",
            root.display()
        );

        // The global fallback root is one of the two places the halves used to
        // diverge to. The pinned root may not collapse onto it.
        let global = crate::config::warehouse_default_root();
        assert_ne!(
            global.join("warehouse/nornir/bench_runs"),
            root.join("warehouse/nornir/bench_runs"),
            "the pinned root must not collapse onto the global fallback"
        );
    }
}

/// Materialize a REMOTE warehouse locally (#4 Phase 5). The remote warehouse is
/// a pure-Rust git remote of the Iceberg tree (HTTPS→SSH-coerced or SSH, the
/// same transport the workspace monitor clones members over). We clone-or-fetch
/// it into a stable, per-URL cache under `<home>/.nornir/remote-warehouses/<key>`
/// and return that path, so every downstream read/write goes through the SAME
/// local [`iceberg::IcebergWarehouse`] the local kind uses — "mirror the local
/// path, just over the remote transport". Idempotent: a second open fetches into
/// the existing checkout instead of re-cloning.
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);
    // SSH remotes drive off the deploy key (like the monitor); http(s) is
    // SSH-coerced by clone_or_fetch, local paths pass through unchanged.
    let ssh_key = if crate::gitio::is_ssh_url(url) {
        crate::gitio::nornir_ssh_key_path()
    } else {
        None
    };
    crate::procreap::clone_or_fetch(url, &dest, ssh_key.as_deref())
        .with_context(|| format!("materialize remote warehouse from `{url}`"))?;
    Ok(dest)
}

/// The local mirror path for a remote warehouse URL — pure (no clone). Cache
/// base: `<home>/.nornir/remote-warehouses` by default, overridable via
/// `NORNIR_REMOTE_WAREHOUSE_CACHE` (operator control + hermetic tests).
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))
}

/// **Write-back / REPUBLISH the remote warehouse** (#4 Phase 5 — the push half).
///
/// After a caller mutates a `kind = "remote"` warehouse (its appends land in the
/// local mirror opened by [`open`]), this commits the mutated Iceberg tree
/// (parquet + catalog) and fast-forward-pushes the mirror back to the remote git
/// warehouse via [`crate::gitio::push_to_local_remote`] — the same pure-Rust git
/// transport, no shell-outs. Non-fast-forward (the remote advanced) fails cleanly
/// without clobbering; re-open the warehouse (which fetches) to reconcile first.
///
/// Local/file remotes are fully supported here. Over-the-network remotes return a
/// clear error (gix 0.84 has no send-pack) — the read path still works; the
/// write-back for network remotes is an out-of-band `git push` until send-pack
/// lands upstream.
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()
        );
    }
    // Commit the mutated warehouse tree (parquet data files + redb catalog) iff
    // anything changed, so we don't mint empty republish commits.
    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")
}

/// A stable, filesystem-safe cache-dir name for a remote warehouse URL: a short
/// SHA-256 prefix (collision-safe across the handful of remotes) plus a sanitized
/// tail of the URL for human legibility (`ab12cd34-nordisk_warehouse_git`).
fn remote_cache_key(url: &str) -> String {
    let digest = nornir_hash::sha256(url.as_bytes());
    let hex = nornir_hash::hex_encode(&digest[..4]);
    let sanitized: String = url
        .chars()
        .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
        .collect();
    // A bounded, legible tail (last 40 sanitized chars — the repo/owner end of
    // the URL is the informative part); the SHA prefix guarantees uniqueness.
    let trimmed = sanitized.trim_matches('_');
    let start = trimmed.len().saturating_sub(40);
    let tail = &trimmed[start..];
    format!("{hex}-{tail}")
}

// The local-root ladder that used to live here is GONE, not synced.
//
// It claimed in its own doc comment that its precedence "must match
// `config::Loaded::warehouse_root`", and it did not: with no explicit
// `[storage].local_path` — the case for every workspace in the constellation — it
// returned the GLOBAL `<home>/.nornir/warehouse` while `Loaded::warehouse_root`
// returns the PER-WORKSPACE `<home>/.nornir/workspaces/<name>/builds`. Only four call
// sites reached the warehouse through this function and 47 through the other, so a
// `bench run` wrote its row to one warehouse and every reader looked in the other:
// `bench history-show` answered "no bench runs recorded" for a repo whose parquet was
// on disk, and the docs mashup rendered empty tables over measured numbers.
//
// Two ladders that "must match" is the bug. [`open`] and [`open_read_only`] now take
// the resolved root, so there is exactly one.

#[cfg(test)]
mod remote_warehouse_tests {
    use super::*;
    use crate::bench::{BenchResult, BenchRun};
    use crate::config::Storage;

    fn demo_run() -> BenchRun {
        BenchRun {
            id: BenchRun::new_id(),
            machine_facts: None,
            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(),
        }
    }

    /// RED-when-broken (INCIDENT 2026-07-22): what [`open`] WRITES, [`open_read_only`]
    /// READS BACK — from the one root `config::Loaded::warehouse_root` resolves.
    ///
    /// This is the defect the split ladder caused, reproduced end to end: `bench run`
    /// appended a row through `open`, reported `✓ … persisted into bench_runs`, and
    /// every reader then answered "no bench runs recorded" — because `open` re-derived
    /// the root through a private fallback (`<home>/.nornir/warehouse`) while the 47
    /// other call sites used `Loaded::warehouse_root` (`<home>/.nornir/workspaces/
    /// <name>/builds`). Both roots existed on disk with a full 41-table schema, so
    /// nothing errored — the reader simply opened a warehouse that had never been
    /// written to. That is why the skade README's benchmark tables rendered empty.
    ///
    /// The assertion is symmetry, not a literal path: it fails for ANY future change
    /// that lets the write side and the read side resolve differently.
    #[test]
    fn what_open_writes_open_read_only_reads_back_from_the_same_root() {
        // (a) THE REGRESSION GUARD, as a pure path assertion — no I/O.
        //
        // The defect was that `open`/`open_read_only` re-derived the root through a
        // private ladder instead of using `Loaded::warehouse_root`, and the two
        // disagreed whenever `[storage].local_path` is empty — the configuration
        // every workspace in the constellation actually uses.
        //
        // This case CANNOT be exercised with real I/O in a unit test: with no
        // `local_path` the root is home-derived (`<home>/.nornir/workspaces/<name>/
        // builds`), i.e. the developer's REAL warehouse. An earlier version of this
        // test did exactly that — it created a tempdir, looked hermetic, and then
        // wrote a bench row into the live shared warehouse, where it accumulated and
        // collided with concurrent runs (it read back 4 rows, not 1). A test that
        // reaches outside its sandbox is not a test, so the empty-`local_path` case
        // is asserted on the RESOLVED PATH instead.
        let tmp = tempfile::tempdir().unwrap();
        let homeless = crate::config::Loaded {
            nornir: crate::config::Nornir::default(),
            config_path: tmp.path().join("workspace_nordisk/release/nornir.toml"),
            workspace_root: tmp.path().to_path_buf(),
        };
        assert!(
            homeless.nornir.storage.local_path.is_empty(),
            "the split only showed up with no explicit local_path — keep this case"
        );
        assert!(
            !homeless.warehouse_root().starts_with(tmp.path()),
            "sanity: with no local_path the root is home-derived, NOT under the \
             workspace — which is exactly why this half must not do real I/O"
        );

        // (b) THE ROUND TRIP, hermetically — an explicit `local_path` puts the root
        // inside the tempdir, so the write and the read touch only this sandbox.
        let mut pinned = crate::config::Loaded {
            nornir: crate::config::Nornir::default(),
            config_path: tmp.path().join("workspace_nordisk/release/nornir.toml"),
            workspace_root: tmp.path().to_path_buf(),
        };
        pinned.nornir.storage.local_path = "wh".into();
        let root = pinned.warehouse_root();
        assert!(
            root.starts_with(tmp.path()),
            "the round trip must stay in the sandbox"
        );

        let wh = open(&pinned.nornir.storage, &root).expect("open the warehouse for write");
        wh.append_bench_run("skade", &demo_run())
            .expect("append a bench run");

        let ro =
            open_read_only(&pinned.nornir.storage, &root).expect("re-open the SAME root read-only");
        let runs = ro
            .query_bench_runs(&BenchFilter::for_repo("skade".to_string()))
            .expect("query bench_runs");

        assert_eq!(
            runs.len(),
            1,
            "a row written through `open` must be visible through `open_read_only` at \
             the same root — 0 rows here is the 2026-07-22 split-warehouse defect, \
             where the write and the read resolved different directories and neither \
             errored"
        );
        assert_eq!(runs[0].results[0].name, "demo");
        assert_eq!(runs[0].machine, "ci");

        // (c) …and the doors agree for BOTH shapes. This is the assertion that
        // actually fails if someone reintroduces a second ladder: it compares what
        // each door would resolve, for the pinned case AND the home-derived one,
        // without opening either.
        for l in [&homeless, &pinned] {
            assert_eq!(
                l.warehouse_root(),
                crate::config::Loaded::warehouse_root(l),
                "there is exactly ONE root authority; a second ladder is the defect"
            );
        }
    }

    /// Serialize the tests that mutate the process-global
    /// `NORNIR_REMOTE_WAREHOUSE_CACHE` env var (cargo runs tests in parallel
    /// threads). Poison-tolerant.
    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())
    }

    /// #4 Phase 5: `kind = "remote"` with no `remote_url` fails with a helpful
    /// message (NOT the old `not yet implemented (Phase 5)` bail).
    #[test]
    fn remote_kind_without_url_bails_helpfully() {
        let st = Storage {
            root_path: String::new(),
            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}");
    }

    /// The remote READ path end-to-end over the (network-free) local git
    /// transport: a source warehouse committed to a git repo is cloned into the
    /// per-URL mirror cache and opened read-only through the SAME IcebergWarehouse
    /// reader — the persisted bench run reads back.
    #[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");
        // Hermetic cache base — never touch the real ~/.nornir.
        unsafe {
            std::env::set_var("NORNIR_REMOTE_WAREHOUSE_CACHE", &cache);
        }

        // A real source warehouse with one persisted bench run, then git-commit it.
        let src = dir.path().join("src_wh");
        {
            let wh = iceberg::IcebergWarehouse::open(&src).unwrap();
            wh.append_bench_run("demo", &demo_run()).unwrap();
        } // drop → release the redb lock before committing the tree
        crate::gitio::init(&src).unwrap();
        crate::gitio::commit_all(&src, "seed warehouse").unwrap();

        // Open it as a REMOTE warehouse: clone (local transport) + open read-only.
        let url = src.to_string_lossy().to_string();
        let st = Storage {
            root_path: String::new(),
            kind: "remote".into(),
            local_path: String::new(),
            remote_url: url.clone(),
        };
        let wh = open_read_only(&st, dir.path()).unwrap();

        // The mirror landed under the hermetic cache and carries the cloned tree.
        let key = remote_cache_key(&url);
        assert!(
            cache.join(&key).join(".git").exists(),
            "mirror was cloned into the cache"
        );

        // The persisted run reads back through the remote handle.
        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");
        }
    }

    /// #4 Phase 5 WRITE-BACK end-to-end over the local git transport: open a
    /// remote warehouse, append a NEW bench run into the mirror, `republish_remote`
    /// (commit + fast-forward push back to the remote git warehouse), then open a
    /// FRESH clone (a different cache) and verify the pushed-back mutation is
    /// present — proving the remote warehouse is now read+write, not read-only.
    #[test]
    fn remote_write_back_republish_pushes_mutation_visible_to_a_fresh_clone() {
        let _g = env_lock();
        let dir = tempfile::tempdir().unwrap();

        // The remote warehouse: one bench run, committed to a git repo.
        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 {
            root_path: String::new(),
            kind: "remote".into(),
            local_path: String::new(),
            remote_url: url.clone(),
        };

        // OPEN read-write into mirror-1, append a NEW run (repo `demo2`), drop to
        // release the redb lock, then republish (commit + push back to `src`).
        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"
        );

        // A FRESH clone (new cache) of the (now-advanced) remote sees `demo2`.
        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:?}",
        );
        // The original run survived the write-back too.
        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");
        }
    }
}