Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

.nornir/facett-platform-gaps.md

facett platform gaps — the pane-suite audit (2026-07-13)

Full inventory of the 66-crate facett UI platform against the Palantir-grade pane suite the constellation needs, mined from the workspace + git history + the nornir test functional/robot-ui matrix. Headline: the suite is essentially complete — every headline pane exists and most are matrix-covered. The honest gaps are (a) ~10 orphan panes that emit no test-matrix cell of any aspect and are not wired into the demo mega_matrix coverage gate, and (b) GUI-polish tranches already filed elsewhere. This doc is the longest gap list; the round's concrete fix is at the bottom.

1. Pane inventory — the headline suite ALL EXISTS

Palantir-grade surface facett crate status
graph / link-analysis facett-graph · facett-graphview · facett-graphpan · facett-graphnav ✅ rich, matrix-covered
3D graph / call-cloud facett-graph3d (+ DNA/time-helix) · facett-helix ✅
timeline / swimlane facett-timeline · facett-gantt ✅ (gantt is a leaf, see §3)
table / grid facett-table · facett-grid · facett-arrow ✅ flagship, copy-to-TSV
map / 3D-OSM / flight facett-map (MapLayer trait) · facett-map3d(+-flight) · facett-geomap · facett-osm ✅ ONE renderer, layers
forms facett-form ✅ (garde-validated)
warehouse deck facett-warehousedeck · facett-icebergview · facett-table::Warehouse… ✅
security / supply-chain facett-security (modgunn twin) ✅
claude chat pane facett-claude ✅ extraction complete (Elm seam, ClaudeTransport, robot JSON-drive + testmatrix cell)
job view facett-jobview ✅
plan-DAG / query-profile facett-plandag · facett-pipeline · facett-sdp · facett-brokkr/-brokkrview/-cicd ✅
data lineage facett-lineage ✅ code, ⚠ no matrix cell (this round's fix)
PM analytics facett-kanban · facett-calendar · facett-cfd ✅ leaf crates (§3)
docs / markdown / plot facett-docview · facett-markdown · facett-plot · facett-plotters ✅
console / log / stat / tabbar facett-console · facett-log · facett-stat · facett-tabbar ✅
misc surfaces facett-card · facett-menu · facett-syschart · facett-model3d · facett-video · facett-git · facett-filedialog · facett-search · facett-file · facett-confirm · facett-toast · facett-matrix · facett-pop ✅

Nothing on the headline suite is missing. The MapLayer trait unification (one renderer, selectable data-to-draw layers, OSM/Trafikverket as sources) is built (facett-map/src/layer.rs, .nornir/maptrait-design.md). facett-claude is a complete, in-design extraction. Do not re-invent any of these (Law #1).

2. THE REAL GAP — panes with zero test-matrix presence

nornir test builds its matrix from two aspects: functional rows (facett_core::testmatrix::emit → nornir_testmatrix::functional_status) and robot-ui rows (nornir-robotui RobotSession/Scenario). A pane invisible to BOTH is a coverage hole: a regression that blanks it shows no red cell.

Panes emitting no cell of either aspect (verified by grep for testmatrix::emit and RobotSession/run_scenario), and not covered by the demo mega_matrix gate (not in the demo LEGEND):

pane facett-core dep testmatrix feature has robot.rs drive note
facett-lineage ✅ (3 refs) ✅ declared ✅ (Msg-drive asserts) wired but forgot to emit — clean fix (§5)
facett-brokkrview ✅ (1) ✗ headless.rs+render.rs needs feature + a functional cell
facett-cfd ✗ (egui-only) ✗ ✅ leaf (§3)
facett-gantt ✗ (egui-only) ✗ ✅ leaf (§3)
facett-kanban ✗ (egui-only) ✗ ✅ leaf (§3)
facett-calendar ✗ (egui-only) ✗ ✅ leaf (§3)
facett-markdown ✗ (egui-only) ✗ render.rs leaf
facett-search ✗ (egui-only) ✗ render.rs leaf
facett-sdp ✗ (egui-only) ✗ render.rs leaf
facet-wrapped ✅ (3) ✗ wasm_smoke wasm host, not a pane per se

Note: facett-holger and facett-brokkr DO emit robot-ui rows (via nornir-robotui Scenario) even though they emit no functional cell — they are covered, not gaps. facett-plandag/-timeline/-korp emit functional cells.

3. Design tension — the egui-only leaf panes

facett-kanban, facett-calendar, facett-gantt, facett-cfd, facett-markdown, facett-search, facett-sdp deliberately do not depend on facett-core — each Cargo.toml has an off-by-default facett = [] feature and a comment:

"Off by default so the crate compiles egui-only (robust against the facett repo's churn). Enable + add the path/registry dep when moving to facett."

So wiring a facett_core::testmatrix::emit cell into them means pulling facett-core as a (dev-)dependency, against their stated churn-robust design. Two honest routes, a decision for Rickard, not a unilateral edit:

Recommend (A) for the four PM/analytics leaves (kanban/calendar/gantt/cfd) since the demo already showcases the deck; leave markdown/search/sdp as-is (thin).

4. Secondary gaps (already filed — do not duplicate)

4b. LANDED — the ONE shared discovery-driven probe (backlog top-10 #6)

The highest-leverage Law-#1 win for the zero-cell gap was not hand-writing 14 per-crate cells but building one generic harness every pane reuses. That landed this round in facett-core:

Adoption is one line: a leaf builds its pane via its own demo()/local() constructor and calls probe_and_emit. facett-brokkrview is the first consumer (facett-brokkrview/tests/robot.rs) — this simultaneously closes its zero-cell gap (§2, follow-up #2) AND its missing robot json-drive scenario (the [medium/medium] upgrade-render-proof item), from one shared path. The remaining zero-cell panes with a facett-core dep (and the demo-side route for the egui-only leaves, §3) now backfill through this same call instead of re-inventing render+emit.

4c. LANDED (2026-07-14) — dead update_json robot seams made LIVE (5 panes)

A distinct gap from §2 (which is about matrix presence): several panes that DO emit an in-view ui_render functional cell were nonetheless not robot-drivable through the standard JSON seam. The impl_facet_via_elm! bridge generates no update_json, and Facet::update_json defaults to a no-op — so unless a pane overrode it (as facett-brokkrview / facett-korp::GraphPane do), a headless robot / the shared probe_facet harness fed it messages that changed nothing. The pane looked "covered" (it had a render cell) but its FC-2 input surface was dead.

Fixed this round for 5 panes by (a) deriving Serialize, Deserialize (rename_all="snake_case") on each pane's Msg, (b) overriding update_json to parse one tagged Msg and apply it through the single Elm::update path, and (c) adding a one-test tests/robot.rs that drives a real state-changing message chain through the SHARED facett_core::testmatrix::probe_and_emit:

pane drive script new cells
facett-matrix select_repo→clear_selection headless_render + responds_to_input
facett-cicd select_pipeline→clear_selection same
facett-log set_search→clear_filters same
facett-stat set_title→clear_rows same
facett-security select(id)→select(null) same (hand-written impl Facet)

responds_to_input is NEW RED-when-broken coverage: it goes red if any of these seams regresses back to a no-op. All additive (L2) — no view/render path changed. Same one-line-adoption path as §4b; the remaining macro-bridged panes with a serde-able Msg (see §6) can adopt it identically. Note: panes whose Msg carries non-serde nested types (e.g. facett-tabbar's egui::Rect, facett-graphpan's egui::Vec2) need those types made serde-able first, or a #[serde(skip)] on the offending variant, before their JSON seam can go live.

4c-follow-up (2026-07-14, second pass) — remaining macro-bridged panes CLOSED

The six panes flagged above as remaining are now all LIVE, same pattern, all additive, each with its own tests/robot.rs. None needed a render-only fallback — every Msg was made cleanly serde-drivable:

pane drive script serde note
facett-jobview select→clear_selection Msg payloads (SortKey/JobEntry) already serde-able
facett-icebergview select_snapshot(100)→(200) (time-travel) all-primitive Msg, trivial
facett-warehousedeck select_pane→clear_selection DeckLayout/usize/String, trivial
facett-git select_path→show_pane(log) Pane/Blob already derive serde → full drive
facett-graphpan select→pan_by([x,y]) Vec2 variants reuse the Model's existing vec2_serde [x,y] codec
facett-tabbar select_tab×2 internal FC-7 AdvanceUnderline{egui::Rect} tick is #[serde(skip)] (never robot-driven); the one real input SelectTab is fully drivable

The facett-tabbar case is the notable one: rather than teach egui::Rect a serde codec, the offending variant is an internal injected-clock tick the pure view emits to itself, not a user input — so #[serde(skip)] is exact and minimal, and the real input surface (SelectTab) is fully covered.

With this pass the dead-update_json seam is closed across all 11 macro-bridged Elm panes that carry a mutable Msg surface (5 first pass + 6 here). Each adds headless_render + RED-when-broken responds_to_input cells.

5. This round's fix — facett-lineage functional-matrix cell

facett-lineage is the only zero-matrix pane already fully wired for the functional aspect (facett-core dep + testmatrix passthrough feature declared in Cargo.toml) that simply never calls emit — a half-wired, in-design gap. It is also the flagship Palantir surface (data lineage / link-analysis over the skade lineage_events fact log, rendered through the facett-graphnav graph-DB IDE).

Fix: a testmatrix_cell_lineage_dag test in facett-lineage/tests/robot.rs that drives the full lineage-DAG gesture chain (build → query → select → provenance path → layout → export) and emits one functional row per meaningful check via facett_core::testmatrix::emit, mirroring facett-graphnav's pattern. No-op in release (feature off); a real row on the sink under --features testmatrix. The Palantir lineage pane now shows green in the nornir test functional matrix instead of being invisible.

6. Follow-up backlog (ranked)

  1. Decision (A vs B) for the egui-only leaves (§3) — then backfill kanban/calendar/gantt/cfd cells. Preferred: demo mega_matrix wiring.
  2. facett-brokkrview — add testmatrix feature + functional cell DONE (§4b): the shared probe_and_emit path in tests/robot.rs.
  3. Backfill the remaining facett-core-dep zero-cell panes (facett-holger, facett-korp, …) through the SAME probe_and_emit path — a one-line tests/robot.rs each, no new per-crate boilerplate.
  4. Wire facett-lineage (and facett-form) into the demo LEGEND/mega_matrix so the coverage gate protects them too (defence in depth).
  5. GUI-polish tranche (§4) — graphics SOTA + idle-rotate on the 3D panes.