knut consolidation seam evaluation (jera / skidbladnir / draupnir / facett panels)
Seam audit against the constellation standard (workspace_nordisk/.nornir/consolidation-panels-maps-design.md): no app re-implements service/systemd, job execution, provisioning, pane hosting, or map drawing — there is ONE crate for each. This is the read-only evaluation for knut; each item states the gap and either the additive fix or the honest reason it is deferred (a working, often feature-gated, hot path — forcing it now would regress a green surface or pull an unrelated dep tree into knut).
1. jobs / provisioning (jera → draupnir)
1.1 knut-pipelines server feature = a bespoke bollard container manager — DEFER
crates/knut-pipelines/src/server.rs (SparkServer, feature server) drives the Spark-Connect + SDP container up/down through bollard 0.20 against podman's REST API directly (Cargo.toml:118). This is the exact concern the consolidation chain owns: app → jera (job) → draupnir (OCI backend). It is effectively a fourth independent bollard engine in the constellation (jera's BollardEngine, draupnir's backend-oci, nornir/src/viz/test_boot.rs, and this).
Target (when unblocked): SparkServer submits a container job to jera::jobs, and jera provisions via draupnir::container (the DraupnirContainerBootRunner + run_to_completion seam that landed 2026-07-12). knut would then drop its bollard dep entirely.
Why deferred, not forced now:
- The jera container consolidation is itself still gated — per
bencher_agents_problems.md(2026-07-12 draupnir/jera responses) jera KEPT itsBollardEngineand has NOT flipped its default off bollard; the repoint ofjera run_containerontodraupnir::run_to_completionis open jera/nornir work. Repointing knut onto jera before jera itself is consolidated would chase a moving seam. serveris a working, feature-gated path (OFF by default — the default build never pulls bollard). It brings up a real Spark JVM and waits on a ready line; a rewrite is a genuine provisioning change that must be bench/-integration verified against a live podman, which the Loki bencher does not have. This is the same class as korp's deferred daemon adoption and draupnir's own deferred jera repoint.- Adopting jera pulls jera + draupnir (+ their trees) into knut-pipelines for a feature that is a thin container up/down — the dependency cost wants the shared seam to settle first.
Filed for: the jera/draupnir owners to finish the bollard consolidation; then a follow-up knut pass repoints SparkServer and removes bollard.
1.2 UI stream/repaint threads — jera N/A (not tracked jobs)
knut-pipelines/src/gui.rs:677,740 and knut-popviz/src/main.rs:93 use std::thread::spawn, and web.rs:189 / knut-bifrost/src/flight.rs:336 use tokio::spawn. These are event-driven UI repaint pumps and a Flight server handler task — in-process, untracked, no durable ledger semantics. Same finding as ordning's seam eval: jera::jobs routing is not applicable to pure in-proc UI/stream threads. No change.
2. service / systemd (skidbladnir)
knut-pipelines/src/server.rs:325 start_podman_socket_unit auto-starts the rootless podman.socket systemd user unit over D-Bus (zbus StartUnit), and bin/knut-spark-server.rs is an up/stop/status/logs lifecycle CLI. This is external-unit lifecycle management (bring up podman's socket so the container API is reachable), not "run knut itself as a managed systemd service", which is what skidbladnir::service/Lifecycle standardises. The overlap is marginal: knut is not daemonising itself. No forced change; if knut ever ships its own long-running service (e.g. a hosted pipeline runner), it should declare a skidbladnir::ServiceSpec then — noted for that future.
3. facett panels — knut is ALREADY on the component-crate model (positive example)
Unlike korp/holger (welded egui, §1.2 of the constellation doc), knut already consumes shared facett component crates, so there is no duplication to remove:
knut-popviz(featuregui) renders throughfacett-pop(Cargo.toml:58) — the progress-bar/pop visual components, cut over from a local copy.knut-pipelines(featurefacett-adapter) maps its Spark/SDPViewerStateontofacett-pipeline's engine-agnosticPipelineModelvia thePipelineAdaptertrait (Cargo.toml:90), the facett types never leaking into knut's public API.
Remaining (plan-only — facett is off-limits to this repo): there is no facett-knut* panel + <guest>-embed adapter (constellation §2) that would let another app HOST knut's pipeline/pop viewer as a Panel tab (the reusable fn panel(endpoint) -> Box<dyn Panel> shape). knut consumes facett panes; it does not yet EXPORT one for embedding. Creating that adapter is facett-side work (new facett-knut* component crate + a knut-embed adapter linking a thin gRPC client) and is explicitly out of scope for the knut repo — captured here so the facett/panel owner can pick it up under the extraction order (dwarves → holger → korp → nornir → …knut).
4. map trait (facett-map) — N/A
knut has no map/geo surface. The selectable MapLayer trait (constellation §3) does not apply. No action.
Summary
| seam | knut status | action |
| jera jobs (container) | bespoke bollard in server feature |
DEFER — gated on jera's own bollard consolidation; working feature-gated path |
| jera jobs (UI threads) | in-proc repaint/stream pumps | N/A (not tracked jobs) |
| skidbladnir service | external podman.socket unit mgmt only | no forced change; adopt if knut ever self-daemonises |
| facett panels (consume) | already uses facett-pop + facett-pipeline | none — no duplication (positive example) |
| facett panels (export) | no facett-knut* embed adapter |
PLAN-only — facett-side, out of knut scope |
| facett-map | no geo surface | N/A |