dwarves — the Jobs pane (fleet-consistent, agent-aware)
Transfers nornir's job list surface into dwarves, closing the
dwarves-parity-spec.md§4b scaffold item "Jobs tab (facett-jobview) — now agent-aware". Mirrors, doesn't fork: the tree/sort/fold/filter/motion live once in the sharedfacett-jobviewcomponent; dwarves only supplies a fixture + the host seam.
What it is
A task-manager-style job/task list — the 4th pane of the dwarves-gui tabbed shell (Forge | Funnel | Claude | Jobs). It renders the forge's work the way a JetBrains-family app shows background jobs: one parent row per pipeline run, one child row per dispatched step, foldable, sortable, kind-filterable, with a live counts header.
Agent-aware (the dwarves-specific bit). dwarves runs forge steps as jera jobs dispatched to worker-group agents (055da45 jera Scheduler wiring, 0aa5920 drain-through-scheduler). Each child step carries the agent and worker group that ran it in its meta — so the Jobs pane is the natural task-manager view of which machine ran what.
Reuse-first (Law #1 / #2) — no twin
| Concern | Where it lives | dwarves' part |
| tree / sort / fold / kind-filter / counts / motion | facett-jobview::JobList (shared) |
mount it |
| the rows | a dwarves-shaped fixture (jera jobs) | JobsView::from_fixture() |
| the robot/CLI seam | host update_json → typed Msg |
JobsView::update_json |
JobsView (dwarves-gui/src/jobs.rs) is a thin host wrapper, exactly like ForgeView wraps facett-brokkrview and ClaudeTab wraps facett-claude: it delegates the whole Facet contract to the inner JobList and adds only the JSON→Msg control vocabulary the shared widget leaves to its host (the widget publishes a rich state_json but takes the no-op update_json default). Pure facett — no backend, no network, no filesystem — so it drives identically native + wasm (browser-safe).
The robot/CLI seam (state_json out / update_json in)
The same channel the tabbed shell, a nornir-robotui scenario, and a thin gRPC client all use:
update_json |
effect |
{"sort":"elapsed"} |
sort by a column (same key re-sent flips direction) |
{"fold":"#1042"} |
collapse/expand a parent by its stable id |
{"select":"#1042.1"} |
select a row (null clears) |
{"kind_filter":"release"} |
scope to a kind (null = all) |
state_json exposes count / parents / children / running / done / failed / selected / sort and the fold-aware jobs[] display tree.
Tests IN CODE (Law #3 — every UI atom robot-tested)
dwarves-gui/src/jobs.rs:
jobs_view_renders_the_shared_jobview_over_an_agent_aware_fixture— the fixture shape (7 entries = 3 runs + 4 dispatched steps; 1 parent, 4 children; 1 running, 1 failed; newest-first sort).robot_jobs_pane_drives_over_the_seam— a headlessnornir-robotui-style drive of fold → unfold → select → sort → kind-filter purely over the seam, emitting anornir-testmatrixcell (dwarves-gui/jobs_pane_drivable) under--features testmatrix. NO pixels; the visiblewatch-on-DISPLAY=:0leg is the flagged follow-up (shared across the demo's panes).
Follow-ups (tracked, not blocking)
- Live data. The fixture is the demo seed; the live pane pulls the jera ledger (
facett-jobview::JobSource) oncedwarves serveexposes aJobs/DrainStatusread RPC (parity-spec D1/D3) — one widget, fat (localjobs.redb) or thin (gRPC). - Bidirectional kill from a selected row (cancel job → kill remote work), per parity-spec §4 H1.