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

nordisk/Skidbladnir

src/vmsuite.rs

//! **VM-SYSTEMD-SUITE** — assert what systemd *resolved*, inside a real KVM guest.
//!
//! ## Why this exists
//!
//! Skidbladnir owns service creation, so a defect in what it installs is a defect in
//! every product that installs through it. But a unit renderer tested by
//! string-comparing its own output is the emptiest kind of green: it asserts what it
//! *wrote*, never what systemd *did* with it.
//!
//! The defect that forced this module, measured on host oden **2026-08-03**:
//! `korp-server --install --system` rendered `User=korp`, printed
//! `✓ installed korp-server systemd service (user korp)` — and the service then ran
//! as **`alice`**, because five stale drop-ins in
//! `/etc/systemd/system/korp-server.service.d/` (dated 25–31 July) overrode it, one
//! of them setting `User=alice`. Read back from `/proc/<pid>/environ`. **No
//! unit-rendering test could ever have caught that** — only asking a live systemd
//! what it resolved after the merge.
//!
//! ## The shape
//!
//! * The **guest** (`skidbladnir-scenario`, a static-musl binary in `probe/`)
//!   executes a host-authored [plan](crate::vmsuite::render_plan) against the guest's
//!   real init and reports one [`Facts`] line per case: `systemctl show`'s resolved
//!   properties, `systemctl cat` (fragment **plus** drop-ins), `/proc/<MainPID>/environ`
//!   and the live process's uid, and the unit's on-disk footprint.
//! * The **host** grades. Every verdict is a pure `fn(&Check, &Facts) -> Verdict`
//!   ([`judge`]) with no IO, so each guard can be driven RED on the host with
//!   synthetic facts.
//!
//! ## Every guard is proven falsifiable, twice
//!
//! A VM harness "passes" most easily by asserting the VM booted. Two independent
//! defences, because either alone can rot:
//!
//! 1. **Host unit tests** feed each judge synthetic facts and assert it returns
//!    `Fail` (see this module's `tests`). A judge that cannot say no is caught here.
//! 2. **Negative cases in the guest.** Several cases carry
//!    [`Expect::expect_pass`]` == false`: the suite plants a contradicting drop-in and
//!    requires the guard to go RED against a *live* systemd. A judge stuck on Pass
//!    fails those; a judge stuck on Fail fails the positive cases. Neither hollow
//!    direction survives.
//!
//! ## What a host-only test could not have caught
//!
//! [`SuiteCase::host_only_blind_spot`] records, per case, why. The load-bearing ones
//! are `dropin-user-override` and `reinstall-inherits-the-landmine` (a merge only a
//! live systemd performs) and `boot-ordering` (an activation order only a fresh boot
//! produces).

use std::path::PathBuf;
#[cfg(feature = "matrix")]
use std::path::Path;
use std::time::Duration;
#[cfg(feature = "matrix")]
use std::time::Instant;

#[cfg(feature = "matrix")]
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};

#[cfg(feature = "matrix")]
use crate::machine::kvm::KvmController;
#[cfg(feature = "matrix")]
use crate::machine::{ImageRef, MachineController, MachineSpec, NetMode, Provision, Readiness};
use crate::service::{Backend, RenderedService, Scope, ServiceSpec, renderer_for};

/// The unit the suite installs and abuses.
pub const UNIT: &str = "skidtest.service";
/// The dedicated non-root system user the spec declares. Non-root on purpose: a
/// service already running as root cannot demonstrate a `User=` override.
pub const SVC_USER: &str = "skidsvc";
/// The home `useradd --create-home` gives [`SVC_USER`]; systemd puts it in the
/// service's `HOME`, which is exactly what korp's defect got wrong.
pub const SVC_HOME: &str = "/var/lib/skidsvc";
/// The injected test service binary.
pub const EXEC: &str = "/usr/local/bin/skidbladnir-testsvc";
/// The in-guest scenario interpreter.
pub const SCENARIO: &str = "/usr/local/bin/skidbladnir-scenario";
/// The port the test service binds.
pub const TEST_PORT: u16 = 7070;
/// The host-readable virtio-serial report port.
pub const REPORT_PORT: &str = "/dev/virtio-ports/org.skidbladnir.report";
/// The deliberately-early control unit: a `sysinit.target` oneshot that CANNOT be
/// ordered after the network. It exists so the boot-ordering guard has a real red.
pub const EARLY_UNIT: &str = "skidearly.service";

// ─────────────────────────────── the facts wire ──────────────────────────────

/// One case's applied state, as the in-guest scenario reported it.
///
/// Mirrors `skidbladnir_probe::facts::Facts`. The two live in different cargo
/// workspaces (the guest crate may depend on nothing but `std`) and deliberately
/// share no type; the format is kept flat — strings and arrays of strings only — so
/// the hand-rolled emitter on one side and serde on the other cannot disagree about
/// anything subtler than a field name. [`tests::the_guest_facts_line_deserializes`]
/// pins a real emitted line.
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Facts {
    pub case: String,
    /// `"<exit> <argv>"` per command the case ran, in order.
    #[serde(default)]
    pub exits: Vec<String>,
    /// `KEY=VALUE` lines from `systemctl show`, plus the synthetic
    /// `NetworkOnlineActiveEnterTimestampMonotonic=`.
    #[serde(default)]
    pub show: Vec<String>,
    /// `systemctl cat <unit>` verbatim — fragment AND drop-ins.
    #[serde(default)]
    pub cat: String,
    /// `/proc/<MainPID>/environ`, as `KEY=VALUE`.
    #[serde(default)]
    pub proc_env: Vec<String>,
    /// The username the live process's real uid resolves to.
    #[serde(default)]
    pub proc_user: String,
    /// Unit-related paths that exist on disk right now.
    #[serde(default)]
    pub files: Vec<String>,
    /// `"<key>=<stdout>"` per [`PlanStep::Capture`] — the **bytes a command produced**
    /// in the guest, which is what an applied-output assertion needs and what an exit
    /// code cannot give (LAW 2: a malformed command's empty output is shaped exactly
    /// like a clean result).
    #[serde(default)]
    pub captures: Vec<String>,
    #[serde(default)]
    pub at: String,
}

impl Facts {
    /// The value of a `systemctl show` property, or `None` when the property was
    /// never captured.
    ///
    /// `None` and `Some("")` are **different**: systemd prints `Group=` for a unit
    /// with no group, and that empty string is an answer. A judge that conflated the
    /// two would read "I never asked" as "the answer is empty" — the exact shape of a
    /// check that cannot fail.
    pub fn show_value(&self, key: &str) -> Option<&str> {
        self.show
            .iter()
            .find_map(|l| l.strip_prefix(key).and_then(|r| r.strip_prefix('=')))
    }

    /// A `/proc/<MainPID>/environ` entry.
    pub fn env_value(&self, key: &str) -> Option<&str> {
        self.proc_env
            .iter()
            .find_map(|l| l.strip_prefix(key).and_then(|r| r.strip_prefix('=')))
    }

    /// A [`PlanStep::Capture`]'s stdout.
    ///
    /// `None` (never captured) and `Some("")` (ran and printed nothing) are different
    /// answers and every judge must treat them so — reading "I never asked" as "the
    /// answer is empty" is the exact shape of a check that cannot fail.
    pub fn capture(&self, key: &str) -> Option<&str> {
        self.captures
            .iter()
            .find_map(|l| l.strip_prefix(key).and_then(|r| r.strip_prefix('=')))
    }

    /// The `"<code> WAITFOR <waited>ms/<timeout>ms <argv…>"` audit line whose argv
    /// contains `needle`, as `(exit_code, waited_ms)`.
    ///
    /// This is how a case reports **how long an outcome took to arrive on the
    /// service's own schedule** — the number that separates "the server noticed by
    /// itself" from "the test slept long enough".
    pub fn waited(&self, needle: &str) -> Option<(i32, u64)> {
        self.exits
            .iter()
            .find(|l| l.contains(" WAITFOR ") && l.contains(needle))
            .and_then(|l| {
                let mut it = l.split_whitespace();
                let code = it.next()?.parse::<i32>().ok()?;
                it.next()?; // "WAITFOR"
                let waited = it.next()?.split_once("ms/")?.0.parse::<u64>().ok()?;
                Some((code, waited))
            })
    }

    /// Every drop-in systemd merged, from BOTH sources: the resolved `DropInPaths`
    /// property and the on-disk listing of `<unit>.d/`.
    ///
    /// Both, because they fail in opposite directions. `DropInPaths` is empty when the
    /// unit is not loaded — which is precisely the state a half-done uninstall leaves,
    /// so trusting it alone would call a machine with a live landmine clean. The disk
    /// listing is empty for a `/run` or `/usr/lib` drop-in, which `DropInPaths` names.
    pub fn drop_ins(&self) -> Vec<&str> {
        let mut v: Vec<&str> = self
            .show_value("DropInPaths")
            .unwrap_or("")
            .split_whitespace()
            .collect();
        for f in &self.files {
            if f.contains(".service.d/") && !f.ends_with('/') && !v.contains(&f.as_str()) {
                v.push(f);
            }
        }
        v.sort_unstable();
        v.dedup();
        v
    }

    /// `After=` as a list.
    pub fn after(&self) -> Vec<&str> {
        self.show_value("After")
            .unwrap_or("")
            .split_whitespace()
            .collect()
    }

    /// A monotonic-microsecond property, `None` when absent or unparseable, and
    /// `Some(0)` only when systemd genuinely reported 0 (= never activated).
    pub fn monotonic(&self, key: &str) -> Option<u64> {
        self.show_value(key).and_then(|v| v.trim().parse().ok())
    }
}

// ───────────────────────────────── the judges ────────────────────────────────

/// A guard's answer. `Fail` always carries the observed value, because a red whose
/// message does not say what it saw costs an extra VM boot to diagnose.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Verdict {
    Pass(String),
    Fail(String),
}

impl Verdict {
    pub fn is_pass(&self) -> bool {
        matches!(self, Verdict::Pass(_))
    }
    pub fn detail(&self) -> &str {
        match self {
            Verdict::Pass(s) | Verdict::Fail(s) => s,
        }
    }
}

