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

nordisk/nornir

src/warehouse/iceberg_schema.rs

//! Iceberg spec::Schema definitions mirroring `super::schema::*` Arrow
//! schemas. Field IDs are explicit and stable — append new fields with
//! a fresh, unused ID; never reuse, never renumber.

use std::sync::Arc;

use anyhow::Result;
use iceberg::spec::{NestedField, PrimitiveType, Schema, Type};

// ─── THE LANGUAGE AXIS ──────────────────────────────────────────────
//
// The knowledge/vector tables were written by ONE producer family (the `syn`
// scanner and `rust-analyzer scip`), so nothing in them said which LANGUAGE a
// row came from. That column is what turns "this function is duplicated" into
// "you maintain the same logic in Rust and in Java, and they have drifted" —
// see `workspace_nordisk/.nornir/mimir-language-axis-design.md`.
//
// Three axes, three distinct columns (they are NOT interchangeable):
//
//   `language`  — the INDEXER that produced the row (`rust` · `java` ·
//                 `typescript` · …), named after the SCIP indexer that emits it
//                 so the vocabulary stays aligned with the one language-neutral
//                 standard already in the stack. It is what the PRODUCER says
//                 about itself, never a guess from a filename: a `.jar` has no
//                 source path at all, and `.jar` is Java, Kotlin, Scala and
//                 Clojure alike.
//   `ecosystem` — the PACKAGE MANAGER whose graph an edge belongs to (`cargo` ·
//                 `maven` · `npm` · `conan`). Orthogonal to `language`: Java and
//                 Kotlin share `maven`; a Rust cdylib shipped through `conan` is
//                 `rust` in a non-cargo ecosystem. This is dwarves'
//                 `Ecosystem::name()` value — one vocabulary, not two.
//   `model_id`  — the READABLE embedding-model id (`jina-v2-base-code`), the
//                 `vector::embed_registry::EmbedModel::id`. It does NOT replace
//                 `model_profile` (the weights-SHA-sensitive dedup key); it makes
//                 that opaque sha256 interpretable, and it is what a
//                 cross-language cosine calibration must be keyed against —
//                 vectors from different models are not comparable, and a
//                 threshold calibrated for one says nothing about another.
//
// All three ship as ADDITIVE-OPTIONAL fields with fresh field ids (the file
// header rule), exactly like `test_results.aspect`, `dep_graph_edges.kind`,
// `funnel_events.item_kind` and `sbom_components.derived_from` before them.
// `iceberg::ensure_table_schema` evolves a live table forward on the first write
// that needs them; old binaries keep reading.

/// Documented default for a NULL `language`: every row written before the axis
/// existed came from a Rust producer. MEASURED, not assumed — `embedding_manifest`
/// was 100% `.rs` when the column landed. NULL therefore means "pre-axis", never
/// "unknown": an unrecognised indexer writes the explicit, visible sentinel
/// `unknown:<tool>` instead, so genuine ignorance stays queryable.
pub const LANG_DEFAULT: &str = "rust";

/// Documented default for a NULL `ecosystem` — every pre-axis dep-graph edge was
/// resolved from `cargo metadata`.
pub const ECOSYSTEM_DEFAULT: &str = "cargo";

/// Documented default for a NULL `derived_by` (the edge DERIVATION-PROVENANCE
/// axis; see [`crate::knowledge::symbols::EdgeDerivation`]). Every `call_edges`
/// row written before the axis came from the `syn` AST scanner — the only
/// producer that persisted to this table — so NULL means "pre-axis", never
/// "unknown". Kept in lock-step with `EdgeDerivation::default().as_str()` (a unit
/// test pins the agreement).
pub const DERIVED_BY_DEFAULT: &str = "ast";

/// Documented default for a NULL `model_id` — the `embed_registry` default model
/// (`DEFAULT_MODEL_ID`), the only one any stored vector was produced by.
pub const MODEL_ID_DEFAULT: &str = "jina-v2-base-code";

/// Read a possibly-NULL `language` cell through the ONE documented default, so
/// the fallback can never drift between call sites. See [`LANG_DEFAULT`].
pub fn language_or_default(v: Option<&str>) -> &str {
    match v {
        Some(s) if !s.is_empty() => s,
        _ => LANG_DEFAULT,
    }
}

/// Read a possibly-NULL `ecosystem` cell. See [`ECOSYSTEM_DEFAULT`].
pub fn ecosystem_or_default(v: Option<&str>) -> &str {
    match v {
        Some(s) if !s.is_empty() => s,
        _ => ECOSYSTEM_DEFAULT,
    }
}

/// Read a possibly-NULL `derived_by` cell through the ONE documented default so
/// the fallback can never drift between call sites. See [`DERIVED_BY_DEFAULT`].
pub fn derived_by_or_default(v: Option<&str>) -> &str {
    match v {
        Some(s) if !s.is_empty() => s,
        _ => DERIVED_BY_DEFAULT,
    }
}

/// Read a possibly-NULL `model_id` cell. See [`MODEL_ID_DEFAULT`].
pub fn model_id_or_default(v: Option<&str>) -> &str {
    match v {
        Some(s) if !s.is_empty() => s,
        _ => MODEL_ID_DEFAULT,
    }
}

/// The `language` value for a SCIP index, derived from its
/// `Index.metadata.tool_info.name` — the indexer identity SCIP already puts on
/// the wire (`rust-analyzer`, `scip-java`, `scip-typescript`, …).
///
/// Total and never-panicking. An unrecognised indexer yields
/// `unknown:<tool>` rather than being coerced to [`LANG_DEFAULT`]: a
/// MIS-tagged row is worse than an untagged one, because it would enter
/// cross-language comparison under a false identity.
pub fn language_for_scip_tool(tool: &str) -> String {
    match tool.trim() {
        "" => LANG_DEFAULT.to_string(),
        "rust-analyzer" | "scip-rust" => "rust".to_string(),
        "scip-java" => "java".to_string(),
        "scip-kotlin" => "kotlin".to_string(),
        "scip-typescript" => "typescript".to_string(),
        "scip-python" => "python".to_string(),
        "scip-go" => "go".to_string(),
        "scip-clang" => "cpp".to_string(),
        "scip-ruby" => "ruby".to_string(),
        "scip-dotnet" => "csharp".to_string(),
        other => format!("unknown:{other}"),
    }
}

pub fn bench_runs() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "run_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                4,
                "date",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "machine",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "cores",
                Type::Primitive(PrimitiveType::Int),
            )),
            // The checkout's HEAD the run measured — set by a forge's Runa `Bench`
            // step (`Telemetry.SubmitStepFeed`), which files keyed by (repo,
            // commit). NULL on a run measured before the column, or by a door
            // that does not know its commit.
            Arc::new(NestedField::optional(
                8,
                "commit",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

pub fn bench_results() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "run_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "result_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "metric_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "metric_value",
                Type::Primitive(PrimitiveType::Double),
            )),
        ])
        .build()?)
}

/// Per-bench runtime telemetry, one row per `(run_id, bench)` — the CPU/mem
/// footprint the in-bench sampler captured while that unit ran. Sibling of
/// `bench_results` (which is one row per scalar metric); kept separate so the
/// load profile never competes in the docs metric-comparison renderer and can
/// be queried on its own. `repo` is carried so reads prune by repo like
/// `bench_runs`. See `.nornir/bencher.md` for what each column means.
///
/// **Two families, and only one of them is about the bench.** Fields 5–8
/// (`cpu_pct_*`, `cores_busy_*`) come from `/proc/stat` and describe the WHOLE
/// HOST — every process on the box. On a shared machine a strictly serial arm
/// reads `cores_busy_max = n_cores`, which is how a saturation gate reading
/// them passed forever (measured on oden 2026-08-03: `gunnar.walk_1m` at 32/32
/// while the process held 0.56 of one core). Keep them: they are honest
/// ambient context and every historical row is expressed in them. But judge a
/// bench only on fields 12–15, which come from `/proc/self/stat` and are
/// host-independent.
///
/// Fields 12–15 are OPTIONAL because rows written before 2026-08-03 genuinely
/// have no such measurement — `NULL` there means "not measured", which a
/// consumer must distinguish from a measured `0.0`. Existing tables evolve
/// forward additively on the next append (`ensure_table_schema`); old data
/// files read back as NULL in the new columns.
pub fn bench_telemetry() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "run_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "bench",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "n_cores",
                Type::Primitive(PrimitiveType::Int),
            )),
            // 5-8: HOST-WIDE (/proc/stat) — the whole box, ambient context only.
            Arc::new(NestedField::required(
                5,
                "cpu_pct_avg",
                Type::Primitive(PrimitiveType::Double),
            )),
            Arc::new(NestedField::required(
                6,
                "cpu_pct_max",
                Type::Primitive(PrimitiveType::Double),
            )),
            Arc::new(NestedField::required(
                7,
                "cores_busy_avg",
                Type::Primitive(PrimitiveType::Double),
            )),
            Arc::new(NestedField::required(
                8,
                "cores_busy_max",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                9,
                "mem_peak_mb",
                Type::Primitive(PrimitiveType::Double),
            )),
            Arc::new(NestedField::required(
                10,
                "mem_pct_max",
                Type::Primitive(PrimitiveType::Double),
            )),
            Arc::new(NestedField::required(
                11,
                "elapsed_ms",
                Type::Primitive(PrimitiveType::Double),
            )),
            // 12-15: PROCESS-SCOPED (/proc/self/stat) — task-clock ÷ wall. The
            // saturation gate's ONLY legitimate input. NULL = not measured.
            Arc::new(NestedField::optional(
                12,
                "proc_cpu_ms",
                Type::Primitive(PrimitiveType::Double),
            )),
            Arc::new(NestedField::optional(
                13,
                "child_cpu_ms",
                Type::Primitive(PrimitiveType::Double),
            )),
            Arc::new(NestedField::optional(
                14,
                "proc_cores_avg",
                Type::Primitive(PrimitiveType::Double),
            )),
            Arc::new(NestedField::optional(
                15,
                "proc_cores_max",
                Type::Primitive(PrimitiveType::Double),
            )),
        ])
        .build()?)
}

