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/variants.rs

//! **The build variants — every `[[build.variant]]` holger declares, as Rust.**
//!
//! ONE product list (lane HOL-PRODUCTS, owner 2026-10-30), the MVP suite:
//!
//! * the four products, each one crate and its `cargo install` line: `holger` (the
//!   server), `holger-downstream` (the airgapped downstream), `holger-ui` (the web
//!   console, in the holger-ui repository) and `holger-cli` (the command-line tool);
//! * what only an estate needs: the static appliance builds of the server and the
//!   downstream, the metered (sold) builds, holger's estate front, the three signed wasm
//!   plugins and the installer media.
//!
//! `cargo xtask build --suite MVP --list` prints it; `--features full` builds the products
//! with every extra. The model: variant → features → settings → typ. Each row is one
//! `(package × bin × features × profile × target)` point with its artifact kind, linkage
//! and suite. The reasoning behind a row is on the row; its history is in git
//! (`.nornir/SUITES.md` "History" says where the old suites went). `emit` overwrites the
//! emitted `.nornir/build-variants.toml`, so new reasoning goes HERE.

use std::collections::BTreeSet;

use nornir_build_thing::plugin::Role;
use nornir_build_thing::variant::{ArtifactKind, BuildVariant, Profile, ServiceShape};

/// The server's crate (`server/cli`): `cargo install holger`, and the estate's builds.
pub const SERVER_CLI: &str = "holger";
/// The downstream's crate (`holger-downstream/`): `cargo install holger-downstream`.
pub const DOWNSTREAM: &str = "holger-downstream";
/// Its directory: a workspace of its own (its `holger` edge with `downstream` must never
/// unify into the root's server), so its rows name it as their `manifest_dir`.
pub const DOWNSTREAM_MANIFEST_DIR: &str = "holger-downstream";
/// The command-line tool's crate (`holger-cli/`): `cargo install holger-cli`.
pub const HOLGER_CLI: &str = "holger-cli";
/// The web console's crate (holger-ui's `crates/holger-ui`): `cargo install holger-ui`.
pub const HOLGER_UI: &str = "holger-ui";
/// Where the console's crate is, from this repository's root (a sibling checkout).
pub const HOLGER_UI_MANIFEST_DIR: &str = "../holger-ui/crates/holger-ui";
/// The four products, in the order the docs name them: each a row of the same name that
/// builds the crate of that name with its defaults.
pub const PRODUCTS: [&str; 4] = [SERVER_CLI, DOWNSTREAM, HOLGER_UI, HOLGER_CLI];
/// The twelve MVP formats every server product serves by default (server/cli features).
pub const MVP_FORMATS: [&str; 12] = [
    "fmt-raw",
    "fmt-rust",
    "fmt-npm",
    "fmt-maven",
    "fmt-python",
    "fmt-docker",
    "fmt-go",
    "fmt-helm",
    "fmt-deb",
    "fmt-rpm",
    "fmt-znippy",
    "fmt-build-thing",
];
/// The static musl triple the appliance payload is cross-built for.
pub const MUSL: &str = "x86_64-unknown-linux-musl";

/// The suite member the service kinds install as.
const MEMBER: &str = "holger";

/// One row, spelled with only the fields holger's declaration uses.
struct Row {
    name: &'static str,
    suites: &'static [&'static str],
    role: Role,
    is_default: bool,
    package: Option<&'static str>,
    bin: Option<&'static str>,
    kind: ArtifactKind,
    member: bool,
    linkage: ServiceShape,
    reaches_holger: bool,
    features: &'static [&'static str],
    no_default_features: bool,
    target: Option<&'static str>,
    release: bool,
    container_ref: Option<&'static str>,
    /// `sign = { purpose = "plugin" }`: the forge writes `<artifact>.p7s` and
    /// `<artifact>.blake3` beside what the row built. Only the wasm guests.
    sign: bool,
}

