src/warehouse/release_events.rs
//! Writer + reader for the **release-op DAG** (`release_events`) — re-exported
//! from the ONE definition in the shared `nornir-release-ledger` edda leaf.
//!
//! `release_lineage` records a release's *outcome* per `(release, repo)`.
//! This table records its *shape*: one row per `component × op × phase`
//! boundary as a release walks the build order. The `depends_on` list carries
//! the upstream components this one waited on (the dep-graph producers), so a
//! reader can draw the live op DAG and see exactly where a partial release
//! stalled — the structural twin of the funnel DAG.
//!
//! ## Why this module is now three lines
//!
//! The row type, the monotonic-`seq` emitter, the Arrow codec and the JSON/topo
//! renderers lived here AND, in a hand-maintained copy, in the release
//! orchestrator — which writes into this very table, in this very warehouse,
//! but may not take a crate edge on this umbrella. Two copies of a codec over
//! one table is a silent-corruption hazard: a column added to one side and not
//! the other compiles perfectly on both. PRE-PROMPT L5 — shared behaviour is
//! CONSUMED, never twinned — so the definition moved to an edda leaf that names
//! only the backend-neutral [`Warehouse`](super::Warehouse) seam, and both
//! halves re-export it. Every `warehouse::release_events::…` path here (the viz
//! Release tab, `server_grpc`, `monitor`, `release::pipeline`, the integration
//! tests) resolves unchanged.
//!
//! ## Write path — two producers, and neither is the CLI any more
//!
//! The release ORCHESTRATION verbs moved out of nornir to `dwarves release`
//! (move=delete, 2026-07-18); nornir keeps the read-only `release
//! trace/events/impacted-crates` views and the gate ENGINE behind the server
//! RPCs. What remains here writes:
//!
//! 1. The library orchestrator [`crate::release::pipeline::run_pipeline`] —
//! a `pub` API driven by embedders and by this repo's integration tests
//! (`tests/release_pipeline.rs`, `tests/release_events.rs`,
//! `tests/scenarios.rs`) plus `examples/release_demo_znippy_holger.rs`. It
//! is NOT called by nornir-server: the publish pipeline is irreversible, so
//! no button fires it.
//! 2. `Ops.RunRelease` (the 🚀 Release button), which runs the repo's
//! configured GATE suite and appends one `release_gate` row per repo
//! directly — it does not go through `ReleaseEventEmitter`.
//!
//! Emits are **best-effort + non-fatal** — a logging-row failure must never
//! abort an otherwise-green release.
//!
//! Read path: `query_release_events` scans the table, scopes by a `run_id` or a
//! `repo`, and returns rows sorted by `(run_id, seq)` — Iceberg gives no scan
//! order, so `seq` is the durable ordering key.
//!
//! Schema: [`super::iceberg_schema::release_events`].
//!
//! ## One API note
//!
//! `ReleaseEventEmitter::emit` (the sync wrapper) used to take a concrete
//! `&IcebergWarehouse` and drive `wh.block_on(..)`. The leaf's version takes
//! `&dyn Warehouse` and routes through the trait's own sync `append_arrow`
//! (which blocks internally), which is strictly WIDER — an `&IcebergWarehouse`
//! still coerces — and is what lets one definition serve both halves.
pub use nornir_release_ledger::release_events::*;