pub fn test_outcomes() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "run_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "test_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "passed",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::optional(
                4,
                "duration_ms",
                Type::Primitive(PrimitiveType::Double),
            )),
            Arc::new(NestedField::optional(
                5,
                "message",
                Type::Primitive(PrimitiveType::String),
            )),
            // Impact selection (feature: run only tests downstream of a changed crate).
            Arc::new(NestedField::optional(
                6,
                "source_repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                7,
                "source_crate",
                Type::Primitive(PrimitiveType::String),
            )),
            // Flake bookkeeping (feature: auto-quarantine).
            Arc::new(NestedField::optional(
                8,
                "attempt_idx",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::optional(
                9,
                "retry_of_run_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                10,
                "quarantined",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            // A Runa test step's own run (`Telemetry.SubmitStepFeed`): its rows have
            // NO `bench_runs` row — `source_repo` / `source_crate` say where the test
            // lives, `commit` which code it ran against, and `status` the verdict in
            // full (`pass` | `fail` | `ignored`; `passed` alone cannot say ignored).
            // NULL on a bench-coupled row, whose `bench_runs` row says all of it.
            Arc::new(NestedField::optional(
                11,
                "status",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                12,
                "commit",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// First-class test-matrix results — one row per `(run_id, suite, test_name)`.
///
/// Where `test_outcomes` is keyed to a `bench_runs.run_id` (bench-shaped,
/// co-written with a bench), this is the standalone green/red board the C6
/// test-matrix writes: `nornir test <repo>` runs the repo's `cargo test`
/// (or `cargo nextest run`), parses each test's pass/fail + duration, and
/// appends one row per case under a fresh `run_id`. The viz **Test** pane
/// reads it back as a per-repo matrix (newest run on top, green/red per test).
///
/// Grain: one row per test case in a run. `(run_id, suite, test_name)` is the
/// logical key. `status` ∈ `pass | fail | ignored | stalled` (the stall
/// watchdog records `stalled` + red when a subprocess goes silent). `suite` is
/// the crate / test target the case lives in. `message` carries the failure
/// detail (`""` = none, never null). `ts_micros` is the run time (shared by all
/// of a run's rows). See `.nornir/test-matrix.md`.
pub fn test_results() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "run_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "suite",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "test_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "status",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "duration_ms",
                Type::Primitive(PrimitiveType::Double),
            )),
            Arc::new(NestedField::required(
                7,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                8,
                "message",
                Type::Primitive(PrimitiveType::String),
            )),
            // EPIC L — multi-aspect engine. Which aspect produced the row
            // (`unit` default, `build`, `clippy`, `coverage`, …) + its numeric
            // metric (coverage %, warning count, advisory count; 0.0 = N/A).
            // OPTIONAL so the columns are migration-safe: tables written before
            // EPIC L carry neither, and the reader defaults them back to
            // `aspect = "unit"`, `metric = 0.0`.
            Arc::new(NestedField::optional(
                9,
                "aspect",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                10,
                "metric",
                Type::Primitive(PrimitiveType::Double),
            )),
        ])
        .build()?)
}

/// Build-provenance ledger (`build_provenance`, task #36) — one row per recorded
/// `nornir build --attest`. The full record travels in `record_json`; the flat
/// columns (variant, digest, outcome, host cores/memory, artifact_count) stay
/// queryable. `digest` is the SHA-256 over the canonical record (the value the
/// znippy seal binds to). Partitioned by `repo`.
pub fn build_provenance() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "variant",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "outcome",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "profile",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "target",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "vcs_rev",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "vcs_branch",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                9,
                "rustc",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                10,
                "host_cores",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                11,
                "host_memory_bytes",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                12,
                "artifact_count",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                13,
                "digest",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                14,
                "built_at",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                15,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                16,
                "record_json",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Build-info record (`build_info`, build-info flight-stream design §f3/§f6) —
/// the exploded columnar record ABOUT a build, the queryable sibling of
/// `build_provenance` (that ledger holds one flat row per build; this holds the
/// per-fact rows). Columns match the design's §f3 Arrow schema **1:1** so the
/// live wire, the at-rest `<artifact>.build-info.znippy` seal, and this warehouse
/// table are one shape — no second format. Grain: one row per (`build_id`,
/// `kind`, `name`); `kind` ∈ `provenance | dep | artifact | log | metric | step`
/// (the first three are the Artifactory-parity manifest, the last three the live
/// feed). `blob` is the ONLY nullable column (a small inline log payload); it
/// keeps `ts_micros` as a raw Int64 (design fidelity), unlike `build_provenance`.
pub fn build_info() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "build_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "step_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "ts_micros",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                4,
                "kind",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "level",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "value",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "content_id",
                Type::Primitive(PrimitiveType::String),
            )),
            // The only nullable column — an inline log chunk (design §f3).
            Arc::new(NestedField::optional(
                9,
                "blob",
                Type::Primitive(PrimitiveType::Binary),
            )),
        ])
        .build()?)
}

