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

nordisk/nornir

.nornir/nordisk_plan.md

nordisk — THE BIG PLAN (single source of truth)

THE one plan — filter every idea in HERE. Rickard + collaborators add/triage ideas in this file only. Renamed from development-plan.md and absorbs the old untracked /run/media/rickard/T9/git/THE_BIG_PLAN.md scratch (deleted 2026-06-14). Living roadmap for the nornir + facett + warehouse + nordisk megaproject (started 2026-06-12). Tracked in nordisk/nornir, renders into the docs book. Checkboxes tick on real close (see Definition of Done).

🚀 FLEET 2026-07-08 — nornir agent session (landed + pushed to main)

One-agent-per-repo fleet pass on nornir. Shipped, each its own commit, cargo green, pushed:

🔄 RE-SYNC 2026-06-30 — canonical tick-list catch-up (folded from the session journal)

This canonical plan was last broadly touched 2026-06-25. The session journal (workspace_nordisk/PLAN.md, the woven cross-repo narrative — it now defers here) carried newer state. Folded in below so nothing drifts. Inline boxes in the sections that follow are also ticked where the audit verified the work shipped.

2026-06-25 — SCIP → FUNCTIONAL pivot. The resolved SCIP knowledge index landed FAST + CORRECT + rayon-free (gatling single-pass goto_definition; 35 min → 63.5 s after the vfs_rel_path workspace-scoping fix; consumers prefer the resolved index via query.rs::load_preferred; scan_repo parallelized 3.3×). Direction then pivoted from SCIP-perf to functional work: (A) metro feed reads the resolved index, (B) the functional test-matrix / autonom completeness gate (Aspect::Functional/functional_status), (C) resume-plan leftovers. Roadmap: nornir/.nornir/scip-resolved-knowledge.md; narrative: workspace_nordisk/PLAN.md §"RESUME HERE — 2026-06-25 (SCIP perf landed → FUNCTIONAL pivot)".

2026-06-29 — four deep analyses (loki bench host + three studies). Stood up loki as a nornir bench host (nornir-server systemd user-scope :7878, 4 TB /mnt/work4t, workspace_holger populated; see memory loki-nornir-bench-host.md) and ran the heavy benches; then three deep multi-agent studies landed as planning docs (all 🔄 roadmaps):

Warehouse writer-side perf — DONE (reconciles the journal's stale "queued"). Both landed and are verified (nornir warehouse-maintenance+sort+zstd 5/5 + skade-bloom 4/4):

Carried-over open bug (from nornir/plan.md, tracked in neither canonical plan):

Cross-repo verified-DONE (2026-06-30 audit) — not inline-tickable here (shipped in leaf repos):

⚖ Cross-cutting laws (every item, every sub-agent)

  1. Warehouse on FAST local disk, NEVER the slow T9 external drive (decided 2026-06-13). ~/.nornir for local, /home/nornir/.nornir for the server — derived from the running user's $HOME, no path env-var. Git checkouts may live on T9; the warehouse must not.
  2. Tests inject values + assert real output — never "didn't panic". (And against the LIVE/remote path, not just embedded — a green embedded test ≠ data shows up thin-mode.)
  3. Every feature ships .nornir/ design + guide.
  4. All viz UI = facett components + facett theme (non-nornir-specific → facett).
  5. Screenshot PROOF, egui-native only — egui_kittest wgpu snapshot (tests) + live ViewportCommand::Screenshot (app screenshots itself) → PNG in robot_test_results. Never KDE/spectacle/compositor grabs.
  6. Persist to the WAREHOUSE — stream, don't /tmp. Everything durable (bench progress + CPU/mem telemetry, release events, test results, action trails) streams into the warehouse; viz reads PRIMARILY from the warehouse. Live transport = Arrow IPC record-batch stream (typed/columnar/cheap — znippy already on Arrow-IPC), NOT text /tmp; durable sink = Iceberg (write both if Iceberg snapshots are too coarse for ~1Hz live). /tmp sinks are stopgaps.
  7. Every facett/viz component exposes what it renders as READABLE DATA — "see what the user sees" as structure, not pixels: state_json + typed $FACETT_TRACE/$NORNIR_VIZ_TRACE IN/OUT/END must carry the ACTUAL rendered data (rows/nodes/selected values). Tests + agents read that (LAW 1 functional proof); the screenshot (LAW 4) is the visual proof.
  8. Containers are started/controlled in RUST — shell *_up.sh are FORBIDDEN. All test/bench containers (RustFS S3, Nessie, Polaris, Spark, …) come up/down via Rust with the operational fixes baked in — skade's bench-containers (src/containers.rs: up/down all|rustfs|nessie| polaris|spark) already replaced the old containers/*.sh. Unify on the SHARED mechanism that holger / nornir-tests / znippy use (audit + converge — they should share one container harness, not per-repo copies). No new shell container scripts, ever.
  9. GATLING + ZERO-COPY for parallel produce→save pipelines. Use znippy's GATLING no-barrier worker-pool (znippy-zoomies, already a dep): the produce stage fans across ALL cores (e.g. encode Parquet parts on 32 cores), AND — when the sink is network/S3 — the save stage is ALSO a GATLING pool (N writes in flight), not a single sequential saver (that's only optimal for local NVMe/RAM). Zero-copy throughout (Arrow IPC / Bytes / mmap / arrow reinterpret bridge — used in znippy + skade); never clone/serialize between stages. This is the G4 S3 fix: single-saver = 12% of NVMe; GATLING-save recovers it.