impl Row {
    fn to_variant(&self) -> BuildVariant {
        BuildVariant {
            name: self.name.to_string(),
            package: self.package.map(str::to_string),
            bin: self.bin.map(str::to_string),
            features: self.features.iter().map(|f| (*f).to_string()).collect(),
            no_default_features: self.no_default_features,
            profile: if self.release {
                Profile::Release
            } else {
                Profile::Dev
            },
            target: self.target.map(str::to_string),
            member: self.member.then(|| MEMBER.to_string()),
            shape: self.linkage,
            role: Some(self.role),
            suites: self.suites.iter().map(|s| (*s).to_string()).collect(),
            is_default: self.is_default,
            kind: self.kind,
            container_ref: self.container_ref.map(str::to_string),
            sign: self.sign.then(nornir_build_thing::sign::SignSpec::default),
            reaches: if self.reaches_holger {
                BTreeSet::from([MEMBER.to_string()])
            } else {
                BTreeSet::new()
            },
            ..BuildVariant::default()
        }
    }
}

const FAT: ServiceShape = ServiceShape::FatService;
const THIN: ServiceShape = ServiceShape::ThinStandalone;

/// A cargo row: package + bin, release profile, no container ref.
#[allow(clippy::too_many_arguments)]
const fn cargo(
    name: &'static str,
    suites: &'static [&'static str],
    role: Role,
    is_default: bool,
    package: &'static str,
    bin: &'static str,
    kind: ArtifactKind,
    member: bool,
    linkage: ServiceShape,
    reaches_holger: bool,
    features: &'static [&'static str],
    no_default_features: bool,
    target: Option<&'static str>,
) -> Row {
    Row {
        name,
        suites,
        role,
        is_default,
        package: Some(package),
        bin: Some(bin),
        kind,
        member,
        linkage,
        reaches_holger,
        features,
        no_default_features,
        target,
        release: true,
        container_ref: None,
        sign: false,
    }
}

/// The wasm32 triple every guest row targets.
pub const WASM32: &str = "wasm32-unknown-unknown";

/// **A signed wasm guest row** — holger's OWN in-server plugins (`plugin/*-wasm`).
///
/// No bin (a `cdylib` package), release, `wasm32-unknown-unknown`, linkage
/// `not-applicable` said out loud (a guest reaches nothing over the wire; the
/// host decides what it may touch), role `library`, and `sign = { purpose =
/// "plugin" }` so the forge writes `<stem>.wasm.p7s` + `<stem>.wasm.blake3`
/// beside the module — the exact pair `holger-plugin-host` checks on load
/// (`guest_host::verify::ModuleTrust`, refused as `holger-plugin-6..9`).
const fn wasm_guest(name: &'static str, is_default: bool, package: &'static str) -> Row {
    Row {
        name,
        suites: &["MVP"],
        role: Role::Library,
        is_default,
        package: Some(package),
        bin: None,
        kind: ArtifactKind::Wasm,
        member: false,
        linkage: ServiceShape::NotApplicable,
        reaches_holger: false,
        features: &[],
        no_default_features: false,
        target: Some(WASM32),
        release: true,
        container_ref: None,
        sign: true,
    }
}