/// Saga record/replay (`saga_events`, EPIC SAGA / task #25) — one row per
/// captured user-journey event, the production sibling of `test_results`.
///
/// Where `test_results` records test verdicts, this records **navigation + log
/// events** (`nornir_saga::SagaEvent`) an app emitted via `record(...)` behind
/// the `saga` feature. The matrix reads a session's rows back, builds a
/// `ReplayPlan` (`Nav`/`Click` → `ReplayStep`), and replays the path as a robot
/// test — a failed replay is a RED matrix row.
///
/// Grain: one row per captured event. `(session_id, seq)` is the logical key —
/// `seq` is the per-process monotonic capture counter the recorder stamps, so a
/// session's events sort into journey order independent of wall-clock skew
/// (Iceberg gives no scan order, so reads sort by `seq`). `kind` ∈
/// `nav | click | log | error | state`; `nav`/`click` are the actionable
/// (replayable) events, the rest are context. `state_json` is the component's
/// readable state at that moment — **PII-free** by adapter contract (the capture
/// adapter emits only render-state, never form secrets). `sha` is the sha256 of
/// the canonical event payload (route/component/action/state_json) for
/// integrity + dedup. `ts_micros` is the recorder's wall-clock stamp.
pub fn saga_events() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "session_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "seq",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                3,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                4,
                "kind",
                Type::Primitive(PrimitiveType::String),
            )),
            // The replay TARGET trio: route (view) + component + action verb.
            Arc::new(NestedField::required(
                5,
                "route",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "component",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "action",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "detail",
                Type::Primitive(PrimitiveType::String),
            )),
            // PII-free readable state the component/route observed at this moment.
            Arc::new(NestedField::required(
                9,
                "state_json",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                10,
                "level",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                11,
                "span_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                12,
                "parent",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                13,
                "app_user",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                14,
                "app",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                15,
                "app_version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                16,
                "git_sha",
                Type::Primitive(PrimitiveType::String),
            )),
            // sha256 of the canonical event payload — integrity + dedup.
            Arc::new(NestedField::required(
                17,
                "sha",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

pub fn dep_graph_edges() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "workspace_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                4,
                "from_repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "to_repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "via_crate",
                Type::Primitive(PrimitiveType::String),
            )),
            // Dependency KIND of the edge (`normal`/`build`/`dev`). Optional so an
            // existing warehouse table (created before kinds were tracked) reads it
            // as null → `Normal`; a fresh snapshot carries the real kind so the
            // warehouse-fed publish order (`release run`) can exclude dev edges.
            Arc::new(NestedField::optional(
                7,
                "kind",
                Type::Primitive(PrimitiveType::String),
            )),
            // ECOSYSTEM AXIS — which package manager's graph this edge belongs to
            // (`cargo` / `maven` / `npm` / `conan`), i.e. dwarves'
            // `Ecosystem::name()`. Deliberately NOT the `language` column: Java and
            // Kotlin share `maven`, and a Rust cdylib consumed through `conan` is
            // `rust` in a non-cargo ecosystem. Same additive-optional contract as
            // `kind` above; NULL reads back as `cargo` via [`ecosystem_or_default`].
            Arc::new(NestedField::optional(
                8,
                "ecosystem",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// The three RELEASE tables — `release_lineage`, `release_events` and
/// `release_changes` — are defined ONCE in the shared `nornir-release-ledger`
/// edda leaf and re-exported here at their original paths.
///
/// They used to live in this file AND, in hand-maintained copy, in the release
/// orchestrator (which may not take a crate edge on this umbrella). Both halves
/// write into the SAME warehouse, so a column added to one copy and not the
/// other yields mutually incompatible tables and **nothing fails at compile
/// time**. PRE-PROMPT L5: consumed, never twinned. Every `iceberg_schema::…`
/// call site — `iceberg::ensure_tables`, the release pipeline's lineage writer,
/// the ledger codecs — resolves unchanged.
pub use nornir_release_ledger::schema::{release_changes, release_events, release_lineage};

/// Airgap-op DAG (EPIC AIRGAP / AIRGAP8): one row per `product × op × phase`
/// boundary as `nornir airgap` packs / moves / unfolds / installs / starts a
/// lake. The airgap twin of [`release_events`]; `depends_on` carries the
/// bring-up edges so a reader can draw where a partial install stalled.
pub fn airgap_events() -> Result<Schema> {
    use iceberg::spec::ListType;

    let depends_on = Type::List(ListType::new(Arc::new(NestedField::required(
        121,
        "element",
        Type::Primitive(PrimitiveType::String),
    ))));

    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "run_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "seq",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                3,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                4,
                "product",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "op",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "phase",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "status",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "detail",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(9, "depends_on", depends_on)),
        ])
        .build()?)
}

/// Clone/fetch/republish populate outcomes (PLAN #6): one row per monitored
/// workspace member attempt as the server's poll loop / `Workspaces.Fetch`
/// clones+fetches the members and republishes the warehouse. The durable,
/// remotely-readable twin of the per-member `eprintln!("…fetch error…")` — a thin
/// viz/CLI client reads this to see *why* a member didn't populate (auth, vanished
/// repo, network) instead of only seeing missing data.
///
/// Mirrors `release_events` shape minus the `depends_on` DAG edges (a fetch has no
/// inter-member ordering): scalar columns only, so SQL readers query it directly.
pub fn clone_events() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                2,
                "workspace",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "member",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "remote",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "op",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "status",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "detail",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "elapsed_ms",
                Type::Primitive(PrimitiveType::Long),
            )),
        ])
        .build()?)
}

/// Workspace-populate STEP stream (`workspace_events`, EPIC #21 POPULATE 6-8).
///
/// Where `clone_events` records the git clone/fetch outcome per member, this
/// records the per-STEP outcome of a `republish_with` POPULATE pass — one row
/// per (member, step) plus a workspace-level `populate` summary row (member
/// `*`). Steps: `snapshot` / `deep-scan` / `test-surface` / `arch-generate` /
/// `populate`. `status` is `ok` | `error` | `skipped`. Same shape/read pattern
/// as `clone_events` so the fat/thin split reuses one renderer.
pub fn workspace_events() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                2,
                "workspace",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "member",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "step",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "status",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "detail",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "elapsed_ms",
                Type::Primitive(PrimitiveType::Long),
            )),
        ])
        .build()?)
}

/// Funnel events: every mutation to the idea-intake DAG lands here as
/// a new row. Each Iceberg append produces a new snapshot, so the
/// table at snapshot T is the funnel state as of time T.
///
/// Schema is **wide** — one optional column per variant-specific field —
/// rather than a JSON blob, so SQL readers (DuckDB / PyIceberg) can
/// query the DAG directly without re-parsing.
///
/// Nested types in use:
///   * `refs`, `targets`, `produced_test_runs` → `list<string>`
///   * `produced_commits` → `list<struct{repo, sha}>`
///
/// `params_json` stays a string because `NodeAdded.params` is an
/// open-ended `serde_json::Map` with no fixed value type. If we ever
/// constrain it, promote to a typed map<string, *>.
pub fn funnel_events() -> Result<Schema> {
    use iceberg::spec::{ListType, StructType};

    // produced_commits element struct {repo, sha}
    let commit_struct = Type::Struct(StructType::new(vec![
        Arc::new(NestedField::required(
            101,
            "repo",
            Type::Primitive(PrimitiveType::String),
        )),
        Arc::new(NestedField::required(
            102,
            "sha",
            Type::Primitive(PrimitiveType::String),
        )),
    ]));

    let list_string = |elem_id: i32| {
        Type::List(ListType::new(Arc::new(NestedField::required(
            elem_id,
            "element",
            Type::Primitive(PrimitiveType::String),
        ))))
    };

    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            // Envelope
            Arc::new(NestedField::required(
                1,
                "event_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                3,
                "kind",
                Type::Primitive(PrimitiveType::String),
            )),
            // Common id refs (any subset depending on kind)
            Arc::new(NestedField::optional(
                4,
                "idea_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                5,
                "plan_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                6,
                "node_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                7,
                "run_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                8,
                "from_node",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                9,
                "to_node",
                Type::Primitive(PrimitiveType::String),
            )),
            // IdeaSubmitted
            Arc::new(NestedField::optional(
                10,
                "source",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                11,
                "text",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(12, "refs", list_string(112))),
            // IdeaTriaged / NodeStatusChanged / PlanStatusChanged / RunRecorded
            Arc::new(NestedField::optional(
                13,
                "decision",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                14,
                "node_status",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                15,
                "plan_status",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                16,
                "why",
                Type::Primitive(PrimitiveType::String),
            )),
            // PlanCreated
            Arc::new(NestedField::optional(
                17,
                "summary",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                18,
                "planner",
                Type::Primitive(PrimitiveType::String),
            )),
            // NodeAdded
            Arc::new(NestedField::optional(
                19,
                "node_kind",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(20, "targets", list_string(120))),
            Arc::new(NestedField::optional(
                21,
                "prompt_excerpt",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                22,
                "params_json",
                Type::Primitive(PrimitiveType::String),
            )),
            // RunRecorded
            Arc::new(NestedField::optional(
                23,
                "ran_by",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                24,
                "outcome",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                25,
                "log_ref",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                26,
                "produced_commits",
                Type::List(ListType::new(Arc::new(NestedField::required(
                    126,
                    "element",
                    commit_struct,
                )))),
            )),
            Arc::new(NestedField::optional(
                27,
                "produced_test_runs",
                list_string(127),
            )),
            // EPIC FUNNEL-INTAKE (FI3): an `IdeaSubmitted` item's KIND —
            // `idea` (default) or `error`. An error report is a first-class
            // funnel item, triageable to a plan like any idea. OPTIONAL so it
            // is migration-safe: pre-FI rows carry no value and the reader
            // defaults them to `idea` (the table is auto-evolved forward on the
            // first FI write via `iceberg::ensure_table_schema`).
            Arc::new(NestedField::optional(
                28,
                "item_kind",
                Type::Primitive(PrimitiveType::String),
            )),
            // funnel-prompt-planner keystone: five more OPTIONAL, defaulted
            // columns, added the EXACT same way `item_kind` (28) landed —
            // pre-keystone rows carry no value and the reader defaults them
            // (mode → None, member/role/from_lane/to_lane → None), and the
            // table auto-evolves forward on the first write that needs them.
            // `IdeaModeSet.idea_id`/`CardAssigned.node`/`CardStateChanged.node`
            // (a generic card id, idea OR task-node) reuse the existing
            // `idea_id`/`node_id` columns above; `why` reuses column 16.
            Arc::new(NestedField::optional(
                29,
                "mode",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                30,
                "member",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                31,
                "role",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                32,
                "from_lane",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                33,
                "to_lane",
                Type::Primitive(PrimitiveType::String),
            )),
            // Plan-DAG ↔ Component-DAG wiring (`Event::PlanComponentWired`): four
            // more OPTIONAL columns, added the EXACT same migration-safe way
            // `item_kind` (28) and the keystone five (29-33) landed — pre-wiring
            // rows carry no value and the reader defaults them, and a live table
            // auto-evolves forward on the first write that needs them.
            // `plan_node` reuses `node_id` (6) — it is a generic card id, idea OR
            // task node, exactly like `CardAssigned.node` — and `why` reuses 16.
            // `origin`/`status` get their own `wire_*` names so they can never be
            // confused with the run `outcome` (24) or the plan/node status columns.
            Arc::new(NestedField::optional(
                34,
                "component",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                35,
                "wire_origin",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                36,
                "wire_status",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                37,
                "wire_confidence",
                Type::Primitive(PrimitiveType::Double),
            )),
        ])
        .build()?)
}