Definition of DONE (a box ticks only when ALL hold)

implemented end-to-end · injected-value auto-test · live-verified on real data/oden:7878 · .nornir design+guide · committed+pushed (+deployed if a binary).

Development graph tree

Plain-text dependency tree. Each node shows its full label and status tag ([done] = green / [wip] = amber / [todo] = grey). Indentation = a parent → child edge; where a node has more than one incoming edge it is listed under its primary parent with the extra incoming edges noted inline as (also ← X).

A · Warehouse ER + docs + gap analysis  [done]
├─ B1/B2 · release_events DAG → warehouse (server + fat CLI) ✅  [done]
│  ├─ B3/B4 · viz Release view + lit dep graph ✅  [done]
│  │  └─ C3 · LiveRun hydrates from warehouse release_events ✅  [done]   (also ← B1)
│  │     └─ N5 · viz action trail → warehouse viz_actions (durable sink; /tmp stays live-channel; read-back in state_json) ✅  [done]   (also ← A, ← R1)
│  └─ C3 · LiveRun hydrates from warehouse release_events ✅  [done]   (see above)
├─ C6 · test-matrix SPINE ✅ (nornir test + test_results + 🧪 Test pane + stall-watchdog); Bench-pane/MCP/robot-shots deferred  [done]   (also ← PROOF, ← D2)
│  ├─ R1 · full UI-state emission (every form/field in state_json) ✅  [done]
│  │  ├─ R2 · $NORNIR_VIZ_CMD control channel (poll+apply each frame) ✅  [done]
│  │  │  └─ R3 · viz.state + viz.click MCP tools (robot loop) ✅  [done]
│  │  │     ├─ R4 · inject-assert robot-loop test ✅  [done]
│  │  │     ├─ R5 · viz-introspection.md docs ✅  [done]
│  │  │     └─ R6 · richer live-drive (field/button/AccessKit events) ✅  [done]
│  │  └─ N5 · viz action trail → warehouse viz_actions … ✅  [done]   (see above)
│  └─ H5 · 🏁 agent/model BAKE-OFF matrix → warehouse (which model+agent won?) ✅  [done]   (also ← H1, ← H3)
├─ N5 · viz action trail → warehouse viz_actions … ✅  [done]   (see above)
└─ E1/E2 · Funnel injection demo ✅  [done]   (also ← E4)
   └─ E3 · viz trigger + disk-nuke ✅  [done]

