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

nordisk/holger

holger-recipe/src/rules.rs

//! # The rules the declaration cannot carry
//!
//! Moved here from edda's `nornir-buildspec-holger` (2026-09-16). The variants come
//! from [`crate::declared`]; what stays code in THIS module is the part that cannot
//! travel as data: the airgap and thin-client rules behind [`validate`] and
//! [`judge_artifact`], which [`crate::HolgerBuildThing`]'s `impl BuildThing`
//! delegates to.
//!
//! **Why they had to move.** Until today these lived only in edda, so holger's own
//! wasm module answered `judge_artifact` with the TRAIT DEFAULT — *"this build thing
//! declares no artifact-level invariant"*, an OK verdict for every artifact. A forge
//! loading holger's module instead of edda's would have passed a `mini` linking
//! reqwest. The keystone belongs in the repo whose artifacts it judges.
//!
//! ## History: three writers, three copies, one now
//!
//! This crate once declared the variants by hand beside holger's TOML, and a second
//! writer drifts — it did three times (the unbuilt `gui` bin, the unseen sixth
//! variant, the `henriks-*` → `ui-*` rename that left its cargo argv unbuildable). It
//! then switched to `include_str!` of a byte copy of the TOML, held by a drift test,
//! while `holger-build-space` kept a second copy. Now the Rust recipe is the only
//! writer and the TOML is its emission, so neither failure is expressible.
//! [`HolgerBuildThing::roles`] is still not overridden: the default groups on the
//! declaration's own `(suite, role)`.
//!
//! ## The airgap rule, and why it is not a table
//!
//! What is **not** data is the rule that gives the products their meaning:
//!
//! > the airgap rows ([`AIRGAP_TIERS`]) must link **no outbound HTTP client**.
//!
//! No field in any schema expresses that. It is a predicate over a built artifact's
//! dependency closure, and only holger knows which rows it applies to: the four
//! products by default, and the static appliance. It lives in
//! [`HolgerBuildThing::judge_artifact`], it runs inside the forge's wasm sandbox, and it
//! is the reason this crate is code. It discriminates: the metered rows link the box's
//! own advisory fetch (an HTTP client), and `--features online` (or `full`) adds one to
//! any product.

//! ## The CLIENT ladder left with the clients (2026-09-16)
//!
//! The four egui rungs and every rule about them — the thin-UI ladder, the
//! read-only client tiers, the panes that link an HTTP client, the engine crates a
//! thin client may not carry — moved to `holger-egui` with `server/ui` itself.
//! They are not kept here in weakened form: a rule naming a variant this repo no
//! longer declares fails OPEN (`links_no_http_client` simply answers `false` and
//! every artifact sails through un-judged), which is the exact defect
//! `every_rule_names_a_declared_variant` exists to catch. What stays is the
//! SERVER-side keystone.
//!
//! ## One definition, two link targets
//!
//! These functions are plain Rust in a plain rlib. `holger-build-thing` is the
//! `cdylib` shim that exports the plugin ABI over the same
//! [`crate::HolgerBuildThing`], so the wasm module the forge loads cannot answer
//! anything the native doors would not.

use nornir_build_thing::plugin::{
    host, ArtifactFacts, BuildPlan, BuildRequest, PlanStep, RebuildRecipe, Role, Verdict,
};
use nornir_build_thing::variant::{BuildVariant, BuildVariantSet, ServiceShape};

/// holger's git remote, for the pull → rebuild → compare loop.
pub const REMOTE: &str = "ssh://git@git.gunnar.rs:2222/nordisk/holger.git";

/// The UI client's package (`server/ui`), whose bins carry `required-features`.
/// **Every Rust outbound-HTTP client an airgap tier is forbidden to link.**
///
/// `reqwest`/`ureq` are holger's actual egress paths (the OIDC `/userinfo` + `jwks_uri`
/// fetch, the `bench` driver, the `rust-remote` pull-through upstream). The rest are
/// the other well-known Rust HTTP clients, denied so a FUTURE re-introduction of
/// egress through a *different* client is caught too — the guarantee must not hinge on
/// the one crate name holger happens to use today.
///
/// `hyper`/`tonic`/`h2` are deliberately ABSENT: they are the INBOUND serve stack,
/// which every tier legitimately links. A denylist that fails a server for being a
/// server would be turned off within a week.
pub const FORBIDDEN_OUTBOUND_CLIENTS: &[&str] = &[
    "reqwest",
    "ureq",
    "isahc",
    "curl",
    "surf",
    "attohttpc",
    "awc",
    "http-client",
];

/// **The TLS backends no holger artifact may link, on ANY variant.**
///
/// Separate from [`FORBIDDEN_OUTBOUND_CLIENTS`] because it is a different
/// question with a different scope. An HTTP client is forbidden only where
/// egress is forbidden — `full` links one BY DESIGN and is refused when it does
/// not. A native TLS stack is forbidden EVERYWHERE, `full` included, and
/// holger's own declaration already says so in as many words
/// (`build-space/tests/auth_ship_small.rs:21`: *"`full` included: every tier
/// MUST link NEITHER the crate NOR openssl"*). holger is rustls, end to end.
///
/// ⚠ **This list exists because its absence is what let OpenSSL in.** The
/// third measured feature leak was `auth-oidc`/`auth-oauth2` dragging the
/// native stack into `server-local` — and `server-local` is neither an airgap
/// tier nor the federating tier, so [`judge_artifact`] fell through to a bare
/// `Verdict::ok()` and **never judged it at all**. Naming the clients without
/// naming the backends judged the wrong noun: the leak arrived as a TLS
/// backend, underneath a client that was allowed to be there.
///
/// The pre-existing assertion of this rule lives in `build-space`, which shells
/// `cargo tree` and therefore SKIPS SILENTLY where cargo is absent. This one is
/// a predicate over a closure the host supplies, so it cannot be vacuous.
pub const FORBIDDEN_TLS_BACKENDS: &[&str] = &[
    "openssl",
    "openssl-sys",
    "native-tls",
    "tokio-native-tls",
    "hyper-tls",
];

/// The rows that must be provably unable to phone home: the four products with their
/// defaults and the static appliance. A request naming no row is judged by its features:
/// [`AIRGAP_FEATURES`].
pub const AIRGAP_TIERS: &[&str] = &[
    "holger",
    "holger-downstream",
    "holger-ui",
    "holger-cli",
    "mvp-server-musl",
];

/// An ad-hoc feature list (no row named) is judged as airgap when it names one of these:
/// the appliance marker or the downstream gateway.
pub const AIRGAP_FEATURES: &[&str] = &["mvp-server", "downstream"];

/// **holger's declared build space** — [`crate::declared`].
///
/// Pure: no filesystem and no clock, so it works unchanged inside the wasm sandbox.
/// Rebuilt on every call rather than cached in a `static` — a plugin is asked a
/// handful of questions per load, and a lazily-initialised global would need a lock
/// the sandbox does not want.
pub fn build_variants() -> BuildVariantSet {
    crate::declared()
}

/// holger's SERVER variants, in declaration order — READ off the declaration's
/// `role` key rather than restated here.
pub fn server_variants() -> Vec<String> {
    variants_in_role(Role::Server)
}

/// holger's CLIENT variants, in declaration order — the UI ladder, the two agent
/// tiers and the Secure Update Gateway CLIs.
pub fn client_variants() -> Vec<String> {
    variants_in_role(Role::Client)
}

fn variants_in_role(role: Role) -> Vec<String> {
    build_variants()
        .variants
        .iter()
        .filter(|v| v.role == Some(role))
        .map(|v| v.name.clone())
        .collect()
}

/// The fat/thin SERVICE-SHAPE of a variant — the linkage axis, orthogonal to the
/// role and to the tier.
///
/// **This used to be a `match` on variant names**, which is how it came to disagree
/// with holger's own file: the function said `full` was fat BECAUSE it embedded
/// skade and `mini` was thin BECAUSE it reached a remote skade, and an audit of the
/// real Cargo graph proved both false — **no holger server tier depends on skade in
/// any direction**. It now returns what holger declares, so the disagreement is not
/// expressible.
///
/// An undeclared variant answers [`ServiceShape::FatService`], which is the schema's
/// own default for an omitted `linkage` key.
pub fn shape_of(variant: &str) -> ServiceShape {
    build_variants()
        .get(variant)
        .map(|v| v.shape)
        .unwrap_or(ServiceShape::FatService)
}

