live jobs + agent-fleet pane — design
Class:
design· Function axis:f0the cockpit pane (the whole) ·f1the jera-ledger jobs leg ·f2the AgentPool fleet leg ·f3the fixture fallback ·f4thedwarves runledger-write wiring Strict: this file states only what the Live-Jobs+fleet surface IS — its parts and why. Sibling how-to: jobs-fleet-pane-guide.md; zero-knowledge walkthrough: jobs-fleet-pane-for-idiots.md.
The Live Jobs + Agent-fleet pane is the forge cockpit's "what is running where": the jera JobRecord ledger (recent CI jobs with status/timing and which node ran each) rendered on the shared facett-jobview widget, plus a worker-fleet roster (the agents the scheduler dispatches to, with idle/busy liveness) over the AgentPool RPC. It is the LIVE twin of the fixture Jobs pane (separation-spec item B3): the two fixture panes become real, node placement (Loki/Odin/NUC/Njord) surfaced.
The system as one — the function map (f0)
| part | lives in | what it is |
f0 the pane |
crates/dwarves-embed/src/jobsfleet.rs JobsFleetPanel |
a Facet/Panel: jobs (shared JobList) + fleet roster + auto-poll |
f1 jobs leg |
read_ledger_jobs + entries_from_records |
jera::jobs::JobStore::open_read_only → list(All) → JobRecord mapped onto facett_jobview::JobEntry, node surfaced |
f2 fleet leg |
fetch_agents + agents_from_wire |
thin gRPC AgentPool → AgentRow{id,group,caps,cores,mem_mb,state,online} |
f3 fixture fallback |
fixture_records / fixture_agents |
clearly-marked (source:"fixture") when the ledger is empty / the fleet RPC is down |
f4 ledger write |
crates/dwarves/src/main.rs run_cmd |
dwarves run records a ci_build job into <warehouse>/jobs so the pane has real data to read |
Why it is shaped this way
- Reuse the shared jobs widget + the one ledger (L5). The jobs list is NOT hand-rolled: it is
facett_jobview::JobList(the same widget nornir/holger/korp mount) fed live. The job data is NOT a bespoke store: it is the constellation's singlejeraJobRecord ledger — the canonical "what ran". The pane is a thin host that mapsJobRecord → JobEntryand delegates the tree/sort/fold to the widget. - Surface the node placement. jera's
JobRecord.node: Option<String>is the fleet machine the multi-machine scheduler stamped. The mapping puts it into BOTH the row's visibledetail([loki] cargo-build …) and itsmeta, and rolls the distinct nodes up intostate_json.nodes— so the cockpit shows where each job ran.None(local control-plane) reads aslocal, never blank. - Two live legs, two sources, one pane. Jobs come from a local ledger read (
open_read_only— the lock-tolerant snapshot nornir's viz uses, so it coexists with a live writer); the fleet comes from a gRPC read (AgentPool, mirroringForgePanel'sHistory/GetRunReportfetch). Each leg fails independently into a marked fixture — a dead server never blanks the jobs; an empty ledger never blanks the fleet. - Auto-poll like ForgePane.
poll_due(now_s)on a 2s interval re-reads the ledger + re-fetches the fleet;request_repaint_afterkeeps a run-in-flight filling in live. - Additive, fallback kept. The existing fixture
Jobstab is untouched; this ships as a newJobs (live)tab, and the live pane itself falls back to a fixture when offline/empty (L2 — no working path removed).
The seam (robot-testable, headless)
The pane drives over state_json (out) / update_json (in) — the same channel a nornir-robotui scenario and a thin gRPC client use. state_json publishes {source, job_count, nodes, node_count, fleet_source, agent_count, online_agents, agents[], auto_poll, jobs:<JobList tree>}; update_json accepts {refresh}, {auto_poll}, and forwards {sort|fold|select|kind_filter} onto the shared widget's typed Msg. The apply(FleetSnapshot) split lets a test inject a live-ledger snapshot + a stub AgentPool reply with no redb file and no server.
RED-when-broken
the_pane_reads_the_jera_ledger_live_and_surfaces_node_placement: writing JobRecords (nodes loki/odin) into a real JobStore and pointing the pane at it yields source:"ledger", job_count==3, and nodes containing both machines; neutralize the ledger read (empty root) and the pane can only show the fixture (source:"fixture") — the live assertions fail. robot_jobs_fleet_pane_drivable drives the full seam (live-ledger snapshot + stub fleet + fold/sort). testmatrix cells dwarves-embed/jobs_fleet_reads_ledger_live + dwarves-embed/jobs_fleet_pane_drivable.