/// What to assert about a case's applied state.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Check {
    /// systemd resolved `User=` to this, AND the live process really runs as it.
    ResolvedUser(String),
    /// The only drop-ins merged are these (usually none).
    NoForeignDropIns(Vec<String>),
    /// `true` ⇒ `ActiveState == active`. `false` ⇒ genuinely STOPPED
    /// (`inactive`/`failed`/not loaded) — NOT merely "not active", which a
    /// still-draining `deactivating` unit would satisfy. See [`judge_active`].
    Active(bool),
    /// No trace of the unit is left: not loaded, no fragment, nothing under
    /// `/etc/systemd/system/<unit>*`.
    CleanSlate,
    /// The live process's environment carries `key=value`.
    ProcEnv(String, String),
    /// The unit declares `After=network-online.target` AND actually activated at or
    /// after network-online.target did, in this boot.
    OrderedAfterNetworkOnline,
}

/// Grade `check` against `facts`. **Pure** — no IO, no clock, no environment — which
/// is what lets every one of these be driven RED from a host unit test.
///
/// The governing rule: a fact that was never captured is a **Fail**, never a Pass.
/// Absence of evidence read as evidence of correctness is how a guard stops being
/// able to fail at all.
pub fn judge(check: &Check, f: &Facts) -> Verdict {
    match check {
        Check::ResolvedUser(want) => judge_resolved_user(want, f),
        Check::NoForeignDropIns(allowed) => judge_no_foreign_drop_ins(allowed, f),
        Check::Active(want) => judge_active(*want, f),
        Check::CleanSlate => judge_clean_slate(f),
        Check::ProcEnv(k, v) => judge_proc_env(k, v, f),
        Check::OrderedAfterNetworkOnline => judge_ordered_after_network_online(f),
    }
}

fn judge_resolved_user(want: &str, f: &Facts) -> Verdict {
    let Some(resolved) = f.show_value("User") else {
        return Verdict::Fail(
            "systemd reported no `User` property at all — the unit is not loaded, so nothing was \
             resolved and there is nothing to pass"
                .into(),
        );
    };
    if resolved != want {
        return Verdict::Fail(format!(
            "systemd RESOLVED User={resolved:?}, the spec declares {want:?} (drop-ins merged: {:?})",
            f.drop_ins()
        ));
    }
    // The resolved property is only half the answer: the process is the other half.
    if !f.proc_user.is_empty() && f.proc_user != want {
        return Verdict::Fail(format!(
            "systemd resolved User={want:?} but the LIVE process runs as {:?} (/proc/<MainPID>/status)",
            f.proc_user
        ));
    }
    if let Some(env_user) = f.env_value("USER") {
        if env_user != want {
            return Verdict::Fail(format!(
                "systemd resolved User={want:?} but the live process's environ says USER={env_user:?}"
            ));
        }
    }
    Verdict::Pass(format!(
        "User={want} resolved, process uid={}, environ USER={}",
        if f.proc_user.is_empty() {
            "-"
        } else {
            &f.proc_user
        },
        f.env_value("USER").unwrap_or("-"),
    ))
}

fn judge_no_foreign_drop_ins(allowed: &[String], f: &Facts) -> Verdict {
    let found = f.drop_ins();
    let foreign: Vec<&str> = found
        .iter()
        .copied()
        .filter(|p| !allowed.iter().any(|a| a == p))
        .collect();
    if foreign.is_empty() {
        Verdict::Pass(format!("drop-ins merged: {found:?} (all declared)"))
    } else {
        Verdict::Fail(format!(
            "{} undeclared drop-in(s) are overriding this unit: {foreign:?}",
            foreign.len()
        ))
    }
}

/// **Grade `ActiveState` — and note that the two directions are NOT each other's
/// negation.**
///
/// `want = true` is `ActiveState == "active"`. `want = false` is *genuinely stopped* —
/// [`crate::systemd::state_is_stopped`], i.e. `inactive`, `failed`, or not loaded.
/// A unit in `deactivating` or `activating` satisfies NEITHER: it is transitional, and
/// grading it as either is a false green in the harness whose whole job is to catch
/// false greens.
///
/// It used to be `is_active == want`, so `want = false` was satisfied by
/// `deactivating` — a unit whose processes are all still running. The suite case that
/// grades it is `systemctl stop` → `Sleep(1500)` → collect, and a service that drains
/// for longer than 1.5 s therefore graded PASS on "it stopped" while it had not.
/// MEASURED on t14s 2026-08-25: a real service sat in `deactivating` for 6.4 s after
/// `StopUnit`. Same defect as the one fixed in the installer's stop wait (35ab55c),
/// found by sweeping every reader of `ActiveState` afterwards.
///
/// `failed` counts as stopped deliberately: a unit SIGKILLed after its stop timeout
/// settles there and never reaches `inactive`, so demanding `inactive` would go red on
/// exactly the services slowest to die.
fn judge_active(want: bool, f: &Facts) -> Verdict {
    let Some(state) = f.show_value("ActiveState") else {
        return Verdict::Fail("systemd reported no `ActiveState` — the unit is not loaded".into());
    };
    let satisfied = if want {
        state == "active"
    } else {
        crate::systemd::state_is_stopped(Some(state))
    };
    if satisfied {
        Verdict::Pass(format!(
            "ActiveState={state} (SubState={})",
            f.show_value("SubState").unwrap_or("-")
        ))
    } else {
        Verdict::Fail(format!(
            "ActiveState={state}, expected {}; Result={}, ExecMainStatus={}",
            if want {
                "active"
            } else {
                "stopped (inactive/failed) — a transitional state is not stopped"
            },
            f.show_value("Result").unwrap_or("-"),
            f.show_value("ExecMainStatus").unwrap_or("-"),
        ))
    }
}

fn judge_clean_slate(f: &Facts) -> Verdict {
    let mut problems: Vec<String> = Vec::new();
    match f.show_value("LoadState") {
        Some("not-found") | Some("") | None => {}
        Some(other) => problems.push(format!("LoadState={other} (systemd still knows this unit)")),
    }
    if let Some(frag) = f.show_value("FragmentPath") {
        if !frag.is_empty() {
            problems.push(format!("FragmentPath={frag} still on disk"));
        }
    }
    let leftovers: Vec<&String> = f
        .files
        .iter()
        .filter(|p| p.starts_with("/etc/systemd/system/skid"))
        .collect();
    if !leftovers.is_empty() {
        problems.push(format!(
            "{} leftover path(s): {leftovers:?}",
            leftovers.len()
        ));
    }
    if problems.is_empty() {
        Verdict::Pass("no fragment, no drop-in dir, unit unknown to systemd".into())
    } else {
        Verdict::Fail(format!(
            "uninstall left a landmine — {}",
            problems.join("; ")
        ))
    }
}

fn judge_proc_env(key: &str, want: &str, f: &Facts) -> Verdict {
    match f.env_value(key) {
        Some(v) if v == want => Verdict::Pass(format!("{key}={v}")),
        Some(v) => Verdict::Fail(format!(
            "the live process has {key}={v:?}, expected {want:?}"
        )),
        None => Verdict::Fail(format!(
            "the live process's environ has no {key} at all (MainPID={}, {} vars captured) — \
             nothing was read, so nothing can pass",
            f.show_value("MainPID").unwrap_or("-"),
            f.proc_env.len()
        )),
    }
}

fn judge_ordered_after_network_online(f: &Facts) -> Verdict {
    const NET: &str = "network-online.target";
    if !f.after().contains(&NET) {
        return Verdict::Fail(format!(
            "the unit does not declare After={NET} (After={:?}) — systemd was never asked to order it",
            f.after()
        ));
    }
    let (Some(unit_t), Some(net_t)) = (
        f.monotonic("ActiveEnterTimestampMonotonic"),
        f.monotonic("NetworkOnlineActiveEnterTimestampMonotonic"),
    ) else {
        return Verdict::Fail(
            "no activation timestamps were captured — an ordering claim needs two clocks".into(),
        );
    };
    if net_t == 0 {
        return Verdict::Fail(format!(
            "{NET} never became active in this boot, so there is nothing to be ordered after \
             (unit activated at {unit_t}µs monotonic)"
        ));
    }
    if unit_t == 0 {
        return Verdict::Fail("the unit never became active in this boot".into());
    }
    if unit_t < net_t {
        return Verdict::Fail(format!(
            "the unit activated {}µs BEFORE {NET} (unit {unit_t}µs, network {net_t}µs monotonic)",
            net_t - unit_t
        ));
    }
    Verdict::Pass(format!(
        "unit activated {}µs after {NET} ({unit_t} ≥ {net_t})",
        unit_t - net_t
    ))
}

// ────────────────────────────── the case model ───────────────────────────────

/// A step in the plan wire (host-side mirror of `skidbladnir_probe::plan::Step`).
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PlanStep {
    Run(Vec<String>),
    Write {
        path: String,
        mode: u32,
        contents: String,
    },
    Rm(String),
    RmTree(String),
    Sleep(u64),
    Collect {
        unit: String,
        exec: String,
    },
    /// Keep a command's **stdout** under `key` for the next `Collect` to carry.
    Capture {
        key: String,
        argv: Vec<String>,
    },
    /// Poll `argv` until it exits 0 or `timeout_ms` elapses; the waited-for latency is
    /// recorded in `exits`.
    WaitFor {
        timeout_ms: u64,
        poll_ms: u64,
        argv: Vec<String>,
    },
    PowerOff,
}

/// Convenience: `RUN systemctl <args…>`.
fn systemctl(args: &[&str]) -> PlanStep {
    let mut v = vec!["systemctl".to_string()];
    v.extend(args.iter().map(|s| s.to_string()));
    PlanStep::Run(v)
}

/// One expectation on a case's facts.
#[derive(Debug, Clone)]
pub struct Expect {
    /// Row name in the test matrix (`<case>::<name>`).
    pub name: String,
    pub check: Check,
    /// `false` marks a **deliberate red**: the case engineers a broken machine and the
    /// suite requires the guard to notice. This is what stops a judge from being
    /// hollow — see the module docs.
    pub expect_pass: bool,
}

