<!-- nornir:class: reasoning -->
# 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:
- **(A) demo-side coverage** — wire these leaves into `facett-demo`'s `LEGEND` +
`mega_matrix` cell registry. The coverage gate then protects them, one place, and
the leaf crates stay egui-only. **Preferred** (single-source, matches the existing
gate). Cost: a `mega_matrix` cell + data fixture per pane in facett-demo.
- **(B) opt-in leaf cell** — add `facett-core` + a `testmatrix = ["facett-core/testmatrix"]`
passthrough as a **dev-dependency** and emit from each crate's own robot.rs (as
`facett-lineage` does). Keeps the cell next to the drive test but adds the dep.
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)
- **GUI tiptop / graphics SOTA** — CSM/VSM shadows, bloom mip-pyramid, GTAO, TAA:
`.nornir/graphics-sota-roadmap-reasoning.md`. Idle auto-rotate + click-to-Yggdrasil
for the 3D map/graph panes: `.nornir/idle-auto-rotate.md`.
- **korp Tools-menu "fill OSM Sweden roads" demo** as a jera job — collectors +
MapLayer bridge exist; verify the end-to-end trigger (`.nornir/facett-worklist.md` P1).
- **stale doc** `facett-demo-reasoning.md` (describes a 19-facet deck; deck is 57+).
- **empty-states / clipping / theming polish** — per-pane pass; most panes handle
empty state (see cfd placeholder, gantt empty range) — spot-check the thin leaves.
## 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`:
- `facett_core::harness::probe_facet(&mut dyn Facet, &[&str]) -> FacetProbe` —
headless-renders ANY object-safe `Facet`, then plays a scripted list of
`update_json` JSON messages, snapshotting `state_json` after each. Returns a
`FacetProbe` with the initial render's vertex proof + per-message `ProbeStep`s
(msg, vertices, `changed`, state). No display, no GPU, no concrete `Msg` type at
the call site. `FacetProbe::{drew,responded,cardinality}` give the three facts a
matrix cell needs (drew geometry · input surface is live · reports domain data).
- `facett_core::testmatrix::emit_facet_probe(component, &probe)` and the one-shot
`probe_and_emit(component, &mut facet, &msgs)` turn a probe into the functional
rows (`headless_render` + `responds_to_input`), feature-gated so release strips
the edge. A blank OR zero-cardinality pane → RED; a dead `update_json` → RED.
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.