orchestrate — design
Class:
design· Function axis:f8(AIRGAP8: ordered bring-up + telemetry). States only the shape we ship.
Dependency-ordered bring-up
orchestrate::start_waves(products) -> Vec<Vec<String>> (orchestrate.rs:42) Kahn-topo-sorts the products into waves: wave i holds every product whose depends_on are all satisfied by earlier waves. Each wave is sorted for determinism, and products within a wave can start concurrently (the caller uses std::thread::scope — no rayon).
start_order(products) -> Vec<String>(orchestrate.rs:23) — the flat order (start_wavesflattened), sources first.teardown_order(products) -> Vec<String>(orchestrate.rs:31) — the reverse, so a dependent is stopped before its dependency.
The node is product::Product (product.rs:235) — name, depends_on, user, ports — the dep-graph view a ComponentSpec yields via as_product(). Deps that point outside the product set (e.g. network.target) are ignored (orchestrate.rs:52). A cycle is detected after the Kahn drain (orchestrate.rs:87) and returned as an error naming the stuck products.
config::LakeSpec::start_waves() (lib.rs:137) is the whole-lake entry point — it maps each ComponentSpec to a Product and calls start_waves.
Telemetry — airgap_events
Every pipeline boundary emits one row. events::AirgapEvent (events.rs:49) — run_id, seq, ts_micros, product, op, phase, status, detail, depends_on. Vocab: op (events.rs:24) = pack | fetch | unfold | install | start | matrix_probe; phase (events.rs:35) = start | end | skip; status (events.rs:40) = ok | fail | running.
events::EventSink { append(&event) } (events.rs:71) is the seam; JsonlSink (events.rs:76) is the default — an append-only JSONL under the warehouse root (under_warehouse, events.rs:83), never /tmp. EventEmitter (events.rs:116) mints the run_id + a monotonic seq and emits best-effort (a sink error logs to stderr, never aborts the bring-up, events.rs:132). read_jsonl (events.rs:161) reads rows back sorted by seq.
Introspection — functional_status surface emits (nornir's coverage gate)
Separate from the airgap_events DAG, each lifecycle surface self-reports an ok/RED verdict into nornir's constellation-wide introspection matrix via the functional_status shim (lib.rs:44, → nornir-testmatrix, reused — no twin). The emit is implanted in the runtime path itself (via the surface_status! macro, lib.rs), so the matrix sees the surface's actual return/state, not a test's re-derivation. Compiled out entirely unless --features testmatrix is on (the lean core stays dep-free, zero format! cost). Wired surfaces + components:
| surface | component | check | fires |
| pack | skidbladnir/pack |
pack_collect_staging_tree |
pack::pack (pack.rs) — RED if the staging tree can't be walked |
| fetch | skidbladnir/fetch |
verify_on_receipt |
fetch::verify_on_receipt (fetch.rs) — RED on a corrupt/unauthentic bundle |
| unfold | skidbladnir/unfold |
extract_all |
archive::TarZstd::extract_all (archive.rs) — RED on a bad/missing bundle |
| install | skidbladnir/install |
install_product |
install::install_product (install.rs) — RED if any step throws |
| start | skidbladnir/start |
start_waves_ordered |
orchestrate::start_waves (orchestrate.rs) — RED on a dependency cycle |
| pki | skidbladnir/pki |
issue_leaf |
pki::MachineCa::issue_leaf (pki.rs) — RED if rcgen can't sign the leaf |
| systemd | skidbladnir/systemd |
install_unit |
systemd::install_systemd_scoped (systemd.rs) — RED when a secret-carrying spec has no private env-file |
drain_functional_rows (lib.rs, testmatrix-only) reads the process-global buffer back — the seam the red-when-broken test uses. The matrix harness collects the same rows a cargo test --features testmatrix subprocess wrote (nornir #32), exactly like the sibling crates (ordning-core, korp-collectors).
Contract (inject-assert tests)
topo_waves_from_fixture_dep_graph (orchestrate.rs:118), teardown_is_reverse_of_start (orchestrate.rs:155), cycle_is_rejected (orchestrate.rs:172), external_deps_are_ignored (orchestrate.rs:147), emits_install_dag_to_warehouse_jsonl_and_reads_back (events.rs:184).