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

nordisk/gunnar

crates/gunnar-recipe/src/emit.rs

//! **The receipt writer, from gunnar's side.** The one function a `build.rs` in
//! this repository calls, and the only place that knows how a gunnar build
//! becomes a `nornir_build_thing::contract::Receipt`.
//!
//! ```text
//! gunnar-cli/build.rs   ->  emit::write_receipt(&[…])
//!                           resolves WHICH variant is being built, from the
//!                           features cargo resolved
//!                       ->  nornir_build_thing::receipt::emit
//!                           writes OUT_DIR/…receipt.rs: a #[used]
//!                           #[link_section = ".nordisk.buildthing"] static
//! gunnar-cli/main.rs    ->  include!(env!("GUNNAR_BUILD_RECEIPT"))
//! ```
//!
//! # The section carries the RECEIPT; the model wants the MODULE too — a named gap
//!
//! `nornir_build_thing::contract::RECEIPT_SECTION` and
//! `nornir_build_thing::plugin::SECTION` are ONE name, `.nordisk.buildthing`.
//! The build-thing model wants
//! an artifact to carry its build thing's wasm module in that section, so a
//! forge holding only the artifact can load and CALL the recipe that built it;
//! what this crate puts there today is the receipt (`receipt::emit_into`, the
//! only writer edda ships — `artifact-section` is a READER,
//! `plugin_host::read_section`, and reads the same bytes). Two payloads under
//! one section name cannot both be there, and this crate is now a cdylib that
//! HAS a module to carry (2026-08-26). The writer, and the section split or
//! framing that lets receipt and module coexist, is upstream work in
//! `nornir-build-thing`; until it exists this crate writes the receipt and
//! says so here rather than embedding a module the reader would mistake for
//! one.
//!
//! # Why the include goes through an env var and not the macro
//!
//! `nornir_build_thing` ships `embed_build_receipt!()`, which is the same
//! `include!` with the file name baked in. Using it would mean gunnar-cli
//! carrying `nornir-build-thing` as a **normal** dependency — serde_json, toml,
//! object, cargo_metadata, chrono, sha2 — in the dependency graph of a git server
//! that is meant to be able to be PID 1, all so one `static` can be spelled with
//! a macro. This crate is a **build**-dependency instead: it does not reach the
//! shipped binary at all, and the only thing that crosses into the compilation is
//! the generated file's path, in [`RECEIPT_ENV`].
//!
//! The file name is still spelled exactly once — `receipt::GENERATED_FILE`, read
//! from the writer rather than repeated here.
//!
//! # What it refuses to do
//!
//! Write a receipt naming a variant the build is not. Two shapes cause that, and
//! both end as [`Attribution::NoVariant`] / [`Attribution::TargetMismatch`] with a
//! `cargo:warning`, never as a receipt:
//!
//! ```text
//! --all-features            matches no declared variant's feature set
//! --features server         with no --target, where the variant says musl
//! ```
//!
//! A missing receipt says "how this was built is unanswerable", which is true. A
//! receipt naming the wrong variant answers the rebuild question **wrongly**, and
//! there is no way to find out afterwards that it did.

use std::collections::{BTreeMap, BTreeSet};
use std::path::{Path, PathBuf};

use nornir_build_thing::receipt::{self, ReceiptBuilder};

use crate::recipe::GunnarBuildThing;
use crate::variants::by_resolved_features;
use crate::Variant;

/// The env var `build.rs` publishes the generated file's path in, and that the
/// crate's own source `include!`s.
pub const RECEIPT_ENV: &str = "GUNNAR_BUILD_RECEIPT";

/// Which variant the running build turned out to be — or why it could not be told.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Attribution {
    /// The resolved feature set is exactly one declared variant's, and the target
    /// agrees. This is the only variant that produces a receipt.
    Variant(&'static Variant),
    /// No declared variant has this feature set. `--all-features`, or a combination
    /// nobody declared.
    NoVariant {
        /// What cargo resolved, in `CARGO_FEATURE_*` spelling.
        resolved: BTreeSet<String>,
    },
    /// The features name a variant, and the build is for a different target or a
    /// different profile than that variant declares.
    Mismatch {
        /// The variant the features named.
        variant: &'static Variant,
        /// Which axis disagrees — `target` or `profile`.
        axis: &'static str,
        /// What the variant declares. `host (<triple>)` when it declares no target.
        declared: String,
        /// What cargo is actually doing.
        actual: String,
    },
}