// ─── Generic artifact blob tables (time machine) ────────────────────
//
// Uniform two-table shape used by every immutable derived artifact
// (Tantivy index, DWARF debuginfo, gimli unwind tables, …):
//
//   <artifact>_snapshots — metadata, one row per (repo, git_sha) capture
//   <artifact>_blobs     — raw bytes, one row per file inside the capture
//
// Restore = SELECT blobs WHERE snapshot_id=X → write each (filename,
// bytes) row to a tmpdir → open with the artifact's native loader.
// No re-tokenize, no rebuild — Tantivy / gimli mmap the bytes back as
// if they had been written by the original producer.
//
// Field IDs use disjoint ranges per artifact kind so future renames /
// merges stay safe:
//   tantivy_index_snapshots : 1–9
//   tantivy_index_blobs     : 1–5
//   (future artifacts re-use the same low IDs — each table is its own
//    schema, IDs don't collide across tables.)

/// Snapshot metadata table for any artifact kind.
pub fn artifact_snapshots() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "workspace",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "git_sha",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "branch",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                7,
                "schema_hash",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "blob_count",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                9,
                "total_bytes",
                Type::Primitive(PrimitiveType::Long),
            )),
        ])
        .build()?)
}

/// Blob payload table for any artifact kind.
pub fn artifact_blobs() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "filename",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "bytes",
                Type::Primitive(PrimitiveType::Binary),
            )),
            Arc::new(NestedField::required(
                4,
                "byte_len",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                5,
                "sha256",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Rendered-document exports, historized inline (one row per distinct
/// `(repo, doc_name, version, format, sha256)`). The `bytes` column carries
/// the full artifact so any past version is recoverable by warehouse read —
/// the file directory under `<gitroot>/docs/` only holds the current copy.
pub fn doc_exports() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "export_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "workspace",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "doc_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "format",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "git_sha",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                9,
                "sha256",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                10,
                "byte_len",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                11,
                "bytes",
                Type::Primitive(PrimitiveType::Binary),
            )),
        ])
        .build()?)
}

// ─── Vector / semantic-search tables ────────────────────────────────
//
// Materialized embeddings live in the warehouse so semantic search at any
// historical git_sha is a warehouse read — never a re-embed, never a git
// walk (the performance point for mega codebases). Three tables:
//
//   embeddings           : content-addressed, deduped vector store. A chunk's
//                          768-float vector for a given model is ONE row,
//                          stored once ever regardless of how many commits
//                          contain that chunk. The vector is a native Arrow
//                          `list<float32>` column — a contiguous f32 buffer
//                          that maps straight to/from VectorIndex's Vec<f32>
//                          (no byte (de)serialization), and stays queryable by
//                          DuckDB / Polars / DataFusion.
//   embedding_snapshots  : identity of one semantic index build —
//                          (repo, git_sha, model_profile, chunker_hash,
//                          fileset_hash, complete). Makes re-index idempotent.
//   embedding_manifest   : per-occurrence rows for a snapshot — which
//                          content_hash sits at which file/span. NO vector and
//                          NO source text (code stays in git, identity =
//                          git_sha). Time-travel = filter manifest by
//                          snapshot_id, JOIN embeddings, build the index.
//
// Field IDs are per-table and start at 1.

/// Content-addressed, deduped vector store. PK (logical) = (content_hash,
/// model_profile).
pub fn embeddings() -> Result<Schema> {
    use iceberg::spec::ListType;
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "content_hash",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "model_profile",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "dim",
                Type::Primitive(PrimitiveType::Int),
            )),
            // Native Arrow list<float32>: a contiguous f32 buffer, mapped
            // straight to/from VectorIndex's Vec<f32> with no byte coding.
            Arc::new(NestedField::required(
                4,
                "vector",
                Type::List(ListType::new(Arc::new(NestedField::required(
                    104,
                    "element",
                    Type::Primitive(PrimitiveType::Float),
                )))),
            )),
            Arc::new(NestedField::required(
                5,
                "normalized",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                6,
                "vector_sha256",
                Type::Primitive(PrimitiveType::String),
            )),
            // LANGUAGE AXIS — the language of the chunk this vector embeds. The
            // embedding tier is the ONLY duplicate-detection tier that can cross a
            // language boundary (a hash or a signature-token overlap cannot, by
            // construction), so this column is what makes "the same logic exists in
            // Rust and in Java, and they have drifted" a warehouse read instead of
            // a filename guess. OPTIONAL; NULL reads back as `rust`.
            Arc::new(NestedField::optional(
                7,
                "language",
                Type::Primitive(PrimitiveType::String),
            )),
            // The READABLE model id (`jina-v2-base-code`) behind the opaque
            // `model_profile` sha256. Both are kept: `model_profile` stays the
            // weights-SHA-sensitive DEDUP key (a re-quantised export must not share
            // rows), `model_id` makes it interpretable and is what a cross-language
            // cosine calibration is keyed against — a threshold measured for one
            // model says NOTHING about another, and mixing vector spaces produces
            // confident nonsense. OPTIONAL; NULL reads back as the registry default.
            Arc::new(NestedField::optional(
                8,
                "model_id",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Identity of one semantic-index build.
pub fn embedding_snapshots() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "workspace",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "git_sha",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "branch",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "model_profile",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "chunker_hash",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "fileset_hash",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                9,
                "complete",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                10,
                "row_count",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                11,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
        ])
        .build()?)
}

/// Per-occurrence rows belonging to one `embedding_snapshots` row.
pub fn embedding_manifest() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ordinal",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                3,
                "content_hash",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "model_profile",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "file",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "start_line",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                7,
                "end_line",
                Type::Primitive(PrimitiveType::Int),
            )),
        ])
        .build()?)
}

// ─── One vector per function node (Mímir v2) ────────────────────────
//
// The link from a code-room node to the vector of its text. The vector itself
// stays in `embeddings`, keyed by `content_hash`: identical bodies share one
// row there. The link is an append-only CHANGE LOG, the shape of the code
// room's own event tables (plan §12): per (repo, moniker) the last event up
// to a consumer ordinal is the state, `+` = the node's text hashes to
// `content_hash`, `-` = the node is gone. A commit writes events only for the
// functions whose text changed.

/// `embedding_node_events` — node id (SCIP moniker) → `content_hash`, as events.
/// `repo` is the member, or `@universe` for the dependency ring (`seq` 0).
pub fn embedding_node_events() -> Result<Schema> {
    let s = |id: i32, name: &str| Arc::new(NestedField::required(id, name, Type::Primitive(PrimitiveType::String)));
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            s(1, "repo"),
            Arc::new(NestedField::required(2, "seq", Type::Primitive(PrimitiveType::Long))),
            s(3, "sha"),
            s(4, "op"),
            s(5, "moniker"),
            // null on a `-` event
            Arc::new(NestedField::optional(6, "content_hash", Type::Primitive(PrimitiveType::String))),
            // which cut rule produced the text (a new rule is a new link set)
            s(7, "chunker"),
            Arc::new(NestedField::required(8, "ts_micros", Type::Primitive(PrimitiveType::Timestamptz))),
        ])
        .build()?)
}

/// `embedding_node_runs` — the ledger of the function-embedding runs: one row
/// per member run (`unit` empty) and one per ring crate (`repo` = `@universe`,
/// `unit` = `crate@version`). What a reader needs to say which state the
/// vectors are of, in which model space, and why a run did not embed.
pub fn embedding_node_runs() -> Result<Schema> {
    let s = |id: i32, name: &str| Arc::new(NestedField::required(id, name, Type::Primitive(PrimitiveType::String)));
    let n = |id: i32, name: &str| Arc::new(NestedField::required(id, name, Type::Primitive(PrimitiveType::Long)));
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            s(1, "run_id"),
            s(2, "repo"),
            s(3, "unit"),
            n(4, "seq"),
            s(5, "sha"),
            s(6, "chunker"),
            s(7, "model_profile"),
            s(8, "model_id"),
            s(9, "backend"),
            // function nodes that have a chunk at this state
            n(10, "functions"),
            n(11, "distinct_bodies"),
            n(12, "new_vectors"),
            n(13, "plus"),
            n(14, "minus"),
            // function nodes without a chunk (macro-generated, no span, file unreadable)
            n(15, "without_chunk"),
            n(16, "ms"),
            // `ok` / `skipped` / `error`
            s(17, "status"),
            Arc::new(NestedField::optional(18, "detail", Type::Primitive(PrimitiveType::String))),
            Arc::new(NestedField::required(19, "ts_micros", Type::Primitive(PrimitiveType::Timestamptz))),
        ])
        .build()?)
}