/// True when `variant` is one of the airgap SERVER tiers — the ones that must be
/// provably unable to phone home at all.
pub fn is_airgap(variant: &str) -> bool {
    AIRGAP_TIERS.contains(&variant)
}

/// True when `variant` must link **no outbound HTTP client**.
///
/// ⚠ This used to be `is_airgap(variant) || is_read_only_client(variant)`. The
/// read-only CLIENT half went to holger-egui with the rungs it judged (2026-09-16);
/// holger's own `agent` tiers are deliberately NOT here — an agent migrates from
/// Nexus, so applying the rule to them would only teach people to turn it off.
pub fn links_no_http_client(variant: &str) -> bool {
    is_airgap(variant)
}

// ⚠ `roles()` IS DELIBERATELY NOT OVERRIDDEN, and that is a fix, not an omission.
//
// It used to be two hand-written `RoleGroup` literals: `Role::Server` over a
// `SERVER_VARIANTS` const, `Role::Client` over a `CLIENT_VARIANTS` const, each
// with a hard-coded `default_variant` and a hard-coded `suite: None`. Three
// separate things could drift from holger's file, and all three had:
//
//   * the variant lists were 8 names against holger's 13, two of them renamed
//     out of existence;
//   * the defaults were restated here instead of read from `default = true`;
//   * `suite: None` asserted "holger ships ONE delivery" while its TOML already
//     carries an MVP tier (`mvp-server` · `mvp-bundle` · `mvp-verify`). The
//     moment holger writes `suites = ["mvp"]` on those, the derived menu grows a
//     second server section with its own normal case — the exact bug the suite
//     axis was added to remove — whereas a frozen `None` would flatten the two
//     deliveries into one section and force them to share a default.
//
// The default implementation groups on `(suite, role)` via
// `BuildVariantSet::groups`, the SAME writer `check_defaults` uses, so the menu
// and the guard cannot disagree about what a section is. What it costs is the
// prose summary per section; what it buys is that none of the above is
// expressible.

/// The plan for a tier, as DATA. holger adds nothing to the default cargo step for
/// its clients; for a SERVER tier it appends the closure resolve the airgap rule
/// needs, so the forge gathers the evidence [`judge_artifact`] will be asked about
/// rather than the plugin trying (and failing) to gather it itself.
pub fn plan(variant: &str) -> Option<BuildPlan> {
    let set = crate::declared();
    let v = set.get(variant)?;
    // A POINTER variant (`kind = "container"` / `"installer"` / `"iso"`) carries
    // no cargo argv of its own: `cargo_args()` on it evaluates to the single token
    // `build`, and a plan made of that is a bare debug build of the whole
    // workspace wearing the appliance's name — holger's `brokkr.toml` measured
    // exactly that green on 2026-08-25. These are built by the forge's assembler
    // (`nornir_build_thing::assemble`, from the `[[build.container]]` /
    // `[[build.installer]]` / `[[build.iso]]` row of the same name), so the plan
    // says so and plans NO cargo step rather than a wrong one. Kind-generic on
    // purpose: `holger-appliance-iso` (2026-09-17) needed no change here.
    if !v.kind.is_cargo() {
        host::log(&format!(
            "holger: '{variant}' is a {} pointer variant — no cargo step planned",
            v.kind.as_str()
        ));
        return Some(BuildPlan {
            variant: variant.to_string(),
            steps: Vec::new(),
            env: Vec::new(),
            expected_artifacts: Vec::new(),
            rationale: Some(format!(
                "'{variant}' is a `{kind}` pointer variant: the forge's {kind} builder \
                     assembles it from the [[build.{kind}]] row of the same name, not a cargo \
                     invocation — a cargo step here would be a bare `cargo build` wearing the \
                     appliance's name",
                kind = v.kind.as_str()
            )),
        });
    }
    let mut plan = BuildPlan {
        variant: variant.to_string(),
        steps: vec![PlanStep {
            name: format!("build-{variant}"),
            program: "cargo".to_string(),
            args: v.cargo_args(),
            env: Vec::new(),
        }],
        env: Vec::new(),
        expected_artifacts: v
            .bin
            .as_ref()
            .map(|b| vec![format!("target/release/{b}")])
            .unwrap_or_default(),
        rationale: None,
    };
    if links_no_http_client(variant) {
        let mut args = vec![
            "tree".to_string(),
            "-e".to_string(),
            "no-dev".to_string(),
            "-p".to_string(),
            v.package.clone().unwrap_or_default(),
            "--features".to_string(),
            v.features.join(","),
        ];
        if v.no_default_features {
            args.push("--no-default-features".to_string());
        }
        plan.steps.push(PlanStep {
            name: format!("egress-closure-{variant}"),
            program: "cargo".to_string(),
            args,
            env: Vec::new(),
        });
        plan.rationale = Some(if is_airgap(variant) {
            format!(
                "'{variant}' is an airgap tier: the build is followed by a \
                     dependency-closure resolve so the zero-egress claim can be CHECKED \
                     rather than asserted"
            )
        } else {
            format!(
                "'{variant}' is a read-only client tier: the build is followed by a \
                     dependency-closure resolve so the no-HTTP-client claim can be CHECKED \
                     rather than asserted"
            )
        });
    } else {
        plan.rationale = Some(format!("'{variant}' materializes to one cargo invocation"));
    }
    host::log(&format!(
        "holger: planned {} step(s) for '{variant}'",
        plan.steps.len()
    ));
    Some(plan)
}

/// The generic rules, plus the one only holger knows: **a no-egress tier may not
/// request a feature that links an HTTP client.** `served` drives HTTP, and
/// `gui`/`signin`/`tools`/`demo` each pull reqwest (and `tools` also pulls skade);
/// none belongs in a red-zone binary, and the generic validator has no way to know
/// that — `offers` lists them all as legitimate features.
pub fn validate(req: &BuildRequest) -> Verdict {
    let set = crate::declared();

    // Start from the declared rules (offers / exclusive / required-features /
    // the fat-thin asymmetry) — no reason to re-derive what the set already knows.
    let base = match &req.variant {
        Some(name) => match set.get(name) {
            None => {
                return Verdict::refuse(format!(
                    "no variant '{name}'; holger declares: {}",
                    set.names().join(", ")
                ))
            }
            Some(v) => match set.validate(v) {
                Ok(()) => Verdict::ok(),
                Err(e) => Verdict::refuse(e.to_string()),
            },
        },
        None => {
            let probe = BuildVariant {
                name: "<ad-hoc>".to_string(),
                features: req.features.clone(),
                target: req.target.clone(),
                ..Default::default()
            };
            match set.validate(&probe) {
                Ok(()) => Verdict::ok(),
                Err(e) => Verdict::refuse(e.to_string()),
            }
        }
    };

    // The features actually in play for this request.
    let features: Vec<String> = match &req.variant {
        Some(name) => set
            .get(name)
            .map(|v| v.features.clone())
            .unwrap_or_default(),
        None => req.features.clone(),
    };
    let named = req.variant.as_deref();
    let no_egress = named.map(links_no_http_client).unwrap_or_else(|| {
        AIRGAP_FEATURES
            .iter()
            .any(|t| features.iter().any(|f| f == t))
    });
    if !no_egress {
        return base;
    }
    // holger's own rule: `served` drives HTTP and has no business in a red-zone
    // binary, and the generic validator cannot know that — `offers` lists it as a
    // legitimate feature. The UI pane half of this rule (`gui`/`signin`/`tools`/
    // `demo` in a read-only client) went to holger-egui with the rungs it judged.
    //
    // The tier names in the message are JOINED from the rule list, not typed out:
    // the sentence used to name `henriks-mini-holger`/`henriks-mikro-holger` and
    // went on naming them for a week after holger renamed both.
    let no_egress_tiers = AIRGAP_TIERS.join("`/`");
    let mut v = base;
    if features.iter().any(|f| f == "served") {
        v = v.and(Verdict::refuse(format!(
            "a no-egress tier may not enable 'served': it links an outbound HTTP path, \
                 and `{no_egress_tiers}` exist precisely to be provably unable to reach \
                 the network"
        )));
    }
    if v.ok {
        v = Verdict::ok_with(
            "airgap tier — the built artifact must link no outbound HTTP client \
                 (checked by judge_artifact against the real dependency closure)",
        );
    }
    v
}