/// **Every build variant holger declares**, in declaration order (the menu and the
/// `(suite, role)` default groups iterate it, and the emitted toml follows it). The
/// console's row, the front's, the downstream medium's and the DEV rows are added by
/// [`variants`].
fn rows() -> [Row; 13] {
    use ArtifactKind::{Container, Exe, Installer, Iso, Service};
    use Role::{Client, Server};
    const MVP: &[&str] = &["MVP"];
    [
        // ══ the products: each row IS its `cargo install` line (twins.rs) ═════════
        //
        // holger — `cargo install holger`: the server with its defaults (the twelve
        // formats, the intake chain, no outbound client). The (MVP, server) normal case.
        cargo(
            SERVER_CLI,
            MVP,
            Server,
            true,
            SERVER_CLI,
            "holger",
            Exe,
            false,
            FAT,
            false,
            &[],
            false,
            None,
        ),
        // holger-downstream — `cargo install holger-downstream`: the airgapped gateway. It
        // trusts its one upstream's signed scan evidence (no scanner of its own) and
        // reaches that upstream only, a configured line, so `reaches` stays empty.
        cargo(
            DOWNSTREAM,
            MVP,
            Server,
            false,
            DOWNSTREAM,
            "holger-downstream",
            Exe,
            false,
            FAT,
            false,
            &[],
            false,
            None,
        ),
        // holger-cli — `cargo install holger-cli`: every console action as a command, and
        // the offline tools (the bundle, the verifier, the courier). THIN: it reaches a
        // holger at `--at` and nothing else. The (MVP, client) normal case.
        cargo(
            HOLGER_CLI,
            MVP,
            Client,
            true,
            HOLGER_CLI,
            "holger-cli",
            Exe,
            false,
            THIN,
            true,
            &[],
            false,
            None,
        ),
        // ══ the estate's builds of the server ════════════════════════════════════
        //
        // mvp-server-musl — the STATIC appliance payload: the server for the OS-less
        // installed shape (it rides `scratch` and the ISO), cross-built for musl. The
        // airgap box: the passkey door (no IdP inside a bubble), the appliance ceremony
        // (gated at run time by HOLGER_APPLIANCE=1), pairing, the built-in Allow meter
        // (no wasm runtime), the job queue, admission and the mirror. Zero egress.
        cargo(
            "mvp-server-musl",
            MVP,
            Server,
            false,
            SERVER_CLI,
            "holger-mvp",
            Exe,
            false,
            FAT,
            false,
            &[
                "mvp-server",
                "appliance",
                "paired",
                "auth-passkey",
                "sign",
                "allow-meter",
                "fmt-raw",
                "fmt-rust",
                "fmt-npm",
                "fmt-maven",
                "fmt-python",
                "fmt-docker",
                "fmt-go",
                "fmt-helm",
                "fmt-deb",
                "fmt-rpm",
                "fmt-znippy",
                "fmt-build-thing",
                "sync",
                "jobs",
                "supply-chain",
                "heimdall",
                "admission",
                "mirror",
            ],
            true,
            Some(MUSL),
        ),
        // mvp-server-metered — the SOLD server: the appliance's doors plus the paid state
        // (the signed `EntitlementFact` monetize pushes), the paid download admission, the
        // front page, the wasm host with the meter guests and the box's own advisory
        // fetch. A separate row, never a feature on the open one: an artifact either has
        // the door or it does not. Its own bin name keeps the two paths apart.
        cargo(
            "mvp-server-metered",
            MVP,
            Server,
            false,
            SERVER_CLI,
            "holger-mvp-metered",
            Service,
            true,
            FAT,
            false,
            &[
                "mvp-server",
                "appliance",
                "paired",
                "auth-passkey",
                "sign",
                "metered",
                "admit-share",
                "front",
                "wasm-plugins",
                "meter-guests",
                "fmt-raw",
                "fmt-rust",
                "fmt-npm",
                "fmt-maven",
                "fmt-python",
                "fmt-docker",
                "fmt-go",
                "fmt-helm",
                "fmt-deb",
                "fmt-rpm",
                "fmt-znippy",
                "fmt-build-thing",
                "sync",
                "jobs",
                "supply-chain",
                "heimdall",
                "admission",
                "intel-fetch",
                "mirror",
            ],
            true,
            None,
        ),
        // mvp-server-musl-metered — the static payload of the PAID medium
        // (`holger-installer-metered`). It consumes holger's own signed monetize plugin
        // (the edge `plugin → monetize-impl/holger-guest : wasm`, added in `variants()`),
        // which `server/lib/build.rs` embeds and refuses by name when it is another
        // commit's.
        cargo(
            "mvp-server-musl-metered",
            MVP,
            Server,
            false,
            SERVER_CLI,
            "holger-mvp-metered",
            Exe,
            false,
            FAT,
            false,
            &[
                "mvp-server",
                "appliance",
                "paired",
                "auth-passkey",
                "sign",
                "metered",
                "admit-share",
                "front",
                "wasm-plugins",
                "meter-guests",
                "fmt-raw",
                "fmt-rust",
                "fmt-npm",
                "fmt-maven",
                "fmt-python",
                "fmt-docker",
                "fmt-go",
                "fmt-helm",
                "fmt-deb",
                "fmt-rpm",
                "fmt-znippy",
                "fmt-build-thing",
                "sync",
                "jobs",
                "supply-chain",
                "heimdall",
                "admission",
                "intel-fetch",
                "mirror",
            ],
            true,
            Some(MUSL),
        ),
        // ══ the media's pointer rows (packaging.rs holds the media) ═══════════════
        //
        // A `kind = "container"` row carries no cargo argv; `container_ref` names its
        // [[build.container]] row.
        pointer(
            "holger-mvp-appliance",
            Container,
            Some(crate::packaging::APPLIANCE),
        ),
        // An installer or ISO row resolves its payload BY ITS OWN NAME, so it shares the
        // name of its [[build.installer]] / [[build.iso]] row. One medium serves the main
        // and the twin: the role is elected at bootstrap, never baked
        // (`packaging::appliance_iso`).
        pointer(crate::packaging::INSTALLER, Installer, None),
        pointer(crate::packaging::METERED_INSTALLER, Installer, None),
        pointer(crate::packaging::APPLIANCE_ISO, Iso, None),
        // ══ holger's own in-server wasm plugins, built in the pinned container and SIGNED
        // by the forge (`.p7s` + `.blake3`, what the plugin host verifies on load) ══
        //
        // plugin-allocation — the OPEN meter guest (Allow, no ceiling). The (MVP, library)
        // normal case.
        wasm_guest("plugin-allocation", true, "holger-plugin-allocation-wasm"),
        // plugin-skidbladnir — the Skidbladnir airgap-bundle package handler.
        wasm_guest(
            "plugin-skidbladnir",
            false,
            "holger-handler-skidbladnir-wasm",
        ),
        // plugin-rust-toolchain — the airgapped Rust-toolchain bundle handler.
        wasm_guest(
            "plugin-rust-toolchain",
            false,
            "holger-handler-rust-toolchain-wasm",
        ),
    ]
}