/// `fn_shape_events` — the clone signals' per-function shape, a change log
/// like `embedding_node_events`: per (repo, moniker) the last event up to an
/// ordinal is the state. A `+` carries the normalised body's exact key, its
/// token count and its MinHash signature (`clone_signals`); a `-` closes the
/// node. `shape` names the normalisation rule (a new rule is a new set).
pub fn fn_shape_events() -> Result<Schema> {
    let s = |id: i32, name: &str| Arc::new(NestedField::required(id, name, Type::Primitive(PrimitiveType::String)));
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            s(1, "repo"),
            Arc::new(NestedField::required(2, "seq", Type::Primitive(PrimitiveType::Long))),
            s(3, "sha"),
            s(4, "op"),
            s(5, "moniker"),
            s(6, "shape"),
            // null on a `-` event
            Arc::new(NestedField::optional(7, "exact", Type::Primitive(PrimitiveType::String))),
            Arc::new(NestedField::required(8, "tokens", Type::Primitive(PrimitiveType::Long))),
            Arc::new(NestedField::optional(9, "minhash", Type::Primitive(PrimitiveType::Binary))),
            // what the text says about itself that the lenses label by: `simd`
            // (a `target_feature` / `std::arch` / intrinsic body — a deliberate width variant)
            Arc::new(NestedField::optional(10, "flags", Type::Primitive(PrimitiveType::String))),
            Arc::new(NestedField::required(11, "ts_micros", Type::Primitive(PrimitiveType::Timestamptz))),
        ])
        .build()?)
}

/// `fn_role_vectors` — the clone signals' role vectors (FastRP over the code
/// room, `clone_signals::structure`), beside the text vectors: one row per
/// function whose vector was (re)computed, keyed by its STABLE id and the seq
/// of its repo at that state; the newest row per id is the vector. `vector`
/// is `dim` little-endian f32; `feat_hash` is the hash of the features it was
/// computed from (what the incremental update compares).
pub fn fn_role_vectors() -> Result<Schema> {
    let s = |id: i32, name: &str| Arc::new(NestedField::required(id, name, Type::Primitive(PrimitiveType::String)));
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            s(1, "repo"),
            s(2, "stable_id"),
            Arc::new(NestedField::required(3, "seq", Type::Primitive(PrimitiveType::Long))),
            s(4, "feat_hash"),
            s(5, "space"),
            Arc::new(NestedField::required(6, "vector", Type::Primitive(PrimitiveType::Binary))),
            Arc::new(NestedField::required(7, "ts_micros", Type::Primitive(PrimitiveType::Timestamptz))),
        ])
        .build()?)
}

// ─── Cargo-pipeline tables ──────────────────────────────────────────
//
// Each table is release-scoped (joined to `release_lineage.release_id`)
// or dep-graph-snapshot-scoped (joined to `dep_graph_edges.snapshot_id`)
// or stand-alone (events / plans). Field IDs restart at 1 per table —
// they are local to each schema.

/// Feature 1 — audit version= on every path-dep.
/// One row per (release, repo, manifest_path, dep_name).
pub fn path_dep_audits() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "release_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "manifest_path",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "dep_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "dep_path",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "has_version",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::optional(
                7,
                "version_req",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "ok",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                9,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
        ])
        .build()?)
}

/// Feature 2 (rich variant) — per-line patch-strip events.
pub fn patch_strip_events() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "release_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "file",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "line",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                5,
                "raw_line",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "action",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
        ])
        .build()?)
}

/// Feature 3 — replaces the planned `sleep 20` between publishes.
/// Loop writes a row per attempt; `index_seen_ts_micros` is set when
/// crates.io's index advertises the new version.
pub fn publish_attempts() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "release_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "crate_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "attempt_idx",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                6,
                "started_ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::optional(
                7,
                "index_seen_ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::optional(
                8,
                "wait_ms",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::optional(
                9,
                "http_status",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                10,
                "outcome",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                11,
                "stderr_excerpt",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Feature 4 — gate readme/license/repository/description metadata.
pub fn crate_metadata_checks() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "release_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "crate_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "has_readme",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                6,
                "has_license",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::optional(
                7,
                "license_expr",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "has_repository",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::optional(
                9,
                "repository_url",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                10,
                "has_description",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::optional(
                11,
                "description_len",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                12,
                "ok",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                13,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
        ])
        .build()?)
}

/// Feature 5 — `.crate` tarball size + largest file warning.
pub fn crate_tarball_stats() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "release_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "crate_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "tarball_bytes",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                6,
                "file_count",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::optional(
                7,
                "largest_file",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                8,
                "largest_file_bytes",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::optional(
                9,
                "p50_bytes_baseline",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                10,
                "exceeds_threshold",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                11,
                "threshold_bytes",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                12,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
        ])
        .build()?)
}

/// Feature 6 — cascade yank/un-yank in dep order. Self-referential via
/// `cascade_root_event_id` so a yank-and-its-cascade is one query.
pub fn yank_events() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "event_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                3,
                "dep_graph_snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "crate_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "action",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                8,
                "reason",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                9,
                "requested_by",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                10,
                "cascade_root_event_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                11,
                "http_status",
                Type::Primitive(PrimitiveType::Int),
            )),
        ])
        .build()?)
}

/// Feature 7 — rustdoc-json semver diff. `from`/`to` reference
/// `rustdoc_json_snapshots.snapshot_id` (the existing artifact-snapshot
/// pattern).
pub fn semver_diffs() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "from_snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "to_snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "crate_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "added_items",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                6,
                "removed_items",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                7,
                "changed_items",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                8,
                "suggested_bump",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                9,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
        ])
        .build()?)
}

/// **`semver_symbol_diffs` — the per-SYMBOL grain of a `compatible?` edge.**
///
/// [`semver_diffs`] carries COUNTS: how many public items were added / removed /
/// changed between two versions and the bump that implies. It cannot say *which*
/// symbol broke — and that name is the only thing a "what breaks" join can start
/// from, so [`crate::coderoom::what_breaks`] had to re-read and re-diff BOTH public
/// surfaces on every query, with nothing durable to join against. This table
/// persists the diff at the grain the join needs: **one row per changed public
/// symbol**, produced by [`crate::coderoom::persist_compat_edge`] from the SAME
/// `nornir_release_core::ecosystem::api_compat_from_symbols` verdict that writes
/// the `semver_diffs` counts — one classifier, two grains, never two opinions.
///
/// Two join keys, deliberately both:
/// * `symbol` — the plain item name, which is what `call_edges.callee_ident`
///   carries. This is the key the SYNTACTIC caller anti-join uses (both the world
///   partitions and the deepscan `repo = "deps"` corpus).
/// * `scip_symbol` — the SCIP moniker of the same item in the FROM version, which
///   is what `scip_occurrences.symbol` carries, so a RESOLVED find-usages joins on
///   this instead. `""` when the syn pass could not place the item — an EMPTY
///   moniker, never a plausible-looking invented one.
///
/// `file` / `enc_start_line` / `enc_end_line` locate the symbol in the FROM
/// version. They are copied from that version's `scip_occurrences` row, which is
/// the only table that has an enclosing range; `0`/`""` when no such row exists.
///
/// # Snapshot keying — and why this table is NOT in `mimir_lens::SNAPSHOT_TABLES`
///
/// It carries `repo` + `snapshot_id` + `ts_micros`, which is all
/// `mimir_lens::rows::latest_snapshot_rows_of` needs, so it is mechanically
/// eligible — and the silent double-count described on `mimir_lens/mod.rs:82-92`
/// is real for any append-only table left off that list. It must still NOT be
/// listed, because that dedup keys on `repo` ALONE while this table's grain is an
/// EDGE, not a repo state: `1.0.0 → 2.0.0` and `1.5.0 → 2.0.0` are two different,
/// both-valid edges sharing `repo = "<crate>@2.0.0"`. Snapshot dedup would
/// silently delete one of them, trading a double-count for a SILENT LOSS — the
/// worse failure, and the one nobody would notice.
///
/// The double-count is closed BY CONSTRUCTION on the writer instead:
/// `persist_compat_edge` refuses to append an edge whose `(from_snapshot_id,
/// to_snapshot_id)` pair is already present, the same content-addressed
/// "already done" discipline `coderoom::partition_uningested` applies to the
/// immutable-version ingest. One writer, no guard watching two copies agree.
/// The same reasoning applies unchanged to [`semver_diffs`] itself, whose absence
/// from `SNAPSHOT_TABLES` is correct for the same reason and whose writer is now
/// idempotent for the same reason.
pub fn semver_symbol_diffs() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            // The partition + dedup key: the world repo of the TO version
            // (`<crate>@<to_version>`), matching `symbol_facts`/`call_edges`/
            // `scip_occurrences` so all four prune to one `scan_filtered`.
            Arc::new(NestedField::required(
                3,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            // The edge identity, in the same `<crate>@<version>` vocabulary
            // `semver_diffs.from_snapshot_id`/`to_snapshot_id` already use.
            Arc::new(NestedField::required(
                4,
                "from_snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "to_snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "crate_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "from_version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "to_version",
                Type::Primitive(PrimitiveType::String),
            )),
            // The SYNTACTIC join key — `call_edges.callee_ident`.
            Arc::new(NestedField::required(
                9,
                "symbol",
                Type::Primitive(PrimitiveType::String),
            )),
            // The RESOLVED join key — `scip_occurrences.symbol`. `""` when the
            // syn pass could not place the item; never an invented moniker.
            Arc::new(NestedField::required(
                10,
                "scip_symbol",
                Type::Primitive(PrimitiveType::String),
            )),
            // `added` | `removed` | `changed` — the T1 public-surface verdict for
            // this one symbol, from the shared `api_compat_from_symbols` seam.
            Arc::new(NestedField::required(
                11,
                "change",
                Type::Primitive(PrimitiveType::String),
            )),
            // The EDGE-level bump this row belongs to (`major`/`minor`/`patch`/
            // `inconclusive`), carried per row so a symbol-grain scan never has to
            // join back to `semver_diffs` to know the verdict it belongs to.
            Arc::new(NestedField::required(
                12,
                "suggested_bump",
                Type::Primitive(PrimitiveType::String),
            )),
            // Where the symbol lived in the FROM version — copied from that
            // version's `scip_occurrences` row. `""`/`0` when there is none.
            Arc::new(NestedField::required(
                13,
                "file",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                14,
                "enc_start_line",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                15,
                "enc_end_line",
                Type::Primitive(PrimitiveType::Int),
            )),
        ])
        .build()?)
}