impl Expect {
    pub fn pass(name: &str, check: Check) -> Self {
        Expect {
            name: name.into(),
            check,
            expect_pass: true,
        }
    }
    /// A guard that MUST go red here.
    pub fn red(name: &str, check: Check) -> Self {
        Expect {
            name: name.into(),
            check,
            expect_pass: false,
        }
    }
}

/// One case of the suite.
pub struct SuiteCase {
    pub id: String,
    pub steps: Vec<PlanStep>,
    pub checks: Vec<Expect>,
    /// Why a host-only (no-VM) test could not have caught what this case catches, or
    /// `""` for a setup case that asserts nothing. Data, not a comment, so the test
    /// can print it and a reviewer can audit the claim per case.
    pub host_only_blind_spot: &'static str,
}

impl SuiteCase {
    fn setup(id: &str, steps: Vec<PlanStep>) -> Self {
        SuiteCase {
            id: id.into(),
            steps,
            checks: Vec::new(),
            host_only_blind_spot: "",
        }
    }
}

/// Render the plan wire the guest interpreter parses.
///
/// Hex payloads and whitespace-split argv: see `skidbladnir_probe::plan` for the
/// grammar and why file bodies must not be escapable.
pub fn render_plan(cases: &[SuiteCase]) -> String {
    let mut s = String::from("# skidbladnir vm-suite plan\n");
    for c in cases {
        s.push_str(&format!("CASE {}\n", c.id));
        for step in &c.steps {
            match step {
                PlanStep::Run(argv) => s.push_str(&format!("RUN {}\n", argv.join(" "))),
                PlanStep::Write {
                    path,
                    mode,
                    contents,
                } => s.push_str(&format!(
                    "WRITE {path} {mode:04o} {}\n",
                    hex_encode(contents.as_bytes())
                )),
                PlanStep::Rm(p) => s.push_str(&format!("RM {p}\n")),
                PlanStep::RmTree(p) => s.push_str(&format!("RMTREE {p}\n")),
                PlanStep::Sleep(ms) => s.push_str(&format!("SLEEP {ms}\n")),
                PlanStep::Collect { unit, exec } => s.push_str(&format!("COLLECT {unit} {exec}\n")),
                PlanStep::Capture { key, argv } => {
                    s.push_str(&format!("CAPTURE {key} {}\n", argv.join(" ")))
                }
                PlanStep::WaitFor {
                    timeout_ms,
                    poll_ms,
                    argv,
                } => s.push_str(&format!(
                    "WAITFOR {timeout_ms} {poll_ms} {}\n",
                    argv.join(" ")
                )),
                PlanStep::PowerOff => s.push_str("POWEROFF\n"),
            }
        }
        s.push_str("END\n");
    }
    s
}

/// Lowercase hex (mirror of `skidbladnir_probe::hex_encode`; the guest crate cannot
/// be depended on from here — separate workspace, `publish = false`).
fn hex_encode(bytes: &[u8]) -> String {
    const D: &[u8; 16] = b"0123456789abcdef";
    let mut s = String::with_capacity(bytes.len() * 2);
    for b in bytes {
        s.push(D[(b >> 4) as usize] as char);
        s.push(D[(b & 0x0f) as usize] as char);
    }
    s
}

// ─────────────────────────── the service under test ──────────────────────────

/// The [`ServiceSpec`] the suite installs — built through the SAME public builder
/// every product uses, and rendered by the SAME [`renderer_for`] renderer, so the
/// thing under test is Skidbladnir's real unit path and not a fixture that resembles
/// it.
pub fn suite_service_spec() -> ServiceSpec {
    ServiceSpec::new("skidtest", "Skidbladnir VM systemd suite service", EXEC)
        .arg("--port")
        .arg(TEST_PORT.to_string())
        .arg("--name")
        .arg("skidtest")
        .user(SVC_USER)
        .scope(Scope::System)
        .after("network-online.target")
        .needs("network-online.target")
        .env("SKID_MARK", "vm-suite")
}

/// The rendered unit for [`suite_service_spec`].
pub fn suite_rendered() -> RenderedService {
    renderer_for(Backend::SystemdSystem)
        .expect("the systemd-system renderer is always present")
        .render(&suite_service_spec())
        .expect("the fixed suite spec renders")
}

/// The hostile drop-in the suite plants — the reproduction of korp's 2026-08-03
/// defect: a stale `.d/` file that silently wins over a correctly rendered unit.
pub const HOSTILE_DROP_IN: &str = "/etc/systemd/system/skidtest.service.d/99-stale-conflict.conf";

fn hostile_drop_in_body() -> String {
    "# A stale drop-in of exactly the kind that survived five korp uninstalls.\n\
     [Service]\n\
     User=root\n\
     Group=root\n\
     Environment=\"SKID_MARK=hijacked\"\n"
        .to_string()
}

/// The deliberately-early control unit: `DefaultDependencies=no` + `Before=sysinit.target`
/// makes systemd activate it long before any network target, so
/// [`Check::OrderedAfterNetworkOnline`] MUST go red on it. `Type=oneshot` +
/// `ExecStart=/bin/true` so it cannot delay or wedge the boot.
fn early_unit_body() -> String {
    "[Unit]\n\
     Description=Skidbladnir boot-ordering NEGATIVE control (activates before the network)\n\
     DefaultDependencies=no\n\
     Before=sysinit.target\n\
     [Service]\n\
     Type=oneshot\n\
     RemainAfterExit=yes\n\
     ExecStart=/bin/true\n\
     [Install]\n\
     WantedBy=sysinit.target\n"
        .to_string()
}

/// The oneshot unit that runs the boot-B plan late in the second boot.
fn boot_report_unit_body(plan_path: &str) -> String {
    format!(
        "[Unit]\n\
         Description=Skidbladnir VM suite boot-B reporter\n\
         After=multi-user.target network-online.target {UNIT}\n\
         [Service]\n\
         Type=oneshot\n\
         ExecStart={SCENARIO} --plan {plan_path} --report {REPORT_PORT} --also /var/log/skid-report-b.jsonl\n\
         [Install]\n\
         WantedBy=multi-user.target\n"
    )
}

/// Where the boot-B plan is staged inside the guest.
pub const PLAN_B_PATH: &str = "/var/lib/skid/plan-b.txt";

fn write_rendered(r: &RenderedService) -> Vec<PlanStep> {
    r.files
        .iter()
        .map(|f| PlanStep::Write {
            path: if f.path.starts_with('/') {
                f.path.clone()
            } else {
                format!("/{}", f.path)
            },
            mode: f.mode,
            contents: f.contents.clone(),
        })
        .collect()
}

