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

nordisk/nornir

.nornir/marker-matrix-plan.md

Markers → Matrix → Architecture-viz — design, data-paths, and the build plan

The authoritative design for nornir's marker / test-matrix / Architecture-tab wiring. Decided with Rickard, 2026-06-16. This doc is also the instructions a programmer reads to know how to mark a function (§4). Companions: autonom.md, self-emitters.md, architecture-wiring.md, viz-architecture-tab.md, mode-matrix.md.

1. The goal (the keystone)

The 🏛 Architecture tab walks every marker (UI-component / gRPC / core-fn / table) and cross-checks it against the test matrix (surface_coverage): green = a test exists for it, red = none. Markers → matrix → visible coverage.

2. Two orthogonal axes (never conflate)

2b. The ATOM axis — the live AccessKit/kittest walk (L0) — added 2026-06-22

The markers above are the declared truth (which UI surface ↔ which gRPC). They do NOT, on their own, prove every rendered atom ran and is error-free — and they are per-button / per-tab, so sub-panels (e.g. the 🧬 tab's CloneEvents "populate status" + Jobs panels) are in no enumeration and slip through (the `` is not served leaks). The fix is a fourth layer that VERIFIES the markers against the real UI, down to the atoms — it does NOT replace them:

L0  egui_kittest + AccessKit  — walk the REAL rendered widget tree (every button,
                                 label, error-text = an AccessKit node); the only
                                 layer that sees sub-panel atoms. EGUI-NATIVE.
L1  markers / metro            — atom ↔ gRPC wiring (button_registry → 🚇). DECLARED.
L2  Facet state_json           — the data a surface renders. (the atom-walk also
                                 covers hand-rolled egui, which has no Facet.)
L3  autonom surface_coverage   — the GATE: green ⟺ every atom covered.

The atom-walk lives in nornir (the dogfood); the framework nornir-testmatrix owns only the generic concept — a surface enumerator emitting surface_coverage rows at atom granularity with a verifier verdict (UI-agnostic):

Integration / what CHANGES (nothing removed):

The AccessKit label is the UNIVERSAL MARKER — one kit, two oracles (Rickard 2026-06-22). The reusable driver is nornir-robotui (the egui_kittest robot — crates/nornir-robotui, addresses widgets by WidgetRef::label/id). Every widget — a nornir-viz atom OR a facett component's control — carries an AccessKit label, so the marker primitive is the same for both; only the oracle differs:

THIRD oracle — wgpu/WGSL renders (map3d, graph3d) are NOT egui (Rickard 2026-06-22). A GPU render is a single OPAQUE AccessKit node — kit sees *that the 3D view is present

The metro LINE = the chain, start→terminus (Rickard 2026-06-22)

A metro line is one button-to-warehouse chain; the atoms/emitters are its stations:

START                stations (emitters)                 END           terminus
[UI button atom]  →  f1 ▪ f2 ▪ f3 ▪ … (call_edges;   →  [gRPC RPC]  →  server → warehouse
 .clicked(),          each functional_status emit         handler        table (thin: LAW 4/8)
 AccessKit marker)    that fired = a LIT station)

Emitters are the oracle of LAST RESORT, testmatrix-flag-gated (Rickard 2026-06-22). An emitter is a side-channel return value, compiled ONLY under the testmatrix feature (zero production cost). EMIT-DOCTRINE: emit a functional_status only when the normal return value can't carry what you must assert (a render that returns (), a deep stage like clipped_escapes nothing surfaces). So the three oracles minimize stations: where the return value, the Facet state_json, or the AccessKit tree already exposes the fact, read that — no emitter. A station (emitter) exists exactly where all three are blind. Station rule: return → state_json → a11y-tree → (only if blind) emit, gated.

Oracle taxonomy (one kit + one marker primitive, three oracles)

component kind driver oracle (correctness)
hand-rolled egui nornir-robotui AccessKit-tree scan (atom presence / no-error)
facett data component nornir-robotui Facet state_json (multidimensional / sample-space)
wgpu/WGSL (map3d, graph3d) nornir-robotui RENDER: geometry state_json + offscreen PNG, swept over the pose sample-space

2c. ATOM-LAYER BUILD PLAN (checklist — 2026-06-22; polish design/guide/idiot-guide AFTER it works)

3. The FLOW

mark in source  →  knowledge scan (syn)  →  warehouse (symbol_facts/call_edges)
   →  arch::classify  →  architecture_wiring table
   →  autonom reads the warehouse  →  test matrix (surface_coverage)
   →  🏛 Architecture tab visualizes (green=tested, red=untested)

4. How a programmer marks a function (READ THIS BEFORE MARKING)

A function's layer is derived, not hand-annotated — you make it discoverable and arch::classify does the rest:

5. Data-paths: leaf repo → warehouse (the emitter, both modes)

The emitter crate nornir-testmatrix is itself a fat/thin client — small, dev-dependency only (test-only, never shipped), so it may pull what it needs.

FAT (nornir test, no --server):

leaf #[test] → functional_status() → nornir-testmatrix[warehouse feat] → skade → local warehouse
   → nornir test / 🏛 Architecture tab read back

THIN (nornir test --server <url>):

leaf #[test] → functional_status() → nornir-testmatrix (thin client) → Submit RPC (gRPC)
   → nornir-server → skade → warehouse → matrix / 🏛 Architecture tab read back

6. fat == thin parity (AUT4)

Same seeded warehouse → identical state_json for fat and thin, asserted as a gate. Law: thin and fat commands are identical in ~99% of cases; any divergence is rare, justified, and explicitly marked GAP(fat) / GAP(thin) in mode-matrix.md. The audit decides the direction per verb — make both shine, don't pick a winner. (Known seed leads: index upload & mimir changed are thin-only; fat workspace populate may be a docs gap, not a code bug — verify first; workspace_nordisk is missing its nornir-workspace.fat.toml.)

7. skade-style flow SVGs (docs — a FEW, not many)

Document §3 + §5 as regenerated skade circuit-board SVGs (arch::to_svg), embedded in nornir docs — NOT mermaid, NOT a hand list of markers.

8. Build order (main is king — NO BRANCHES LEFT)

  1. Commit this design (anchor).
  2. Emitter: optional warehouse feature → skade-direct (fat); thin via Submit RPC; kill JSON.
  3. nornir self-adoption (the uncommitted selftest.rs + self_emitters_* redone on this design).
  4. autonom: enumerate the warehouse-marked UI/gRPC fns; add SurfaceKind::Grpc + a layer field on rows.
  5. 🏛 Architecture tab ↔ surface_coverage cross-check (green/red per marker).
  6. fat↔thin parity gate (AUT4) + the divergence audit + add nornir-workspace.fat.toml.
  7. Consolidate: main ← the 0.4.42 line + this work; cherry-pick the ~3–4 genuinely-new orphan commits; delete every branch (merged / superseded / spike) + clean worktrees; preserve nornir-orch's uncommitted edits onto a salvage branch first. (Blind-merging the stale branches would REGRESS — they carry 0.4.36-era airgap, a Graphviz revert of NUKE-MERMAID, and the old JSON-sink emitter.)
  8. Docs: mode-matrix truth + GAP markers; the FLOW; §4 marking instructions; the skade-style SVGs.
  9. Regenerate docs/book.{md,pdf} at the consolidated version.
  10. Push main.