/// A media pointer row: no cargo argv, MVP, role server.
const fn pointer(
    name: &'static str,
    kind: ArtifactKind,
    container_ref: Option<&'static str>,
) -> Row {
    Row {
        name,
        suites: &["MVP"],
        role: Role::Server,
        is_default: false,
        package: None,
        bin: None,
        kind,
        member: false,
        linkage: FAT,
        reaches_holger: false,
        features: &[],
        no_default_features: false,
        target: None,
        release: false,
        container_ref,
        sign: false,
    }
}

/// **The console's row** (`holger-ui`): `cargo install holger-ui`, built from the sibling
/// holger-ui checkout. A client of holger: the bundle's host and a same-origin pass-through
/// to the holger it is pointed at. holger-ui's own declaration builds the bundle (trunk).
fn console_variant() -> BuildVariant {
    BuildVariant {
        manifest_dir: Some(HOLGER_UI_MANIFEST_DIR.to_string()),
        siblings: vec!["holger-ui".to_string()],
        ..cargo(
            HOLGER_UI,
            &["MVP"],
            Role::Client,
            false,
            HOLGER_UI,
            "holger-ui",
            ArtifactKind::Exe,
            false,
            THIN,
            true,
            &[],
            false,
            None,
        )
        .to_variant()
    }
}

/// The declared variants as nornir-build-thing's declaration type.
pub fn variants() -> Vec<BuildVariant> {
    let mut out: Vec<BuildVariant> = rows()
        .iter()
        .map(|r| {
            let mut v = r.to_variant();
            // The one consumption edge a cargo row declares: the metered musl
            // payload embeds holger's own signed plugin (see packaging.rs).
            if v.name == crate::packaging::METERED_PAYLOAD_VARIANT {
                let (feature, edge) = crate::packaging::own_plugin_edge();
                v.edges.insert(feature, edge);
            }
            v
        })
        .collect();
    // The console after the command-line tool's row, so the products read in a row.
    let at = out
        .iter()
        .position(|v| v.name == HOLGER_CLI)
        .map_or(out.len(), |i| i + 1);
    out.insert(at, console_variant());
    out.extend(front_variants());
    out.extend(downstream_variants());
    with_narrate_rows(&mut out);
    for v in out
        .iter_mut()
        .filter(|v| v.package.as_deref() == Some(DOWNSTREAM))
    {
        v.manifest_dir = Some(DOWNSTREAM_MANIFEST_DIR.to_string());
    }
    out
}