/// **Boot A** — the lifecycle and drop-in suite: eight assertable cases in ONE boot.
///
/// Ordered as a story, because the interesting bugs are sequential: a clean install,
/// a stale drop-in hijacking it, the drop-in removed and the guard recovering, a
/// naive uninstall leaving that drop-in behind, and a *fresh, correct* install
/// silently inheriting it — which is korp's defect, reproduced from first principles.
pub fn plan_boot_a() -> Vec<SuiteCase> {
    let rendered = suite_rendered();
    let install = write_rendered(&rendered);
    let no_drop_ins = Check::NoForeignDropIns(Vec::new());
    let right_user = || Check::ResolvedUser(SVC_USER.to_string());
    let mut cases: Vec<SuiteCase> = Vec::new();

    cases.push(SuiteCase::setup(
        "prepare",
        vec![
            PlanStep::Run(vec![
                "/usr/sbin/useradd".into(),
                "--system".into(),
                "--home-dir".into(),
                SVC_HOME.into(),
                "--create-home".into(),
                "--shell".into(),
                "/usr/sbin/nologin".into(),
                SVC_USER.into(),
            ]),
            systemctl(&["daemon-reload"]),
        ],
    ));

    let bringup = |extra_sleep: u64| -> Vec<PlanStep> {
        vec![
            systemctl(&["daemon-reload"]),
            systemctl(&["enable", UNIT]),
            systemctl(&["start", UNIT]),
            PlanStep::Sleep(extra_sleep),
        ]
    };

    // 1 ── a clean install resolves to the declared user.
    let mut steps = install.clone();
    steps.extend(bringup(3000));
    steps.push(PlanStep::Collect {
        unit: UNIT.into(),
        exec: EXEC.into(),
    });
    cases.push(SuiteCase {
        id: "clean-install".into(),
        steps,
        checks: vec![
            Expect::pass("resolved-user", right_user()),
            Expect::pass("no-foreign-dropins", no_drop_ins.clone()),
            Expect::pass("active", Check::Active(true)),
            Expect::pass("proc-env-user", Check::ProcEnv("USER".into(), SVC_USER.into())),
            Expect::pass("proc-env-home", Check::ProcEnv("HOME".into(), SVC_HOME.into())),
            Expect::pass("proc-env-declared", Check::ProcEnv("SKID_MARK".into(), "vm-suite".into())),
        ],
        host_only_blind_spot:
            "`User=`/`HOME`/`Environment=` as the LIVE process received them come from \
             /proc/<MainPID>/environ of a process systemd forked. Nothing on the host reads that \
             for a unit the host never started.",
    });

    // 2 ── THE RED: a contradicting drop-in silently wins.
    cases.push(SuiteCase {
        id: "dropin-user-override".into(),
        steps: vec![
            PlanStep::Write {
                path: HOSTILE_DROP_IN.into(),
                mode: 0o644,
                contents: hostile_drop_in_body(),
            },
            systemctl(&["daemon-reload"]),
            systemctl(&["restart", UNIT]),
            PlanStep::Sleep(3000),
            PlanStep::Collect { unit: UNIT.into(), exec: EXEC.into() },
        ],
        checks: vec![
            Expect::red("resolved-user", right_user()),
            Expect::red("no-foreign-dropins", no_drop_ins.clone()),
            Expect::red("proc-env-user", Check::ProcEnv("USER".into(), SVC_USER.into())),
            Expect::red("proc-env-declared", Check::ProcEnv("SKID_MARK".into(), "vm-suite".into())),
            // Still running — which is what makes the bug so quiet in production.
            Expect::pass("active", Check::Active(true)),
        ],
        host_only_blind_spot:
            "This is korp's 2026-08-03 defect: the unit body still says User=skidsvc; only \
             systemd's own merge of fragment + drop-ins produces the wrong answer. A renderer \
             test reads the fragment and sees nothing wrong.",
    });

    // 3 ── the guard recovers: not stuck on fail.
    cases.push(SuiteCase {
        id: "dropin-removed".into(),
        steps: vec![
            PlanStep::Rm(HOSTILE_DROP_IN.into()),
            PlanStep::RmTree(format!("/etc/systemd/system/{UNIT}.d")),
            systemctl(&["daemon-reload"]),
            systemctl(&["restart", UNIT]),
            PlanStep::Sleep(3000),
            PlanStep::Collect { unit: UNIT.into(), exec: EXEC.into() },
        ],
        checks: vec![
            Expect::pass("resolved-user", right_user()),
            Expect::pass("no-foreign-dropins", no_drop_ins.clone()),
            Expect::pass("active", Check::Active(true)),
        ],
        host_only_blind_spot:
            "Proves the two guards above are not stuck on red — the same live systemd, the same \
             two judges, opposite verdict.",
    });

    // 4 ── stop: the Active guard proven in both directions.
    cases.push(SuiteCase {
        id: "stopped".into(),
        steps: vec![
            systemctl(&["stop", UNIT]),
            PlanStep::Sleep(1500),
            PlanStep::Collect { unit: UNIT.into(), exec: EXEC.into() },
        ],
        checks: vec![
            Expect::pass("inactive", Check::Active(false)),
            Expect::red("active", Check::Active(true)),
        ],
        host_only_blind_spot:
            "An ActiveState transition of a real system unit, driven by a real systemctl stop.",
    });

    // 5 ── a naive uninstall: unit file gone, drop-in dir left behind.
    cases.push(SuiteCase {
        id: "uninstall-naive-leaves-a-landmine".into(),
        steps: vec![
            PlanStep::Write {
                path: HOSTILE_DROP_IN.into(),
                mode: 0o644,
                contents: hostile_drop_in_body(),
            },
            systemctl(&["disable", UNIT]),
            PlanStep::Rm(format!("/etc/systemd/system/{UNIT}")),
            systemctl(&["daemon-reload"]),
            PlanStep::Collect { unit: UNIT.into(), exec: EXEC.into() },
        ],
        checks: vec![
            Expect::red("clean-slate", Check::CleanSlate),
            Expect::red("no-foreign-dropins", no_drop_ins.clone()),
        ],
        host_only_blind_spot:
            "The unit is now UNLOADED, so systemd reports DropInPaths= (empty). A guard trusting \
             only the resolved property would call this machine clean; only the on-disk \
             /etc/systemd/system/<unit>.d listing shows the landmine.",
    });

    // 6 ── the payload: a fresh, CORRECT install inherits the stale override.
    let mut steps = install.clone();
    steps.extend(bringup(3000));
    steps.push(PlanStep::Collect {
        unit: UNIT.into(),
        exec: EXEC.into(),
    });
    cases.push(SuiteCase {
        id: "reinstall-inherits-the-landmine".into(),
        steps,
        checks: vec![
            Expect::red("resolved-user", right_user()),
            Expect::red("no-foreign-dropins", no_drop_ins.clone()),
            Expect::red("proc-env-user", Check::ProcEnv("USER".into(), SVC_USER.into())),
            Expect::pass("active", Check::Active(true)),
        ],
        host_only_blind_spot:
            "korp's defect END TO END: an install that rendered the right unit and reported \
             success, running as the wrong user. The install is correct; the machine is not.",
    });

    // 7 ── a thorough uninstall really is clean.
    cases.push(SuiteCase {
        id: "uninstall-thorough".into(),
        steps: vec![
            systemctl(&["disable", "--now", UNIT]),
            PlanStep::Rm(format!("/etc/systemd/system/{UNIT}")),
            PlanStep::RmTree(format!("/etc/systemd/system/{UNIT}.d")),
            systemctl(&["daemon-reload"]),
            systemctl(&["reset-failed", UNIT]),
            PlanStep::Sleep(500),
            PlanStep::Collect { unit: UNIT.into(), exec: EXEC.into() },
        ],
        checks: vec![Expect::pass("clean-slate", Check::CleanSlate)],
        host_only_blind_spot:
            "Proves the clean-slate guard is not stuck on red, against the same live systemd \
             that reported the landmine one case earlier.",
    });

    // 8 ── install → uninstall → install round-trips with no residue.
    let mut steps = install.clone();
    steps.extend(bringup(3000));
    steps.push(PlanStep::Collect {
        unit: UNIT.into(),
        exec: EXEC.into(),
    });
    cases.push(SuiteCase {
        id: "reinstall-clean-roundtrip".into(),
        steps,
        checks: vec![
            Expect::pass("resolved-user", right_user()),
            Expect::pass("no-foreign-dropins", no_drop_ins),
            Expect::pass("active", Check::Active(true)),
            Expect::pass("proc-env-user", Check::ProcEnv("USER".into(), SVC_USER.into())),
        ],
        host_only_blind_spot:
            "After a thorough uninstall, the SAME spec installs to the SAME resolved state — the \
             round-trip property, asserted against systemd's merge rather than a rendered string.",
    });

    // 9 ── arm the second boot, then power off.
    cases.push(SuiteCase::setup(
        "arm-boot-b",
        vec![
            PlanStep::Write {
                path: format!("/etc/systemd/system/{EARLY_UNIT}"),
                mode: 0o644,
                contents: early_unit_body(),
            },
            PlanStep::Write {
                path: PLAN_B_PATH.into(),
                mode: 0o644,
                contents: render_plan(&plan_boot_b()),
            },
            PlanStep::Write {
                path: "/etc/systemd/system/skid-bootreport.service".into(),
                mode: 0o644,
                contents: boot_report_unit_body(PLAN_B_PATH),
            },
            systemctl(&["daemon-reload"]),
            systemctl(&["enable", EARLY_UNIT]),
            systemctl(&["enable", "skid-bootreport.service"]),
            systemctl(&["enable", UNIT]),
            PlanStep::PowerOff,
        ],
    ));

    cases
}

/// **Boot B** — what only a fresh boot can show: did systemd honour the ordering it
/// was given?
///
/// Run by `skid-bootreport.service` in the second boot of the SAME disk, so the unit
/// was brought up by systemd from its `[Install]` wants — not by a `systemctl start`
/// whose timing would mean nothing.
pub fn plan_boot_b() -> Vec<SuiteCase> {
    vec![
        SuiteCase {
            id: "boot-ordering".into(),
            steps: vec![PlanStep::Collect {
                unit: UNIT.into(),
                exec: EXEC.into(),
            }],
            checks: vec![
                Expect::pass(
                    "ordered-after-network-online",
                    Check::OrderedAfterNetworkOnline,
                ),
                Expect::pass("active", Check::Active(true)),
                Expect::pass("resolved-user", Check::ResolvedUser(SVC_USER.to_string())),
                Expect::pass("no-foreign-dropins", Check::NoForeignDropIns(Vec::new())),
            ],
            host_only_blind_spot: "ONLY a fresh boot produces this: systemd, not a test, decided when to activate \
                 the unit relative to network-online.target. It also proves the install survived \
                 a reboot as the declared user.",
        },
        SuiteCase {
            id: "boot-ordering-early-control".into(),
            steps: vec![PlanStep::Collect {
                unit: EARLY_UNIT.into(),
                exec: "/bin/true".into(),
            }],
            checks: vec![Expect::red(
                "ordered-after-network-online",
                Check::OrderedAfterNetworkOnline,
            )],
            host_only_blind_spot: "The NEGATIVE control for the ordering guard, and it is only obtainable from a \
                 boot: a sysinit.target oneshot that genuinely activated before the network.",
        },
        SuiteCase::setup("boot-b-done", vec![PlanStep::PowerOff]),
    ]
}

// ──────────────────────────────── the driver ─────────────────────────────────

/// Where the suite finds its inputs and puts its scratch.
#[derive(Debug, Clone)]
pub struct SuiteConfig {
    /// The cached cloud qcow2. Never booted directly — a per-run copy is made, so a
    /// shared base image cannot be mutated (`draupnir`'s `BootloaderDisk` has no
    /// per-drive `snapshot=on`; see `KvmController::to_boot_spec`'s COW gap note).
    pub base_image: PathBuf,
    pub work_root: PathBuf,
    pub scenario_bin: PathBuf,
    pub testsvc_bin: PathBuf,
    pub probe_bin: PathBuf,
    pub boot_timeout: Duration,
    /// How long to let boot A keep running after its terminal marker, so cloud-init's
    /// `scripts-user` module returns (writing its per-instance semaphore) and the
    /// scheduled power-off lands. Kill the guest before that and the second boot
    /// re-runs the whole plan from cloud-init instead of being a fresh boot.
    pub shutdown_grace: Duration,
    pub memory_mb: u32,
    pub cpus: u32,
}

/// One graded expectation.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Outcome {
    pub case: String,
    pub check: String,
    pub verdict: Verdict,
    /// What the case declared it wanted the guard to say.
    pub expect_pass: bool,
    /// The guard behaved as declared. **This** is the suite's pass/fail, not
    /// `verdict.is_pass()` — a deliberate-red case passes by going red.
    pub as_declared: bool,
    /// Milliseconds from the boot's start to this case's facts line arriving.
    pub elapsed_ms: u128,
}

/// The result of a whole suite run.
#[derive(Debug, Default)]
pub struct SuiteRun {
    pub outcomes: Vec<Outcome>,
    pub facts: Vec<Facts>,
    /// `(case, wall-clock ms since that boot started)` in arrival order.
    pub case_timings: Vec<(String, u128)>,
    pub boot_a_ms: u128,
    pub boot_b_ms: u128,
    /// The case ids boot B reported. If this contains a boot-A case, boot B was a
    /// cloud-init REPLAY rather than a fresh boot of an installed system — and its
    /// ordering facts would then be meaningless.
    pub boot_b_cases: Vec<String>,
    /// Anything the run could not determine, verbatim.
    pub notes: Vec<String>,
}

impl SuiteRun {
    pub fn failures(&self) -> Vec<&Outcome> {
        self.outcomes.iter().filter(|o| !o.as_declared).collect()
    }
}

