Plan: facett-brokkrview — the forge panel as a shared facett component
Filed 2026-07-12 (dwarves love pass). ✅ LANDED 2026-07-12 — the facett-brokkrview crate now exists in facett/ and dwarves-gui mounts it (replacing the interim two-table ForgeView). The rest of this doc is the contract that was implemented; deviations from it are noted in the "As built" section below.
Why it is flagged referenced-but-MISSING
The constellation consolidation matrix (workspace_nordisk/.nornir/consolidation-panels-maps-design.md §1.2, dwarves row) marks dwarves as 🟡 PARTIAL for the panel seam: facett-brokkr exists, but facett-brokkrview is referenced but MISSING. The reference is real and lives in this repo:
crates/dwarves/src/brokkr/elm.rs:8— the module doc namesfacett-brokkrviewas the intended facett-side eguiview+impl_facet_via_elm!bridge over the pure Elm core defined here.dwarves-gui/src/panel.rs— an INTERIM native render (two plainfacett_table::Tables over a fixture), explicitly labelled interim, to be swapped for the real component once it lands.
The seam is already done on the dwarves side (nothing to build here)
The whole point of the Elm split is that dwarves already ships the pure, testable core the panel renders — facett-brokkrview is a thin facett-side follow-up, not new logic:
- Model / Msg / Effect —
crate::brokkr::elm::{BrokkrModel, BrokkrMsg, BrokkrEffect}(single serializable state, one mutation pathBrokkr::update, side work returned asBrokkrEffect::RunPipelinethe host executes and feeds back viaBrokkrMsg::RunFinished). Covered bybrokkr/mod.rs::elm_facet_run_flow_greens_the_state_json. - Headless contract —
Brokkr::state_json()is the wire the robot harness and any renderer key on (runs[].status=passed/failed,steps="4/4"). - Richer disposition surface — the Phase-2 incremental taxonomy the panel can tint distinctly (
ran/cache-hit/unchanged/when-skipped/upstream-skipped/failed, plus acachedflag) is already emitted bycrate::incremental::CachedRunReport::state_json().
What facett-brokkrview must be (the contract for the facett agent)
- A
facett-<app>component crate underfacett/(mirrorsfacett-brokkr), deps:egui+facett-core+ a thindwarves-client(gRPC) — NO dwarves logic copied, only the shared UI crate + a thin stub (native cross-host backend 2, no wasm — see wasm-ui-panels-design §3). impl Elm for <the view>delegating to dwarves'Brokkrcore, thenimpl_facet_via_elm!for the eguiview. It rendersBrokkrModeland emitsBrokkrMsg; the disposition chips read thecached/dispositionfields.- Data path: fat = in-process
dwarveslib; thin =dwarves-serverover gRPC (the split in.nornir/ui-embedding-and-standalone.md). dwarves does not yet daemonize, so the thin adapter is gated on adwarves-serverexisting. - Test win (required): one
nornir-robotuiscenario + one testmatrix row that exercises the component in BOTH hosts (nornir's CI/CD tab + the dwarves standalone app). Wire-once, verified-everywhere.
Explicitly NOT done here (and why)
- No crate created in
facett/— facett is contended (korp + holger consumers, concurrent editors); creating it from this repo would collide. Per the mega-prompt hard constraint, this is a plan item only. dwarves-gui/src/panel.rsstays as the interim native render (additive — removing no working path) until the real component lands; the swap is API-compatible (FacetApp→NativeDemo/WebDemounchanged).
Extraction order (matrix §2)
facett-brokkrview is the closest / first in the extraction order (dwarves → holger facett-holger → korp facett-korp* → de-INTERIM nornir-demo), because the Elm core + headless contract + interim render already exist — only the facett-side bridge crate is missing.
As built (2026-07-12)
- Crate:
facett/facett-brokkrview(workspace member). Deps:egui+facett-core+serde/serde_jsononly — nonornirand nodwarvesedge (it mirrors the dwarves brokkr model shape so dwarves can depend on it without a cycle, the same self-contained trickfacett-brokkruses for thebrokkr.tomlschema). - Three surfaces over one model: run Roster (mirrors
BrokkrModel; Run button per pipeline + status chips + log), the Tree (TreeFacethierarchy with the incremental disposition taxonomy tinted per step), and the DAG (DagFacet, nodes tinted by status, longest-path column layout). - Elm → Facet → Panel: implements
facett_core::Elm;impl_facet_via_elm!(custom_state_json form) bridges toFacet, and theupdate_jsonmutation path is routed into the Elmupdate, so it is aPanelvia the blanket impl and drives headless through JSON (panel::drive→state_jsonasserts). - Data seam:
BrokkrView::from_brokkr_state(&Brokkr::state_json())adopts the dwarves roster wire (backend (2) native cross-host). Thedwarves-servergRPC transport is deferred (gated on dwarves daemonizing), as this doc's §3 says. - Wiring:
dwarves-guidepends onfacett-brokkrview;ForgeViewis now a thin wrapper mountingBrokkrViewover a dwarves fixture (build/test/bench/release/ publish roster + the build pipeline's tree + DAG). The harness API is unchanged (FacetApp→NativeDemo/WebDemo, state hook__dwarves_state). The now-deadfacett-tabledep + the interim two-table render were removed (the swap this plan called for).crates/dwarvesis untouched except this doc pointer inbrokkr/elm.rs— the CLI's minimal-dependency footprint is preserved (no egui edge in the lib). - Tests: 7 inline (update transitions, effect emission, run-finished folding into tree+DAG,
from_brokkr_state) + 2 headless JSON-drive + 4 kittest render-smoke (all three surfaces + a real toggle click) + 2 indwarves-gui. - Deferred: a dedicated
nornir-robotuiscenario + testmatrix row exercising the pane in BOTH hosts (nornir + dwarves). The headless JSON drive covers the pane's behaviour now; the shared robotui/testmatrix row lands withdwarves-server(it needs a real host to embed into). A native frame-time bench arm for the pane is N/A here — the Phase-0facett.panel_framearm already measures theBox<dyn Panel>native-frame floor this pane rides.
The "Explicitly NOT done here" section above is now superseded: the crate WAS created (a facett-owning gated agent did it, so no collision), and dwarves-gui's interim render was swapped for the shared component.