/// **A downstream's four rows** (lane OX-WGDS3, 2026-10-28; lane HOL-CDS-5, 2026-10-30): two
/// payloads and their media's pointers.
///
/// * `downstream-musl` — the ONE-WAY appliance: `holger-downstream` + `pid1` (its own init
///   without pairing, the medium's network, a HOLGER-INBOX stick's bundles into its inbox);
///   it dials nothing. Medium `holger-downstream-oneway-installer`.
/// * `downstream-fetch-musl` — the FETCHING appliance: the product's gateway plus `fetch` and
///   `downstream-wg` (the tunnel to its upstream's front from a signed invite, lane
///   HOL-WGDS) and `paired`, whose PID-1 duties (the reaper, the declared NIC by DHCP, the
///   clean stop) make it the box's init; with no pairing seed staged it pairs nothing.
///   Static musl for the OS-less medium.
/// * `holger-downstream-installer` — the medium's pointer; it shares the name of its
///   [[build.installer]] row.
fn downstream_variants() -> Vec<BuildVariant> {
    let row = |name: &'static str,
               package: Option<&'static str>,
               bin: Option<&'static str>,
               kind: ArtifactKind,
               features: &'static [&'static str],
               target: Option<&'static str>,
               release: bool| {
        Row {
            name,
            suites: &["MVP"],
            role: Role::Server,
            is_default: false,
            package,
            bin,
            kind,
            member: false,
            linkage: FAT,
            reaches_holger: false,
            features,
            no_default_features: false,
            target,
            release,
            container_ref: None,
            sign: false,
        }
        .to_variant()
    };
    vec![
        row(
            crate::packaging::ONEWAY_PAYLOAD_VARIANT,
            Some(DOWNSTREAM),
            Some(crate::packaging::DOWNSTREAM_ENTRY),
            ArtifactKind::Exe,
            ONEWAY_MEDIUM_FEATURES,
            Some(MUSL),
            true,
        ),
        row(
            crate::packaging::ONEWAY_INSTALLER,
            None,
            None,
            ArtifactKind::Installer,
            &[],
            None,
            false,
        ),
        row(
            crate::packaging::DOWNSTREAM_PAYLOAD_VARIANT,
            Some(DOWNSTREAM),
            Some(crate::packaging::FETCH_ENTRY),
            ArtifactKind::Exe,
            DOWNSTREAM_MEDIUM_FEATURES,
            Some(MUSL),
            true,
        ),
        row(
            crate::packaging::DOWNSTREAM_INSTALLER,
            None,
            None,
            ArtifactKind::Installer,
            &[],
            None,
            false,
        ),
    ]
}

/// The features of the ONE-WAY downstream medium's payload (lane HOL-CDS-5): its own init
/// without pairing, nothing that dials; its jobs under Heimdall (lane cds4, HOL-CDS-4).
pub const ONEWAY_MEDIUM_FEATURES: &[&str] = &["pid1", "heimdall"];
/// The features of the fetching downstream medium's payload (see [`downstream_variants`]); its
/// jobs under Heimdall (lane cds4, HOL-CDS-4).
pub const DOWNSTREAM_MEDIUM_FEATURES: &[&str] = &["fetch", "downstream-wg", "paired", "heimdall"];

/// The cargo feature DEV-NARRATE is (holger and holger-estate-front alike).
pub const DEV_NARRATE: &str = "dev-narrate";
/// The cargo profile the `…-narrate` rows build with (`[profile.dev-media]`, Gunnar's).
pub const DEV_MEDIA_PROFILE: &str = "dev-media";
/// What a payload's DEV row is called: `<payload>-narrate`.
pub const NARRATE_SUFFIX: &str = "-narrate";
/// The payloads whose medium carries the `dev-narrate` option: the estate's main/twin and
/// its front (and their keep media, which compose the same payloads).
pub const NARRATED_PAYLOADS: [&str; 2] = [
    crate::packaging::METERED_PAYLOAD_VARIANT,
    crate::packaging::FRONT_PAYLOAD_VARIANT,
];

/// The media whose installer row declares the `dev-narrate` option (packaging.rs).
pub const NARRATED_MEDIA: [&str; 4] = [
    crate::packaging::METERED_INSTALLER,
    crate::packaging::FRONT_INSTALLER_METERED,
    crate::packaging::KEEP_MEDIUM,
    crate::packaging::FRONT_KEEP_MEDIUM,
];