/// Grade every case's facts. Cases with no facts line are graded as a **hard fail**
/// per expectation, never skipped: a case that did not report is a case that asserted
/// nothing, and silence must not read as success.
pub fn grade(cases: &[SuiteCase], facts: &[Facts], arrival_ms: &[(String, u128)]) -> Vec<Outcome> {
    let mut out = Vec::new();
    for c in cases {
        if c.checks.is_empty() {
            continue;
        }
        let elapsed = arrival_ms
            .iter()
            .find(|(id, _)| *id == c.id)
            .map(|(_, ms)| *ms)
            .unwrap_or(0);
        match facts.iter().find(|f| f.case == c.id) {
            Some(f) => {
                for e in &c.checks {
                    let v = judge(&e.check, f);
                    let as_declared = v.is_pass() == e.expect_pass;
                    out.push(Outcome {
                        case: c.id.clone(),
                        check: e.name.clone(),
                        verdict: v,
                        expect_pass: e.expect_pass,
                        as_declared,
                        elapsed_ms: elapsed,
                    });
                }
            }
            None => {
                for e in &c.checks {
                    out.push(Outcome {
                        case: c.id.clone(),
                        check: e.name.clone(),
                        verdict: Verdict::Fail(
                            "no facts line arrived for this case — it asserted NOTHING".into(),
                        ),
                        expect_pass: e.expect_pass,
                        as_declared: false,
                        elapsed_ms: 0,
                    });
                }
            }
        }
    }
    out
}

/// The cloud-init `user-data` for boot A: mount the payload, install the three
/// injected binaries, stage the plan, run the scenario.
///
/// Pure (strings in → string out) so its shape is unit-testable without booting.
pub fn render_user_data(plan_written_to: &str) -> String {
    format!(
        "#cloud-config\n\
         # Skidbladnir VM systemd suite — boot A.\n\
         runcmd:\n\
         \x20 - [ sh, -c, \"mkdir -p /mnt/skid; for d in /dev/vd* /dev/sd*; do mount -t vfat $d /mnt/skid 2>/dev/null && [ -f /mnt/skid/skidbladnir-scenario ] && break; umount /mnt/skid 2>/dev/null; done\" ]\n\
         \x20 - [ sh, -c, \"install -m0755 /mnt/skid/skidbladnir-scenario /usr/local/bin/skidbladnir-scenario; install -m0755 /mnt/skid/skidbladnir-testsvc {EXEC}; install -m0755 /mnt/skid/skidbladnir-probe /usr/local/bin/skidbladnir-probe\" ]\n\
         \x20 - [ sh, -c, \"mkdir -p /var/lib/skid; cp /mnt/skid/plan.txt {plan_written_to}\" ]\n\
         \x20 - [ sh, -c, \"{SCENARIO} --plan {plan_written_to} --report {REPORT_PORT} --also /var/log/skid-report-a.jsonl\" ]\n"
    )
}

/// The FAT payload image (label `skiddata`) — authored by the ONE seed builder
/// (`draupnir::seed::build_fat_image`), never a twinned `fatfs` call (dup-audit L5).
#[cfg(feature = "matrix")]
fn build_payload(out: &Path, cfg: &SuiteConfig, plan: &str) -> Result<()> {
    let files: Vec<(String, Vec<u8>)> = vec![
        (
            "skidbladnir-scenario".into(),
            std::fs::read(&cfg.scenario_bin)
                .with_context(|| format!("read {}", cfg.scenario_bin.display()))?,
        ),
        (
            "skidbladnir-testsvc".into(),
            std::fs::read(&cfg.testsvc_bin)
                .with_context(|| format!("read {}", cfg.testsvc_bin.display()))?,
        ),
        (
            "skidbladnir-probe".into(),
            std::fs::read(&cfg.probe_bin)
                .with_context(|| format!("read {}", cfg.probe_bin.display()))?,
        ),
        ("plan.txt".into(), plan.as_bytes().to_vec()),
    ];
    draupnir::seed::build_fat_image(out, "skiddata", &files)?;
    Ok(())
}

/// Parse every complete facts line present in `text`, ignoring the scenario's own
/// start/end markers and any partial trailing line.
pub fn parse_report(text: &str) -> Vec<Facts> {
    let mut out = Vec::new();
    for line in text.lines() {
        let line = line.trim().trim_matches('\0').trim();
        if !line.starts_with('{') || !line.ends_with('}') {
            continue;
        }
        if let Ok(f) = serde_json::from_str::<Facts>(line) {
            if !f.case.is_empty() {
                out.push(f);
            }
        }
    }
    out
}

/// The scenario's terminal marker. Waiting for it — not merely for the last
/// *asserting* case — is load-bearing: the arming case that stages boot B runs
/// AFTER the last assertion, and stopping the guest at the last assertion killed it
/// mid-cloud-init (measured on oden 2026-08-03, which is why this exists).
#[cfg(feature = "matrix")]
const END_MARKER: &str = "\"scenario_end\"";

/// Tail the host-side serial file until every id in `want` has arrived AND the
/// scenario reported it was done (or the timeout), stamping each case's **arrival
/// wall-clock** relative to `t0` — the honest per-case cost of the suite, since the
/// guest does not time itself.
#[cfg(feature = "matrix")]
fn tail_report(
    path: &Path,
    want: &[String],
    t0: Instant,
    timeout: Duration,
) -> (Vec<Facts>, Vec<(String, u128)>, bool) {
    let deadline = t0 + timeout;
    let mut seen: Vec<Facts> = Vec::new();
    let mut timings: Vec<(String, u128)> = Vec::new();
    let mut ended = false;
    loop {
        if let Ok(text) = std::fs::read_to_string(path) {
            for f in parse_report(&text) {
                if !seen.iter().any(|s| s.case == f.case) {
                    timings.push((f.case.clone(), t0.elapsed().as_millis()));
                    seen.push(f);
                }
            }
            ended = text.contains(END_MARKER);
        }
        if ended && want.iter().all(|w| seen.iter().any(|f| f.case == *w)) {
            return (seen, timings, true);
        }
        if Instant::now() >= deadline {
            return (seen, timings, ended);
        }
        std::thread::sleep(Duration::from_millis(750));
    }
}

#[cfg(feature = "matrix")]
fn boot_once(
    cfg: &SuiteConfig,
    name: &str,
    disk: &Path,
    payload: Option<&Path>,
    user_data: String,
    report_path: &Path,
) -> Result<(KvmController, crate::machine::Handle)> {
    let _ = std::fs::write(report_path, b"");
    let spec = MachineSpec {
        name: name.to_string(),
        image: ImageRef::Path(disk.to_path_buf()),
        cpus: cfg.cpus,
        memory_mb: cfg.memory_mb,
        // cloud-init's first boot wants a datasource + package mirror reachability;
        // the suite itself installs nothing from the network.
        net: NetMode::Nat,
        provision: Provision::CloudInit {
            user_data,
            meta_data: None,
        },
        mounts: Vec::new(),
        readiness: Readiness::Immediate,
        iso: None,
        data_iso: payload.map(|p| p.to_path_buf()),
        serial_out: Some(report_path.to_path_buf()),
        qga_sock: None,
        // The suite handed over its OWN per-run copy (see `run_suite`), and it boots
        // that copy TWICE: once to install, once to watch systemd bring the installed
        // system up. Without this the second boot gets a pristine image, re-runs
        // cloud-init, and produces confident ordering facts about a machine that was
        // never installed. draupnir >= 0.1.9.
        persist_disk: true,
    };
    let ctrl = KvmController::new();
    let handle = ctrl
        .start(&spec)
        .with_context(|| format!("boot `{name}`"))?;
    Ok((ctrl, handle))
}

/// Run the whole suite: boot A (lifecycle + drop-ins), then boot B (fresh-boot
/// ordering) off the SAME disk.
#[cfg(feature = "matrix")]
pub fn run_suite(cfg: &SuiteConfig) -> Result<SuiteRun> {
    let mut run = SuiteRun::default();
    std::fs::create_dir_all(&cfg.work_root)?;

    // A per-run copy: the cached base image is never written to.
    let disk = cfg.work_root.join("suite-disk.qcow2");
    let t_copy = Instant::now();
    std::fs::copy(&cfg.base_image, &disk)
        .with_context(|| format!("copy base image {}", cfg.base_image.display()))?;
    run.notes.push(format!(
        "copied base image → per-run disk in {} ms ({} MiB)",
        t_copy.elapsed().as_millis(),
        std::fs::metadata(&disk)
            .map(|m| m.len() / 1_048_576)
            .unwrap_or(0),
    ));

    // ── boot A ───────────────────────────────────────────────────────────────
    let cases_a = plan_boot_a();
    let plan_a = render_plan(&cases_a);
    let payload = cfg.work_root.join("skiddata.img");
    build_payload(&payload, cfg, &plan_a)?;

    let report_a = cfg.work_root.join("report-a.jsonl");
    let user_data = render_user_data("/var/lib/skid/plan.txt");
    let t0 = Instant::now();
    let (ctrl_a, h_a) = boot_once(
        cfg,
        "skid-vmsuite-a",
        &disk,
        Some(&payload),
        user_data.clone(),
        &report_a,
    )?;
    let want_a: Vec<String> = cases_a
        .iter()
        .filter(|c| !c.checks.is_empty())
        .map(|c| c.id.clone())
        .collect();
    let (facts_a, timings_a, ended_a) = tail_report(&report_a, &want_a, t0, cfg.boot_timeout);
    if !ended_a {
        run.notes.push(
            "boot A never reported `scenario_end` — the arming case that stages boot B may not \
             have run"
                .into(),
        );
    }
    // Let cloud-init's `scripts-user` module return and write its per-instance
    // semaphore, and let the scheduled power-off land. Without this grace the guest
    // is killed mid-cloud-init and the SECOND boot re-runs the whole plan from
    // cloud-init instead of being a fresh boot of an installed system.
    std::thread::sleep(cfg.shutdown_grace);
    run.boot_a_ms = t0.elapsed().as_millis();
    let _ = ctrl_a.stop(&h_a);
    run.outcomes.extend(grade(&cases_a, &facts_a, &timings_a));
    run.case_timings.extend(timings_a);
    run.facts.extend(facts_a);

    // ── boot B: the SAME disk, booted again. cloud-init sees the same instance-id
    //    and skips its per-instance modules, so the only thing that runs our code is
    //    `skid-bootreport.service`, started by systemd from its [Install] wants. ────
    let cases_b = plan_boot_b();
    let report_b = cfg.work_root.join("report-b.jsonl");
    let t1 = Instant::now();
    let (ctrl_b, h_b) = boot_once(
        cfg,
        "skid-vmsuite-b",
        &disk,
        Some(&payload),
        user_data,
        &report_b,
    )?;
    let want_b: Vec<String> = cases_b
        .iter()
        .filter(|c| !c.checks.is_empty())
        .map(|c| c.id.clone())
        .collect();
    let (facts_b, timings_b, _) = tail_report(&report_b, &want_b, t1, cfg.boot_timeout);
    run.boot_b_ms = t1.elapsed().as_millis();
    let _ = ctrl_b.stop(&h_b);
    run.boot_b_cases = facts_b.iter().map(|f| f.case.clone()).collect();
    run.outcomes.extend(grade(&cases_b, &facts_b, &timings_b));
    run.case_timings.extend(timings_b);
    run.facts.extend(facts_b);

    Ok(run)
}