impl Attribution {
    /// The variant, when there is one.
    #[must_use]
    pub fn variant(&self) -> Option<&'static Variant> {
        match self {
            Attribution::Variant(c) => Some(c),
            _ => None,
        }
    }

    /// Whether a `build.rs` should turn [`note`](Self::note) into a
    /// `cargo:warning`, given the profile cargo is actually building.
    ///
    /// # A debug build is not a delivery, and never warns
    ///
    /// `cargo build`, `cargo check --workspace`, every run of the test suite:
    /// none of them is any declared variant, because every variant passes
    /// `--no-default-features` and a default build resolves `DEFAULT` on top of
    /// everything else. MEASURED 2026-08-06 — a plain workspace check resolves
    /// `{CLIENT, CONTROL, DEFAULT, SERVER}`, which is nobody's variant.
    ///
    /// Warning about that would put a `cargo:warning` on every compile in the
    /// repository, and a warning that fires on every build is a warning nobody
    /// reads — including the ones that matter. The reason is still recorded in
    /// the generated file either way; only the shout is suppressed.
    ///
    /// A **release** build that is not a variant is loud, because that is somebody
    /// producing something and getting it wrong.
    #[must_use]
    pub fn should_warn(&self, actual_profile: &str) -> bool {
        !matches!(self, Attribution::Variant(_)) && actual_profile != "debug"
    }

    /// The line a `build.rs` prints as a `cargo:warning`, when there is one to
    /// print.
    ///
    /// Names the resolved set rather than saying "no match": a warning that does
    /// not say what it saw cannot be acted on, and this one fires during a build
    /// somebody is in the middle of.
    #[must_use]
    pub fn note(&self) -> Option<String> {
        match self {
            Attribution::Variant(_) => None,
            Attribution::NoVariant { resolved } => Some(format!(
                "no build-thing receipt: the resolved feature set {{{}}} is not any declared \
                 variant's, so this binary cannot say which build point it is. Declared sets: {}",
                comma(resolved),
                declared_sets(),
            )),
            Attribution::Mismatch {
                variant,
                axis,
                declared,
                actual,
            } => Some(format!(
                "no build-thing receipt: the features name variant {:?}, which declares \
                 {axis} {declared:?}, and this build's {axis} is {actual:?}. A receipt naming \
                 a variant the build is not answers the rebuild question wrongly",
                variant.name,
            )),
        }
    }
}

/// What [`write_receipt`] did.
#[derive(Debug, Clone)]
pub struct Emitted {
    /// The generated file, always written and always in [`RECEIPT_ENV`] — even
    /// when it holds no receipt, because the `include!` in the crate's source
    /// has to find something either way.
    pub path: PathBuf,
    /// Which variant this build is, or why it could not be told.
    pub attribution: Attribution,
}

/// **The `build.rs` call.** Resolve the variant, write the receipt, publish the
/// path.
///
/// `extra_inputs` are build inputs only the calling crate can know —
/// `source-commit` is the one gunnar passes. They land in the receipt's `inputs`
/// map. Absolute paths and wall-clock times are **refused** by
/// `receipt::audit_receipt`, so do not pass a build date: two identical builds
/// would differ by it and by nothing else.
///
/// Prints `cargo:rustc-env=` and `cargo:warning=` on stdout, which is what a
/// build script's stdout is for.
///
/// # Errors
///
/// When `OUT_DIR` is unset (this is not a build script), when the manifest of
/// the crate being built cannot be read, or when the receipt is refused by its
/// own audit. Refusing loudly is the point: a build script that swallowed the
/// error would leave a binary with no receipt and no reason.
pub fn write_receipt(extra_inputs: &[(&str, String)]) -> anyhow::Result<Emitted> {
    let out_dir = std::env::var("OUT_DIR").map_err(|_| {
        anyhow::anyhow!("OUT_DIR is unset — emit::write_receipt is a build.rs call")
    })?;
    let out_dir = PathBuf::from(out_dir);
    let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").map_err(|_| {
        anyhow::anyhow!("CARGO_MANIFEST_DIR is unset — emit::write_receipt is a build.rs call")
    })?;

    let profile = std::env::var("PROFILE").unwrap_or_default();
    let attribution = attribute(
        &resolved_features(),
        &std::env::var("TARGET").unwrap_or_default(),
        &profile,
    );

    let path = match attribution.variant() {
        Some(variant) => {
            let r = receipt_for(variant, Path::new(&manifest_dir), extra_inputs)?;
            // `emit_into` and not `emit`: the same writer, with the directory
            // named once here rather than read from `OUT_DIR` a second time.
            receipt::emit_into(&out_dir, &r)?
        }
        None => write_absent(&out_dir, &attribution)?,
    };

    if attribution.should_warn(&profile) {
        if let Some(note) = attribution.note() {
            println!("cargo:warning={note}");
        }
    }
    println!("cargo:rustc-env={RECEIPT_ENV}={}", path.display());
    Ok(Emitted { path, attribution })
}

