Add warehouse (SSH) → Populate — dwarves control over nornir's warehouse — design
Class:
design· Function axis:f0the whole (Add + Populate) ·f1SSH validation + descriptor synth ·f2theWorkspacesgRPC client ·f3theAddWarehouseform model ·f4the selector-header UI wiring. Strict: states only what the feature IS. Sibling how-to: guide; zero-knowledge: for-idiots (to be rendered by the Loki benchernornir docs book).
dwarves' warehouse header can now add a warehouse from an SSH git remote and populate it — the exact affordance nornir's own menu has, mirrored into the dwarves cockpit.
Architecture (amended doctrine)
The warehouse is nornir's (it owns the future/present/history). dwarves reaches it by gRPC to nornir-server, never directly to skade. So "Add warehouse (SSH) → Populate" is a thin gRPC client in dwarves driving nornir's existing Workspaces RPCs — the UI lives in dwarves, the warehouse-WRITE (clone the SSH members, build the Iceberg warehouse) happens in nornir. One-directional dwarves → nornir; no crate cycle (dwarves never links the nornir crate — the <guest>-embed pattern, same as nornir-funnel-embed / the Telemetry submit path).
No new nornir RPC was needed — nornir already exposes the full seam: Workspaces.Register{lazy=false} (record + EAGER populate: clone members + build the warehouse inline) and Workspaces.Fetch{force} (re-sync). dwarves consumes them.
The function map (f0)
| part | lives in | what it is |
f1 SSH + descriptor |
nornir-warehouse-embed/src/lib.rs |
validate_ssh_remote (L6: accept git@host:owner/repo.git / ssh://…, REJECT HTTPS) · repo_name_from_ssh · descriptor_for_ssh (synthesize a one-member nornir-workspace.toml) |
f2 Workspaces client |
same crate + proto/workspaces.proto |
trimmed nornir.v1.Workspaces subset (List/Register/Fetch, byte-identical field numbers) → add_warehouse_by_ssh (Register eager) · populate_warehouse (Fetch force) · list_warehouses |
f3 form model |
same crate | AddWarehouse — the drivable state_json/update_json core (name + ssh_url → Add → Populate), all server I/O injected in tests |
f4 UI wiring |
dwarves-gui/src/warehouse_select.rs |
WarehouseSelector::with_add_source grows an ➕ Add… control; a successful register commit_added → folds the warehouse into the picker + selects it (tabs re-bind) |
Why it is shaped this way
- The warehouse-WRITE stays in nornir. dwarves synthesizes a descriptor and ships its CONTENT (
RegisterWorkspaceRequest.descriptor_content); nornir writes it to its own descriptors dir, clones the SSH member with the server's deploy key, and builds the warehouse. dwarves holds no warehouse-write logic — it is the client (L5a). - SSH-only, enforced at the door (L6).
validate_ssh_remoterejects anyhttp(s)://remote and any URL without anowner/repopath; the Add button is disabled until the URL validates, so an HTTPS remote can never reach the server. - Eager populate = one click. Register with
lazy=falseclones + builds inline, so the warehouse is populated NOW (not after a poll tick). This also fixes the funnel'snot_served: once the warehouse is populated, nornir serves it and the funnel loads a real DAG. - Reuse, not a new crate (L5). The client lives in the existing
nornir-warehouse-embed(already the dwarves→nornir warehouse embed), extended with a second trimmed proto — not a fifth embed crate. - Drivable headless (L4).
AddWarehousesplits pure state (validation, status transitions) from I/O; the robot cell drives Add→Populate against a MOCKWorkspacesserver (no network) and asserts the server received a monitored, eager, SSH-only registration + a forced fetch. RED-when-broken: an HTTPS URL is unaddable; a populated warehouse must fold into the picker + become selected.
Place in the constellation
The "active warehouse" spine (217055c) gains its onboarding door: a user with a bare SSH remote can register + populate a warehouse from dwarves without touching nornir's CLI — dwarves the cockpit, nornir the warehouse.
Deferred
- Live
list_warehousesrefresh on open. The client fn exists; wiring the header to pre-fill the picker fromWorkspaces.Liston startup is a follow-up. - Multi-member descriptors. The synthesizer ships ONE member (the SSH remote); a multi-repo workspace descriptor (or pasting a full
nornir-workspace.toml) is a later refinement. - Pixel
watchleg. Driven headless overstate_json; the visible egui_kittestwatchreplay is the standing UI follow-up (as with the other dwarves panes). - PDFs left for the Loki bencher's
nornir docs bookrender.