crates/gunnar-recipe/tests/twin_is_the_same_medium.rs
//! **A twin is the SAME medium as the primary it twins — so it cannot be
//! another binary.**
//!
//! This test exists because of one line that was wrong for two days and could
//! only have been found at the worst possible moment.
//!
//! `gunnar-twin` was a `[[build.installer]]` row of its own, made by cloning
//! `gunnar-installer-open` and changing four things: the volume id, `--role
//! twin` welded into `korp.args`, two `ZNIPPY_*` env tokens and
//! `korp.data.disks=vdb`. Cloning the KEYLESS row also cloned its `variant`,
//! `gunnar-server`. gunnar.rs's appliance is `gunnar-installer-metered`, whose
//! variant is `gunnar-server-metered` — the build point that links
//! `monetize-embed` and the entitlement gate — and `tests/metered_symbols.rs`
//! GUARANTEES, off the artifact's own symbol table, that `gunnar-server`
//! contains no entitlement symbol at all.
//!
//! **The twin exists to BECOME the primary.** Promoted after a restore, it
//! would have served gunnar.rs from a binary with no plan enforcement in it:
//! every suspended tenant live again, silently, with nothing on the box able to
//! say why — because nothing on the box would have been wrong. The medium was,
//! and a medium is read once, at mastering, months before the takeover that
//! needs it.
//!
//! **Since 2026-09-22 there is nothing to realize at all** (owner: "gunnar twin
//! must be built EXACTLY like the main, it MUST use the SAME iso"; "the weakest
//! machine must become the twin … a bootstrap thing from xtask"). The medium
//! carries no `role` and no `data_disks` parameter: every box installs as a
//! fresh appliance, and the twin is made one over the wire
//! (`Bootstrap.BecomeTwin`, after `cargo xtask elect twin --apply` in
//! private-gunnar-ops). Where `/data` goes is korp-installer's own election.
//! So the twin's medium IS the primary's medium — the same row, the same
//! variant, the same cmdline — and this file stops that from being undone: by a
//! twin row, by a role or disk parameter coming back, or by a role token baked
//! on a cmdline.
//!
//! Every assertion here is about the DECLARATION and costs no build.
use gunnar_recipe::GunnarBuildThing;
use nornir_build_thing::installer::InstallerBuild;
use nornir_build_thing::plugin::BuildThing;
fn installers() -> Vec<InstallerBuild> {
GunnarBuildThing.variants().installers
}
fn row(name: &str) -> InstallerBuild {
installers()
.into_iter()
.find(|i| i.name == name)
.unwrap_or_else(|| panic!("gunnar declares an installer row {name:?}"))
}
/// **The defect, pinned by name.** gunnar.rs's appliance is metered; its twin
/// installs that SAME row, so the twin lays the metered binary.
#[test]
fn the_twin_of_the_metered_appliance_is_metered() {
let primary = row(gunnar_recipe::METERED_INSTALLER);
assert_eq!(
primary.variant,
gunnar_recipe::METERED_VARIANT,
"the row gunnar.rs installs stopped naming the metered build point, so there is \
nothing for its twin to inherit"
);
}
/// ★ **No medium can be told what it is.** No installer row declares a `role`
/// or a `data_disks` parameter — FAILS ON THE OLD RECIPE, which declared both
/// on every row (2026-09-17 → 2026-09-22).
#[test]
fn no_medium_takes_a_role_or_a_disk_declaration() {
for i in installers() {
for p in &i.params {
assert!(
p.name != "role" && p.name != "data_disks",
"installer row {:?} declares the `{}` parameter (landing {:?}). The role is \
conferred over the wire (Bootstrap.BecomeTwin, from the election record) and \
the data disks are the installer's own election — a parameter for either is \
a second medium by another name",
i.name,
p.name,
p.boot_param
);
assert!(
p.boot_param != "korp.env.GUNNAR_ROLE" && p.boot_param != "korp.data.disks",
"{}: `{}` lands on {:?}, which says what the box is or where its data goes",
i.name,
p.name,
p.boot_param
);
}
}
}
/// **No row may be a twin, and no cmdline may say what a box is.**
#[test]
fn no_medium_is_a_twin() {
for i in installers() {
assert!(
!i.name.contains("twin") && !i.volume_id.contains("TWIN"),
"installer row {:?} (volume {:?}) names itself a twin. A twin is a role conferred \
over the wire, not a medium: the moment it is a row of its own, it is a row \
someone has to remember to keep in step with the primary's lineage — and the \
first time nobody did, the metered appliance's twin was unmetered",
i.name,
i.volume_id
);
for a in i.boot_params.iter().filter(|p| p.starts_with("korp.args=")) {
assert!(
!a.contains("--role"),
"{}: the role is welded into `korp.args` ({a:?})",
i.name
);
}
for p in &i.boot_params {
assert!(
!p.starts_with("korp.env.ZNIPPY_GIT_EXPLODE")
&& !p.starts_with("korp.env.ZNIPPY_GIT_GRAPH_CACHE")
&& !p.starts_with("korp.data.disks=")
&& !p.starts_with("korp.env.GUNNAR_ROLE="),
"{}: {p:?} is baked on the medium. What a box is and where its data goes are \
not the medium's to say (BecomeTwin; korp-installer's own disk election)",
i.name
);
}
}
}