/// The receipt for `variant`, with every setting resolved.
///
/// Two independent sources, deliberately:
///
/// ```text
/// the variant        atom, column, kind, linkage, suites, features, profile,
///                 target, package, bin      -- what was DECLARED
/// cargo           feature.<name> = true/false for the whole universe, plus
///                 the target triple, profile, opt-level and rustc string
///                                           -- what was RESOLVED
/// ```
///
/// They can disagree, and that is the value: a variant declaring
/// `no-default-features` while `feature.default` resolved to `true` is a build
/// that did not do what the variant says, and the receipt carries both halves for
/// anyone who looks.
///
/// # Errors
///
/// When the manifest cannot be read or parsed, or the receipt fails its audit.
fn receipt_for(
    variant: &Variant,
    manifest_dir: &Path,
    extra_inputs: &[(&str, String)],
) -> anyhow::Result<nornir_build_thing::contract::Receipt> {
    // `from_cargo_env` is used for its INPUTS — the target triple, profile,
    // opt-level, debug flag and the rustc version string of the compilation
    // actually running. Its `settings` are discarded and rebuilt below.
    let cargo = ReceiptBuilder::from_cargo_env(
        GunnarBuildThing::coordinate(),
        variant.atom.as_str(),
        variant.column.as_str(),
    )?
    .build()?;

    let mut builder = ReceiptBuilder::new(
        cargo.build_thing.clone(),
        cargo.atom.clone(),
        cargo.target.clone(),
    );
    for (k, v) in &cargo.inputs {
        builder = builder.input(k, v);
    }

    // Why the feature universe is re-derived instead of taken from
    // `from_cargo_env`: that one is built from the compilation's environment
    // alone, and the universe wants the manifest's whole `[features]` table so
    // an OFF feature is recorded `false` rather than absent.
    //
    // Until 2026-08-17 the manifest was SLICED to its `[features]` table first,
    // because 0.1.5's `declared_features` counted every `optional = true`
    // dependency reachable only as `dep:<name>` as a declared feature and
    // recorded it `false` in a binary that links it (MEASURED 2026-08-06: 27 of
    // 33 `feature.*` entries on the first real gunnar-server receipt were
    // dependencies) — a receipt that lies. The old comment here said the slice
    // "comes out the day a `nornir-build-thing` carrying the upstream fix is
    // published"; 0.1.7 is that version, the pin moved, and this is that day.
    // `the_feature_universe_keeps_features_and_drops_optional_dependencies`
    // still holds the property, now against the upstream directly.
    let manifest = std::fs::read_to_string(manifest_dir.join("Cargo.toml"))?;
    let universe = receipt::resolved_feature_settings(&manifest, |var| std::env::var(var).is_ok())?;
    for (k, v) in universe {
        builder = builder.setting(k, v);
    }

    for (k, v) in variant.resolved_settings() {
        builder = builder.setting(k, v);
    }
    for (k, v) in extra_inputs {
        builder = builder.input(*k, v.clone());
    }
    builder.build()
}

/// The feature set cargo resolved, in `CARGO_FEATURE_*` spelling.
///
/// Read out of the environment rather than from a command line, because the
/// environment is the RESOLVED set: it already carries whatever feature
/// unification, implication and `default` added, which is exactly the thing a
/// declaration cannot be trusted about.
fn resolved_features() -> BTreeSet<String> {
    std::env::vars()
        .filter_map(|(k, _)| k.strip_prefix("CARGO_FEATURE_").map(str::to_string))
        .collect()
}