/// **The airgap keystone, applied to a BUILT artifact.** The host resolves the
/// dependency closure (`cargo tree`, or by reading a pulled artifact) and hands
/// the crate names over; holger decides what they mean.
///
/// This is the check that cannot travel as data: which variants it applies to,
/// which crates count as egress, and why `hyper` does not — all holger's.
pub fn judge_artifact(facts: &ArtifactFacts) -> Verdict {
    let Some(variant) = facts.variant.as_deref() else {
        return Verdict::refuse("cannot judge an artifact that does not say which variant it is");
    };
    if facts.linked_crates.is_empty() {
        return Verdict::refuse(format!(
            "no dependency closure supplied for '{variant}' — an UNMEASURED zero-egress \
                 claim is not a zero-egress claim"
        ));
    }
    let linked: Vec<&str> = FORBIDDEN_OUTBOUND_CLIENTS
        .iter()
        .copied()
        .filter(|c| facts.linked_crates.iter().any(|l| l == c))
        .collect();

    // ── The TLS backend, judged FIRST and on EVERY variant ──────────────
    //
    // Before the airgap/federating split, because this rule has no tiers:
    // holger is rustls end to end and a native stack is wrong in `full` for
    // exactly the reason it is wrong in `mini`. Judging it first also means
    // the refusal names the real problem — "this links openssl-sys" —
    // rather than a downstream symptom, or (as before) nothing at all.
    let tls: Vec<&str> = FORBIDDEN_TLS_BACKENDS
        .iter()
        .copied()
        .filter(|c| facts.linked_crates.iter().any(|l| l == c))
        .collect();
    if !tls.is_empty() {
        return Verdict::refuse(format!(
            "'{variant}' links native TLS backend(s): {} — holger is rustls end to end, \
                 on EVERY variant. This is the shape all three measured feature leaks had, \
                 and it is refused whatever else is true of this artifact.",
            tls.join(", ")
        ));
    }

    // The THIN-UI half of this judgement (a client that links the storage engine
    // is a second writer on the warehouse lock) went to holger-egui with the
    // rungs it judged, 2026-09-16.
    if links_no_http_client(variant) {
        if linked.is_empty() {
            return Verdict::ok_with(format!(
                "'{variant}' is an airgap tier and links NO outbound HTTP client — it \
                     provably cannot phone home"
            ));
        }
        return Verdict::refuse(format!(
            "'{variant}' is an airgap tier but links outbound HTTP client(s): {}. \
                 This artifact must not be promoted.",
            linked.join(", ")
        ));
    }
    // Not an airgap row (the metered builds, the front, the media) — still JUDGED:
    // the TLS rule above has run, and the verdict says what was looked at.
    Verdict::ok_with(if linked.is_empty() {
        format!("'{variant}' is not an airgap row, and links no outbound HTTP client and no native TLS backend")
    } else {
        format!(
                "'{variant}' is not an airgap row, so its outbound HTTP client(s) ({}) are not \
                 constrained — it links no native TLS backend, which is the rule that does apply here",
                linked.join(", ")
            )
    })
}

