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.