/// Feature 8 — `links =` declarations from every manifest in a
/// dep-graph snapshot. Conflicts: `GROUP BY links_value
/// HAVING COUNT(DISTINCT crate_name) > 1`.
pub fn links_declarations() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "dep_graph_snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "crate_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "links_value",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "manifest_path",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Feature 9 — resolved feature set per workspace member, long/narrow.
/// `SELECT … FROM resolved_features WHERE member_repo='a' EXCEPT
///  SELECT … FROM resolved_features WHERE member_repo='b'`.
pub fn resolved_features() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "dep_graph_snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "workspace_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "member_repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "member_crate",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "dep_crate",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "dep_version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "feature",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "source",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Feature 10 — actual MSRV via cargo +<toolchain> check probes.
pub fn msrv_probes() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "probe_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "crate_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                4,
                "declared_rust_version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "probed_rust_version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "probe_status",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::optional(
                8,
                "ci_run_id",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Feature 11 — auditable record of which tests nornir chose to run
/// for an impact-set selection (so a green run is reproducible from
/// the dep-graph snapshot + the changed-crate set).
pub fn test_impacted_selections() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "run_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "dep_graph_snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "changed_repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "selected_test_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "reason",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
        ])
        .build()?)
}

/// Feature 12 — flake decision state (the rates themselves come from
/// a window query over `test_outcomes`).
pub fn test_quarantines() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "test_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "quarantined_at_ts",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::optional(
                4,
                "unquarantined_at_ts",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                5,
                "pass_rate_window",
                Type::Primitive(PrimitiveType::Double),
            )),
            Arc::new(NestedField::required(
                6,
                "sample_size",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                7,
                "decision_reason",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                8,
                "decided_by",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Feature 13 — commits between previous release SHA and current,
/// parsed as conventional commits for CHANGELOG generation.
pub fn release_commits() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "release_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "git_sha",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                4,
                "parent_sha",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "author",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::optional(
                7,
                "conventional_type",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                8,
                "scope",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                9,
                "breaking",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                10,
                "subject",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                11,
                "body",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Feature 14 — mirror crates.io publishes to additional registries
/// (e.g. holger). One row per (crate@version, target_registry).
pub fn registry_mirrors() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "mirror_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "release_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "crate_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "source_registry",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "target_registry",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "started_ts",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::optional(
                9,
                "completed_ts",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::optional(
                10,
                "bytes_copied",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::optional(
                11,
                "sha256",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                12,
                "outcome",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                13,
                "error",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Feature 15 — coordinated cross-workspace version bump (plan header).
pub fn version_bump_plans() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "plan_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                3,
                "dep_graph_snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "scope",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                5,
                "requested_by",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Feature 15 — coordinated bump (targets / per-crate rows).
pub fn version_bump_targets() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "plan_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "crate_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "from_version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "to_version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "reason",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "applied",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::optional(
                8,
                "applied_release_id",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

// ─── knowledge map: pure-Rust producers (syn + gix) ─────────────────────
//
// One snapshot_id groups every row emitted by a single
// `nornir knowledge scan <repo>` invocation, so the renderer can
// reconstruct a consistent point-in-time map.

/// **Feature ACTIVATION graph** — one row per edge of the graph parsed out of a
/// package's `Cargo.toml`: which feature turns on which dependency or which other
/// feature. This is the edge `cargo metadata` provably CANNOT supply: its
/// `features` map is flattened and already resolved, so the *conditional*
/// structure (what would still be pulled if a feature were switched off, and via
/// which of several routes) is gone by the time cargo hands it over. Parsing the
/// manifest is the only way to get it, so it gets its own fact table.
///
/// Grain: `(repo, crate_name, feature, enables, kind, target_cfg, dep_kind)`.
///
/// Column semantics that are load-bearing (read these before querying):
///
/// * `feature` — the feature that DECLARES the edge. An **empty string `""` is
///   not "unknown", it means UNCONDITIONAL**: the package pulls `enables` with no
///   feature behind it, so no feature toggle can ever remove it. The UI's
///   "cannot be removed" ⊥ case is exactly `feature = ''`, so a consumer that
///   treats `''` as a missing value inverts the answer.
/// * `kind` — one of `dep` (the feature enables an optional dependency),
///   `feature` (it enables another feature of the same package), `dep-feature`
///   (the `pkg/feat` form — enables `feat` on `pkg` AND implicitly enables `pkg`),
///   `weak-dep-feature` (the `pkg?/feat` form) or `implicit-dep` (the
///   auto-generated `foo = ["dep:foo"]` feature of an optional dep).
///   **`weak-dep-feature` is the whole point of this table**: `pkg?/feat` is the
///   only form that creates an AND-group — it enables `feat` on `pkg` *only if*
///   `pkg` was already enabled by some other route — so it is the one edge whose
///   activation cannot be decided by looking at a single edge in isolation.
/// * `target_cfg` — OPTIONAL, the `[target.'cfg(...)']` predicate this edge sits
///   under; NULL when the edge is unconditional across targets.
/// * `dep_kind` — `normal` | `build` | `dev`, so a consumer can exclude dev-deps
///   the way `cargo tree -e no-dev` does.
///
/// Partitioned by `repo` like [`feature_gate_facts`] (its `#[cfg]`-side sibling:
/// that table records where features are CONSUMED in source, this one records how
/// they are WIRED in the manifest).
pub fn feature_dep_edges() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                3,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "crate_name",
                Type::Primitive(PrimitiveType::String),
            )),
            // "" == UNCONDITIONAL (not behind any feature) — see the doc above.
            Arc::new(NestedField::required(
                5,
                "feature",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "enables",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "kind",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "optional",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            // NULL when the edge is not under a `[target.'cfg(...)']` block.
            Arc::new(NestedField::optional(
                9,
                "target_cfg",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                10,
                "dep_kind",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Yggdrasil **infra crown** — nodes: one row per machine / service / VM /
/// container in the constellation, grouped into one snapshot by `snapshot_id`
/// (mirrors `dep_graph_edges`' snapshot envelope). `node_group`/`from_node`/
/// `to_node` avoid SQL-reserved bare `group`/`from`/`to`. See the
/// `yggdrasil-supergraph.md` design doc (the CROWN band, previously "MISSING ⛔").
pub fn infra_nodes() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "workspace_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                4,
                "node_id",
                Type::Primitive(PrimitiveType::String),
            )),
            // machine | service | vm | container
            Arc::new(NestedField::required(
                5,
                "kind",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "host",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "node_group",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "cores",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                9,
                "mem_mb",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                10,
                "role",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                11,
                "online",
                Type::Primitive(PrimitiveType::Boolean),
            )),
        ])
        .build()?)
}

/// Yggdrasil **infra crown** — edges between infra nodes: `runs_on` (service →
/// machine), `hosts` (machine → vm/container), `deploys`, `member_of` (node →
/// worker-group). One snapshot per `snapshot_id`, same envelope as `infra_nodes`.
pub fn infra_edges() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "workspace_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                4,
                "from_node",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "to_node",
                Type::Primitive(PrimitiveType::String),
            )),
            // runs_on | hosts | deploys | member_of
            Arc::new(NestedField::required(
                6,
                "rel",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Yggdrasil **runtime / trace** band — one row per executed span (a jera job
/// or a `nornir-server` op). Seeded from the jera JobRecord ledger (`node` →
/// `machine`, `elapsed_ms` → `dur_us`). General trace shape, not bench-coupled.
pub fn runtime_spans() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "workspace_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                4,
                "span_id",
                Type::Primitive(PrimitiveType::String),
            )),
            // Parent span id (`""` = a root/top-level span).
            Arc::new(NestedField::required(
                5,
                "parent_span",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "service",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "op",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "start_micros",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                9,
                "dur_us",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                10,
                "job_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                11,
                "machine",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                12,
                "status",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// autonom completeness-gate coverage (AUT2 / n-005). One row per discovered
/// surface node × mode × workspace, tagged with its verdict
/// (`covered`/`allowlisted`/`missing`) — the persisted form of the gate, the
/// same shape as `tests/mcp_tool_coverage.json` generalized to the whole
/// surface. Additive / schema-evolving: ships via the standard evolution path,
/// old binaries keep reading. `kind`/`id`/`mode` are split out of `surface_key`
/// (`"kind:id@mode"`) so the warehouse/viz can filter without re-parsing.
pub fn surface_coverage() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "run_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                3,
                "workspace",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "surface_key",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "kind",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "mode",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "verdict",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                9,
                "reason",
                Type::Primitive(PrimitiveType::String),
            )),
            // utfallsrum (outcome-space) coverage ∈ [0,1] for this surface's
            // function(s): exercised-classes / declared-classes. Additive optional
            // field — pre-utfallsrum rows read back as 0.0 (no outcome space
            // measured), so old binaries keep reading and new ones evolve the table.
            Arc::new(NestedField::optional(
                10,
                "utfallsrum_covered",
                Type::Primitive(PrimitiveType::Double),
            )),
        ])
        .build()?)
}