/// Collect [`Facts`] for a unit on **this host's** live systemd — read-only.
///
/// The judges are pure functions over facts, so nothing about them is VM-specific:
/// the same `ResolvedUser` / `NoForeignDropIns` guards that grade a guest can grade
/// the box you are standing on. That is the cheap half of this suite and it needs no
/// boot at all — which matters, because the defect that started all of this is
/// sitting on oden right now (`korp-server`: fragment declares `User=korp`, five
/// drop-ins resolve it to `alice`).
///
/// Strictly read-only: `systemctl show` and `systemctl cat`, plus reads under
/// `/etc/systemd/system` and `/proc`. It never starts, stops, reloads or writes
/// anything — a diagnostic that could perturb the machine it is diagnosing would be
/// useless on the production box you most want to point it at.
///
/// This mirrors `skidbladnir_probe::facts::collect`, and cannot share code with it:
/// the guest collector must cross-compile to static musl depending on nothing but
/// `std`, so it lives in a separate cargo workspace (`probe/`) this crate cannot
/// depend on. What the two share is the *format*, pinned from both sides by
/// [`tests::the_guest_facts_line_deserializes`] and the golden-plan pair.
pub fn collect_host_facts(unit: &str) -> Facts {
    use std::process::Command;
    /// The properties a judge may read. Mirrors `skidbladnir_probe::facts::SHOW_PROPS`
    /// — the guest crate is a separate workspace this one cannot depend on. A property
    /// missing here is not a silent "" : every judge treats an uncaptured property as
    /// a **Fail**, so a drift between the two lists surfaces as a red, not as a pass.
    const SHOW_PROPS: &[&str] = &[
        "Id",
        "LoadState",
        "ActiveState",
        "SubState",
        "UnitFileState",
        "FragmentPath",
        "DropInPaths",
        "User",
        "Group",
        "Environment",
        "EnvironmentFiles",
        "WorkingDirectory",
        "After",
        "Wants",
        "MainPID",
        "ExecMainStatus",
        "Result",
        "ActiveEnterTimestampMonotonic",
    ];
    let run = |args: &[&str]| -> String {
        Command::new("systemctl")
            .args(args)
            .output()
            .map(|o| String::from_utf8_lossy(&o.stdout).to_string())
            .unwrap_or_default()
    };

    let mut show_args: Vec<&str> = vec!["show", "--no-pager"];
    for p in SHOW_PROPS {
        show_args.push("-p");
        show_args.push(p);
    }
    show_args.push(unit);
    let mut show: Vec<String> = run(&show_args)
        .lines()
        .filter(|l| !l.trim().is_empty())
        .map(|l| l.trim_end().to_string())
        .collect();
    if let Some(v) = run(&[
        "show",
        "--no-pager",
        "-p",
        "ActiveEnterTimestampMonotonic",
        "network-online.target",
    ])
    .lines()
    .find_map(|l| l.strip_prefix("ActiveEnterTimestampMonotonic="))
    {
        show.push(format!(
            "NetworkOnlineActiveEnterTimestampMonotonic={}",
            v.trim()
        ));
    }

    let mut f = Facts {
        case: format!("host:{unit}"),
        cat: run(&["cat", "--no-pager", unit]),
        show,
        at: chrono::Utc::now().format("%Y-%m-%dT%H:%M:%SZ").to_string(),
        ..Default::default()
    };

    if let Some(pid) = f
        .show_value("MainPID")
        .and_then(|v| v.trim().parse::<u32>().ok())
        .filter(|p| *p != 0)
    {
        if let Ok(raw) = std::fs::read(format!("/proc/{pid}/environ")) {
            f.proc_env = raw
                .split(|b| *b == 0)
                .filter(|s| !s.is_empty())
                .map(|s| String::from_utf8_lossy(s).to_string())
                .collect();
        }
        let uid = std::fs::read_to_string(format!("/proc/{pid}/status"))
            .ok()
            .and_then(|s| {
                s.lines()
                    .find_map(|l| l.strip_prefix("Uid:"))
                    .and_then(|v| {
                        v.split_whitespace()
                            .next()
                            .and_then(|n| n.parse::<u32>().ok())
                    })
            });
        if let Some(uid) = uid {
            f.proc_user = std::fs::read_to_string("/etc/passwd")
                .ok()
                .and_then(|pw| {
                    pw.lines().find_map(|l| {
                        let c: Vec<&str> = l.split(':').collect();
                        (c.len() >= 3 && c[2].parse::<u32>() == Ok(uid)).then(|| c[0].to_string())
                    })
                })
                .unwrap_or_else(|| format!("uid:{uid}"));
        }
    }

    let frag = format!("/etc/systemd/system/{unit}");
    if std::path::Path::new(&frag).exists() {
        f.files.push(frag);
    }
    let d = format!("/etc/systemd/system/{unit}.d");
    if std::path::Path::new(&d).is_dir() {
        f.files.push(format!("{d}/"));
        if let Ok(rd) = std::fs::read_dir(&d) {
            let mut e: Vec<String> = rd
                .flatten()
                .map(|x| x.path().to_string_lossy().to_string())
                .collect();
            e.sort();
            f.files.extend(e);
        }
    }
    f
}

/// Every case of the suite (both boots), for reporting and for the arms declaration.
pub fn all_cases() -> Vec<SuiteCase> {
    let mut v = plan_boot_a();
    v.extend(plan_boot_b());
    v
}

#[cfg(test)]
mod tests {
    use super::*;

    fn facts(pairs: &[(&str, &str)]) -> Facts {
        Facts {
            case: "t".into(),
            show: pairs.iter().map(|(k, v)| format!("{k}={v}")).collect(),
            ..Default::default()
        }
    }

    // ─────────────────── the wire: host renders what the guest parses ───────────

    /// The GOLDEN plan text, byte-for-byte the same literal as
    /// `skidbladnir_probe::plan::tests::GOLDEN` in the guest crate. The two crates
    /// live in different cargo workspaces and share no type, so this pair of tests is
    /// the only thing standing between them and a silent wire drift.
    #[test]
    fn the_rendered_plan_is_exactly_the_golden_the_guest_parser_pins() {
        let cases = vec![
            SuiteCase::setup(
                "clean-install",
                vec![
                    PlanStep::Write {
                        path: "/etc/systemd/system/skidtest.service".into(),
                        mode: 0o644,
                        contents: "[Unit]\n".into(),
                    },
                    PlanStep::Run(vec!["systemctl".into(), "daemon-reload".into()]),
                    PlanStep::WaitFor {
                        timeout_ms: 60_000,
                        poll_ms: 500,
                        argv: vec![
                            "systemctl".into(),
                            "is-active".into(),
                            "skidtest.service".into(),
                        ],
                    },
                    PlanStep::Capture {
                        key: "footer".into(),
                        argv: vec![
                            "tail".into(),
                            "-c".into(),
                            "4".into(),
                            "/var/lib/skid/nodes.parquet".into(),
                        ],
                    },
                    PlanStep::Sleep(2000),
                    PlanStep::Collect {
                        unit: "skidtest.service".into(),
                        exec: "/usr/local/bin/skidbladnir-testsvc".into(),
                    },
                ],
            ),
            SuiteCase::setup("done", vec![PlanStep::PowerOff]),
        ];
        let expected = "\
# skidbladnir vm-suite plan
CASE clean-install
WRITE /etc/systemd/system/skidtest.service 0644 5b556e69745d0a
RUN systemctl daemon-reload
WAITFOR 60000 500 systemctl is-active skidtest.service
CAPTURE footer tail -c 4 /var/lib/skid/nodes.parquet
SLEEP 2000
COLLECT skidtest.service /usr/local/bin/skidbladnir-testsvc
END
CASE done
POWEROFF
END
";
        assert_eq!(render_plan(&cases), expected);
    }

    /// A real emitted guest line (captured from `Facts::to_json_line`) must
    /// deserialize into every field this side reads.
    #[test]
    fn the_guest_facts_line_deserializes() {
        // `r##` (not `r#`): the captured line contains `"#` — the `systemctl cat`
        // header comment — which would end an `r#"…"#` literal mid-JSON.
        let line = r##"{"case":"clean-install","exits":["0 systemctl daemon-reload"],"show":["User=skidsvc","DropInPaths=","ActiveState=active","MainPID=812"],"cat":"# /etc/systemd/system/skidtest.service\n[Service]\n","proc_env":["USER=skidsvc","HOME=/var/lib/skidsvc"],"proc_user":"skidsvc","files":["/etc/systemd/system/skidtest.service"],"at":"2026-08-03T09:00:00Z"}"##;
        let f: Facts = serde_json::from_str(line).expect("guest line parses");
        assert_eq!(f.case, "clean-install");
        assert_eq!(f.show_value("User"), Some("skidsvc"));
        assert_eq!(f.env_value("HOME"), Some("/var/lib/skidsvc"));
        assert_eq!(f.proc_user, "skidsvc");
        assert!(f.cat.contains("[Service]"));
    }