/// Which variant a resolved feature set, target and profile are — or why none.
///
/// Split out from [`write_receipt`] with no I/O in it so every refusal can be
/// watched going red without a build script, a manifest or an `OUT_DIR`.
///
/// `actual_profile` is cargo's `PROFILE`, which is `debug` or `release` and
/// **not** the `--profile` name: a custom profile that inherits release reports
/// `release`. That is why the comparison below is against the variant's profile
/// mapped through the same convention rather than against its label.
#[must_use]
pub fn attribute(
    resolved: &BTreeSet<String>,
    actual_target: &str,
    actual_profile: &str,
) -> Attribution {
    // **Resolve on the build point, not on the features alone.** The target was
    // already in hand here and was only ever used to report a mismatch AFTER
    // picking a row; with two rows sharing a feature set and differing by
    // target, using it to PICK is what lets both be declared at all.
    //
    // The host fallback is unchanged: `None` in the table means "whatever the
    // host is", so a row with no target is looked up as the host's.
    let host = std::env::var("HOST").unwrap_or_default();
    let variant = crate::variants::by_build_point(resolved, Some(actual_target))
        .or_else(|| {
            // The host row, asked for by the host's own triple.
            (actual_target == host)
                .then(|| crate::variants::by_build_point(resolved, None))
                .flatten()
        })
        // Nothing matched the point; fall back to the feature set alone so a
        // WRONG-TARGET build is still attributed to the row it meant and
        // reported as a `Mismatch` below, rather than as "no variant".
        .or_else(|| by_resolved_features(resolved));
    let Some(variant) = variant else {
        return Attribution::NoVariant {
            resolved: resolved.clone(),
        };
    };
    // `None` in the table means "whatever the host is", and cargo answers that
    // by setting TARGET to the host triple. So the comparison is against HOST,
    // not against "anything goes" — a cross build of a host-only variant is still a
    // build the variant did not describe.
    let declared_target = variant
        .target
        .map(str::to_string)
        .unwrap_or_else(|| std::env::var("HOST").unwrap_or_default());
    if declared_target != actual_target {
        return Attribution::Mismatch {
            variant,
            axis: "target",
            declared: if variant.target.is_some() {
                declared_target
            } else {
                format!("host ({declared_target})")
            },
            actual: actual_target.to_string(),
        };
    }
    // Only checked when cargo answered at all: an empty `PROFILE` means this is
    // not a build script, and "not measured" must not be turned into a pass by
    // comparing against the empty string.
    let declared_profile = cargo_profile_word(variant.profile_resolved().label());
    if !actual_profile.is_empty() && declared_profile != actual_profile {
        return Attribution::Mismatch {
            variant,
            axis: "profile",
            declared: format!(
                "{} ({declared_profile})",
                variant.profile_resolved().label()
            ),
            actual: actual_profile.to_string(),
        };
    }
    Attribution::Variant(variant)
}

/// The word cargo puts in a build script's `PROFILE` for a `--profile` name.
///
/// Cargo says `debug` or `release` and nothing else, so a declared profile has
/// to be mapped the same way before it can be compared. An unrecognised custom
/// name maps to `release`, because a custom profile in a delivery declaration is
/// an optimised one — and if that guess is ever wrong the result is a refused
/// receipt with the reason printed, not a wrong one.
fn cargo_profile_word(label: &str) -> &'static str {
    match label {
        "dev" | "debug" | "test" => "debug",
        _ => "release",
    }
}

/// Write a generated file that declares nothing.
///
/// The `include!` in the crate's own source has to resolve on every build, or a
/// combination nobody declared would stop compiling rather than stop carrying a
/// receipt. Those are very different failures and only one of them is wanted.
fn write_absent(out_dir: &Path, why: &Attribution) -> anyhow::Result<PathBuf> {
    let path = out_dir.join(receipt::GENERATED_FILE);
    let reason = why
        .note()
        .unwrap_or_else(|| "unattributed build".to_string());
    std::fs::write(
        &path,
        format!("// No build-thing receipt for this compilation.\n// {reason}\n"),
    )?;
    Ok(path)
}

/// `a, b, c`.
fn comma(set: &BTreeSet<String>) -> String {
    set.iter().cloned().collect::<Vec<_>>().join(", ")
}

/// Every declared variant's feature set, for the warning that says none matched.
fn declared_sets() -> String {
    crate::variants::VARIANTS
        .iter()
        .filter(|c| c.package.is_some())
        .map(|c| format!("{}={{{}}}", c.name, comma(&c.normalised_features())))
        .collect::<Vec<_>>()
        .join(" ")
}