/// **Precomputed kNN neighbour list** (`knn_neighbors`) — the GPU's answer,
/// landed as a TABLE so a lens can consume it without ever calling a GPU.
///
/// # Why this table exists at all
///
/// Every one of the 11+2 Mímir lenses is a pure fold `Sources → Report`. That
/// purity is the whole reason they are testable with no warehouse, and it is not
/// negotiable: a lens that reached out to a Vulkan device mid-fold would be
/// untestable, non-deterministic, and unavailable on a headless forge runner.
///
/// So the GPU does not move INTO the fold; its output moves into `Sources`. A
/// neighbour list is a table exactly like `call_edges` is a table — the lens
/// reads rows, and where those rows came from is the producer's business. This
/// is the same move `lens_chain.rs` already made for the folds themselves:
/// *"the fold moved OFF the request; it did not change."* Here the SCAN moves
/// off the fold, and the fold does not change either.
///
/// # Columns
///
/// `snapshot_id` / `ts_micros` / `repo` — the standard snapshot key. This table
/// belongs in `SNAPSHOT_TABLES`, so `rows::latest_snapshot_rows_of` keeps only
/// the newest `(repo, snapshot_id)` per repo by `ts_micros`; a re-run
/// SUPERSEDES rather than doubling, with no delete path.
///
/// `model_profile` — WHICH embedding space these neighbours live in. Without it
/// a jina-768 neighbour list and a potion-256 one would merge into one
/// meaningless table; with it a consumer can refuse a profile it did not ask
/// for. This is the column whose absence would be silent.
///
/// `k` / `metric` — the fold parameters the list was built under. A `k = 8`
/// mutual-kNN read out of a `k = 32` list is indistinguishable from a real
/// result: same shape, same keys, plausible numbers. The same trap
/// `lens_chain::is_default_params` exists to catch.
///
/// `src_symbol` / `dst_symbol` — the symbol pair, by FQN, so the list joins to
/// `symbol_facts` and `call_edges` on a key those tables already carry. Ids are
/// deliberately NOT used: a row index is meaningful only inside the one index
/// build that produced it.
///
/// `rank` — 0-based position in `src_symbol`'s list. Keeping it explicit means a
/// consumer never has to re-sort to recover the order, and a truncated read is
/// visibly truncated.
///
/// `cosine` — the int8 cosine, bit-identical on GPU and CPU (see
/// `crate::vector::gpu`).
///
/// `mutual` — whether `src` is also in `dst`'s top-k. Computed by the PRODUCER,
/// which holds the whole list in memory, rather than by each consumer
/// re-deriving it from a partial read. `mimir_clones`' mutual-kNN retain step is
/// exactly this predicate; materialising it here means there is ONE writer of
/// "mutual" (LAW 5) instead of one per consumer.
///
/// `producer` — `gpu:<adapter>` or `cpu:<simd>`. An operator must be able to
/// tell from the ROWS whether the GPU ran, without trusting a log line that may
/// have scrolled away. This is the anti-silent-fallback rule made durable.
///
/// # Anti-silent-emptiness
///
/// An EMPTY `knn_neighbors` is a MISSING PRODUCER, never "no neighbours". A lens
/// reading it must list it in its `sources.feeds(&[...])` set, so
/// `evidence_note` renders the MISSING FEEDS sentence and the finding count is
/// declared a LOWER bound. A crate with no analysis substrate must never report
/// zero findings in silence.
pub fn knn_neighbors() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                3,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "model_profile",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "k",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                6,
                "metric",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "src_symbol",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "dst_symbol",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                9,
                "rank",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::required(
                10,
                "cosine",
                Type::Primitive(PrimitiveType::Float),
            )),
            Arc::new(NestedField::required(
                11,
                "mutual",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                12,
                "producer",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}


/// Source-based **line/region coverage** (feature N — maven-style). One row per
/// `(run_id, repo, scope)` where `scope` ∈ `overall | crate:<name> | file:<path>`,
/// carrying the line/region totals + covered counts. Historized like
/// `bench_telemetry` so coverage is time-travellable + feeds docs/viz. Partitioned
/// by `repo`. The fine-grained per-function/boundary rows live in `coverage_fn`.
pub fn coverage() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "run_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                3,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            // `overall` | `crate:<name>` | `file:<path>`
            Arc::new(NestedField::required(
                4,
                "scope",
                Type::Primitive(PrimitiveType::String),
            )),
            // crate name for crate/file rows ("" for overall); file path for file rows.
            Arc::new(NestedField::required(
                5,
                "krate",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "file",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "lines",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                8,
                "lines_covered",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                9,
                "regions",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                10,
                "regions_covered",
                Type::Primitive(PrimitiveType::Long),
            )),
        ])
        .build()?)
}

/// Per-function coverage with its **layer boundary** tag (feature N, task #4).
/// One row per function llvm-cov measured; `boundary` ∈ `ui | grpc | emitter |
/// core`. The viz "boundary coverage" view + the boundary tally read this to
/// prove the ui/grpc/emitter surfaces are exercised. Partitioned by `repo`.
pub fn coverage_fn() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "run_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                3,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "file",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "boundary",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "lines",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                8,
                "lines_covered",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                9,
                "regions",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                10,
                "regions_covered",
                Type::Primitive(PrimitiveType::Long),
            )),
            // WHERE the function is: its first and last source line, with `file`
            // the key the Mímir code room's functions join on (`(repo, file, line
            // span)`; a demangled llvm name is no join key). NULL on a row written
            // before the columns.
            Arc::new(NestedField::optional(
                11,
                "line",
                Type::Primitive(PrimitiveType::Int),
            )),
            Arc::new(NestedField::optional(
                12,
                "end_line",
                Type::Primitive(PrimitiveType::Int),
            )),
            // The checkout's HEAD the run measured (a Runa `Coverage` step files
            // keyed by (repo, commit)).
            Arc::new(NestedField::optional(
                13,
                "commit",
                Type::Primitive(PrimitiveType::String),
            )),
            // An `only: Affected` run, merged with the previous one
            // (`coverage::merge_affected`): the commit whose run measured an
            // unchanged function's counts, and whether the function changed
            // since the baseline. NULL on a run of every test.
            Arc::new(NestedField::optional(
                14,
                "carried_from",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                15,
                "changed",
                Type::Primitive(PrimitiveType::Boolean),
            )),
        ])
        .build()?)
}

