facett-build-thing/tests/declared.rs
//! **facett declares its two PyPI wheels, so the forge has a door to them.**
//!
//! (Since 0.2.0 the components row is `facett-wheel` — PyPI `facett`, import `facett` —
//! and the demo app is a second package row, `facett-demo-wheel`. Until then it was
//! one row named `facet-wrapped-web` after its distribution; the history below is
//! that row's.)
//!
//! Written RED, before the crate it tests. What it is asserting is the second half
//! of HO-T5: edda now HAS `ArtifactKind::Package`, and a kind nobody declares is a
//! kind nobody can build. `xtask/tests/release_manifest.rs` states the gap in its
//! own module docs — *"The brief's door is `dwarves buildthing facett --variant
//! facet-wrapped-web`. That needs the forge to have an artifact kind for a
//! **package**, and it does not."* — and this file is what closes the sentence.
//!
//! # THE MODEL, and it decides the shape of every assertion here
//!
//! The 2026-08-27 law: **the CODE is the source.** `.nornir/build-variants.toml` is
//! EMITTED from the Rust `impl BuildThing` to DESCRIBE the build, and is never read
//! back as authority. So this test does not check that a file says the right thing.
//! It checks that the DECLARATION says it, and that the description survives being
//! written down — which is why every assertion below starts from
//! `FacettBuildThing.variants()` and only then looks at the emitted text.
//!
//! A test that loaded the toml and asserted on it would be asserting on the output
//! of the thing under test, and it would stay green if the code changed and the file
//! did not. That is the parity-mirror shape the law exists to end.
use nornir_build_thing::plugin::BuildThing;
use nornir_build_thing::variant::{ArtifactKind, BuildVariantSet};
use nornir_build_thing::package::PackageMember;
use facett_build_thing::{
emitted_toml, FacettBuildThing, DEMO_DISTRIBUTION, DEMO_OUT_DIR, DEMO_PIP_VARIANT, DEMO_SOURCE,
PIP_TOOLCHAIN_IMAGE, VARIANT,
};
#[test]
fn every_flow_capability_has_an_isolated_and_gpu_build() {
let manifest = std::fs::read_to_string(facett_build_thing::repo_root().join("facett-flow/Cargo.toml")).unwrap();
let mut in_features = false;
let mut features = Vec::new();
for line in manifest.lines().map(str::trim) {
if line.starts_with('[') { in_features = line == "[features]"; continue; }
if in_features && !line.starts_with('#') {
if let Some((name, _)) = line.split_once('=') {
let name = name.trim();
if !matches!(name, "default" | "wgpu" | "testmatrix") { features.push(name); }
}
}
}
let set = FacettBuildThing.variants();
let mut expected = facett_build_thing::FLOW_FEATURES.to_vec();
features.sort_unstable(); expected.sort_unstable();
assert_eq!(features, expected, "new rendering capabilities need proof rows");
for feature in features {
for gpu in [false, true] {
let name = format!("facett-flow-{feature}{}", if gpu { "-wgpu" } else { "" });
let row = set.get(&name).unwrap_or_else(|| panic!("missing {name}"));
assert_eq!(row.kind, ArtifactKind::Lib);
assert_eq!(row.package.as_deref(), Some("facett-flow"));
assert!(row.no_default_features);
let expected: Vec<String> = if gpu { vec![feature.into(), "wgpu".into()] } else { vec![feature.into()] };
assert_eq!(row.features, expected);
}
}
assert!(set.get("facett-flow-plain").unwrap().features.is_empty());
assert_eq!(set.get("facett-flow-wgpu").unwrap().features, ["wgpu"]);
let native = set.get("facett-flow-all").unwrap();
let wasm = set.get("facett-flow-all-wasm32").unwrap();
assert_eq!(native.features, wasm.features);
assert_eq!(wasm.target.as_deref(), Some("wasm32-unknown-unknown"));
assert_eq!(native.features.len(), expected.len() + 1);
}
/// The variant is declared, it is a package, and its cell says what the release is.
#[test]
fn the_components_wheel_is_a_declared_package_variant() {
let set = FacettBuildThing.variants();
let v = set
.get(VARIANT)
.expect("the components wheel is not declared — the forge has no door to it");
assert_eq!(
v.kind,
ArtifactKind::Package,
"declared as {:?}: `wasm` would make the forge build a bare .wasm and stop — \
no wheel, no sdist, no release set",
v.kind
);
let cell = set
.package(VARIANT)
.expect("the variant has no [[build.package]] cell, so nothing says what it produces");
assert_eq!(VARIANT, "facett-wheel");
assert_eq!(
cell.distribution, "facett",
"the distribution name is what `pip install` says, and what holger's PEP 503 \
index serves"
);
assert!(
!cell.sdist,
"the facett wheel carries PREBUILT wasm; an sdist that cannot rebuild it would be \
binaries labelled as source (0.2.0 decision)"
);
assert_eq!(
cell.image.as_deref(),
Some(PIP_TOOLCHAIN_IMAGE),
"no pinned toolchain image — `python -m build` would have to run on the HOST, \
and no python runs on the host"
);
assert_eq!(cell.out_dir, "pkg-facet-wrapped/dist", "the directory publish-pip already writes");
// THE SET, which is the whole reason this is a kind of its own.
assert_eq!(
cell.required_members(),
vec![PackageMember::Wheel, PackageMember::Sums, PackageMember::Provenance],
"a release is the wheel AND the sums a downloader checks it with AND the \
provenance over the produced bytes"
);
}
/// The DEMO app is its own package row (PyPI `facett-demo`): pure Python, so it has
/// no inputs and it DOES carry an sdist (that tarball really is its source).
#[test]
fn the_demo_wheel_is_a_declared_package_variant() {
let set = FacettBuildThing.variants();
let v = set.get(DEMO_PIP_VARIANT).expect("the demo wheel is not declared");
assert_eq!(v.kind, ArtifactKind::Package);
assert_eq!(DEMO_PIP_VARIANT, "facett-demo-wheel");
assert!(v.suites.iter().any(|s| s == "ORIGINAL"), "an untagged row cannot be selected by delivery");
let cell = set.package(DEMO_PIP_VARIANT).expect("no [[build.package]] cell for the demo");
assert_eq!(cell.distribution, DEMO_DISTRIBUTION);
assert_eq!(DEMO_DISTRIBUTION, "facett_demo");
assert_eq!(cell.source.as_deref(), Some(DEMO_SOURCE));
assert_eq!(cell.out_dir, DEMO_OUT_DIR);
assert!(cell.inputs.is_empty(), "nothing is BUILT into the demo wheel: {:?}", cell.inputs);
assert!(cell.sdist, "a pure-Python package's sdist is honest source");
assert_eq!(cell.image.as_deref(), Some(PIP_TOOLCHAIN_IMAGE));
assert_eq!(
cell.required_members(),
vec![PackageMember::Wheel, PackageMember::Sdist, PackageMember::Sums, PackageMember::Provenance]
);
// Two releases, two directories: one SHA256SUMS per release, never one listing both.
assert_ne!(cell.out_dir, set.package(VARIANT).unwrap().out_dir);
}
/// The wasm bundle is declared as an INPUT, by the same three filenames the wheel
/// verifier looks for inside the built zip.
///
/// This is the half that makes the door refuse honestly. `cargo xtask wrap-wasm`
/// produces these; nothing in a package build does. Declaring them means a forge
/// run before `wrap-wasm` refuses BY NAME on a missing (or 0-byte) input instead of
/// building a wheel that loads nothing — which is exactly what
/// `pip::check_wasm_bundle` does for the xtask door, now said in the declaration so
/// both doors ask the same question.
#[test]
fn the_wasm_bundle_is_declared_as_the_input_it_is() {
let set = FacettBuildThing.variants();
let cell = set.package(VARIANT).expect("declared");
let staged: Vec<(String, String)> = cell
.inputs
.iter()
.map(|r| cell.input_pair(r).expect("a well-formed input row"))
.collect();
for produced in ["facet_wrapped_bg.wasm", "facet_wrapped.js", "manifest.json"] {
let row = staged
.iter()
.find(|(from, _)| from.ends_with(produced))
.unwrap_or_else(|| panic!("{produced} is not staged — `cargo xtask wrap-wasm` writes it and the wheel needs it"));
assert!(
row.0.starts_with("facet-wrapped/dist/"),
"the input comes from somewhere other than wrap-wasm's output dir: {row:?}"
);
assert_eq!(
row.1,
format!("src/facett/assets/{produced}"),
"staged somewhere the wheel does not look for it — `verify_wheel` reads \
facett/assets/{produced} out of the built zip"
);
}
// index.html is package SOURCE, not build output. It must NOT be an input:
// staging it would mean the loader page came from somewhere other than the
// committed package, which is the one file facett's js guard scans.
assert!(
!staged.iter().any(|(f, _)| f.ends_with("index.html")),
"index.html is package source, not a build output"
);
}
/// The declaration survives being written down — the emitted description is the
/// code's, and it reads back EQUAL.
#[test]
fn the_emission_describes_the_declaration_and_reads_back() {
let set = FacettBuildThing.variants();
let text = emitted_toml().expect("facett's declaration emits");
assert!(text.contains("EMITTED, NOT SOURCE"), "the file does not say what it is:\n{text}");
assert!(text.contains("kind = \"package\""), "the emission lost the kind:\n{text}");
assert!(text.contains("[[build.package]]"), "the emission lost the cell:\n{text}");
// R1: this recipe needs a reader that knows BOTH vocabularies it uses, and it
// SAYS so — an older one refuses by name rather than with a serde error about a
// word the author spelled correctly.
//
// It moved from 3 to 4 when the wasm cell landed, and the move is the mechanism
// working rather than a number needing an update: `required_by` takes the MAX
// over what the set actually declares, so adding `[[build.wasm]]` to a recipe
// that already had `[[build.package]]` raises the floor for readers by itself.
// A recipe that declares neither still emits no header at all.
assert!(
text.contains("[nornir-build-thing]") && text.contains("schema = 4"),
"no schema-4 header: a reader without the wasm cell would refuse this whole \
file with `unknown field \\`wasm\\``\n{text}"
);
let back = BuildVariantSet::from_toml_str(&text).expect("the emission reads back");
assert_eq!(back, set, "the emitted description is not the declaration");
}
/// The declaration is VALID — every cell rule the engine has, run over it.
#[test]
fn the_declaration_validates() {
FacettBuildThing
.variants()
.validate_all()
.expect("facett's declaration does not validate");
}
// ─────────────────────────────────────────────────────────────────────────────
// ROAD B — the bundle is DECLARED, not remembered
// ─────────────────────────────────────────────────────────────────────────────
/// **The wasm cell exists, and it declares the two stages `wrap-wasm` runs.**
///
/// Until this row, the wheel's three inputs were produced by a step nobody
/// declared: a human ran `cargo xtask wrap-wasm` from memory and the door then
/// worked. Two lanes hand-built on 2026-09-06 for exactly that reason.
#[test]
fn the_wasm_bundle_is_a_declared_cell_with_typed_stages() {
use nornir_build_thing::wasm::BindgenTarget;
let set = FacettBuildThing.variants();
let v = set
.get("facet-wrapped-wasm")
.expect("the wasm variant is not on the roster — `--variant facet-wrapped-wasm` \
would answer `no such variant`, which is how tunnr ended up with seven \
undispatchable ISO cells");
assert_eq!(v.kind, ArtifactKind::Wasm);
assert_eq!(
v.target.as_deref(),
Some("wasm32-unknown-unknown"),
"a wasm variant without a wasm32 target does not validate"
);
let cell = set.wasm("facet-wrapped-wasm").expect("the wasm cell is not declared");
assert_eq!(cell.out_dir, "facet-wrapped/dist", "the directory wrap-wasm already writes");
// ① wasm-bindgen. `web` because the loader page is a plain
// `<script type="module">`, not a bundler build.
let b = cell.bindgen.as_ref().expect("no bindgen stage — the wheel's wasm and js are its output");
assert_eq!(b.target, BindgenTarget::Web);
assert!(!b.typescript, "a .d.ts nobody consumes is a file no declaration accounts for");
// ② the component manifest. THE STAGE THE ORDER DID NOT ASK FOR, and without
// which the wheel's third input stays undeclared and the door refuses on it one
// stage later.
let m = cell.manifest.as_ref().expect("no manifest stage — manifest.json is the wheel's third input");
assert_eq!(m.example, "manifest", "facet-wrapped/examples/manifest.rs prints it on stdout");
assert_eq!(m.file, "manifest.json");
}
/// **The wheel stages exactly what the bundle-group cells produce** — the
/// bijection, held HERE since 2026-09-29.
///
/// Until the bundle groups this test asserted `from_wasm == "facet-wrapped-wasm"`
/// and leaned on edda's `validate_package` for the rest. edda's `from_wasm` names
/// ONE producer cell and refuses every input that cell does not write, so a wheel
/// carrying three groups' bundles cannot name one: the edge is gone (the recipe
/// says so where it used to be) and its guarantee lives in this test until edda's
/// field becomes a list. `from_variant` stays refuted.
#[test]
fn the_wheel_stages_exactly_what_the_group_cells_produce() {
use facett_build_thing::BUNDLE_GROUPS;
let set = FacettBuildThing.variants();
let pkg = set.package(VARIANT).expect("declared");
assert!(pkg.from_wasm.is_none(), "edda's single-cell edge would refuse the non-core inputs");
assert!(
pkg.from_variant.is_empty(),
"from_variant is the REFUTED edge: it means `cargo-build this`, and cargo does \
not produce a wasm bundle — it would build an 11.6 MB file nothing consumes \
and then refuse for the same missing inputs, with a success in between"
);
let mut produced: Vec<String> = Vec::new();
for g in BUNDLE_GROUPS {
let cell = set.wasm(g.variant).unwrap_or_else(|| panic!("group '{}' has no wasm cell", g.name));
let v = set.get(g.variant).expect("declared");
let outs = cell.outputs(v);
assert_eq!(outs.len(), 3, "group '{}' cell produces {outs:?}", g.name);
produced.extend(outs);
}
// One direction: every input is written by a group cell…
for row in &pkg.inputs {
let (from, _) = pkg.input_pair(row).expect("well formed");
assert_eq!(
produced.iter().filter(|p| **p == from).count(),
1,
"the wheel stages `{from}`, which exactly one group cell must produce: {produced:?}"
);
}
// …and the other: nothing a group produces is left unstaged, because a bundle
// file the wheel forgets is a group the browser cannot load.
for out in &produced {
assert!(
pkg.inputs.iter().any(|r| r.starts_with(&format!("{out}:"))),
"a group cell produces `{out}` and the wheel does not stage it"
);
}
assert_eq!(pkg.inputs.len(), produced.len());
}
// ─────────────────────────────────────────────────────────────────────────────
// THE CARGO TOOLCHAIN — the row that decides whether the CODE is read at all
// ─────────────────────────────────────────────────────────────────────────────
/// **facett's `[build.toolchain]` is declared IN THE CODE and PINNED BY DIGEST.**
///
/// Written RED on 2026-09-06, and the defect it closes is the inversion this whole
/// crate exists to prevent. MEASURED on t14s, the real door:
///
/// ```text
/// ── kod · cargo build -p facett-build-thing --lib --release --target wasm32-unknown-unknown
/// ── kod · VÄGRAT: [build.toolchain] i `/home/rickard/git/facett`: [build.toolchain]
/// `nordisk-cargo-toolchain`: no `image_sha256` — a named tag is a convenience, NOT a
/// pin, and an unpinned build image can be replaced under you between two builds that
/// report the same provenance
/// ── väg · deklarationen (toml) — kodvägen VÄGRAD: …
/// ```
///
/// The refusal is CORRECT and the consequence is the bug: the forge falls back to
/// PARSING `.nornir/build-variants.toml`, so the emitted description becomes the
/// authority and the code is never asked. facett declared no toolchain at all — the
/// old `variants()` comment said "no `toolchain` (the package cell names its own
/// pinned image)", and that conflated two different images. `nordisk-pip-toolchain`
/// is where `python -m build` runs; `nordisk-cargo-toolchain` is where CARGO runs,
/// including the wasm build of THIS crate, which is the forge's front door
/// (`dwarves/crates/dwarves/src/build_thing/code.rs:607-608` loads the repo's
/// toolchain, `unwrap_or_default()`s it, and validates — an undeclared toolchain
/// arrives as the DEFAULT one, unpinned, and is refused).
///
/// Every assertion is a step the forge takes before it starts the container, in the
/// order it takes them, so a refusal lands here instead of at the door.
#[test]
fn the_cargo_toolchain_is_declared_in_code_and_pinned_by_digest() {
use nornir_build_thing::cargo_container::CARGO_TOOLCHAIN_IMAGE;
let set = FacettBuildThing.variants();
let tc = set.toolchain.as_ref().expect(
"facett declares no [build.toolchain] — the forge's code road takes the repo's \
toolchain or `CargoToolchain::default()`, and the default carries no \
`image_sha256`, so the kod road is REFUSED and the emitted toml becomes the \
authority",
);
assert_eq!(tc.image, CARGO_TOOLCHAIN_IMAGE, "one image for the constellation, not a second name");
// ① the refusal in the measurement above.
tc.validate().expect("the pin does not validate");
// ② the road the forge builds this very crate on.
tc.check_target("facett-build-thing-wasm", Some("wasm32-unknown-unknown"))
.expect("the declaration does not carry the wasm32 road the recipe crate is built on");
// ③ the declaration held against the ONLY thing that can put a std in the image.
tc.check_declared_targets().expect("declares a triple the committed Containerfile does not install");
// ④ the sibling checkouts facett's path dependencies reach into. Undeclared, the
// container sees only facett and cargo dies on `failed to read …/Cargo.toml`.
tc.check_escaping_path_deps(&facett_build_thing::repo_root())
.expect("a path dependency escapes into a sibling repo the declaration does not list");
// The pin survives being written down: the emission is what a reader sees.
let toml = emitted_toml().expect("the declaration emits");
assert!(toml.contains("[build.toolchain]"), "the emission carries no toolchain table");
assert!(
toml.contains(&format!("image_sha256 = \"{}\"", tc.image_sha256)),
"the emitted toml does not carry the declared digest"
);
}
// ─────────────────────────────────────────────────────────────────────────────
// THE DEMO — a product, not a library (2026-09-18)
// ─────────────────────────────────────────────────────────────────────────────
/// **Both demo rows are on the roster, and they are different artifacts.**
///
/// Written for the gap the earlier declaration left open on purpose and then did
/// not re-examine: "facett's seventy crates are LINKED, not built" is an argument
/// about LIBRARIES, and `facett-demo` is not one. It is a binary a human runs and a
/// page a browser loads, and before this row the only way to produce either was to
/// remember `cargo xtask demo-wasm` — the same undeclared-step shape Road B closed
/// for `wrap-wasm`.
#[test]
fn the_demo_is_declared_native_and_wasm() {
use facett_build_thing::{DEMO_PACKAGE, DEMO_VARIANT, DEMO_WASM_VARIANT};
let set = FacettBuildThing.variants();
let native = set
.get(DEMO_VARIANT)
.expect("facett-demo is not declared — the demo binary has no door");
assert_eq!(native.kind, ArtifactKind::Exe);
assert_eq!(native.package.as_deref(), Some(DEMO_PACKAGE));
assert!(
native.target.is_none(),
"the native row must not pin a target: it builds for the host, and a row that \
named one would build the demo for exactly one machine"
);
assert!(
!native.no_default_features && native.features.is_empty(),
"the native row re-states cargo's defaults, which makes it a second writer of them"
);
let web = set
.get(DEMO_WASM_VARIANT)
.expect("facett-demo-wasm is not declared — the gh-pages bundle has no door");
assert_eq!(web.kind, ArtifactKind::Wasm);
assert_eq!(web.package.as_deref(), Some(DEMO_PACKAGE));
assert_eq!(
web.target.as_deref(),
Some("wasm32-unknown-unknown"),
"a wasm variant without a wasm32 target does not validate"
);
assert_ne!(
native.name, web.name,
"one crate, two artifacts — a single row meaning 'the native one, unless…' \
cannot be dispatched by name"
);
}
/// **The wasm demo's feature axis is declared, and it has ONE writer.**
///
/// The axis is not decoration: `--no-default-features` drops the native-only
/// `region-clip`/osm-katana lanes that do not compile for wasm32, and the two GPU
/// lanes are what give the browser build the WebGPU backend and the real 3D OSM
/// render instead of the old glow/CPU painters. It lived as a string literal inside
/// `xtask::pages_cfg` — which was fine until this row existed, and then became two
/// places deciding what the browser build contains.
#[test]
fn the_wasm_demo_carries_the_gpu_axis_from_one_place() {
use facett_build_thing::{DEMO_WASM_CARGO_ARGS, DEMO_WASM_FEATURES, DEMO_WASM_FEATURE_LIST};
let set = FacettBuildThing.variants();
let web = set.get("facett-demo-wasm").expect("declared");
assert!(
web.no_default_features,
"without --no-default-features the wasm build pulls the native-only lanes and \
does not compile at all"
);
assert_eq!(
web.features,
DEMO_WASM_FEATURES.iter().map(|f| (*f).to_string()).collect::<Vec<_>>(),
"the row's features are not the declared axis"
);
// The two spellings of one fact, held equal. `DEMO_WASM_CARGO_ARGS` is what the
// xtask passes to `nornir_pages`; `DEMO_WASM_FEATURES` is what the row declares.
// A test is what makes that pair safe — a comment saying "keep these in sync" is
// how the literal in pages_cfg survived in the first place.
assert_eq!(
DEMO_WASM_FEATURE_LIST,
DEMO_WASM_FEATURES.join(","),
"the joined cargo argument and the declared feature list disagree"
);
assert_eq!(
DEMO_WASM_CARGO_ARGS,
["--no-default-features", "--features", DEMO_WASM_FEATURE_LIST],
"the cargo arguments the pages build passes are not the declared axis"
);
}
// ─────────────────────────────────────────────────────────────────────────────
// THE IMAGES — declared in FILE MODE, and the files are there
// ─────────────────────────────────────────────────────────────────────────────
/// **Every image this repo masters is declared, every cell is claimed by a row, and
/// every Containerfile is on disk.**
///
/// The set's own comment used to read "no containers/vms/isos/installers/kernels
/// (facett masters no media)". Half true: facett masters no vm/iso media, and it is
/// the only writer of three Containerfiles that `xtask` builds. An undeclared image
/// is the container-shaped version of the gap the demo rows closed.
///
/// `validate_in` already refuses a missing file; this asserts it from the test side
/// too, because the refusal only fires on a door somebody opens and a cell nobody
/// dispatches is exactly the tunnr failure this crate's tests keep citing.
#[test]
fn the_three_images_are_declared_in_file_mode_and_exist() {
use facett_build_thing::{repo_root, PIP_CONSUMER_IMAGE, PIP_TOOLCHAIN_IMAGE, STREAMLIT_IMAGE};
let set = FacettBuildThing.variants();
let root = repo_root();
for image in [PIP_TOOLCHAIN_IMAGE, PIP_CONSUMER_IMAGE, STREAMLIT_IMAGE] {
let v = set
.get(image)
.unwrap_or_else(|| panic!("{image} is not on the roster — `--variant {image}` would answer `no such variant`"));
assert_eq!(v.kind, ArtifactKind::Container);
assert_eq!(
v.container_ref.as_deref(),
Some(image),
"the row does not name its cell, which is a dangling delegation"
);
let cell = set
.container(image)
.unwrap_or_else(|| panic!("{image} has no [[build.container]] cell"));
assert!(
!cell.containerfile.trim().is_empty(),
"{image} is declared in SYNTHESIS mode: a synthesized cell cannot express a \
`RUN`, and all three of these recipes assert their own contents with one"
);
assert!(
cell.base.trim().is_empty() && cell.layers.is_empty(),
"{image} blends file mode with synthesis fields"
);
let on_disk = root.join(&cell.containerfile);
assert!(
on_disk.is_file(),
"{image} declares `{}`, which is not a file under {}",
cell.containerfile,
root.display()
);
}
// The cells and the rows are ONE list, not two that agree today.
assert_eq!(
set.containers.len(),
3,
"the container cells are {:?}",
set.containers.iter().map(|c| &c.name).collect::<Vec<_>>()
);
}
/// **The declaration validates against the checkout**, which is the half
/// `validate_all` cannot do: `validate_in` is what reads the disk, and a file-mode
/// cell pointing at a path nobody wrote is refused there and nowhere else.
#[test]
fn the_declaration_validates_against_this_checkout() {
let set = FacettBuildThing.variants();
let root = facett_build_thing::repo_root();
for c in &set.containers {
c.validate_in(&root)
.unwrap_or_else(|e| panic!("container '{}' does not validate against the checkout: {e:#}", c.name));
}
}