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

nordisk/holger

mannequin/Cargo.toml

[package]
name = "holger-mannequin"
# 0.6.10: local source DRIFTED from the published 0.6.9 under the same version number.
# crates.io bytes are immutable, so the edit only reaches consumers as a new
# version. Bumped 2026-08-23, second wave of the release cascade.
version.workspace = true
edition = "2021"
authors = ["Ignalina ApS", "Vetra Automation AB"]
description = "Test dummy daemon: PKI, OIDC, mock registries for holger development"
license = "AGPL-3.0-only"
repository = "https://git.gunnar.rs/nordisk/holger"
# Development notes, agent instructions and machine-local tooling stay in the
# repository; they are not part of the published crate.
exclude = [
    ".nornir/",
]

[[bin]]
name = "holger-mannequin"
path = "src/main.rs"

[lib]
name = "mannequin"
path = "src/lib.rs"

[dependencies]
axum = { version = "0.8", features = ["json"] }
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
# holger's OWN frozen application error codes (`holger-<subsystem>-<n>`). Named here
# so `facet_react` can prove the two vocabularies COMPOSE (a facett UI code is not a
# holger app code and vice-versa) rather than asserting it by eye.
# PATH+VERSION: cargo strips `path` at package time and rejects a version-less dep
# ("all dependencies must have a version specified when publishing"), so this line made
# `holger-mannequin` unpublishable. `0.1.0` is holger-errcode's own local version and
# its FIRST publish (sparse index 404, measured 2026-08-02) — it sits in wave 0, so it
# reaches the index before anything here needs to resolve it.
holger-errcode = { path = "../errcode", version = "3.0.0" }
clap = { version = "4", features = ["derive"] }
anyhow = "1"
cert-helper = "0.5"
uuid = { version = "1", features = ["v4"] }
base64 = "0.23"
chrono = { version = "0.4", features = ["serde"] }
tracing = "0.1"
tracing-subscriber = "0.3"
# LAW #4 — WebGPU everywhere, no OpenGL/WebGL. This was a bare `eframe = "0.34"`.
#
# To be accurate about what that was and was NOT: eframe 0.34.3's default feature set is
# ["accesskit", "default_fonts", "wayland", "web_screen_reader", "wgpu", "winit/default",
# "x11"] — `wgpu`, NOT `glow` — so the bare line already rendered WebGPU. This crate was
# never a hidden OpenGL renderer. `cargo tree -p holger-mannequin -e features -i glow`
# attributed the glow in this crate's tree to `nornir-robotui 0.2.6` (the sibling edda path
# dep) alone, before and after this change.
#
# That is now HISTORY: the egui 0.35 migration dropped the `[patch.crates-io]` to that
# unpublished sibling copy for the published, glow-free `nornir-robotui 0.3.0`, so the
# `eframe feature "glow"` edge is gone from this tree. Re-measured 2026-08-01, the only
# root of `glow v0.17.0` anywhere in the workspace is `wgpu-hal v29.0.3` — wgpu's own
# optional GL backend, not eframe's renderer.
#
# So this is housekeeping with a real point: naming the backend means eframe's release
# notes cannot move this GUI's renderer, and the tree states what it renders with instead
# of inheriting it. `accesskit` stays because nornir-robotui drives this GUI through it
# (it is also a default, so dropping defaults would have silently removed it).
# Enforced by ../server/ui/tests/law4_no_opengl_backend.rs.
eframe = { version = "0.36", default-features = false, features = ["default_fonts", "wgpu", "wayland", "x11", "accesskit"], optional = true }
egui = { version = "0.36", optional = true }
ron = "0.12"
tempfile = "3"
reqwest = { version = "0.13", features = ["rustls-no-provider"], default-features = false }
# reqwest 0.13 has no bundled roots and its `rustls` feature means aws-lc-rs (C) + the
# OS trust store; ring + the Mozilla bundle keep 0.12 `rustls-tls` behaviour (see the
# `tls_roots` helpers). 2026-10-02.
rustls = { version = "0.23", default-features = false, features = ["ring", "std"] }
webpki-root-certs = { version = "1" }

# nordisk house pattern: the mannequin GUI draws through facett components. The
# system map is a facett `SystemChart`, the per-node event log a facett `Table`.
# The GUI adopts the unified `facett_core::look::Theme` + `apply()` (one preset
# per frame → derived legacy palette → coherent re-theme, COH-1).
#
# These are PATH deps to the sibling facett checkout, exactly as `server/ui` uses
# (`path` + `version`, so they still publish). They used to resolve from crates.io,
# which was fine while the GUI drew only components — but the shell now adopts
# `facett_app::scene`, and facett-app depends on facett-core BY PATH. A registry
# facett-core beside a path facett-core is two copies of the same crate in one
# binary (two `Facet` traits, two look registries): the duplication L5 exists to
# stop. One checkout, one facett.
facett-core = { version = "0.2.0", optional = true }
facett-syschart = { version = "0.2.0", optional = true }
facett-table = { version = "0.2.0", optional = true }
# facett-app `scene` — the SHARED declarative pane/scene host (L5 — ADOPTION). The
# mannequin shell is a master/detail app (pick a system on the map → read ITS event
# log) and is now described as one, so it gets the same draggable divider and the
# same per-pane window chrome (fold · minimise · maximise) as holger-server-ui's shell.
facett-app = { version = "0.2.0", optional = true }

# Robot-UI — the SHARED nornir-robotui drive/observe/replay framework (edda leaf,
# resolved workspace-wide via `[patch.crates-io]` to ../edda). The mannequin GUI
# adopts it for a CHOOSABLE robot: `robot` (headless egui_kittest → CI matrix) OR
# `robot --watch` (a real on-screen eframe window replaying the SAME scenario). The
# `watch` feature pulls the visible eframe replayer; the default headless path needs
# no extra feature. See `src/robot.rs`.
nornir-robotui = { version = "0.4.1", features = ["watch"], optional = true }

[dev-dependencies]
traits = { package = "holger-traits", path = "../traits", features = ["test-support"] }
# The headless render harness for the shell's robot cells: `egui_kittest` drives a
# REAL egui frame, so a test can press the master/detail divider and the chrome
# controls with a real pointer / AccessKit click and assert the resulting RECTS.
# Test-only; the shipped mannequin links no kittest.
egui_kittest = { version = "0.36", features = ["snapshot"] }

[features]
# The egui/facett/wgpu GUI and its robot. Off by default: agent/cli dev-depends on
# mannequin only for the mock PKI, OIDC and Nexus, so the daemon builds headless.
gui = ["dep:eframe", "dep:egui", "dep:facett-core", "dep:facett-syschart", "dep:facett-table", "dep:facett-app", "dep:nornir-robotui"]

# Feature-gated test targets: cargo skips them unless the features are on,
# instead of linking an empty binary. The gate's arms (.nornir/testmatrix-arms.json)
# turn them on; the silenced-tests guard reads `required-features`.
[[test]]
name = "facet_reaction_matrix"
required-features = ["gui"]

[[test]]
name = "gui_robot"
required-features = ["gui"]

[[test]]
name = "look_preset_robot"
required-features = ["gui"]

[[test]]
name = "robot_shell"
required-features = ["gui"]