    /// `capture` must tell "never asked" from "asked, got nothing" — and must not be
    /// answered by a longer key that merely starts the same way.
    #[test]
    fn a_capture_distinguishes_absence_from_emptiness_and_refuses_a_prefix_match() {
        let f = Facts {
            captures: vec![
                "footer=PAR1".into(),
                "empty=".into(),
                "journal=z12 → 41 tiles\nz9 → 3 tiles\n".into(),
            ],
            ..Default::default()
        };
        assert_eq!(f.capture("footer"), Some("PAR1"));
        assert_eq!(
            f.capture("empty"),
            Some(""),
            "ran and printed nothing IS an answer"
        );
        assert_eq!(
            f.capture("nope"),
            None,
            "never captured is not an empty answer"
        );
        assert!(
            f.capture("journal").unwrap().lines().count() == 2,
            "multi-line survives"
        );
        // The trap: `foot` must not be answered by `footer=PAR1`.
        assert_eq!(f.capture("foot"), None, "prefix collision must not match");
    }

    /// The waited-for latency is parsed back out of the audit line, in BOTH
    /// directions — a timeout carries its non-zero code, not a shrug.
    #[test]
    fn the_waitfor_latency_is_readable_and_a_timeout_is_visible() {
        let f = Facts {
            exits: vec![
                "0 RUN systemctl daemon-reload".into(),
                "0 WAITFOR 4210ms/120000ms korp-probe --expect vaduz".into(),
                "1 WAITFOR 120000ms/120000ms test -f /var/x :: TIMED OUT ::".into(),
            ],
            ..Default::default()
        };
        assert_eq!(f.waited("korp-probe"), Some((0, 4210)));
        assert_eq!(
            f.waited("/var/x"),
            Some((1, 120_000)),
            "a timeout is data, not absence"
        );
        assert_eq!(f.waited("never-ran"), None);
    }

    #[test]
    fn parse_report_skips_the_scenario_markers_and_partial_lines() {
        let text = "{\"scenario_start\":\"0.1.0\",\"cases\":9}\n\
                    {\"case\":\"a\",\"show\":[\"User=x\"]}\n\
                    {\"case\":\"b\",\"sho";
        let f = parse_report(text);
        assert_eq!(
            f.len(),
            1,
            "the marker has no `case`, the last line is truncated"
        );
        assert_eq!(f[0].case, "a");
    }

    // ─────────────────────── every judge, seen RED ─────────────────────────────

    /// The korp defect, as a unit test: the fragment says `skidsvc`, systemd
    /// resolved `alice`.
    #[test]
    fn resolved_user_goes_red_when_a_dropin_overrode_it() {
        let mut f = facts(&[
            ("User", "alice"),
            (
                "DropInPaths",
                "/etc/systemd/system/skidtest.service.d/99-stale-conflict.conf",
            ),
        ]);
        f.proc_user = "alice".into();
        let v = judge(&Check::ResolvedUser("skidsvc".into()), &f);
        assert!(!v.is_pass(), "must be red");
        assert!(
            v.detail().contains("alice"),
            "names what it saw: {}",
            v.detail()
        );
        assert!(
            v.detail().contains("99-stale-conflict"),
            "names the hijacker: {}",
            v.detail()
        );
    }

    /// The subtler half: systemd's property is right but the live process is not.
    #[test]
    fn resolved_user_goes_red_when_only_the_live_process_disagrees() {
        let mut f = facts(&[("User", "skidsvc")]);
        f.proc_user = "root".into();
        assert!(!judge(&Check::ResolvedUser("skidsvc".into()), &f).is_pass());

        let mut f = facts(&[("User", "skidsvc")]);
        f.proc_env = vec!["USER=root".into()];
        let v = judge(&Check::ResolvedUser("skidsvc".into()), &f);
        assert!(
            !v.is_pass(),
            "environ USER disagreeing is a red: {}",
            v.detail()
        );
    }

    /// The anti-hollow rule: no `User` property captured is a FAIL. If this returned
    /// Pass, every case where the unit failed to load would score green.
    #[test]
    fn an_uncaptured_property_is_a_fail_not_a_pass() {
        let empty = Facts::default();
        assert!(!judge(&Check::ResolvedUser("skidsvc".into()), &empty).is_pass());
        assert!(!judge(&Check::Active(true), &empty).is_pass());
        assert!(
            !judge(&Check::Active(false), &empty).is_pass(),
            "even the negative form"
        );
        assert!(!judge(&Check::ProcEnv("USER".into(), "skidsvc".into()), &empty).is_pass());
        assert!(!judge(&Check::OrderedAfterNetworkOnline, &empty).is_pass());
    }

    #[test]
    fn resolved_user_passes_only_when_all_three_agree() {
        let mut f = facts(&[("User", "skidsvc"), ("DropInPaths", "")]);
        f.proc_user = "skidsvc".into();
        f.proc_env = vec!["USER=skidsvc".into(), "HOME=/var/lib/skidsvc".into()];
        assert!(judge(&Check::ResolvedUser("skidsvc".into()), &f).is_pass());
    }

    #[test]
    fn foreign_dropins_are_caught_from_the_property_and_from_the_disk() {
        // (a) the unit is loaded: DropInPaths names it.
        let f = facts(&[(
            "DropInPaths",
            "/etc/systemd/system/skidtest.service.d/99-stale-conflict.conf",
        )]);
        assert!(!judge(&Check::NoForeignDropIns(Vec::new()), &f).is_pass());

        // (b) the unit is NOT loaded (naive uninstall) → DropInPaths is empty and the
        //     property alone would say "clean". The disk listing is what catches it.
        let mut f = facts(&[("DropInPaths", "")]);
        f.files = vec!["/etc/systemd/system/skidtest.service.d/99-stale-conflict.conf".into()];
        let v = judge(&Check::NoForeignDropIns(Vec::new()), &f);
        assert!(
            !v.is_pass(),
            "a landmine on disk must be red even when systemd forgot the unit"
        );
        assert!(v.detail().contains("99-stale-conflict"), "{}", v.detail());

        // (c) a DECLARED drop-in is fine — the guard is about foreign ones.
        let allowed = "/etc/systemd/system/skidtest.service.d/10-declared.conf".to_string();
        let f = facts(&[("DropInPaths", &allowed)]);
        assert!(judge(&Check::NoForeignDropIns(vec![allowed]), &f).is_pass());
    }

    /// **RED — `Check::Active(false)` passed for a unit that was still SHUTTING DOWN.**
    ///
    /// The twin of the `restart_over_dbus` defect (fixed 35ab55c), in the grading
    /// harness rather than in the installer. `judge_active` asked
    /// `ActiveState == "active"` and compared that to `want`, so `want = false` was
    /// satisfied by `deactivating` — a unit whose processes are all still running.
    ///
    /// The suite case it grades is `systemctl stop` → `Sleep(1500)` → collect →
    /// `Check::Active(false)`. A service that drains for longer than 1.5 s therefore
    /// graded PASS on "it stopped" while it had not. MEASURED on t14s 2026-08-25: a
    /// real service sat in `deactivating` for 6.4 s after `StopUnit`.
    ///
    /// A false green in the harness that exists to catch false greens is the worst
    /// place for this shape to hide.
    ///
    /// RED direction: restore `is_active == want` and the `deactivating` /
    /// `activating` rows below flip to pass.
    #[test]
    fn a_unit_that_is_still_shutting_down_does_not_grade_as_stopped() {
        let draining = facts(&[
            ("ActiveState", "deactivating"),
            ("SubState", "stop-sigterm"),
        ]);
        assert!(
            !judge(&Check::Active(false), &draining).is_pass(),
            "`deactivating` means the processes are STILL RUNNING — grading that as \
             stopped is the defect this test exists for"
        );
        assert!(
            !judge(&Check::Active(true), &draining).is_pass(),
            "…and it is not active either: a draining unit satisfies NEITHER direction"
        );
        assert!(
            judge(&Check::Active(false), &draining)
                .detail()
                .contains("deactivating"),
            "the red must name the state it actually saw: {}",
            judge(&Check::Active(false), &draining).detail()
        );

        // The same asymmetry on the way up: `activating` is not yet running.
        let starting = facts(&[("ActiveState", "activating"), ("SubState", "start")]);
        assert!(!judge(&Check::Active(true), &starting).is_pass());
        assert!(
            !judge(&Check::Active(false), &starting).is_pass(),
            "`activating` is not stopped either — it has, or is about to have, processes"
        );

        // `failed` IS stopped. A unit SIGKILLed after its stop timeout settles there,
        // never in `inactive`, so a stop check that demanded `inactive` would go red on
        // exactly the services slowest to die.
        let failed = facts(&[("ActiveState", "failed"), ("SubState", "failed")]);
        assert!(
            judge(&Check::Active(false), &failed).is_pass(),
            "`failed` is a unit that has finished — nothing of it is running"
        );
    }

    #[test]
    fn active_is_falsifiable_in_both_directions() {
        let up = facts(&[("ActiveState", "active"), ("SubState", "running")]);
        let down = facts(&[("ActiveState", "inactive"), ("SubState", "dead")]);
        assert!(judge(&Check::Active(true), &up).is_pass());
        assert!(!judge(&Check::Active(true), &down).is_pass());
        assert!(judge(&Check::Active(false), &down).is_pass());
        assert!(!judge(&Check::Active(false), &up).is_pass());
        let failed = facts(&[
            ("ActiveState", "failed"),
            ("Result", "exit-code"),
            ("ExecMainStatus", "203"),
        ]);
        let v = judge(&Check::Active(true), &failed);
        assert!(
            v.detail().contains("203"),
            "a red must carry the exit status: {}",
            v.detail()
        );
    }

