Yggdrasil infra crown + runtime band — design (f0)
The super-graph (.nornir/yggdrasil-supergraph.md) models the whole constellation as one tree whose Iceberg tables are bands of nodes/edges at every scale — instruction → symbol → call → module → crate → repo → dependency → architecture. Its top band, where the code actually runs (the machines / services / VMs / worker-groups), and its runtime/trace band were the last "MISSING ⛔" scales: spec'd, zero code. This is the design that landed them.
The chosen design
Three new Iceberg tables on the EXISTING warehouse, no new skade dependency. The IcebergWarehouse already stores arbitrary tables (63 of them); the crown is just three more, registered in ensure_layout and written through the same append_batch rail. The domain/orchestration stays in nornir (the conductor, L5a); only the dep-light warehouse primitive (append_batch / read_filtered) is consumed from skade.
| Table | Grain | Columns |
infra_nodes |
one row per machine / service / vm / container in a snapshot | snapshot_id, workspace_name, ts_micros, node_id, kind, host, node_group, cores, mem_mb, role, online |
infra_edges |
one row per infra relationship | snapshot_id, workspace_name, ts_micros, from_node, to_node, rel |
runtime_spans |
one row per executed span | snapshot_id, workspace_name, ts_micros, span_id, parent_span, service, op, start_micros, dur_us, job_id, machine, status |
node_group / from_node / to_node avoid the SQL-reserved bare group/from/to. All three are snapshot-enveloped (every record_* write shares a fresh snapshot_id + one ts_micros) and workspace-scoped on read — the exact persistence shape of dep_graph_edges (warehouse::dep_graph), reused rather than reinvented. Unpartitioned: a constellation is a handful of machines/services, so the residual workspace_name filter in the reader is enough (same call as warehouse_access_edges).
The real producer — the jera job ledger
The crown is not dead schema. Its first real producer is the jera JobRecord ledger — the one durable redb list of every long-running nornir op, which already stamps which fleet node ran the job (JobRecord::node, set by the multi-machine scheduler) and its lifecycle timing. warehouse::yggdrasil derives (all pure, warehouse-free, unit-tested):
infra_from_jobs→ onemachinenode per distinctnode(unset →localcontrol-plane), oneservicenode per distinct jobkind, aruns_onedgeservice → machinefor each(kind, node)that co-occurred, and amember_ofedgemachine → constellationper machine.spans_from_jobs→ oneRuntimeSpanper job (span_id = job_id,parent = parent_id,service = kind,op = target,machine = node,dur_us = elapsed_ms × 1000).
ingest_from_jobs / IcebergWarehouse::record_yggdrasil_from_jobs do the derive-and-persist in one call. monitor::republish_with invokes it on every workspace populate (lock-tolerant ledger read, best-effort), so the scales fill from real ledger rows as the constellation runs.
Testable / RED-when-broken
producer_derives_machines_services_edges_and_spans— asserts the exact machine/service node sets, the preciseruns_on/member_ofedge sets, and the per-span machine/parent/dur_usderivation (alocalfallback + a running job'sdur_us == 0).ledger_scales_round_trip_field_identical— records the ledger-derived crown + runtime band, reads all three back, and asserts field-identical to what the pure producer built; a wrong column mapping, dropped row, or lost numeric (Long→Int truncation ofdur_us) flips anassert_eq!. Plus a workspace-scope isolation check (a different workspace sees none of the rows).empty_ledger_writes_no_rows— an empty ledger is a no-op, not a stub row.
Alternatives (see reasoning doc)
A dedicated infra service / new skade table type, or a separate graph store, were rejected — they would fork the warehouse and violate L5a (domain stays in the conductor, only primitives leave). Producers beyond the ledger (skidbladnir ServiceSpec, tunnr/draupnir VM/container boots, roster cores/mem) and a read-only supergraph viz pane are follow-ups, not part of this landing.