/// **DEV-NARRATE's build points** (owner 2026-10-19, Gunnar's `…-narrate` rows): each
/// narrated payload keeps `dev-narrate` a SWITCH (`open`, never decided), and beside it a
/// `<payload>-narrate` row names it — the row the medium's option switched ON resolves to.
/// The release media build the payload row itself: no sender is compiled in.
fn with_narrate_rows(out: &mut Vec<BuildVariant>) {
    // The four estate media's pointer rows carry the option's switch too (LAW A: an
    // installer's settings tree renders back to its pointer row's `open` axis).
    for v in out
        .iter_mut()
        .filter(|v| NARRATED_MEDIA.contains(&v.name.as_str()))
    {
        v.open.insert(DEV_NARRATE.to_string());
    }
    for name in NARRATED_PAYLOADS {
        let Some(i) = out.iter().position(|v| v.name == name) else {
            continue;
        };
        out[i].open.insert(DEV_NARRATE.to_string());
        let mut dev = out[i].clone();
        dev.name = format!("{name}{NARRATE_SUFFIX}");
        dev.open.remove(DEV_NARRATE);
        dev.features.push(DEV_NARRATE.to_string());
        dev.is_default = false;
        // Its own profile (Gunnar's `dev-media`): its own artifact, never the base row's.
        dev.profile = Profile::Custom(DEV_MEDIA_PROFILE.to_string());
        out.insert(i + 1, dev);
    }
}

/// **vm1's two rows** (2026-09-27): the payload and the medium's pointer.
///
/// * `estate-front-musl-metered` — holger's OWN front program
///   (`holger-estate-front`, bin of the same name), `metered` (the bare
///   monetize, the plugin door) over its default `console`, static musl for the
///   OS-less medium. Its crate is its own workspace — it links monetize and
///   holger-ui, which the open holger resolves nothing of — so the row names
///   `manifest_dir`. Kind `exe` (it ships inside the ISO).
/// * `holger-front-installer-metered` — the medium's pointer; it shares the
///   name of its [[build.installer]] row (`packaging::front_installer_metered`).
///
/// MVP, like the metered box medium it stands beside: one estate, two media — and the two
/// keep media's pointers (`holger-keep`, `holger-front-keep`), which the ONE shop upgrades a
/// sold estate from.
fn front_variants() -> Vec<BuildVariant> {
    let payload = BuildVariant {
        manifest_dir: Some(crate::packaging::FRONT_MANIFEST_DIR.to_string()),
        siblings: crate::front_siblings(),
        ..Row {
            name: crate::packaging::FRONT_PAYLOAD_VARIANT,
            suites: &["MVP"],
            role: Role::Server,
            is_default: false,
            package: Some("holger-estate-front"),
            bin: Some("holger-estate-front"),
            kind: ArtifactKind::Exe,
            member: false,
            linkage: FAT,
            reaches_holger: true,
            // `console` NAMED (it is the crate's default): a toggled feature needs
            // `no_default_features`, or the crate's default list decides behind the option.
            // `public-site`: holger.rs's public face (TASKS-12 S-6, owner 2026-10-25),
            // holger-ui's holger-public-site, which holds no HTTP client. The same row
            // ships every sold Holger front: there `HOLGER_UI_PUBLIC_SITE=off` turns it off.
            features: &["console", "metered", "public-site"],
            no_default_features: true,
            target: Some(MUSL),
            release: true,
            container_ref: None,
            sign: false,
        }
        .to_variant()
    };
    let pointer = |name: &'static str| {
        Row {
            name,
            suites: &["MVP"],
            role: Role::Server,
            is_default: false,
            package: None,
            bin: None,
            kind: ArtifactKind::Installer,
            member: false,
            linkage: FAT,
            reaches_holger: false,
            features: &[],
            no_default_features: false,
            target: None,
            release: false,
            container_ref: None,
            sign: false,
        }
        .to_variant()
    };
    let medium = Row {
        name: crate::packaging::FRONT_INSTALLER_METERED,
        suites: &["MVP"],
        role: Role::Server,
        is_default: false,
        package: None,
        bin: None,
        kind: ArtifactKind::Installer,
        member: false,
        linkage: FAT,
        reaches_holger: false,
        features: &[],
        no_default_features: false,
        target: None,
        release: false,
        container_ref: None,
        sign: false,
    }
    .to_variant();
    // The keep media's pointers (L7): each shares its [[build.installer]] row's name
    // (`packaging::keep_installer`, `packaging::front_keep_installer`).
    vec![
        payload,
        medium,
        pointer(crate::packaging::KEEP_MEDIUM),
        pointer(crate::packaging::FRONT_KEEP_MEDIUM),
    ]
}