/// Per-file git activity heat. One row per file at scan time.
pub fn git_heat_facts() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                3,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "file",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "commits_total",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                6,
                "commits_30d",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                7,
                "commits_90d",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                8,
                "authors_total",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                9,
                "last_commit_ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
        ])
        .build()?)
}

/// MCP server call telemetry — one row per tool invocation. Metrics only
/// (no request/response payloads): which tool, ok/err, and how long it took.
/// Lets the viz answer "are agents using the MCP, and which tools?".
pub fn mcp_requests() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                2,
                "tool",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "status",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "latency_ms",
                Type::Primitive(PrimitiveType::Long),
            )),
        ])
        .build()?)
}

/// **The lake IS the lens cache** (the owner, 2026-10-18). One row per lens
/// answer computed from a room: `room_version` is the room the answer was
/// folded from (1:1 with the consumed iceberg transaction of the event log),
/// `key` the lens + canonical request (`mimir_lens::queued::key_of`), `body`
/// the JSON text the door hands out. A reader takes the LATEST row of
/// (room_version, key); a version that moved reads nothing old by key design.
pub fn lens_answers() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            // The version as a DECIMAL STRING: skade partitions identity-prune
            // on Utf8 columns only, and the read is pure equality (no ranges).
            Arc::new(NestedField::required(
                1,
                "room_version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "key",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                3,
                "state",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "body",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
        ])
        .build()?)
}

/// N5 — viz **action trail** durable sink. One row per user-action the viz
/// records (tab switch, button click, query, RPC, error, lifecycle), the same
/// stream that also tails to the `$NORNIR_VIZ_ACTIONLOG` `/tmp` file (the file
/// stays a fast local live-channel; THIS is the durable, queryable sink, per
/// the persist-to-warehouse-stream-not-`/tmp` law).
///
/// Grain: one row per pushed action. `session_id` groups one viz launch's
/// trail (a fresh UUID minted per `ActionLog`); `seq` is that session's
/// monotonic counter — the stable ordering key (Iceberg gives no scan order, so
/// reads sort by `(session_id, seq)`). `kind` ∈
/// `LIFE | TAB | CLICK | QUERY | RPC | ERROR` (the action category). `workspace`
/// and `tab` carry the active context at push time (`""` when not applicable,
/// never null). `detail` is the free-form action text. Partitioned by
/// `session_id` so a per-session read prunes to that launch's files.
/// See `.nornir/viz-action-trail.md`.
pub fn viz_actions() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "session_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "seq",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                3,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                4,
                "kind",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "workspace",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "tab",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "detail",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Cached OSV/RUSTSEC vulnerability findings keyed by the immutable
/// `crate@version` — the security scan reads this warehouse-first and only hits
/// OSV (or a local advisory-db) for crate@versions not yet cached.
pub fn vuln_findings() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "crate",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "version",
                Type::Primitive(PrimitiveType::String),
            )),
            // comma-joined advisory ids (empty string = checked, no vulns)
            Arc::new(NestedField::required(
                3,
                "ids",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "summary",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "checked_at_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
        ])
        .build()?)
}

/// SBOM component rows (one per resolved dependency in a repo's closure):
/// `(name, version, license)`, captured from a deep-scan / `cargo metadata`
/// sweep and keyed by `repo` + capture `snapshot_id`. Lets the CycloneDX SBOM
/// be assembled from the warehouse (the latest snapshot per repo) instead of
/// re-invoking `cargo metadata` server-side.
pub fn sbom_components() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                3,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "version",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "license",
                Type::Primitive(PrimitiveType::String),
            )),
            // task #65 slice 4a — add-field-only evolution: `source` (cargo metadata)
            // vs `binary` (derived from the shipped bytes: a statically-linked C dep
            // / vendored `.a` / embedded version string the source SBOM misses).
            // Optional so tables written before the column read back as `source`.
            Arc::new(NestedField::optional(
                7,
                "derived_from",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Binary-analysis header — one row per analysed compiled artifact (the
/// checksec-class hardening + format/size header). Keyed by `content_sha256`
/// (the `build_info.content_id` / `build_provenance.digest` join key every
/// binary fact hangs off), plus the capture `snapshot_id` + `ts_micros` and the
/// build context (`repo`/`git_sha`/`build_id`). The release binary-gate reads
/// this row. Produced by `nornir-introspect::hardening`. See
/// `.nornir/binary-analysis-design.md` §5.1.
pub fn binary_facts() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                3,
                "repo",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "git_sha",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "build_id",
                Type::Primitive(PrimitiveType::String),
            )),
            // THE JOIN KEY — sha256 of the artifact bytes (build_info.content_id).
            Arc::new(NestedField::required(
                6,
                "content_sha256",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "artifact_path",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "format",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                9,
                "arch",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                10,
                "class",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                11,
                "total_bytes",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                12,
                "stripped",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                13,
                "has_debug_info",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                14,
                "pie",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                15,
                "relro",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                16,
                "nx",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                17,
                "stack_canary",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                18,
                "fortify",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                19,
                "rpath",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                20,
                "runpath",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                21,
                "build_id_note",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                22,
                "n_sections",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                23,
                "n_sym_defined",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                24,
                "n_sym_undefined",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                25,
                "n_dyn_deps",
                Type::Primitive(PrimitiveType::Long),
            )),
        ])
        .build()?)
}

/// Per-(artifact, section) size row — the Bloaty section view. Keyed by
/// `content_sha256` (the artifact join key) + capture `snapshot_id`. The
/// `.text`/`.rodata`/`.data`/`.debug_*` split tells debug-info-vs-code at a
/// glance. Produced by `nornir-introspect::size`. See §5.2.
pub fn section_sizes() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                3,
                "content_sha256",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "section_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "size_bytes",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                6,
                "vaddr",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                7,
                "alloc",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                8,
                "exec",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                9,
                "write",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::required(
                10,
                "file_offset",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                11,
                "kind",
                Type::Primitive(PrimitiveType::String),
            )),
        ])
        .build()?)
}

/// Per-(artifact, symbol) size row — the cargo-bloat / twiggy per-symbol +
/// per-crate + monomorphization view. Keyed by `content_sha256` + capture
/// `snapshot_id`. `crate_name` (GROUP BY → per-crate roll-up) and
/// `is_monomorphization` (twiggy `monos`) are the columns the "what's driving
/// binary size" query hits; `source_file`/`source_line` come from the DWARF
/// join. Produced by `nornir-introspect::size`. See §5.3.
pub fn symbol_sizes() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),
            )),
            Arc::new(NestedField::required(
                3,
                "content_sha256",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                4,
                "symbol_mangled",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                5,
                "symbol_demangled",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                6,
                "symbol_demangled_no_generics",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                7,
                "crate_name",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                8,
                "section",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                9,
                "size_bytes",
                Type::Primitive(PrimitiveType::Long),
            )),
            Arc::new(NestedField::required(
                10,
                "kind",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                11,
                "binding",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                12,
                "is_monomorphization",
                Type::Primitive(PrimitiveType::Boolean),
            )),
            Arc::new(NestedField::optional(
                13,
                "source_file",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::optional(
                14,
                "source_line",
                Type::Primitive(PrimitiveType::Int),
            )),
        ])
        .build()?)
}

/// Artifact-to-artifact **diff** (task #65 slice 2) — one narrow row per change
/// between two analysed artifacts, keyed on the pair
/// `(from_content_sha256, to_content_sha256)` (the two `build_info.content_id`s).
/// `kind` discriminates the change (`size_delta` / `section_delta` /
/// `crate_delta` / `symbol_added` / `symbol_removed` / `symbol_grew` /
/// `symbol_shrunk` / `abi_added` / `abi_removed`); `before`/`after`/`delta_bytes`
/// carry the size waterfall, `severity` the gate hint. The binary twin of
/// `semver_diffs`. Produced by `nornir-introspect::diff`. See
/// `.nornir/binary-analysis-design.md` §5.4.
pub fn artifact_diff() -> Result<Schema> {
    Ok(Schema::builder()
        .with_schema_id(0)
        .with_fields(vec![
            Arc::new(NestedField::required(
                1,
                "snapshot_id",
                Type::Primitive(PrimitiveType::String),
            )),
            Arc::new(NestedField::required(
                2,
                "ts_micros",
                Type::Primitive(PrimitiveType::Timestamptz),

The file goes on; the console shows all of it.