P1 · Heavy bench DONE + CPU/mem telemetry→warehouse ✅  [done]
├─ G4 · S3 read/write concurrency — 3.35× (13%→46% of NVMe) ✅  [done]
│  └─ G4b · gatling::io async-save sibling (14.06M rows/s) ✅  [done]
└─ G2 · optimize CPU vector path — AVX2 4.4× + int8 3.8× ✅  [done]

PROOF · LAW4 · screenshot-proof harness (egui_kittest wgpu → PNG) ✅  [done]
├─ D5 · facett-demo: all 16 components + snapshot proof ✅  [done]   (also ← D4)
└─ C6 · test-matrix SPINE … ✅  [done]   (see above)

PROOF4b · LAW4b · live-app self-screenshot (ViewportCommand::Screenshot) ✅  [done]

D1 · facett wave: caps…form…card…menu…plotters…fx…pipeline  [done]
├─ D4 · theme-compliance matrix ✅ (all 12 themeable, enforcement test)  [done]
│  └─ D5 · facett-demo: all 16 components + snapshot proof ✅  [done]   (see above)
└─ D2 · 🏆 facett-grid SHIPPED (virtualized 1M-row · frozen · sort · select→TSV · heat · themed) ✅  [done]
   ├─ D3 · ALL viz UI → facett-ui module + facett theme everywhere ✅ (egui-skew: re-home pending 0.34)  [done]
   └─ C6 · test-matrix SPINE … ✅  [done]   (see above)

C1 · About popup ✅  [done]
C2 · Knowledge: async scan (5s→~0) + rescan + re-scope ✅  [done]

C5 · DepGraph deep transitive + coloring + navigable ✅  [done]
├─ C7 · direct/transitive coloring ✅  [done]   (also ← C4)
└─ I3 · graphs navigable (pan/zoom/collapse) ✅  [done]   (also ← I2)

C4 · TimeTravel: text + graph views ✅  [done]
└─ C7 · direct/transitive coloring ✅  [done]   (see above)

F1 · Incremental republish (affected_by_change) ✅  [done]
F2 · aegir uring · 3D fog · SBOM-from-warehouse  [todo]

G1 · AMD ROCm/MIGraphX vector/embed EP + probe ✅  [done]
G3 · interchangeable embedding model ✅  [done]

H1 · MCP tool harness — functional, matrix-wired (56 tools, in/out asserted, coverage gate) ✅  [done]
├─ H4 · manual-for-idiots: local LLM + nornir MCP setup ✅  [done]   (also ← H2, ← H3)
└─ H5 · 🏁 agent/model BAKE-OFF matrix … ✅  [done]   (see above)
H2 · local-LLM/GPU support audit + gaps ✅  [done]
└─ H4 · manual-for-idiots … ✅  [done]   (see above)
H3 · web analysis: best 2026 on-prem LLM ✅  [done]
├─ H4 · manual-for-idiots … ✅  [done]   (see above)
└─ H5 · 🏁 agent/model BAKE-OFF matrix … ✅  [done]   (see above)

I2 · dep graph populates (cargo metadata) ✅  [done]
├─ I1 · design-doc dep graphs VISIBLE ✅  [done]
└─ I3 · graphs navigable (pan/zoom/collapse) ✅  [done]   (see above)

E4 · CLI↔server funnel store-split FIXED ✅  [done]
└─ E1/E2 · Funnel injection demo ✅  [done]   (see above)

Checklist (tick on real close)

🔴🔴 P0 — WAREHOUSE LAST-MILE for test-matrix functional rows (Rickard 2026-06-21)

The home is the WAREHOUSE; the JSONL (NORNIR_TESTMATRIX_OUT) is only the WIRE. Reinforces Law 5.

🔴 P1 — Heavy bench, live-visible

EPIC A — Warehouse docs ✅

EPIC B — release_events DAG + follow-along viz

EPIC C — Viz fixes & features