    #[test]
    fn clean_slate_is_red_for_each_kind_of_leftover_and_green_only_when_all_are_gone() {
        let gone = facts(&[("LoadState", "not-found"), ("FragmentPath", "")]);
        assert!(judge(&Check::CleanSlate, &gone).is_pass());

        let loaded = facts(&[("LoadState", "loaded"), ("FragmentPath", "")]);
        assert!(
            !judge(&Check::CleanSlate, &loaded).is_pass(),
            "systemd still knows the unit"
        );

        let frag = facts(&[
            ("LoadState", "not-found"),
            ("FragmentPath", "/etc/systemd/system/skidtest.service"),
        ]);
        assert!(!judge(&Check::CleanSlate, &frag).is_pass());

        let mut landmine = facts(&[("LoadState", "not-found"), ("FragmentPath", "")]);
        landmine.files =
            vec!["/etc/systemd/system/skidtest.service.d/99-stale-conflict.conf".into()];
        let v = judge(&Check::CleanSlate, &landmine);
        assert!(!v.is_pass());
        assert!(v.detail().contains("landmine"), "{}", v.detail());

        // The exec binary is not a systemd leftover — it must not make clean-slate red.
        let mut with_exec = facts(&[("LoadState", "not-found"), ("FragmentPath", "")]);
        with_exec.files = vec![EXEC.into()];
        assert!(judge(&Check::CleanSlate, &with_exec).is_pass());
    }

    #[test]
    fn ordering_is_red_for_every_way_it_can_be_wrong() {
        let ok = facts(&[
            ("After", "network-online.target basic.target"),
            ("ActiveEnterTimestampMonotonic", "9000000"),
            ("NetworkOnlineActiveEnterTimestampMonotonic", "8000000"),
        ]);
        assert!(judge(&Check::OrderedAfterNetworkOnline, &ok).is_pass());

        // (a) the unit never declared the ordering.
        let no_after = facts(&[
            ("After", "sysinit.target"),
            ("ActiveEnterTimestampMonotonic", "9000000"),
            ("NetworkOnlineActiveEnterTimestampMonotonic", "8000000"),
        ]);
        assert!(!judge(&Check::OrderedAfterNetworkOnline, &no_after).is_pass());

        // (b) it declared it and STILL came up first — the real ordering violation.
        let early = facts(&[
            ("After", "network-online.target"),
            ("ActiveEnterTimestampMonotonic", "3000000"),
            ("NetworkOnlineActiveEnterTimestampMonotonic", "8000000"),
        ]);
        let v = judge(&Check::OrderedAfterNetworkOnline, &early);
        assert!(!v.is_pass());
        assert!(v.detail().contains("BEFORE"), "{}", v.detail());

        // (c) network-online.target never activated → nothing to order against. The
        //     identity-value trap: 0 must not read as "0 µs, therefore in order".
        let no_net = facts(&[
            ("After", "network-online.target"),
            ("ActiveEnterTimestampMonotonic", "9000000"),
            ("NetworkOnlineActiveEnterTimestampMonotonic", "0"),
        ]);
        assert!(!judge(&Check::OrderedAfterNetworkOnline, &no_net).is_pass());

        // (d) the unit never activated.
        let no_unit = facts(&[
            ("After", "network-online.target"),
            ("ActiveEnterTimestampMonotonic", "0"),
            ("NetworkOnlineActiveEnterTimestampMonotonic", "8000000"),
        ]);
        assert!(!judge(&Check::OrderedAfterNetworkOnline, &no_unit).is_pass());
    }

    // ───────────────────────── the grader itself ───────────────────────────────

    /// A case that never reported must be a FAIL for every one of its checks —
    /// including the deliberate-red ones. A missing report is not "the red we
    /// wanted"; it is a case that ran nothing.
    #[test]
    fn a_case_with_no_facts_line_fails_every_check_including_the_negative_ones() {
        let cases = plan_boot_a();
        let out = grade(&cases, &[], &[]);
        assert!(!out.is_empty());
        assert!(
            out.iter().all(|o| !o.as_declared),
            "silence is never success"
        );
        assert!(
            out.iter()
                .all(|o| o.verdict.detail().contains("asserted NOTHING"))
        );
    }

    /// The grader scores a deliberate-red case as PASSING when the guard goes red,
    /// and as FAILING when the guard is hollow. This is the mechanism that makes a
    /// stuck-on-pass judge impossible to ship.
    #[test]
    fn a_hollow_always_passing_guard_would_fail_the_negative_cases() {
        let cases = plan_boot_a();
        // Facts from a machine where the hostile drop-in IS present and winning.
        let hijacked = Facts {
            case: "dropin-user-override".into(),
            show: vec![
                "User=root".into(),
                format!("DropInPaths={HOSTILE_DROP_IN}"),
                "ActiveState=active".into(),
            ],
            proc_user: "root".into(),
            proc_env: vec!["USER=root".into(), "SKID_MARK=hijacked".into()],
            ..Default::default()
        };
        let out = grade(&cases, std::slice::from_ref(&hijacked), &[]);
        let red_ones: Vec<&Outcome> = out
            .iter()
            .filter(|o| o.case == "dropin-user-override" && !o.expect_pass)
            .collect();
        assert_eq!(
            red_ones.len(),
            4,
            "four guards are required to notice this machine"
        );
        assert!(
            red_ones
                .iter()
                .all(|o| o.as_declared && !o.verdict.is_pass()),
            "each declared-red guard actually went red: {red_ones:?}"
        );
        // …and the ONE positive check on that case (still running) also holds.
        let active = out
            .iter()
            .find(|o| o.case == "dropin-user-override" && o.check == "active")
            .unwrap();
        assert!(active.as_declared && active.verdict.is_pass());
    }

    // ───────────────────── the suite's own shape ────────────────────────────────

    /// The suite must contain deliberate reds in BOTH boots. Without them a judge
    /// could be stuck on Pass and every case would still be green.
    #[test]
    fn both_boots_carry_deliberate_red_cases() {
        let a: usize = plan_boot_a()
            .iter()
            .flat_map(|c| &c.checks)
            .filter(|e| !e.expect_pass)
            .count();
        let b: usize = plan_boot_b()
            .iter()
            .flat_map(|c| &c.checks)
            .filter(|e| !e.expect_pass)
            .count();
        assert!(a >= 4, "boot A must engineer real failures, has {a}");
        assert!(
            b >= 1,
            "boot B must engineer a real ordering failure, has {b}"
        );
        let pass: usize = all_cases()
            .iter()
            .flat_map(|c| &c.checks)
            .filter(|e| e.expect_pass)
            .count();
        assert!(
            pass >= 10,
            "…and enough positive checks that a stuck-on-red judge fails too ({pass})"
        );
    }

    /// Every asserting case must say why a host-only test could not have caught it.
    /// The claim is auditable data, not a comment nobody re-reads.
    #[test]
    fn every_asserting_case_declares_its_host_only_blind_spot() {
        for c in all_cases() {
            if !c.checks.is_empty() {
                assert!(
                    c.host_only_blind_spot.len() > 40,
                    "case `{}` asserts things but does not say what a host-only test would miss",
                    c.id
                );
            }
        }
    }

    /// The spec under test is the REAL one: rendered by the shipped renderer, and it
    /// must actually carry the ordering the boot-B guard asks systemd about — else
    /// that guard would be red for a reason that has nothing to do with systemd.
    #[test]
    fn the_rendered_unit_carries_the_user_and_the_ordering_the_suite_asserts() {
        let r = suite_rendered();
        let unit = r
            .file_ending("skidtest.service")
            .expect("a unit file was rendered");
        assert!(unit.contains(&format!("User={SVC_USER}")), "unit:\n{unit}");
        assert!(
            unit.contains("After=") && unit.contains("network-online.target"),
            "unit:\n{unit}"
        );
        assert!(
            unit.contains("SKID_MARK"),
            "the declared env is in the unit:\n{unit}"
        );
        assert_eq!(r.files[0].path, "/etc/systemd/system/skidtest.service");
    }

    /// The hostile drop-in must genuinely contradict the spec — a "conflict" that
    /// agreed with the unit would make every negative case a fake red.
    #[test]
    fn the_planted_dropin_really_contradicts_the_spec() {
        let body = hostile_drop_in_body();
        assert!(body.contains("User=root"));
        assert_ne!("root", SVC_USER, "the override must name a DIFFERENT user");
        assert!(body.contains("SKID_MARK=hijacked"));
        let unit = suite_rendered()
            .file_ending("skidtest.service")
            .unwrap()
            .to_string();
        assert!(
            unit.contains("SKID_MARK=vm-suite"),
            "…and a different env value:\n{unit}"
        );
    }

    /// The negative ordering control must be built so it CANNOT be ordered after the
    /// network — otherwise its red would be luck, not construction.
    #[test]
    fn the_early_control_unit_is_constructed_to_activate_before_the_network() {
        let b = early_unit_body();
        assert!(b.contains("DefaultDependencies=no"), "{b}");
        assert!(b.contains("Before=sysinit.target"), "{b}");
        assert!(b.contains("WantedBy=sysinit.target"), "{b}");
        assert!(
            !b.contains("network-online.target"),
            "it must not declare the ordering: {b}"
        );
        assert!(
            b.contains("Type=oneshot") && b.contains("/bin/true"),
            "cannot wedge the boot: {b}"
        );
    }

    #[test]
    fn the_cloud_init_userdata_installs_the_scenario_and_runs_the_plan() {
        let ud = render_user_data("/var/lib/skid/plan.txt");
        assert!(ud.starts_with("#cloud-config"));
        assert!(
            ud.contains("mount -t vfat"),
            "finds the payload by scanning vfat devices"
        );
        assert!(ud.contains("install -m0755 /mnt/skid/skidbladnir-scenario"));
        assert!(
            ud.contains(REPORT_PORT),
            "reports over the virtio-serial port"
        );
        assert!(ud.contains("--plan /var/lib/skid/plan.txt"));
    }

    /// The boot-B plan is embedded INSIDE boot A's plan (as a WRITE payload). A hex
    /// payload can carry a plan containing newlines and its own verbs without the
    /// outer parser ever seeing them — assert that nesting really survives.
    #[test]
    fn boot_b_plan_survives_being_embedded_in_boot_a() {
        let a = render_plan(&plan_boot_a());
        assert_eq!(
            a.lines().filter(|l| l.starts_with("CASE ")).count(),
            10,
            "boot A case count"
        );
        let b = render_plan(&plan_boot_b());
        assert!(b.contains("COLLECT skidtest.service"));
        assert!(
            a.contains(&hex_encode(b.as_bytes())),
            "boot A must carry boot B's plan verbatim as hex"
        );
        // …and the outer plan must not have gained stray verbs from the inner one.
        assert!(
            !a.lines()
                .any(|l| l == "COLLECT skidearly.service /bin/true")
        );
    }
}