/// The settings a variant resolves to, without a build script — so a caller can see
/// what a receipt WOULD say.
#[must_use]
pub fn settings_for(variant: &Variant) -> BTreeMap<String, String> {
    variant.resolved_settings()
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::atom::Column;
    use crate::variants::{by_build_point, by_name, normalise_feature};

    fn set(names: &[&str]) -> BTreeSet<String> {
        names.iter().map(|n| normalise_feature(n)).collect()
    }

    /// **The cargo variants have pairwise distinct feature sets**, which is what
    /// makes the resolved environment able to name one.
    ///
    /// The count was 5 until 2026-08-27 and is 6 with `gunnar-server-thin` — the
    /// build point `--opt wireguard=off` arrives at. The literal is raised only
    /// AFTER the distinctness assertion below was seen green on the new row: a
    /// bumped denominator that nothing re-checked is how a guard stops guarding.
    ///
    /// Watched failing: two variants built here with the same set collide, and the
    /// same `HashSet`-of-sets count is what detects it. Without the red half a
    /// counting test over a table that happens to be distinct today cannot tell a
    /// working rule from `true`.
    #[test]
    fn the_cargo_variants_have_pairwise_distinct_build_points() {
        let cargo_variants: Vec<&Variant> = crate::variants::VARIANTS
            .iter()
            .filter(|c| c.package.is_some())
            .collect();
        assert_eq!(
            cargo_variants.len(),
            15,
            "the fifteen cargo variants are the subject (GUN-PRODUCTS, 2026-10-30: the three \
             products gunnar, gunnar-ui and gunnar-cli, each its crate's defaults named out \
             loud; the six appliance rows; the front's gunnar-cli-musl and its metered twin; \
             the four gunnar-front rows. Retired that day: the client-only gunnar, the old \
             gunnar-cli row, gunnar-musl, gunnar-solo, gunnar-service, gunnar-open and \
             gunnar-open-client)"
        );
        // **The build point is (features, target), not the features alone.**
        // Raised 2026-09-19: `gunnar-cli` and `gunnar-cli-musl` are one feature
        // set and two artifacts at two paths, and the front needs the second.
        // Keyed on the feature set alone this assertion refused to let it be
        // declared at all, which is why that binary was being built from a
        // cargo line in another repository instead.
        let points: BTreeSet<(BTreeSet<String>, Option<&str>)> = cargo_variants
            .iter()
            .map(|c| (c.normalised_features(), c.target))
            .collect();
        assert_eq!(
            points.len(),
            cargo_variants.len(),
            "two variants resolve to the same build point, so a build script cannot tell \
             them apart and the receipt would name whichever came first: {:?}",
            cargo_variants
                .iter()
                .map(|c| (c.name, c.normalised_features(), c.target))
                .collect::<Vec<_>>()
        );

        // Red side: the same count over a table that DOES collide must drop.
        let colliding: BTreeSet<(BTreeSet<String>, Option<&str>)> = [
            (set(&["server"]), None),
            (set(&["server"]), None),
            (set(&["client"]), None),
        ]
        .into_iter()
        .collect();
        assert_eq!(
            colliding.len(),
            2,
            "the de-duplication does not de-duplicate, so the assertion above cannot fail"
        );
    }

    /// Each cargo variant's own declared set resolves back to it.
    #[test]
    fn every_cargo_variant_is_found_by_the_features_it_declares() {
        for c in crate::variants::VARIANTS
            .iter()
            .filter(|c| c.package.is_some() && c.built_here())
        {
            let found = crate::variants::by_build_point(&c.normalised_features(), c.target);
            assert_eq!(
                found.map(|f| f.name),
                Some(c.name),
                "{} is not found by its own build point",
                c.name
            );
        }
    }

    /// The two feature sets the design cares about most, spelled the way cargo
    /// spells them, and the one that must NOT resolve.
    #[test]
    fn the_resolved_features_name_the_variant_and_refuse_when_they_do_not() {
        assert_eq!(
            by_resolved_features(&set(&[
                "server",
                "engine-znippy",
                "mimalloc",
                "clock-fetch",
                "resolver-probe",
                "fleet-pull",
                "mirror-http",
                "sso-egress",
                "dhcp-client",
                "wg-client",
                "replication",
                "grow-runtime",
                "live-app"
            ]))
            .map(|c| c.name),
            Some("gunnar-server"),
        );
        // `["server", "engine-znippy"]` was the appliance until 2026-08-11 and is
        // now NOTHING, by exactly the argument the paragraph below makes about
        // the engine. `mimalloc` is not a tuning knob: a gunnar built without it
        // serves clones at 2.2x the CPU (`gunnar-server/src/lib.rs` has the
        // grid), so a receipt calling that artifact the appliance would vouch
        // for a build point nobody agreed to ship.
        assert_eq!(
            by_resolved_features(&set(&["server", "engine-znippy"])),
            None,
            "an allocator-less appliance build still attributes to the server variant, so the \
             slow-heap artifact would ship with a receipt saying it is the appliance"
        );
        // `["server"]` alone stopped being the appliance on 2026-08-10, when the
        // engine became a feature of this package. It must now resolve to
        // NOTHING rather than to the server variant: a build that forgot to name an
        // engine is a server with no storage, and a receipt calling it
        // `gunnar-server` would vouch for an artifact nobody can serve from.
        assert_eq!(
            by_resolved_features(&set(&["server"])),
            None,
            "an engine-less `--features server` still attributes to the appliance variant, so \
             the one build the collapse exists to abolish would ship with a receipt saying \
             it is the appliance"
        );
        // The product rows attribute by their crates' defaults, named out loud.
        assert_eq!(
            by_resolved_features(&set(&["engine-znippy", "http", "replication"])).map(|c| c.name),
            Some("gunnar"),
        );
        // `gunnar-cli`'s set is also `gunnar-cli-musl`'s: only the target settles it.
        assert_eq!(by_resolved_features(&set(&["client", "control"])), None);
        assert_eq!(
            by_build_point(&set(&["client", "control"]), None).map(|c| c.name),
            Some("gunnar-cli"),
        );
        // The retired shapes (`gunnar-service`, `gunnar-solo`) are no row any more.
        assert_eq!(by_resolved_features(&set(&["server", "systemd"])), None);
        assert_eq!(
            by_resolved_features(&set(&["server", "client", "control"])),
            None
        );
        // `--all-features`: a superset, and not a variant.
        assert_eq!(
            by_resolved_features(&set(&["server", "client", "control", "systemd", "http"])),
            None,
            "a superset resolved to a variant, so `--all-features` would write a receipt \
             naming a build point that was not built"
        );
        // A subset is not a variant either.
        assert_eq!(by_resolved_features(&set(&["control"])), None);
        // And the empty set is not `gunnar-image`. This one HAS been red: the
        // container and ISO variants declare no features, so before the candidate
        // set was narrowed to the cargo variants, `--no-default-features` alone
        // resolved to `gunnar-image` — a variant that compiles nothing.
        assert_eq!(
            by_resolved_features(&BTreeSet::new()),
            None,
            "the empty feature set resolved to a variant that runs no cargo"
        );
    }

    /// Measured on all three refusals of [`attribute`], each watched red for
    /// its own reason and naming its own subject.
    #[test]
    fn attribution_refuses_a_set_a_target_and_a_profile_the_variant_denies() {
        let musl = "x86_64-unknown-linux-musl";
        // The appliance's resolved set. `["server"]` alone until 2026-08-10 — the
        // engine is a feature of this package now and the variant names it, so an
        // engine-less `--features server` is no longer this variant and no longer
        // anything (see `the_resolved_features_name_the_variant_and_refuse_when_they_do_not`).
        let appliance = || {
            set(&[
                "server",
                "engine-znippy",
                "mimalloc",
                "clock-fetch",
                "resolver-probe",
                "fleet-pull",
                "mirror-http",
                "sso-egress",
                "dhcp-client",
                "wg-client",
                "replication",
                "grow-runtime",
                "live-app",
            ])
        };

        // Green: the server variant, built for the target and profile it declares.
        let a = attribute(&appliance(), musl, "release");
        assert_eq!(a.variant().map(|c| c.name), Some("gunnar-server"));
        assert_eq!(a.note(), None, "a clean attribution warned about something");

        // Red 1: a feature set nobody declared.
        let a = attribute(
            &set(&[
                "server",
                "engine-znippy",
                "mimalloc",
                "clock-fetch",
                "resolver-probe",
                "fleet-pull",
                "mirror-http",
                "sso-egress",
                "dhcp-client",
                "wg-client",
                "http",
            ]),
            musl,
            "release",
        );
        assert!(matches!(a, Attribution::NoVariant { .. }), "{a:?}");
        let note = a
            .note()
            .expect("a refusal with no message cannot be acted on");
        assert!(
            note.contains("HTTP"),
            "the warning does not say what it saw: {note}"
        );
        assert!(
            note.contains(
                "gunnar-server={CLOCK_FETCH, DHCP_CLIENT, ENGINE_ZNIPPY, FLEET_PULL, GROW_RUNTIME, LIVE_APP, MIMALLOC, MIRROR_HTTP, REPLICATION, RESOLVER_PROBE, SERVER, SSO_EGRESS, WG_CLIENT}"
            ),
            "the warning does not say what it expected: {note}"
        );

        // Red 2: the right features, the wrong target. This is the one that would
        // otherwise write `target = musl` into a glibc binary.
        let a = attribute(&appliance(), "x86_64-unknown-linux-gnu", "release");
        assert!(
            matches!(a, Attribution::Mismatch { axis: "target", .. }),
            "{a:?}"
        );
        let note = a.note().expect("a refusal with no message");
        assert!(note.contains("gunnar-server"), "{note}");
        assert!(note.contains("musl"), "{note}");
        assert!(note.contains("gnu"), "{note}");
        assert_eq!(
            a.variant(),
            None,
            "a mismatched target still produced a variant"
        );

        // Red 3: the right features and target, a debug build of a variant that
        // declares `release`. `cargo build` without `--release` is exactly this.
        let a = attribute(&appliance(), musl, "debug");
        assert!(
            matches!(
                a,
                Attribution::Mismatch {
                    axis: "profile",
                    ..
                }
            ),
            "{a:?}"
        );
        let note = a.note().expect("a refusal with no message");
        assert!(note.contains("release"), "{note}");
        assert!(note.contains("debug"), "{note}");

        // And the "not measured" hole: no `PROFILE` at all must not be compared
        // against, because an empty string equals nothing and would refuse every
        // build. The target check still applies.
        assert_eq!(
            attribute(&appliance(), musl, "").variant().map(|c| c.name),
            Some("gunnar-server"),
            "an unset PROFILE was treated as a profile"
        );
    }

    /// **Which refusals are loud.** A `cargo:warning` on every `cargo build` in
    /// the repository is a warning nobody reads.
    ///
    /// Watched red in both directions: the silent case must stay silent, and the
    /// loud ones must stay loud — a `should_warn` that answered `false` for
    /// everything would pass the first half and switch the guard off.
    #[test]
    fn only_the_ordinary_developer_build_refuses_quietly() {
        let musl = "x86_64-unknown-linux-musl";

        // Silent: `cargo build`. MEASURED — a default build resolves DEFAULT on
        // top of everything, and every variant is `--no-default-features`, so no
        // ordinary developer command is ever a variant.
        let dev = attribute(
            &set(&["server", "client", "control", "default"]),
            musl,
            "debug",
        );
        assert!(matches!(dev, Attribution::NoVariant { .. }), "{dev:?}");
        assert!(!dev.should_warn("debug"), "every debug build would warn");
        assert!(
            dev.note().is_some(),
            "the reason is still recorded — the generated file carries it, only the \
             cargo:warning is suppressed"
        );
        // Same set, same silence, for the other refusal shape.
        assert!(!attribute(&set(&["server", "engine-znippy"]), musl, "debug").should_warn("debug"));

        // Loud: a RELEASE build that is not a variant is somebody producing
        // something and getting it wrong.
        assert!(attribute(&set(&["server", "http"]), musl, "release").should_warn("release"));
        // And this one is now loud for a NEW reason worth spelling out: a release
        // build of `--features server` with no engine named is not the appliance
        // any more, it is a server with no storage. It resolves to no variant at all.
        assert!(attribute(&set(&["server"]), musl, "release").should_warn("release"));
        assert!(attribute(
            &set(&[
                "server",
                "engine-znippy",
                "mimalloc",
                "clock-fetch",
                "resolver-probe",
                "fleet-pull",
                "mirror-http",
                "sso-egress",
                "dhcp-client",
                "wg-client"
            ]),
            "x86_64-unknown-linux-gnu",
            "release"
        )
        .should_warn("release"));
        // And a clean attribution says nothing, in any profile.
        let good = attribute(
            &set(&[
                "server",
                "engine-znippy",
                "mimalloc",
                "clock-fetch",
                "resolver-probe",
                "fleet-pull",
                "mirror-http",
                "sso-egress",
                "dhcp-client",
                "wg-client",
                "replication",
                "grow-runtime",
                "live-app",
            ]),
            musl,
            "release",
        );
        assert!(!good.should_warn("release"));
        assert!(!good.should_warn("debug"));
    }

    /// The declared-profile mapping, both ways.
    #[test]
    fn a_declared_profile_maps_to_the_word_cargo_puts_in_the_environment() {
        assert_eq!(cargo_profile_word("release"), "release");
        assert_eq!(cargo_profile_word("dev"), "debug");
        assert_eq!(cargo_profile_word("debug"), "debug");
        // A custom optimised profile. Guessed, and the guess is stated where it
        // is made; a wrong guess refuses a receipt rather than writing one.
        assert_eq!(cargo_profile_word("appliance"), "release");
        // The variants' own declarations must map to something cargo can produce.
        for c in crate::variants::VARIANTS
            .iter()
            .filter(|c| c.package.is_some())
        {
            let word = cargo_profile_word(c.profile_resolved().label());
            assert!(
                word == "debug" || word == "release",
                "{} maps to {word:?}, which cargo never sets",
                c.name
            );
        }
    }

    /// The feature universe keeps the features and drops the optional
    /// dependencies — held against the upstream directly since the 0.1.7 pin
    /// bump. This property used to be gunnar's own `features_table` slice, with
    /// a red-side canary asserting the upstream STILL over-reported; 0.1.7
    /// shipped the real fix (`declared_features` skips a dependency some
    /// feature names as `dep:<name>`), the canary tripped, and the slice came
    /// out exactly as `receipt_for`'s comment promised. What stays is the
    /// property the slice existed for, against the same manifest shape that
    /// measured the defect: `feature.gunnar-core = "false"` in a binary that
    /// links gunnar-core is a receipt that lies.
    #[test]
    fn the_feature_universe_keeps_features_and_drops_optional_dependencies() {
        let manifest = r#"
[package]
name = "gunnar-cli"

[features]
default = ["server"]
server = ["dep:gunnar-core"]
client = []

[dependencies]
gunnar-core = { version = "1", optional = true }
"#;
        let universe =
            receipt::resolved_feature_settings(manifest, |v| v == "CARGO_FEATURE_SERVER")
                .expect("the manifest parses");
        let keys: Vec<&str> = universe.keys().map(String::as_str).collect();
        assert_eq!(
            keys,
            vec!["feature.client", "feature.default", "feature.server"],
            "the upstream universe over-reports again — an optional dependency \
             reachable only as `dep:<name>` is not a feature"
        );
        assert_eq!(
            universe.get("feature.server").map(String::as_str),
            Some("true")
        );
        assert_eq!(
            universe.get("feature.client").map(String::as_str),
            Some("false")
        );

        // A manifest with no [features] at all is an empty universe, not an error.
        assert!(
            receipt::resolved_feature_settings("[package]\nname = \"x\"\n", |_| false)
                .expect("an empty features table parses")
                .is_empty()
        );
    }

    /// The receipt a variant would produce passes the audit that guards the writer —
    /// no absolute paths, no timestamps, a populated recipe hash.
    ///
    /// This is the check that would have caught `coordinate()` returning `None`
    /// for `hash`, which `receipt::audit_receipt` refuses outright.
    #[test]
    fn every_cargo_variant_produces_a_receipt_its_own_audit_accepts() {
        for variant in crate::variants::VARIANTS
            .iter()
            .filter(|c| c.package.is_some())
        {
            let mut b = ReceiptBuilder::new(
                GunnarBuildThing::coordinate(),
                variant.atom.as_str(),
                variant.column.as_str(),
            );
            for (k, v) in settings_for(variant) {
                b = b.setting(k, v);
            }
            let r = b.build().unwrap_or_else(|e| {
                panic!(
                    "{} produces a receipt its audit refuses: {e:#}",
                    variant.name
                )
            });
            assert!(
                receipt::audit_receipt(&r).is_empty(),
                "{} has flaws: {:?}",
                variant.name,
                receipt::audit_receipt(&r)
            );
            assert_eq!(r.build_thing.krate, crate::recipe::KRATE);
            assert_eq!(
                r.build_thing.hash.as_deref(),
                Some(crate::recipe::CONTENT_HASH),
                "{} does not pin the recipe that built it",
                variant.name
            );
            assert!(
                receipt::encode(&r).is_ok(),
                "{} does not encode",
                variant.name
            );
        }

        // Red side: strip the hash and the same audit refuses, by name.
        let mut r = ReceiptBuilder::new(
            GunnarBuildThing::coordinate(),
            "gunnar-server",
            Column::Exe.as_str(),
        )
        .build()
        .expect("a bare receipt is clean");
        r.build_thing.hash = None;
        let flaws = receipt::audit_receipt(&r);
        assert!(
            flaws
                .iter()
                .any(|f| f.to_string().contains("build_thing.hash")),
            "the audit accepts a receipt with no recipe hash, so the passes above are \
             not evidence: {flaws:?}"
        );
    }

    /// The recipe's content hash is a real sha256 over real bytes.
    ///
    /// It is `env!`-injected by `build.rs`, so the failure worth guarding is the
    /// build script silently producing nothing — an empty or placeholder value
    /// that every version of the recipe would share.
    #[test]
    fn the_content_hash_is_a_full_sha256_and_not_a_placeholder() {
        let h = crate::recipe::CONTENT_HASH;
        assert_eq!(h.len(), 64, "not a sha256: {h:?}");
        assert!(h.chars().all(|c| c.is_ascii_hexdigit()), "not hex: {h:?}");
        assert_ne!(
            h, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
            "the recipe hashed the EMPTY input — build.rs found no sources"
        );
        assert_eq!(
            GunnarBuildThing::coordinate().hash.as_deref(),
            Some(h),
            "the coordinate does not carry the hash the crate computed"
        );
    }

    /// The generated file's name is the writer's, not a second spelling of it.
    #[test]
    fn the_absent_file_uses_the_writers_own_file_name() {
        let dir = std::env::temp_dir().join(format!("gbt-absent-{}", std::process::id()));
        std::fs::create_dir_all(&dir).expect("temp dir");
        let why = Attribution::NoVariant {
            resolved: set(&["server", "http"]),
        };
        let p = write_absent(&dir, &why).expect("write");
        assert_eq!(p.file_name().unwrap(), receipt::GENERATED_FILE);
        let body = std::fs::read_to_string(&p).expect("read back");
        assert!(
            !body.contains("link_section"),
            "the absent file declares a section: {body}"
        );
        assert!(
            body.contains("HTTP"),
            "the absent file does not say why: {body}"
        );
        std::fs::remove_dir_all(&dir).ok();
    }

    /// `by_name` and the emitter agree about which variant is `gunnar-server`, and
    /// the receipt's `target` field is the COLUMN, not the triple.
    #[test]
    fn the_receipt_target_field_is_the_delivery_column() {
        let variant = by_name("gunnar-server").expect("the server variant");
        assert_eq!(variant.column.as_str(), "exe");
        let s = settings_for(variant);
        assert_eq!(s.get("column").map(String::as_str), Some("exe"));
        assert_eq!(
            s.get("target").map(String::as_str),
            Some("x86_64-unknown-linux-musl"),
            "the triple belongs in settings.target; the receipt's own `target` field is \
             the delivery column"
        );
    }
}