⭐ EPIC AUTONOM — self-discovering completeness gate (the test-matrix FRAMEWORK) 🔴🔴🔴 (started 2026-06-14)

autonom = the autonomous, self-discovering test-matrix framework. Turns C6's results-recorder into a PROVABLE completeness gate: green ⟺ every surface wired. Reusable across all nordisk (engine in nornir-testmatrix). Design+idiot guide: .nornir/autonom.md + .nornir/autonom-for-idiots.md; FC component contract: facett/.nornir/component-contract.md (authored 2026-06-14). Forged 2026-06-14 with Rickard.

⭐ EPIC AIRGAP — Skíðblaðnir: 100% Rust airgap pack/move/unfold/install (crate skidbladnir, sibling repo ../Skidbladnir) 🔴 (started 2026-06-14)

RENAMED + RELOCATED (reconcile): the crate was renamed nornir-airgap → skidbladnir and extracted out of crates/ into its own sibling repo ../Skidbladnir. nornir now depends on it as a path dep (skidbladnir = { version = "0.1.3", path = "../Skidbladnir" } in Cargo.toml) — there is no crates/nornir-airgap in this repo any more, and no nornir-airgap crate is published. The crates/nornir-airgap/src/… paths in the completed AIRGAP/INSTALL notes below are the historical locations; the code now lives under ../Skidbladnir/src/… as skidbladnir::…. nornir's airgap CLI verb + airgap_* MCP tools drive it.

Pack a product/lake into an air-gapped bundle, move it across the gap, unfold the target (Redfish · Terraform · KVM), install + configure + start every product in dependency order — no shell. Design + source prompt + prior-art map: .nornir/airgap-install.md. Prior art: dist · airgap-kubernetes-main · airgap_llm · tunnr · msi-agent · bifrost. (An earlier agent failed to filter this prompt in — now captured here + in the crate.)

⭐ EPIC ARCH — living architecture diagrams: UI buttons ↔ gRPC backends, wired (skade-style SVG) 🔴 (2026-06-14)

nornir's architecture as auto-generated, always-current wired SVG diagrams (skade circuit-board style, Typst-rendered — NOT mermaid): every UI "button"/surface wired to the gRPC backend it calls and the core fn + warehouse table behind it. The readable, regenerated picture of how the program is wired — and the visual twin of the AUTONOM completeness gate (same warehouse data: entrypoints + call_edges + fn→table). First-class for nornir. Storage candidates: per-workspace_*/ (travels with source) OR the warehouse (historized, time-travel per git sha) — DECIDE (maybe both: warehouse durable + doc-embedded).

Subsumes/extends AUT7 + EPIC J for the UI↔gRPC angle — the "diagrams of UI-buttons and gRPC backends, wired" ask (Rickard 2026-06-14).

⭐ EPIC DOC-SEED — docbook render emits a git-committed structured seed (cold-start bootstrap) 🔴 (Rickard 2026-07-02)

Ask: when nornir docs book renders, also persist a compact structured artifact in git (via the existing gix seam) so an EMPTY warehouse can still bootstrap some data — vs. the alternative of parsing data back out of the already-rendered doc. DECISION (my call, recorded):

EPIC R — Robot UI tester (viz-introspection: full UI-state + viz.state/viz.click)

LAW #6 "see what the user sees as data" + the robot loop. Read-half mostly existed (state_json → $NORNIR_VIZ_STATE + action log + $NORNIR_VIZ_TRACE); this EPIC completes the emission and wraps both halves as MCP tools. See .nornir/viz-introspection.md.

EPIC D — Facett components

EPIC E — Funnel demo + store-split

EPIC G — GPU acceleration + vector performance

EPIC H — Local LLM / on-prem + MCP tool testing 🟠 BIG

EPIC #45 — Funnel local-LLM task decomposition with compiler-as-oracle ✅

EPIC J — Beautiful SVG flow diagrams (skade-katalog circuit-board style)

EPIC I — Dependency graphs: more types, working, navigable, visible in design docs