pub fn rebuild_recipe(variant: &str) -> Option<RebuildRecipe> {
    let set = crate::declared();
    let v = set.get(variant)?;
    Some(RebuildRecipe {
        repo: crate::REPO.to_string(),
        remote: Some(REMOTE.to_string()),
        rev: None,
        variant: variant.to_string(),
        cargo_args: v.cargo_args(),
        toolchain: None,
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    /// ★ **The keep media the ONE shop upgrades a sold Holger from** (monetize lane L7,
    /// `lifecycle::Holger`: main and twin keep-booted from `holger-keep`, the front from
    /// `holger-front-keep`): the metered media, composed to upgrade in place — the disk's data
    /// kept, the box powered off after INSTALL-OK for the shop to boot it from its disk.
    #[test]
    fn the_keep_media_are_the_metered_media_upgrading_in_place() {
        let set = crate::declared();
        for (keep, from) in [
            ("holger-keep", "holger-installer-metered"),
            ("holger-front-keep", "holger-front-installer-metered"),
        ] {
            let k = set
                .installers
                .iter()
                .find(|i| i.name == keep)
                .unwrap_or_else(|| panic!("no {keep} row"));
            let f = set.installers.iter().find(|i| i.name == from).unwrap();
            assert_eq!(
                (k.variant.as_str(), k.installer_variant.as_str()),
                (f.variant.as_str(), f.installer_variant.as_str()),
                "{keep} lays what {from} lays"
            );
            assert_ne!(
                k.volume_id, f.volume_id,
                "{keep} is resolved by its own volume id"
            );
            for p in ["korp.reinstall=keep", "korp.install.then=poweroff"] {
                assert!(
                    k.boot_params.iter().any(|b| b == p),
                    "{keep} boots with {p}: {:?}",
                    k.boot_params
                );
            }
            assert_eq!(
                set.get(keep).expect("its pointer variant").kind,
                ArtifactKind::Installer
            );
        }
    }
    // The delegation is what these exercise: every call below goes through the trait
    // on the type the wasm shim exports, not through the free functions directly.
    use crate::HolgerBuildThing;
    use nornir_build_thing::plugin::BuildThing;
    use nornir_build_thing::plugin::Ecosystem;
    use nornir_build_thing::variant::ArtifactKind;

    /// The embedded declaration parses, and the `expect` in [`build_variants`] can
    /// therefore never fire in a forge. Also the floor under every other test here:
    /// a set of zero variants would make most of them vacuously true.
    #[test]
    fn the_declaration_parses_and_is_not_empty() {
        let set = build_variants();
        assert!(
            set.variants.len() >= 8,
            "holger declared {} variant(s) — a shrunk declaration makes every roster \
             assertion below vacuous",
            set.variants.len()
        );
        assert!(
            !set.offers.is_empty(),
            "the feature universe must be declared"
        );
    }

    /// **The bijection laws** (Rickard 2026-08-26: *"det måste vara i traitsen"*)
    /// — conformance to `nornir_build_thing::laws` is part of the `BuildThing`
    /// contract, and this is holger's call: declaration ↔ struct, menu ↔
    /// declaration, option row ↔ CLI flag, decision ↔ fragment, receipt →
    /// recipe, each failure naming the law and the inverse that broke.
    #[test]
    fn the_build_thing_obeys_the_bijection_laws() {
        nornir_build_thing::laws::assert_bijective(&HolgerBuildThing);
    }

    /// **holger's real roster, read off its own file.** The names, their roles and
    /// their bins are asserted as literals HERE on purpose: this is the one place
    /// that says out loud what the mirror currently contains, so a re-copy that
    /// brings a rename lands as a reviewable diff instead of a silent behaviour
    /// change. It is NOT the source — `tests/no_drift_from_holgers_declaration.rs`
    /// holds the mirror against holger's tree.
    #[test]
    fn the_declared_builds_are_holgers_real_ones() {
        let set = build_variants();
        assert_eq!(
            set.names(),
            vec![
                // the four products (HOL-PRODUCTS, 2026-10-30): each its `cargo install` line
                "holger",
                "holger-downstream",
                "holger-cli",
                "holger-ui",
                // the estate's server builds: the static appliance, the sold ones, the DEV row
                "mvp-server-musl",
                "mvp-server-metered",
                "mvp-server-musl-metered",
                "mvp-server-musl-metered-narrate",
                // the media's pointer rows: no cargo argv, each the tagged variant its
                // packaging row is payload FOR
                "holger-mvp-appliance",
                "holger-installer",
                "holger-installer-metered",
                "holger-appliance-iso",
                // role = library — holger's own signed wasm guests
                "plugin-allocation",
                "plugin-skidbladnir",
                "plugin-rust-toolchain",
                // vm1: holger's OWN front program and its medium
                "estate-front-musl-metered",
                "estate-front-musl-metered-narrate",
                "holger-front-installer-metered",
                // the keep media's pointers: the ONE shop's in-place upgrade
                "holger-keep",
                "holger-front-keep",
                // a downstream's payloads and media: the one-way and the fetching one
                "downstream-musl",
                "holger-downstream-oneway-installer",
                "downstream-fetch-musl",
                "holger-downstream-installer",
            ]
        );
        assert_eq!(
            server_variants().len(),
            19,
            "the server and the downstream, the four estate server builds, the four media pointers, \
             the front's payload, its DEV row and its medium, the two keep media, and a downstream's \
             two payloads and media (one-way, fetching)"
        );
        assert_eq!(
            client_variants().len(),
            2,
            "the command-line tool and the console"
        );

        // ── the two pointer variants, and the rows they point at ────────────────
        // These are what the mirror LACKED for 13 days (edda 3068cf0 → holger
        // a9ad3bf/9c1d3c9): the drift guard names a missing variant, but only an
        // assertion BY NAME proves the mirror carries the settings under the row —
        // two equally empty files would pass parity.
        let appliance = set.get("holger-mvp-appliance").unwrap();
        assert_eq!(appliance.kind, ArtifactKind::Container);
        assert_eq!(
            appliance.container_ref.as_deref(),
            Some("holger-mvp-appliance")
        );
        assert!(
            appliance.bin.is_none() && appliance.package.is_none(),
            "a pointer carries no cargo argv"
        );
        assert!(
            set.containers
                .iter()
                .any(|c| c.name == "holger-mvp-appliance"),
            "the [[build.container]] row the pointer resolves to is declared"
        );
        let installer_ptr = set.get("holger-installer").unwrap();
        assert_eq!(installer_ptr.kind, ArtifactKind::Installer);
        let installer = set
            .installers
            .iter()
            .find(|i| i.name == "holger-installer")
            .expect("the [[build.installer]] row of the same name");
        assert_eq!(
            installer.variant, "mvp-server-musl",
            "the installer lays down the static musl tier"
        );
        // The SETTINGS on the installer row: the SEVEN per-site params, the declared
        // fixture for the hub, and the env the metal appliance boots with.
        //
        // `data_disks` and `reinstall` joined on 2026-09-17 — the two measured
        // re-image failures private-holger-ops' REIMAGE_WARNING names, answered on
        // the declaration rather than at a boot prompt on a machine with no shell.
        // estate.toml already claimed the first of them existed; it did not.
        let params: Vec<&str> = installer.params.iter().map(|p| p.name.as_str()).collect();
        // `pairing_seed` joined on 2026-09-27 (owner plan 2a): the estate's
        // nordisk-pairing seed, a STAGED FILE and never a boot param.
        // `install_then` joined the same day: gunnar's blank-disk lay reboots into the
        // laid disk instead of installing again (`korp.install.then`).
        assert_eq!(
            params,
            [
                "site",
                "hub_conf",
                "holger_ron",
                "plugin_trust_root",
                "intel_trust_policy",
                "bundles_trust_policy",
                "underlay",
                "data_disks",
                "pairing_seed",
                "reinstall",
                "install_then",
                "live_app"
            ]
        );
        assert_eq!(
            installer
                .params
                .iter()
                .find(|p| p.name == "install_then")
                .unwrap()
                .boot_param,
            "korp.install.then"
        );
        let metered = set
            .installers
            .iter()
            .find(|i| i.name == "holger-installer-metered")
            .expect("the metered row");
        assert!(
            metered.params.iter().any(|p| p.name == "install_then"),
            "the paid medium takes it too"
        );
        let seed = installer
            .params
            .iter()
            .find(|p| p.name == "pairing_seed")
            .unwrap();
        assert_eq!(
            (
                seed.staged_file.as_str(),
                seed.boot_param.as_str(),
                seed.required
            ),
            ("pairing/seed.toml", "", false),
            "the seed carries a key: never on the cmdline"
        );
        assert_eq!(
            installer
                .params
                .iter()
                .find(|p| p.name == "data_disks")
                .unwrap()
                .boot_param,
            "korp.data.disks",
            "THE BOOT DISK IS THE LARGER ONE — and this is how a site declares which is which"
        );
        assert_eq!(
            installer
                .params
                .iter()
                .find(|p| p.name == "reinstall")
                .unwrap()
                .boot_param,
            "korp.reinstall",
            "RE-IMAGE AND RE-MINT GO TOGETHER — absent reads as `keep`, which is the brick"
        );
        // The LIVE medium beside it: one row, the installer's own payload, and it
        // writes nothing — which is why neither failure above has a path through it.
        let live_ptr = set.get("holger-appliance-iso").unwrap();
        assert_eq!(live_ptr.kind, ArtifactKind::Iso);
        assert!(
            live_ptr.bin.is_none() && live_ptr.package.is_none(),
            "a pointer carries no cargo argv"
        );
        let live = set
            .isos
            .iter()
            .find(|i| i.name == "holger-appliance-iso")
            .expect("the [[build.iso]] row of the same name");
        assert_eq!(
            live.from_variant.as_deref(),
            Some(installer.variant.as_str()),
            "ONE payload, two media"
        );
        assert!(live.boot_params.iter().any(|t| t == "korp.mode=live"));
        assert!(
            installer
                .params
                .iter()
                .find(|p| p.name == "holger_ron")
                .unwrap()
                .required
        );
        // ★ THE DECLARATION RIDES THE RELEASE (lane B1). Seen red in R10: `holger.ron` and the
        // korp root were first-boot `/data` stages, a keep medium skips the stage by design, and
        // the installed main panicked on a `/data/holger.ron` that never came. Every installer
        // medium — the keep medium included — lays them with the app, signed with it.
        for set_installer in set
            .installers
            .iter()
            .filter(|i| i.params.iter().any(|p| p.name == "holger_ron"))
        {
            for name in [
                "holger_ron",
                "plugin_trust_root",
                "intel_trust_policy",
                "bundles_trust_policy",
            ] {
                let p = set_installer
                    .params
                    .iter()
                    .find(|p| p.name == name)
                    .unwrap_or_else(|| panic!("{}: {name}", set_installer.name));
                assert_eq!(
                    p.lands,
                    nornir_build_thing::params::Landing::Release,
                    "{}: {name} lands on the release",
                    set_installer.name
                );
            }
        }
        assert_eq!(
            installer
                .params
                .iter()
                .find(|p| p.name == "underlay")
                .unwrap()
                .boot_param,
            "korp.env.HOLGER_UNDERLAY"
        );
        assert_eq!(
            installer
                .fixtures
                .keys()
                .map(String::as_str)
                .collect::<Vec<_>>(),
            ["hub_conf"],
            "hub_conf declares the wg-hub fixture (holger 9c1d3c9)"
        );
        assert_eq!(
            installer.env.get("HOLGER_APPLIANCE").map(String::as_str),
            Some("1")
        );
        assert_eq!(installer.cmd, ["start", "--config", "/data/holger.ron"]);
        // ★ THE PAYLOAD MUST BE ABLE TO SERVE SOMETHING.
        //
        // MEASURED 2026-09-21, lane H2, by running the fleet proof: its helper
        // hand-spelled `--features mvp-server,appliance` — a SUBSET of this row —
        // and the appliance it installed died at first boot with
        //
        //     [holger-mvp-1] repository 'bundles' is `ron_repo_type: "raw"` but
        //     this server was built without the `fmt-raw` feature; the formats
        //     this binary serves are []
        //     Kernel panic - not syncing: Attempted to kill init!
        //
        // "boots but does not serve", inside the proof that exists to catch it,
        // and a panic because holger is PID 1 there. The helper now takes the
        // row's own `cargo_args()`; this is the other end — a payload row that
        // declares NO format is a medium that installs a server serving nothing,
        // whatever any RON on it says.
        let payload = set
            .get(installer.variant.as_str())
            .expect("the payload row");
        assert!(
            payload.features.iter().any(|f| f.starts_with("fmt-")),
            "the appliance payload '{}' declares no `fmt-*` feature, so it serves NO repository \
             type at all and every appliance installed from it dies at first boot with \
             holger-mvp-1: {:?}",
            payload.name,
            payload.features
        );
        assert!(
            installer.options.is_empty(),
            "holger declares NO installer features: underlay and hub_conf are runtime \
             presence checks in server/cli/src/appliance.rs, not compile-time branches"
        );

        // ★★ **THE TWIN IS A ROLE OF THIS MEDIUM, NOT A MEDIUM OF ITS OWN.**
        //
        // Owner ruling 2026-09-21: *"gunnar twin must be built EXACTLY like the
        // main, it MUST use the SAME iso !!!"* / *"DO not build a special gunnar
        // TWIN iso !"*, extended to holger in the same breath. gunnar's metered
        // appliance had an UN-METERED twin precisely because the twin had its own
        // row; promoted, it would have enforced nothing.
        //
        // TWO assertions, and the second is the one that makes the first safe.
        assert!(
            !set.installers.iter().any(|i| i.name.contains("twin"))
                && !set.isos.iter().any(|i| i.name.contains("twin"))
                && !set.variants.iter().any(|v| v.name.contains("twin")),
            "a twin MEDIUM was declared. The twin is `--param role=twin` on \
             holger-installer; a second row is gunnar's un-metered-twin scar, verbatim"
        );
        // ★ ONE ISO, NOT ONE ROW WITH TWO COMPOSES. A role parameter here would
        // mean mastering the medium twice, and "it MUST use the SAME iso" is not
        // satisfied by two ISOs off one row. The role is conferred AFTER install,
        // over the control plane, by `AdminService.BecomeTwin`.
        assert!(
            !installer
                .params
                .iter()
                .any(|p| p.name == "role" || p.name == "primary"),
            "the medium declares a role parameter, so a twin needs its own compose: \
             that is two ISOs, and the ruling was ONE"
        );

        // ★ THE PAID MEDIUM IS THE OPEN ONE WITH ANOTHER BINARY — and nothing else.
        // Built like gunnar's `gunnar-installer-metered` (`metered_twin`): only
        // name, payload variant and volume id are its own; every param (the seed,
        // data_disks, reinstall, hub_conf…), the env, the argv and the kernel are
        // the open row's, so vm2 and vm3 boot one ISO and the role is elected.
        let metered = set
            .installers
            .iter()
            .find(|i| i.name == "holger-installer-metered")
            .expect("the metered [[build.installer]] row");
        assert_eq!(
            set.get("holger-installer-metered").unwrap().kind,
            ArtifactKind::Installer
        );
        assert_eq!(metered.variant, "mvp-server-musl-metered");
        assert_eq!(metered.volume_id, "HOLGER_INSTALL_METERED");
        let mut same = metered.clone();
        same.name = installer.name.clone();
        same.variant = installer.variant.clone();
        same.volume_id = installer.volume_id.clone();
        // ... and the DEV-NARRATE switch (default off, 2026-10-19): an estate medium's option.
        assert_eq!(same.options, vec![crate::packaging::dev_narrate_option()]);
        same.options = installer.options.clone();
        assert_eq!(&same, installer, "the metered medium differs from the open one ONLY in name, payload, volume id and the dev-narrate option");
        // The FRONT medium declares the estate's root of time (edda estate-clock):
        // `clock` → korp.env.ESTATE_CLOCK, optional; the box media declare none —
        // a box takes `clock_peer` + `clock_key` from the front's offer.
        let front = set
            .installers
            .iter()
            .find(|i| i.name == "holger-front-installer-metered")
            .expect("the front row");
        let front_params: Vec<&str> = front.params.iter().map(|p| p.name.as_str()).collect();
        assert_eq!(
            front_params,
            [
                "site",
                "data_disks",
                "pairing_seed",
                "reinstall",
                "install_then",
                "live_app",
                "clock"
            ]
        );
        let clock = front.params.iter().find(|p| p.name == "clock").unwrap();
        assert_eq!(
            (clock.boot_param.as_str(), clock.required),
            ("korp.env.ESTATE_CLOCK", false)
        );
        assert!(
            !installer
                .params
                .iter()
                .chain(&metered.params)
                .any(|p| p.name.starts_with("clock")),
            "a box takes its clock from the front's offer"
        );
        // tunnr's kernel on EVERY holger medium (owner 2026-09-27).
        for donor in [
            &installer.kernel_donor,
            &metered.kernel_donor,
            &live.kernel_donor,
        ] {
            let d = donor.as_ref().expect("a declared kernel donor");
            assert_eq!(
                (d.repo.as_str(), d.kernel.as_str()),
                ("tunnr", "tunnr-kernel")
            );
        }
        // ...and that kernel carries kvmclock on EVERY holger medium: the row-level
        // requirement on edge `kernel` names the four paravirt wall-clock symbols
        // =y (edda `clock_requires`), so `--build kernel` merges them into
        // tunnr's `nuked` fragment, whose tinyconfig base leaves HYPERVISOR_GUEST
        // off (measured 2026-09-28) — else the box boots on the emulated CMOS, +2 h.
        let clock_rows =
            |reqs: &[nornir_build_thing::requires::EdgeRequirement]| -> Vec<(String, String)> {
                reqs.iter()
                    .filter_map(|r| match &r.what {
                        nornir_build_thing::requires::Requirement::Kconfig(k)
                            if r.edge == "kernel"
                                && k.value
                                    == nornir_build_thing::kernel_requires::KconfigValue::Y =>
                        {
                            Some((r.edge.clone(), k.symbol.clone()))
                        }
                        _ => None,
                    })
                    .collect()
            };
        let want: Vec<(String, String)> = [
            "CONFIG_HYPERVISOR_GUEST",
            "CONFIG_PARAVIRT",
            "CONFIG_KVM_GUEST",
            "CONFIG_PARAVIRT_CLOCK",
        ]
        .into_iter()
        .map(|s| ("kernel".to_string(), s.to_string()))
        .collect();
        for (name, reqs) in [
            (installer.name.as_str(), &installer.requires),
            (metered.name.as_str(), &metered.requires),
            (front.name.as_str(), &front.requires),
            (live.name.as_str(), &live.requires),
        ] {
            let got = clock_rows(reqs);
            for w in &want {
                assert!(
                    got.contains(w),
                    "{name}: the kernel row must carry {}=y (kvmclock), got {got:?}",
                    w.1
                );
            }
        }
        // The metered payload = the open musl payload, its built-in allow-meter swapped for the
        // wasm host (H2 #2), + `metered` + `admit-share` + `intel-fetch`
        // (owner 2026-09-28: the admit-share row applies to every metered row) +
        // `front` (2026-10-17: monetize's sale check reads `GET /-/releases`), and
        // it consumes holger's own signed plugin through a declared edge.
        let open_payload = set.get("mvp-server-musl").unwrap();
        let paid_payload = set.get("mvp-server-musl-metered").unwrap();
        // H2 #2: the open payload meters with the built-in allow-meter; the paid one
        // carries the wasm host (`wasm-plugins` + `meter-guests`) and loads signed guests.
        let mut plus: Vec<&str> = open_payload
            .features
            .iter()
            .map(String::as_str)
            .filter(|f| *f != "allow-meter")
            .collect();
        plus.push("wasm-plugins");
        plus.push("meter-guests");
        plus.push("metered");
        plus.push("admit-share");
        plus.push("front");
        // `intel-fetch` (lane W4): the sold estate is online and refreshes its own
        // intel; the open appliance payload stays zero-egress.
        plus.push("intel-fetch");
        plus.sort_unstable();
        let mut got: Vec<&str> = paid_payload.features.iter().map(String::as_str).collect();
        got.sort_unstable();
        assert_eq!(got, plus);
        assert_eq!(paid_payload.target, open_payload.target);
        assert_eq!(paid_payload.bin.as_deref(), Some("holger-mvp-metered"));
        let edge = paid_payload
            .edges
            .get("plugin")
            .expect("the own-plugin edge");
        assert_eq!(
            (edge.repo.as_str(), edge.variant.as_str(), edge.typ),
            ("monetize-impl", "holger-guest", ArtifactKind::Wasm)
        );
        assert!(
            open_payload.edges.is_empty(),
            "the open payload carries no plugin"
        );

        // The products' bins are their crates' names; the estate's builds of the server
        // share `holger-mvp` / `holger-mvp-metered` — the `target` triple separates the files.
        let bins: Vec<&str> = [
            "holger",
            "holger-downstream",
            "holger-cli",
            "holger-ui",
            "mvp-server-musl",
            "mvp-server-metered",
            "mvp-server-musl-metered",
            "downstream-musl",
        ]
        .iter()
        .map(|t| set.get(t).unwrap().bin.as_deref().unwrap())
        .collect();
        assert_eq!(
            bins,
            [
                "holger",
                "holger-downstream",
                "holger-cli",
                "holger-ui",
                "holger-mvp",
                "holger-mvp-metered",
                "holger-mvp-metered",
                "holger-downstream"
            ]
        );
        for p in crate::variants::PRODUCTS {
            let v = set.get(p).unwrap();
            assert_eq!(
                v.package.as_deref(),
                Some(p),
                "{p}: the row builds the crate of its name"
            );
            assert_eq!(
                v.kind,
                ArtifactKind::Exe,
                "{p}: what `cargo install` leaves in ~/.cargo/bin"
            );
            assert!(
                v.features.is_empty() && !v.no_default_features,
                "{p}: its defaults"
            );
        }
        // The sold server is a service with a member identity.
        assert_eq!(
            set.get("mvp-server-metered").unwrap().kind,
            ArtifactKind::Service
        );
        assert_eq!(
            set.get("mvp-server-metered").unwrap().member.as_deref(),
            Some("holger")
        );
        // Every declared variant validates against its own set.
        for v in &set.variants {
            assert!(
                set.validate(v).is_ok(),
                "'{}': {:?}",
                v.name,
                set.validate(v).err()
            );
        }
    }

    /// **Every variant name this file's RULES mention must be a declared variant.**
    ///
    /// This is the guard the `henriks-*` rename walked straight past. The rule lists
    /// are holger knowledge and stay hand-written — which tiers must be airgapped is
    /// not in the schema — but a rule naming a variant that does not exist is a rule
    /// that fires on nothing, and it fails OPEN: `links_no_http_client` simply
    /// answered `false` and every artifact sailed through un-judged.
    #[test]
    fn every_rule_names_a_declared_variant() {
        let set = build_variants();
        let declared = set.names();
        let mut ghosts: Vec<(&str, &str)> = Vec::new();
        for (list, name) in [(AIRGAP_TIERS.to_vec(), "AIRGAP_TIERS")] {
            for v in list {
                if !declared.contains(&v) {
                    ghosts.push((name, v));
                }
            }
        }
        assert!(
            ghosts.is_empty(),
            "these rules name variants holger does not declare: {ghosts:?}\n\
             declared: {declared:?}"
        );

        // …and the rules DISCRIMINATE: a check that applies to everything or to
        // nothing proves nothing either way.
        assert!(
            !AIRGAP_TIERS.is_empty() && AIRGAP_TIERS.len() < set.variants.len(),
            "the airgap rule must apply to SOME but not all variants"
        );
        for p in crate::variants::PRODUCTS {
            assert!(
                links_no_http_client(p),
                "{p}: every product's default dials nothing"
            );
        }
        assert!(
            !links_no_http_client("mvp-server-metered"),
            "the sold box fetches its own advisories"
        );
        // An undeclared name is fat by the schema's default, not a panic.
        assert_eq!(shape_of("ghost"), ServiceShape::FatService);
    }

    /// The menu groups by the declaration's own role axis, every variant is reachable
    /// from some section, and the entries carry the ecosystem.
    #[test]
    fn the_menu_groups_the_servers_and_the_clients() {
        let m = HolgerBuildThing.menu();
        // One suite (MVP), so the menu's sections are its roles, in declaration order.
        assert_eq!(
            m.in_role(Role::Server),
            vec![
                "holger",
                "holger-downstream",
                "mvp-server-musl",
                "mvp-server-metered",
                "mvp-server-musl-metered",
                "mvp-server-musl-metered-narrate",
                "holger-mvp-appliance",
                "holger-installer",
                "holger-installer-metered",
                "holger-appliance-iso",
                "estate-front-musl-metered",
                "estate-front-musl-metered-narrate",
                "holger-front-installer-metered",
                "holger-keep",
                "holger-front-keep",
                "downstream-musl",
                "holger-downstream-oneway-installer",
                "downstream-fetch-musl",
                "holger-downstream-installer",
            ]
        );
        assert_eq!(m.in_role(Role::Client), vec!["holger-cli", "holger-ui"]);
        // No variant is unreachable from the menu — a declared build nobody can pick
        // is the same rot as a feature nobody builds. Deduplicated before the
        // compare: a dual-suite atom legitimately has one entry PER delivery,
        // and the claim here is coverage (nothing declared is missing, nothing
        // undeclared appears), not entry count.
        let set = m.set();
        let mut menu: Vec<String> = m.menu_variants().iter().map(|s| s.to_string()).collect();
        let mut declared: Vec<String> = set.names().iter().map(|s| s.to_string()).collect();
        menu.sort();
        menu.dedup();
        declared.sort();
        assert_eq!(
            menu, declared,
            "every declared variant appears in at least one role"
        );
        assert!(m.entries.iter().all(|e| e.ecosystem == Ecosystem::Cargo));
        assert_eq!(m.role_of("holger-cli"), Some(Role::Client));
        assert_eq!(m.role_of("holger"), Some(Role::Server));
    }

    /// **The LINKAGE axis and the NORMAL case**, both read off the declaration
    /// rather than restated in Rust for a caller to trust.
    #[test]
    fn every_role_names_its_normal_case_and_every_entry_its_runtime_cost() {
        use nornir_build_thing::plugin::Linkage;
        let m = HolgerBuildThing.menu();

        // Exactly one default per section — a menu with no normal case makes every
        // caller guess: the server, the command-line tool and the open meter guest.
        assert!(m.check_defaults().is_empty(), "{:?}", m.check_defaults());
        assert_eq!(m.default_for(Role::Server), Some("holger"));
        assert_eq!(m.default_for(Role::Client), Some("holger-cli"));
        assert_eq!(m.default_for(Role::Library), Some("plugin-allocation"));
        assert_eq!(m.entries.iter().filter(|e| e.is_default).count(), 3);

        let e = |id: &str| m.entries.iter().find(|e| e.id == id).unwrap().clone();

        // ⚠ THIS TEST USED TO ASSERT A FICTION, and that is why it is worth reading.
        // It required `full` to say "embeds skade" and `mini` to say "NEEDS SKADE
        // RUNNING" — and neither was true of the artifact. holger's server tiers have
        // no skade dependency in any direction; `cargo tree -p holger`
        // finds none under any tier. A test that asserts a declaration against
        // ANOTHER declaration cannot catch that. What follows asserts the MEASURED
        // shape instead.
        //
        // FAT: every server tier owns its own storage and needs no nordisk sibling
        // running. "Read-only" (`mini`) is not "thin" — a read-only server is still a
        // state OWNER.
        for tier in server_variants() {
            assert_eq!(e(&tier).linkage, Linkage::Fat, "{tier}");
            assert!(
                e(&tier)
                    .runtime
                    .contains("nothing else needs to be running"),
                "{tier}: {}",
                e(&tier).runtime
            );
            // And none of them claims to embed a sibling, because none does.
            assert!(
                !e(&tier).runtime.contains("skade"),
                "{tier} must not claim a skade edge it does not have: {}",
                e(&tier).runtime
            );
        }

        // THIN, and `reaches` is where the runtime cost is stated: a holger must be
        // running or the client can do nothing.
        for tier in ["holger-cli", "holger-ui"] {
            assert_eq!(e(tier).linkage, Linkage::Thin, "{tier}");
            assert_eq!(
                build_variants()
                    .get(tier)
                    .unwrap()
                    .reaches
                    .iter()
                    .collect::<Vec<_>>(),
                vec!["holger"],
                "{tier}"
            );
            assert!(
                build_variants().get(tier).unwrap().embeds.is_empty(),
                "{tier}"
            );
        }

        // A role that marks no default is a declaration bug, and says which role.
        let mut broken = m.clone();
        broken.roles[0].default_variant = None;
        for entry in broken.entries.iter_mut() {
            if entry.id == "holger" {
                entry.is_default = false;
            }
        }
        let problems = broken.check_defaults();
        assert!(
            problems.iter().any(|p| p.contains("NO default")),
            "{problems:?}"
        );
        assert!(
            problems.iter().any(|p| p.contains("server")),
            "{problems:?}"
        );
    }

    /// A plan is DATA. holger never runs anything; it says what should happen and the
    /// forge decides. An airgap tier's plan carries the closure resolve, so the
    /// zero-egress claim can be CHECKED rather than asserted.
    #[test]
    fn a_plan_is_data_and_an_airgap_tier_plans_its_own_evidence() {
        let bt = HolgerBuildThing;
        // A row that is not airgap plans its one cargo step, and names the bin it builds.
        let p = bt.plan("mvp-server-metered").unwrap();
        assert_eq!(p.steps.len(), 1);
        assert_eq!(p.steps[0].program, "cargo");
        assert_eq!(
            p.expected_artifacts,
            vec!["target/release/holger-mvp-metered".to_string()]
        );

        // A product is airgap: build, then resolve the closure the zero-egress claim is
        // CHECKED against.
        let p = bt.plan("holger").unwrap();
        assert_eq!(
            p.expected_artifacts,
            vec!["target/release/holger".to_string()]
        );
        assert_eq!(p.steps.len(), 2, "build, then resolve the closure");
        assert_eq!(p.steps[1].args[0], "tree");
        assert!(p.rationale.as_deref().unwrap().contains("CHECKED"), "{p:?}");
        // Nothing in a plan is a shell.
        assert!(p.steps.iter().all(|s| s.program == "cargo"));
        // The static appliance is airgapped too, so it plans its own evidence.
        assert_eq!(bt.plan("mvp-server-musl").unwrap().steps.len(), 2);
        assert!(bt.plan("ghost").is_none());
        // A POINTER variant plans NO cargo step — never the bare `cargo build` its
        // empty argv would spell — and says which builder assembles it instead.
        for (ptr, kind) in [
            ("holger-mvp-appliance", "container"),
            ("holger-installer", "installer"),
            ("holger-installer-metered", "installer"),
            ("holger-appliance-iso", "iso"),
        ] {
            let p = bt.plan(ptr).unwrap();
            assert!(
                p.steps.is_empty(),
                "{ptr} must not plan a cargo step: {p:?}"
            );
            assert!(p.expected_artifacts.is_empty(), "{ptr}: {p:?}");
            let why = p.rationale.as_deref().unwrap();
            assert!(why.contains(&format!("[[build.{kind}]]")), "{ptr}: {why}");
            assert!(why.contains("pointer variant"), "{ptr}: {why}");
        }
    }

    /// **The graph is what the fat/thin measurement looks like.** A `reaches` edge is
    /// dashed — the thing must be RUNNING; an `embeds` edge is solid — it is in the
    /// binary. That distinction is the thing a table communicates badly.
    ///
    /// ⚠ This test, too, used to assert the skade fiction: `full` embedding skade and
    /// `mini` reaching it. Neither edge exists in holger's Cargo graph. It now asserts
    /// that the server tiers claim NO sibling edge at all, and that the dashed edge
    /// belongs where it is real — on the clients that cannot work without a holger up.
    #[test]
    fn the_graph_shows_what_a_variant_compiles_in_and_what_it_needs_running() {
        use nornir_build_thing::plugin::{EdgeKind, NodeKind};
        let bt = HolgerBuildThing;

        let g = bt.graph("holger");
        assert_eq!(g.repo, "holger");
        assert_eq!(g.root, "holger");
        assert!(g.dangling_edges().is_empty(), "{:?}", g.dangling_edges());
        assert!(
            g.embedded().is_empty(),
            "no holger server tier compiles in a sibling"
        );
        assert!(g.reached().is_empty(), "and none needs one running");

        let g = bt.graph("holger-downstream");
        assert!(
            g.embedded().is_empty(),
            "the downstream compiles in nothing"
        );
        assert!(
            g.reached().is_empty(),
            "…and, being a state owner, needs nothing running"
        );

        // The dashed edge is REAL on the clients: the tool embeds no holger core, so
        // a holger must be up or its server commands can do nothing.
        let g = bt.graph("holger-cli");
        assert!(g.embedded().is_empty());
        assert_eq!(
            g.reached(),
            vec!["holger"],
            "the thin client needs a holger RUNNING"
        );
        assert!(
            EdgeKind::Reaches.dashed(),
            "a runtime dep is dashed, not solid"
        );
        assert!(!EdgeKind::Embeds.dashed(), "compiled-in is solid");

        // The plan DAG and the artifact are in the picture, and the root node carries
        // the variant to select — which is why this is data, not an SVG.
        let g = bt.graph("holger");
        let steps: Vec<&str> = g
            .nodes
            .iter()
            .filter(|n| n.kind == NodeKind::Step)
            .map(|n| n.label.as_str())
            .collect();
        assert_eq!(steps.len(), 2, "build, then resolve the closure: {steps:?}");
        let artifact = g
            .nodes
            .iter()
            .find(|n| n.kind == NodeKind::Artifact)
            .unwrap();
        assert_eq!(artifact.label, "holger");
        let root = g
            .nodes
            .iter()
            .find(|n| n.kind == NodeKind::Variant)
            .unwrap();
        assert_eq!(
            root.selects.as_deref(),
            Some("holger"),
            "a node you can click to BUILD"
        );
        // The server is fat: it owns its own storage and needs nothing else up. It
        // embeds no NORDISK sibling either, so the detail is the plain
        // self-containment line and NOT an "embeds …" claim.
        assert!(
            root.detail
                .as_deref()
                .unwrap()
                .contains("nothing else needs to be running"),
            "{:?}",
            root.detail
        );
        assert!(
            !root.detail.as_deref().unwrap().contains("embeds"),
            "{:?}",
            root.detail
        );

        // An unknown variant yields an EMPTY graph, not a panic and not a fake node.
        let g = bt.graph("ghost");
        assert!(g.nodes.is_empty() && g.edges.is_empty());
    }

    /// **The rev pin.** A build thing is only true for the revision it was built from.
    #[test]
    fn a_rev_mismatch_refuses_the_rebuild() {
        use nornir_build_thing::plugin::RevMatch;
        host::set_native_facts(host::NativeFacts {
            rev_and_dirty: ("a".repeat(40), false),
            ..Default::default()
        });
        let prov = HolgerBuildThing.provenance();
        assert_eq!(prov.repo, "holger");
        assert_eq!(prov.rev, "a".repeat(40));

        assert!(
            !prov.check(&"a".repeat(40)).refuse_rebuild(),
            "the tree it describes"
        );
        let m = prov.check(&"b".repeat(40));
        assert!(m.refuse_rebuild(), "a different tree must be REFUSED");
        assert!(matches!(m, RevMatch::Mismatch { .. }));
        assert!(m.line().contains("REFUSING to rebuild"), "{}", m.line());
        // An unknown revision is never treated as a match.
        assert!(prov.check("").refuse_rebuild());
        host::set_native_facts(host::NativeFacts::default());
    }

    // ⚠ TWO TESTS MOVED TO holger-egui ON 2026-09-16, with the rules they exercised:
    // `the_ui_tiers_mirror_their_required_features` (each rung names the feature its
    // `[[bin]]` requires) and `a_read_only_client_may_not_ask_for_an_egress_pane`
    // (the client-side half of the airgap rule, the one that stops `mini = ["gui"]`
    // being written again). They assert holger-egui's declaration now.

    /// **The rule that is not data.** `served` is a perfectly legitimate holger
    /// feature — it is in `offers` — so the generic validator accepts it. Only holger
    /// knows it must never appear in an airgap tier.
    #[test]
    fn an_airgap_tier_may_not_ask_for_an_egress_feature() {
        let bt = HolgerBuildThing;
        // The generic set says yes: both features are offered and not exclusive.
        let set = build_variants();
        let probe = BuildVariant {
            name: "probe".into(),
            features: vec!["downstream".into(), "served".into()],
            ..Default::default()
        };
        assert!(
            set.validate(&probe).is_ok(),
            "the DECLARED rules permit this combination"
        );

        // holger's own rule says no.
        let v = bt.validate(&BuildRequest::features(["downstream", "served"]));
        assert!(
            !v.ok,
            "holger's build thing refuses what its declaration alone allows"
        );
        assert!(
            v.line().contains("provably unable to reach the network"),
            "{}",
            v.line()
        );
    }

    #[test]
    fn a_valid_airgap_tier_is_accepted_and_says_what_still_has_to_hold() {
        let v = HolgerBuildThing.validate(&BuildRequest::variant("holger"));
        assert!(v.ok);
        assert!(
            v.line().contains("must link no outbound HTTP client"),
            "{}",
            v.line()
        );
        // The static appliance is held to the same claim.
        let v = HolgerBuildThing.validate(&BuildRequest::variant("mvp-server-musl"));
        assert!(v.ok, "{}", v.line());
        assert!(
            v.line().contains("must link no outbound HTTP client"),
            "{}",
            v.line()
        );
    }

    /// The artifact-level keystone, in both directions — and the second direction is
    /// what proves it discriminates rather than always passing.
    #[test]
    fn the_airgap_verdict_discriminates_between_the_tiers() {
        let bt = HolgerBuildThing;
        let facts = |variant: &str, linked: &[&str]| ArtifactFacts {
            variant: Some(variant.to_string()),
            file_name: format!("holger-{variant}"),
            bytes: 26_700_000,
            sha256: "0".repeat(64),
            linked_crates: linked.iter().map(|s| s.to_string()).collect(),
        };

        // The products link no client.
        let v = bt.judge_artifact(&facts("holger", &["serde", "hyper", "tonic"]));
        assert!(v.ok, "{}", v.line());
        assert!(v.line().contains("cannot phone home"), "{}", v.line());

        // hyper/tonic are the INBOUND stack and must not trip the rule.
        assert!(
            bt.judge_artifact(&facts("holger-downstream", &["hyper", "h2", "tonic"]))
                .ok
        );

        // The sold box is deliberately NOT under the no-egress rule: it fetches its own
        // advisories.
        assert!(
            bt.judge_artifact(&facts("mvp-server-metered", &["ureq", "tonic"]))
                .ok
        );

        // An airgap row that somehow linked reqwest is refused, by name.
        let v = bt.judge_artifact(&facts("holger", &["serde", "reqwest"]));
        assert!(!v.ok);
        assert!(v.line().contains("reqwest"), "{}", v.line());
        assert!(v.line().contains("must not be promoted"), "{}", v.line());
    }

    // ⚠ `every_ui_tier_is_thin_and_only_the_named_one_may_embed` MOVED to holger-egui
    // on 2026-09-16 with `THIN_FORBIDDEN_CRATES` and `EMBEDDED_UI_VARIANT`: it holds
    // an artifact's real closure to the thin rule, and the artifacts it judges are
    // that repo's four rungs.

    /// ★ **The leak that got in arrived as a TLS backend, and on a tier the judge
    /// had no opinion about. Both halves of that are now closed.**
    ///
    /// The third measured feature leak was `auth-oidc`/`auth-oauth2` dragging the
    /// native OpenSSL stack into `server-local`. `server-local` is neither an
    /// airgap tier nor `full`, so [`judge_artifact`] fell through to a bare
    /// `Verdict::ok()` and returned GREEN over the one artifact it most needed to
    /// look at — and `FORBIDDEN_OUTBOUND_CLIENTS` named eight HTTP clients and
    /// not one TLS backend, so even a tier it DID judge would have passed.
    ///
    /// RED against the real history: written against `server-local` because that
    /// is the row it actually happened on.
    #[test]
    fn a_native_tls_backend_is_refused_on_every_row() {
        let bt = HolgerBuildThing;
        let facts = |variant: &str, linked: &[&str]| ArtifactFacts {
            variant: Some(variant.to_string()),
            file_name: format!("holger-{variant}"),
            bytes: 26_700_000,
            sha256: "0".repeat(64),
            linked_crates: linked.iter().map(|s| s.to_string()).collect(),
        };

        // THE HISTORICAL LEAK, exactly as it shipped: an ordinary tier, an
        // allowed HTTP client, and openssl-sys riding underneath it.
        let v = bt.judge_artifact(&facts(
            "mvp-server-metered",
            &["reqwest", "openssl-sys", "hyper"],
        ));
        assert!(
            !v.ok,
            "a row with openssl-sys must be refused: {}",
            v.line()
        );
        assert!(v.line().contains("openssl-sys"), "{}", v.line());
        assert!(v.line().contains("rustls end to end"), "{}", v.line());

        // The tier that is ALLOWED to reach the network is not allowed a native
        // stack either — this is the rule with no tiers.
        let v = bt.judge_artifact(&facts(
            "mvp-server-musl-metered",
            &["reqwest", "ureq", "native-tls"],
        ));
        assert!(!v.ok, "the sold box is not exempt: {}", v.line());
        assert!(v.line().contains("native-tls"), "{}", v.line());

        // And an airgap tier, where it would previously have been refused for the
        // WRONG reason (the client) or not at all.
        let v = bt.judge_artifact(&facts("holger-downstream", &["hyper", "tonic", "openssl"]));
        assert!(!v.ok, "{}", v.line());
        assert!(v.line().contains("openssl"), "{}", v.line());

        // rustls is what holger actually links, and it is not a refusal.
        assert!(
            bt.judge_artifact(&facts(
                "mvp-server-metered",
                &["reqwest", "rustls", "hyper"]
            ))
            .ok
        );
        assert!(
            bt.judge_artifact(&facts("holger-downstream", &["hyper", "rustls", "tonic"]))
                .ok
        );
    }

    /// ★ **A tier the judge has no rule for is still JUDGED, and says so.**
    ///
    /// A bare `Verdict::ok()` and "judged and accepted" are different sentences,
    /// and a reader of a verdict could not tell them apart. `server-local` is the
    /// tier this matters on, because it is the one an artifact-level check
    /// silently skipped while OpenSSL rode in.
    #[test]
    fn a_row_that_is_not_airgap_is_judged_rather_than_ignored() {
        let bt = HolgerBuildThing;
        let facts = |variant: &str, linked: &[&str]| ArtifactFacts {
            variant: Some(variant.to_string()),
            file_name: format!("holger-{variant}"),
            bytes: 1,
            sha256: "0".repeat(64),
            linked_crates: linked.iter().map(|s| s.to_string()).collect(),
        };

        let v = bt.judge_artifact(&facts(
            "mvp-server-metered",
            &["reqwest", "hyper", "rustls"],
        ));
        assert!(v.ok, "{}", v.line());
        assert!(
            !v.reasons.is_empty(),
            "a verdict with no reasons is 'no opinion', not 'accepted': {v:?}"
        );
        assert!(v.line().contains("mvp-server-metered"), "{}", v.line());
        assert!(v.line().contains("not constrained"), "{}", v.line());

        let v = bt.judge_artifact(&facts("mvp-ui", &["hyper", "rustls"]));
        assert!(v.ok, "{}", v.line());
        assert!(
            v.line().contains("links no outbound HTTP client"),
            "{}",
            v.line()
        );
    }

    /// An unmeasured guarantee is not a guarantee — refuse rather than green-tick.
    #[test]
    fn an_artifact_with_no_closure_is_refused_not_assumed_clean() {
        let bt = HolgerBuildThing;
        let v = bt.judge_artifact(&ArtifactFacts {
            variant: Some("holger".into()),
            ..Default::default()
        });
        assert!(!v.ok);
        assert!(v.line().contains("UNMEASURED"), "{}", v.line());

        let v = bt.judge_artifact(&ArtifactFacts::default());
        assert!(!v.ok);
        assert!(
            v.line().contains("does not say which variant"),
            "{}",
            v.line()
        );
    }

    #[test]
    fn a_rebuild_recipe_carries_what_a_rebuild_needs() {
        let r = HolgerBuildThing.rebuild_recipe("mvp-server-musl").unwrap();
        assert_eq!(r.repo, "holger");
        assert_eq!(r.remote.as_deref(), Some(REMOTE));
        assert!(r.cargo_args.contains(&"--bin".to_string()));
        assert!(r.cargo_args.contains(&"holger-mvp".to_string()));
        assert!(r.cargo_args.contains(&"--features".to_string()));
        assert!(HolgerBuildThing.rebuild_recipe("ghost").is_none());
    }
}