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

nordisk/facett

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));
    }
}