EPIC K — Bencher mashup polish (compact "absurd-best" + complete variants)

Cross-cutting law harness

✅ Foundation already shipped (this session)

⭐ EPIC N — Deployment modes: home-derived root + per-workspace + viz mode-resolution (2026-06-13)

The three modes (fat / server-monitored / thin) made coherent end-to-end. Decided + built with Rickard.

EPIC Holger — pluggable artifact server: deploy + docs

D3-followup — extract the viz top-bar as a facett component (Rickard, 2026-06-13)

D5b — facett-demo mega matrix: + a LIVE-DRIVE row (Rickard, 2026-06-13)

Session 2026-06-13 — releases 0.4.14 → 0.4.20 + new epics (ALL captured here per Rickard)

EPIC RELEASES (shipped to codeberg + crates.io this session)

LAW (new) — Iceberg schema evolution for migrations

EPIC N-data — feed the live server warehouse (partial: benches done)

⭐ EPIC POPULATE-OVERVIEW — Nornir tab = all-workspaces populate status + viz Test-tab status (Rickard, 2026-06-18)

Goal (Rickard): the 🧬 Nornir root tab must show a list of ALL the server's workspaces with a status column for populate (and friends), not just the active workspace's members. Today the populate-status panel (EPIC #6) is scoped to one workspace; we want the workspace-level roll-up so you can see, at a glance, which of holger/knut/korp/njord/nordisk/skade/znippy populated cleanly vs has a failed/stale member.

🔴 POPULATE-FINDINGS — bugs found while generating warehouse data for every workspace (2026-06-18)

EPIC HOLGER-UI — holger/for_ui_dev.md brief (for a Claude agent + human dev)

Goal: crisp/barren brief pointing the dev/agent to read holger book.pdf (codeberg link) → writing-a-ui chapter; egui via facett components preferred (facett component list); gRPC OR direct-Rust-call against holger core; circuit-diagram chapter; start mannequin (idiot-guide link); facett components are robot-testable. PUSH to codeberg when prerequisites valid.

EPIC MANNEQUIN-REVIVAL (Rickard: "go through all source, make it really work, rework UI onto facett, invent facetts if needed")

EPIC HENRIK-BUGS — nornir-mcp install/first-run friction (0.4.21, reported by Henrik)

Full original report (B1–B5 + repro + suggested fixes): .nornir/henrik-bug-nornir-mcp-install.md.

DOCS-LIVE — live-server docs-export gap (Henrik, 2026-06-13, MCP against oden)

The book.pdf renders LOCALLY but not against the live oden workspaces — confirmed driving the nornir MCP while trying to docs-gen the holger repo. This is the live-path face of UIP-prereq1 (facett book.pdf MISSING) + EPIC A docs.

EPIC FUNNEL-INTAKE — paste errors/ideas in (viz + CLI) + browse history (Rickard, 2026-06-13)

The funnel (ideas→plan DAG, src/funnel/) gets a human-facing intake + history UI:

MASTER QUEUE — 2026-06-13 wave 2 (ONE place for ALL dev, incl. non-nornir repos)

Rickard: keep every thread here even if it lives in another repo. Status as of this wave.

Done (this wave)

Done (2026-06-13 late wave)

Queue (fires as each repo frees — no two agents per repo)

EPIC NJORD-MAIL — isolated mail-in-out (decisions locked 2026-06-13, branch feat/njord-mail-in-out → PR for owner)

Session 2026-06-13 — late: HONEST status reckoning + Security live-fix (NOT pushed yet)

Rickard caught me over-claiming: "you always claim test matrix is done and working and it never catches the errors … press Security on nornir … WHY??" This section is the straight answer + the fix. Honest labels from here on: live-verified (proven against the real oden server) vs wiring-tested (passes against seeded/ephemeral fixtures only).

WHY pressing 🛡 Security on nornir fails (root cause, reproduced live)

WHY the matrix never caught it (the gap I must own)

FIX A — net-scan feature: clone missing path-dep siblings (✅ coded, ⏳ uncommitted)

FIX A also hits Docs.Render (same cargo-metadata death — Henrik, 2026-06-13, MCP against oden)

FIX B — matrix covers ALL workspaces, live + synthetic (⏳ todo)

EPIC #44 — callgraph / dep-graph performance (njord ~10s → sub-second) ✅

Full write-up: .nornir/callgraph-perf.md. Branch feat/callgraph-perf.

#44 viz callgraph/dep-graph njord ~10s
├─ PROFILE first (MEASURE, don't guess)
│  ├─ njord symbol_facts=5928 files/15GB, call_edges=5764/14GB
│  ├─ bottleneck = SCAN: read_all materializes whole table (35.4s+25.3s)
│  └─ layout NOT it: ClusterZ 97ms / MDS 265ms @160 nodes
├─ FIX dominant cost
│  ├─ scan_limited: stream Arrow + STOP at limit (0.66s+0.60s, ~50x)
│  ├─ keep cheap default ClusterZ; Spectral/MDS opt-in (off-thread unjustified by data)
│  └─ memoize draw_drilldown transitive_closure (per-frame → cache hit)
├─ adjacent: Mímir-njord build fails
│  ├─ build_graph_from_warehouse: rebuild from dep_graph_edges
│  ├─ WorkspaceCtx.name + graph() fallback on descriptor-missing
│  └─ ensure_repo/svg use has_component; seed single-repo members
└─ inject-assert tests + matrix rows
   ├─ callgraph layout-budget + closure-memo unit tests
   ├─ mimir edges-only + single-repo-seed tests
   └─ tests/callgraph_perf_matrix.rs perf-aspect rows (synthetic + live njord)

Side threads resolved/observed this session

Session 2026-06-14 — plan sync + funnel matrix + lock-spam fix

Done this session

Open (confirmed not done, no agent running)

New epic — nornir-install: common service installer + LAKEhouse packager

⭐ RECONCILED 2026-06-15: INSTALL == EPIC AIRGAP — ONE install system, not two. This epic's nornir-install crate idea SHIPPED as the airgap crate — since renamed skidbladnir and extracted to the sibling repo ../Skidbladnir (path dep skidbladnir 0.1.3; the earlier nornir-airgap 0.1.0 name is retired and no nornir-airgap is published). There is no separate nornir-install crate; skidbladnir IS it. INSTALL-2..6 below are the adoption follow-ups (CLI verbs + product specs + tests) layered on skidbladnir, not a second stack.

Rickard 2026-06-14: holger must be as installable as nornir. Shared installer crate (in nornir) — systemd unit gen, init-system detect, atomic service upgrade, LAKEhouse component registration, health-check wiring. Targets: holger, nornir-server, mail-server, tunnr, future lake components. Scope expanded 2026-06-14: also covers tunnr appliance packaging, Redfish BMC/bare-metal provisioning, Terraform resource definitions, and delta-package delivery (binary delta = znippy zero-copy patch; bsdiff/zstd diff + znippy verify). Better than Ansible; pure Rust. AIRGAP IS PRIMARY — every component must work with zero network on the target; the full lake is packed into a signed znippy bundle on a staging host, transferred by USB/relay, verified on receipt, then installed with no further network calls.

New epic — FACETT-CONTRACT: Component Contract & Agent Enforcement (FC-1..FC-9)

Rickard 2026-06-14: first phase = codebase analysis. Normative spec pasted in full — FC-1 (no hidden state) through FC-9 (pure view). Authority: where spec conflicts with existing facett code, code is wrong. Agent mandate: audit every component, produce compliance table, apply minimal refactor to full compliance. No sweeping rewrites unless no smaller path exists.

New epic — FACETT-WASM: facett components in Apache Superset (+ browser)

Rickard 2026-06-14: embed facett egui components as Superset viz plugins. Reference: github.com/Ignalina/superset-egui-demo — currently just a ChartPlugin skeleton with no actual WASM/Rust; proves plugin registration works. eframe has a web feature that renders to a WebGL/WebGPU canvas.

Two delivery targets: (1) Apache Superset viz plugin (@superset-ui/core ChartPlugin — React/TypeScript shell, egui renders into a <canvas> via useEffect); (2) standalone browser page (facett-demo served as WASM, no Superset). Superset passes props.data (Arrow/JSON) → JS calls #[wasm_bindgen] Rust function → facett renders.

Pragmatic path: <iframe> + postMessage for first-pass Superset integration (no npm bundling of WASM, avoids wasm-in-npm complexity); direct-canvas (wasm-pack --target web + useEffect canvas) is the clean target once the WASM API is stable.

facett MAP components (from old osm-katana → archived) — 2D + 3D, each CPU+GPU (2026-06-16)

⛺ RENDER-ENGINE SPEC (ratified 2026-06-21): the canonical map+graph render design is facett/.nornir/render-engine.md. Key decisions referenced here in pieces: 2 hardware categories ONLY — CPU (SIMD assumed; no-SIMD = free vello_cpu scalar fallback, not a tier; Apple/x86 always have SIMD) and CPU+GPU; build axis = native+wasm (wasm = 2 SIMD bundles + WebGL2-no-compute path). velo = Vello family (vello_cpu CPU row · facett L0 instanced-wgpu + vello L1 overlay GPU row). SIMD 3-way split: Ragnar stree = search/index · DIY kernels = projection/cull · vello_cpu = raster (never DIY a rasterizer). Black box: (OSM + border polygons + Theme) → navigable viewer. One kernel, two skins: facett-core (L0 kernel) + facett-graphview (graph engine); map/3D/syschart/pipeline stay as thin kinds; facett-geomap folds into facett-map (settles MAP-GEOMAP below); facett-osm = data. galileo = design references only (Renderer-seam/Layer-trinity/Symbol/TileSchema+Lod/CRS patterns), never a dep. TEST LAW (start→pixel): instrument every render-matrix column with a functional_status emit checkpoint (testmatrix-gated, stripped in release); the final picture is emitted as a PNG blob so an agent inspects the render without asking; the 3D map clipping bug = clip.ink_outside_rect oracle, binary-searched + fail-on-bug/pass-on-fix matrix row. See MAP-RENDER-ENGINE + MAP-CLIP-TEST below.

facett CONSOLIDATION CHECKLIST — tick one crate at a time (2026-06-21)

Rule: render engine consolidates; domain "kinds" stay as thin skins (render-engine.md). Each box = one crate's migration onto the shared kernel, done & matrix-green independently.

Two facett map components born from the (now Codeberg-archived) mikronova/katana-osm viewer; each runtime-selects CPU vs GPU like nornir's #9 embedder selector. Real data = ways.parquet/nodes.parquet; synthetic test data = the znippy rabbit (2D + 3D).

facett GRAPH components — nodes/edges/text, 2 categories (CPU / CPU+GPU) (2026-06-21)

Same render kernel + 2 categories + SIMD split as the maps — ONE kernel, two skins. Full GRAPH render matrix + consolidation in facett/.nornir/render-engine.md. Graphs draw lines+nodes +text (the user's ask); graph DATA comes from knut (FalkorDB/openCypher) — facett never learns Cypher. Graphs-over-maps overlay = LATER (the shared-camera+z-layer seam is added now so it's not a retrofit — see GRAPH-OVERLAY-SEAM).

znippy TILE container — planet-scale map data source (2026-06-21)

Idea (Rickard): a znippy archive holds millions of tiles with O(1) zero-copy access — a better PMTiles. Strategy: standard where it matters, novel only in the container. Addressing = XYZ / Web-Mercator (universal); content = MVT vector tiles (+ PNG/WebP raster); interop = read/write MBTiles (SQLite, most users) AND PMTiles (serverless, rising). znippy's value-add = O(1) Morton/Hilbert coordinate→offset index + zero-copy mmap + GATLING parallel build + airgap host. Feeds the render-engine "data scale" axis (tiles → cull/LOD → renderer). Ties to F2 (znippy geo-host).

Njord (Tillsynia) — 2 tracks (2026-06-16)

test-matrix functional-status emitters (2026-06-16)

AIRGAP bundle format — name + ownership (Rickard 2026-06-16, OPEN design)

The airgap installer is Skíðblaðnir (the fold-up ship; nornir-airgap codename). Its bundle is the znippy format — today a self-contained ZNIPGAP1 archive (content-addressed cache + delta + O(1) seekable read) living inside nornir-airgap/src/archive.rs.

AIRGAP — Go-bundler carry-overs (from airgap-kubernetes-main prior art, 2026-06-21)

Reviewed the original Go Talos bundler (git/airgap-kubernetes-main Design.md). Structural DNA already absorbed (two-phase, pure-language, version-pinned, atomic-rollback, no-shell). Open carry-overs to track:

WAREHOUSE-TRAIT — make the nornir warehouse detachable (Rickard 2026-06-16, OPEN design)

The warehouse is always the nornir warehouse — never a per-feature sink choice. But it should become pluggable behind a trait so the backend can be swapped/detached later.

SAGA — collect user navigation for replay + bug-finding (Rickard 2026-06-16)

New nornir crate nornir-saga, production sibling of nornir-testmatrix: collect users' navigation → persist to the nornir warehouse saga_events → the matrix replays the path AND generates a robot test from it (egui = kittest/nornir-robotui; web app = Leptos+Axum via WebDriver) for bug-finding + regression (+ later AI via sigtuna OnPremLlm). Toolkit-neutral core; writes to THE nornir warehouse only (alt backends via [[WAREHOUSE-TRAIT]], not here). North star = the real-person-debugging loop: a real non-developer ("Henrik") tries Njord, hits a bug / gets lost → Saga records the session (nav + clicks + path) → a dev REPLAYS the exact steps, SEES the nav path / stuck point, and the replay becomes a standing robot regression test. "Real user hit a problem" → "dev reproduces in one click + it never regresses." Inspiration survey + the funnel/stuck/scrubber/privacy ideas: workspace_nordisk/saga-inspiration.md; full roadmap: workspace_nordisk/PLAN.md §R.

HEAVY opt-in + bench-vs-test + chains (Rickard 2026-06-17)

Triggered by "test → run full matrix" spinning the fans for ~1 min: it was the unit aspect running heavy #[ignore]'d tests (large corpora / network), never benches. Settled model: heavy is a TEST-only opt-in; benches are explicit so never heavy-gated; bench-type tests get cloned to benches + the test downscaled.

WAREHOUSE → skade (nornir uses skade as its warehouse engine) (Rickard 2026-06-17, AUTO)

Gap analysis (.nornir/warehouse-trait-skade-migration.md): nornir's "own engine" is mostly glue already over skade (append_batch→skade::append, scan_all→skade::read_all, bulk→skade::ingest_parallel). Do it via a Warehouse trait so the backend is swappable (skade now, DuckDB/remote later); scrap nornir's own engine since nothing is unique once the gaps are filled. Decisions: sync trait (block_on internally), generic Arrow core + named convenience wrappers, iceberg_schema.rs stays table-shape source of truth, Predicate backend-neutral (DuckDB-ready).

znippy format: arrow-ipc default + skade iceberg + seal() (Rickard 2026-06-17) — funnel [[i-005]]

MR-ROBOT-ARROWIPC — deep analysis: new/changed znippy arrow-ipc impl (Rickard 2026-06-17) → workspace_nordisk

GATLING-SATURATION + FACETT-VIEWERS + AUTONOMOUS-TEST LAWS (2026-06-17/18 night)

✅ RELEASE CYCLE 2026-06-18 — clean-slate merge + docs + publish across workspace_nordisk