//! **About surface** — modgunn's identity card in the constellation-wide COMMON
//! FRAMEWORK (the JetBrains-style shared shell every suite app carries: an *About*,
//! a *Tools* menu, and a shared *lifecycle*). This is the always-compiled half:
//! pure identity data (name / version / role / tagline / engines), so even the lean
//! `scan` build — and holger / static-holger, which link modgunn's lib — can answer
//! `modgunn about` with **no** heavy dependency (the shared model is serde-only).
//!
//! **Shared-component note (L5 — DRY, RECONCILED).** modgunn used to carry its OWN
//! `struct Identity` here; that stale "no shared About component yet" note is gone.
//! The identity **model** now lives ONCE in the [`nornir_appshell::Identity`] edda
//! leaf (name / display_name / version / tagline / subtitle / logo / repository /
//! links / framework / engines + a `state_json` oracle), and modgunn CONSUMES it:
//! [`identity`] builds a `nornir_appshell::Identity`, so the shared **`facett-about`**
//! egui card — which renders exactly that model — paints modgunn's About unchanged
//! (korp / holger feed the SAME shape). modgunn keeps only its identity DATA here
//! and consumes the shared Tools (jera) + lifecycle (skidbladnir) surfaces too (see
//! [`crate::tools`] / [`crate::service`]).
use nornir_appshell::Identity;
/// modgunn's identity card as the shared [`nornir_appshell::Identity`] — the data an
/// About surface (CLI `modgunn about`, or the shared `facett-about` egui card)
/// renders. `version` tracks the crate version automatically.
///
/// `subtitle` carries modgunn's one-line **role** (the gatekeeper); `engines` lists
/// the two sharply-split engines it ships; `framework` names the shared components it
/// is built on (the reuse story). No logo bytes are embedded — the `facett-about`
/// renderer falls back to the text identity, never a panic.
pub fn identity() -> Identity {
Identity {
// modgunn's one-line role in the constellation (was the bespoke `role` field).
subtitle: "the nordisk security + SCIP world-delta gatekeeper (Gjallarbrú)".to_string(),
repository: "ssh://git@git.gunnar.rs:2222/mikronova/modgunn.git".to_string(),
// The two sharply-split engines modgunn ships.
engines: vec![
"Engine A — artifact security VERDICT (scan: multi-ecosystem CVE / license / provenance)".to_string(),
"Engine B — SCIP whole-world dep-tree BEHAVIOUR-DELTA (scip: tripwires / graph-algs / anomaly)".to_string(),
],
// The shared framework modgunn is BUILT ON (LAW #5 reuse, shown on the card).
framework: vec![
"nornir-appshell — the shared About / Tools app-shell models".to_string(),
"jera — the shared job ledger + no-shell container runtime".to_string(),
"skidbladnir — the shared service lifecycle (one systemd renderer)".to_string(),
],
..Identity::new(
"modgunn",
"Móðguðr",
// `<semver> (<git-hash>)` — the SAME string `modgunn --version` prints and
// the ONE source of truth for which build this is (build-version-githash-law).
crate::version_with_hash(),
"Guards the bridge: scrutinizes what passes (CVE / license / provenance \
verdict) and tracks every change in the dependency world.",
)
}
}
/// The About surface's headless oracle: the identity as JSON — what `modgunn about
/// --json` prints and a robot asserts (name · version · role · engines present).
/// A thin passthrough to [`Identity::state_json`] (the shared oracle every suite
/// About surface asserts); `open` is `true` for the CLI (the card is "showing").
pub fn state_json() -> serde_json::Value {
identity().state_json(true)
}
#[cfg(test)]
mod tests {
use super::*;
/// **RED-when-broken: the About surface carries modgunn's real identity, on the
/// SHARED model.** The identity names modgunn / Móðguðr, tracks the crate version
/// (never blank), states the gatekeeper role (as `subtitle`), and lists BOTH
/// engines (A verdict + B world-delta). If the About lost its identity (blank
/// name/version, or an engine dropped), this is red — the surface a `modgunn
/// about` robot asserts, and the shape `facett-about` renders.
#[test]
fn identity_carries_name_version_and_both_engines() {
let id = identity();
assert_eq!(id.name, "modgunn");
assert_eq!(id.display_name, "Móðguðr");
assert!(
!id.version.is_empty(),
"version is stamped from CARGO_PKG_VERSION"
);
// The version carries BOTH the semver and the git-hash (build-version-githash-law),
// in the suite shape `<semver> (<hash>)` — the same string `modgunn --version` prints.
assert!(
id.version.starts_with(env!("CARGO_PKG_VERSION")),
"version starts with the crate semver: {}",
id.version
);
assert!(
id.version.contains(env!("MODGUNN_GIT_HASH")),
"version carries the git-hash stamp: {}",
id.version
);
assert!(
id.subtitle.contains("gatekeeper"),
"the role names the gatekeeper: {}",
id.subtitle
);
assert_eq!(id.engines.len(), 2, "both Engine A + Engine B are listed");
assert!(id.engines[0].contains("Engine A"));
assert!(id.engines[1].contains("Engine B"));
// The reuse story is shown: the shared framework modgunn is built on.
assert!(
!id.framework.is_empty(),
"About names the shared framework it consumes"
);
crate::functional_status(
"modgunn/about",
"identity_name_version_engines",
id.name == "modgunn" && !id.version.is_empty() && id.engines.len() == 2,
"the About surface carries modgunn's identity on nornir_appshell::Identity: name + version + both engines",
);
}
/// The `state_json` oracle mirrors the identity — the exact surface `modgunn about`
/// dumps and an out-of-crate CLI robot asserts. It is the shared
/// [`Identity::state_json`], so `wordmark` (korp/holger key) and `display_name`
/// (modgunn key) both resolve to Móðguðr.
#[test]
fn state_json_mirrors_identity() {
let js = state_json();
assert_eq!(js["name"], "modgunn");
let jver = js["version"].as_str().unwrap_or_default();
assert!(
jver.starts_with(env!("CARGO_PKG_VERSION")) && jver.contains(env!("MODGUNN_GIT_HASH")),
"state_json version carries semver + git-hash: {jver}"
);
assert_eq!(js["engines"].as_array().unwrap().len(), 2);
assert_eq!(js["display_name"], "Móðguðr");
assert_eq!(
js["wordmark"], "Móðguðr",
"the shared oracle carries both keys"
);
assert_eq!(
js["open"],
serde_json::json!(true),
"the CLI card is showing"
);
}
/// The identity round-trips through serde as the shared model — the oracle a CLI
/// dumps can be read back into an owned `nornir_appshell::Identity` out of process.
#[test]
fn identity_round_trips_as_shared_model() {
let id = identity();
let s = serde_json::to_string(&id).unwrap();
let back: Identity = serde_json::from_str(&s).unwrap();
assert_eq!(id, back, "modgunn's Identity survives a serde round-trip");
}
}