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

nordisk/gunnar-ui

crates/gunnar-ui-server/src/api/machine.rs

//! **What the machine IS**: what the installer decided, what its filesystems
//! hold now, and where gunnar is configured to put things.
//!
//! The appliance has no shell. `:22` is closed, PID 1 is `gunnar-server`, and
//! there is no way in — so the control plane is the only road these facts
//! have, and this module is the whole of it.
//!
//! # It rides on `Admin.StorageInfo`, and that is gunnar's choice
//!
//! This console spent a while drawing an `Admin.Machine` RPC that gunnar never
//! served. gunnar answered the same need ADDITIVELY instead, on a call that
//! already existed: [`StorageInfoResponse.reality`][pb::StorageReality], field
//! 10, landed 2026-09-13. gunnar is the one serving it, so gunnar's shape is
//! the shape, and this module is the seam that was repointed.
//!
//! # Three layers, carried separately all the way to the browser
//!
//! [`Machine::record`] is what the installer DECIDED, written once and never
//! updated. [`Machine::filesystems`] is what is true NOW, measured on the
//! call. [`Machine::placement`] is what gunnar is CONFIGURED to do. They age
//! differently, and nothing here folds one into another: in particular **no
//! field of layer 1 is ever derived from layer 2**. An appliance installed
//! before the record existed has none, and the filesystem table is not a
//! substitute — `statvfs` can say how full `/data` is, and it can never say
//! which disk was rejected and why. Reconstructing the installer's reasoning
//! out of the running system is how "why is this disk unused" gets answered
//! wrongly and confidently.
//!
//! # The install record is carried UNPARSED, on purpose
//!
//! gunnar sends the layout config as `repeated InstallRecordField {key,
//! value}` and says why in its own comment: *"a key this build does not know
//! is still shown, because the admin reading the page may know what it means
//! when this binary does not."* So [`InstallRecord::fields`] is a key/value
//! table in key order and nothing here folds it back into disks, partitions
//! and sets. That folding is precisely the invention gunnar declined to make,
//! and a console that made it would go blind on every key gunnar adds next.
//!
//! # Absent is not zero
//!
//! Every byte figure is an `Option` and is `None` when it was not measured,
//! with gunnar's own reason beside it in words. This is `Admin.Capacity`'s own
//! rule for its box fields ("absent when it was not measured — never 0") and
//! it is the rule that matters most on this page: somebody reading it is often
//! reading it because something already broke.
//!
//! # An older gunnar is not an error, and there are now TWO of those
//!
//! `reality` is a FIELD and not an RPC, so "this server cannot answer" no
//! longer arrives as `Code::Unimplemented`. It arrives as `reality == None` on
//! a perfectly successful call, and the two are handled apart because they are
//! different servers:
//!
//! * **`Unimplemented`** — this gunnar does not serve `Admin.StorageInfo` at
//!   all. Rare; the anonymous plane answers this way.
//! * **`reality == None`** — this gunnar serves `Admin.StorageInfo` and is
//!   older than field 10. This is the one a real appliance will show.
//!
//! Both reach the page as a 200 whose [`Machine::unanswered`] carries words,
//! so it can still draw the three layers and say which server it is talking
//! to. Every OTHER refusal — `PermissionDenied` above all — is propagated as a
//! refusal, because a credential that may not read the machine is a fact about
//! this console and not about the machine.
//!
//! # The one seam to repoint
//!
//! [`render`] is the only place that touches gunnar's message. If gunnar moves
//! `reality` again, that function and the vendored `admin.proto` are what
//! change, and nothing above the JSON moves.

use axum::Json;
use serde::Serialize;

use crate::api::{ApiError, ApiResult};
use crate::pb;

/// The machine, in the three layers the page keeps apart.
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
pub struct Machine {
    /// **Empty when gunnar answered.** gunnar's own words, or this console's
    /// when gunnar sent none, for a server that could not be asked at all.
    /// Not an error: see the module header, which also explains why there are
    /// two ways to get here.
    pub unanswered: String,

    // ── layer 1: what the installer decided ───────────────────────────────
    /// `None` on any appliance whose layout config is absent, and then
    /// [`Machine::record_absent`] says so in words. Never reconstructed.
    pub record: Option<InstallRecord>,
    /// Where gunnar looked for the record.
    pub record_path: String,
    /// Why there is none. Empty when there is one.
    pub record_absent: String,

    // ── layer 2: what is true now ─────────────────────────────────────────
    /// Only the paths gunnar was TOLD to use. Nothing here walks a mount table
    /// looking for others, so an empty list is gunnar naming no filesystems
    /// and never "this box has no disks".
    pub filesystems: Vec<Filesystem>,

    // ── layer 3: what gunnar is configured to do ──────────────────────────
    pub placement: Option<Placement>,

    // ── the machine at a glance (2026-10-04) ──────────────────────────────
    /// **gunnar's own few lines** — `/data`'s shape, the off-stripe copies,
    /// the free space, the disk speed — each with gunnar's verdict
    /// (`StorageReality.glance`). Carried AS THEY CAME: the Overview's Machine
    /// card draws them and decides none of them (owner: the console is a thin
    /// layer). Empty from a gunnar older than the field.
    pub glance: Vec<Glance>,
}

/// One line of the machine at a glance, exactly as gunnar sent it.
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
pub struct Glance {
    /// `data` | `serialdat` | `free` | `speed`.
    pub key: String,
    /// The whole sentence.
    pub line: String,
    /// `ok` | `warn` | `bad` | `unknown` — gunnar's verdict, drawn as is.
    pub state: String,
    /// Why that verdict, for the "?" beside the line. May be empty.
    pub detail: String,
}

/// What the installer decided, **in the installer's own keys**. Historical.
///
/// There is no `Disk`, no `Partition` and no `DataSet` here, and their absence
/// is the design: see the module header.
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
pub struct InstallRecord {
    /// The config's own schema version.
    pub version: u32,
    /// gunnar's two words and no others: `verified` or `INTEGRITY ONLY`. A
    /// signature that FAILS to verify never reaches here — it makes the whole
    /// record absent — so this is never a third, quieter kind of failure.
    pub signature: String,
    /// True only for `verified`. An unsigned config is used and is never
    /// presented as verified.
    pub signature_verified: bool,
    /// The installer's own sentence saying what is NOT verified. Empty on a
    /// signed config.
    pub signature_note: String,
    /// Every field of the config, **unparsed**, in key order.
    pub fields: Vec<RecordField>,
}

/// One `key=value` from the install record, exactly as the installer wrote it.
#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Serialize)]
pub struct RecordField {
    pub key: String,
    pub value: String,
}

/// Layer 2: what one configured filesystem has, read at the moment of the
/// call.
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
pub struct Filesystem {
    /// `data root` | `configured directory`.
    pub what: String,
    pub path: String,
    /// `None` when the `statvfs` failed; [`Filesystem::error`] carries the OS
    /// error. Never 0 — a zero here would read as an empty disk.
    pub total_bytes: Option<u64>,
    pub free_bytes: Option<u64>,
    pub error: String,
}

/// Layer 3: gunnar's placement settings, as configured.
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
pub struct Placement {
    pub data_root: String,
    /// **`/data`'s own shape** (`data.shape`: `raid0` | `plain` | `p3`), from
    /// the installer's layout config. Empty when nothing said. Never filled
    /// from [`Placement::backing_device`], which is `/serialdat`'s disk.
    pub data_shape: String,
    /// `data.<N>.dev`, in N order: the devices `/data` is made of.
    pub data_devices: Vec<String>,
    /// `serialdat.mountpoint` as the config gives it. Reported, never used to
    /// build a path.
    pub slow_root: String,
    /// How gunnar learned where to write. "We were told" and "we fell back"
    /// are different facts, and proto3's absent `string` cannot hold the
    /// difference — this field is where gunnar puts it.
    pub slow_root_source: String,
    /// **`/serialdat`'s disk** (`serialdat.dev`) — NOT `/data`'s. The Machine
    /// page once drew it as "Backing device" under "Data root" (2026-10-04).
    pub backing_device: String,
    /// `p3` | `device` | `fallback`, or empty when nothing said. A class that
    /// was not read is not reported as one.
    pub backing_class: String,
    /// The one verdict, in this console's vocabulary. See
    /// [`off_stripe_word`].
    pub off_stripe: Option<&'static str>,
    /// The copies that need another failure domain, each said as a whole
    /// sentence — present AND its limitation, never "OK".
    pub off_stripe_health: Vec<String>,
    pub rows: Vec<PlacementRow>,
}

/// Layer 3: one thing gunnar writes, and the path it is configured to write it
/// to.
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize)]
pub struct PlacementRow {
    pub what: String,
    pub path: String,
    /// Is this one of the copies that must be on another failure domain?
    pub requires_off_stripe: bool,
    /// `None` for a row that does not require it, and for a word this build
    /// has no name for. See [`off_stripe_word`].
    pub off_stripe: Option<&'static str>,
    /// **Does gunnar write here today?** A directory that exists is not a
    /// feature, so a row that is not wired says so.
    pub wired: bool,
    /// When `wired` is false, gunnar's own words for why not.
    pub note: String,
}

/// ★ **The three states of a copy, as one word each — and `None` for "gunnar
/// did not say".**
///
/// gunnar spells them `off-stripe` · `same-device` · `absent`; this console
/// has said `elsewhere` · `same_device` · `none` since before the field
/// existed, and the mapping is one-to-one and tested. Translating is not
/// inventing — but mapping a word this build does NOT know onto the nearest
/// one it does would be, so an unknown word carries no word at all.
///
/// They are **not a scale**. A renderer that treats `same_device` as a weaker
/// `elsewhere` has drawn the worst of the three as an almost-good one: a
/// metadata mirror that shares a device with what it mirrors dies in the event
/// it exists for, and is worse than no mirror at all because somebody will
/// trust it.
///
/// `None` is a state of the ANSWER, not of the copy — gunnar also sends the
/// empty string for a row that does not require an off-stripe copy at all
/// ([`crate::api::usage::enforcement_word`] has the same idiom), because a
/// placeholder would be this console asserting a topology it was never told.
pub fn off_stripe_word(word: &str) -> Option<&'static str> {
    match word.trim() {
        "off-stripe" => Some("elsewhere"),
        "same-device" => Some("same_device"),
        "absent" => Some("none"),
        _ => None,
    }
}

/// `GET /api/machine`
///
/// Not cached. Every other read on this surface is held for a few seconds
/// because a page of panels asks the same question at once; this page asks
/// once, and an operator who reloads it is reloading it because something
/// changed under them.
pub async fn machine(
    reader: crate::api::Reader) -> ApiResult<Machine> {
    // `repo: None` is the whole box, which is also how `/api/storage` asks.
    // There is no narrower request that still carries `reality`: it hangs off
    // the response and not off a filter, so asking for one repository would
    // buy nothing and risk a gunnar that only fills the field on the box-wide
    // call.
    match reader
        .gunnar
        .admin()
        .storage_info(pb::StorageInfoRequest { repo: None })
        .await
    {
        Ok(response) => Ok(Json(render(response.into_inner()))),
        // **A gunnar that cannot be asked is a state of the page, not a
        // failure of it.** The console still draws the three layers and names
        // the server that cannot answer for them. Every other refusal falls
        // through to the failure box with gunnar's words in it.
        Err(status) if status.code() == tonic::Code::Unimplemented => Ok(Json(Machine {
            unanswered: unserved_words(status.message()),
            ..Machine::default()
        })),
        Err(status) => Err(ApiError::from(status)),
    }
}

/// gunnar's refusal, kept verbatim, with a fallback when it sent no words.
///
/// tonic answers `Unimplemented` with an empty message for a method the server
/// does not have at all, and an empty string on the page would render as a
/// blank explanation of a blank page.
fn unserved_words(message: &str) -> String {
    if message.trim().is_empty() {
        "this Gunnar does not serve Admin.StorageInfo".to_owned()
    } else {
        message.to_owned()
    }
}

/// ★ **The words for the absence a real appliance will actually show.**
///
/// Kept apart from [`unserved_words`] because the servers are different and so
/// are the fixes. `Unimplemented` is a gunnar with no `Admin.StorageInfo` at
/// all. This one SERVES it, answered successfully, and simply predates
/// `StorageInfoResponse.reality` — an additive field, so an older server is
/// silently missing it rather than refusing. There is nothing in the status
/// code, the message or the response to distinguish it from a machine with
/// nothing to say, which is why this sentence has to name the field.
fn unreported_words() -> String {
    "this Gunnar serves Admin.StorageInfo but sends no `reality`: the server is older \
     than the machine report (StorageInfoResponse field 10)"
        .to_owned()
}

/// gunnar's message → the console's shape. **The only place that touches it.**
///
/// Every field is carried and none is derived. The conversions that are not a
/// copy are all about absence: an unmeasured filesystem carries no numbers
/// rather than zeroes, and a word this build has no name for carries no word.
pub fn render(response: pb::StorageInfoResponse) -> Machine {
    let Some(reality) = response.reality else {
        return Machine {
            unanswered: unreported_words(),
            ..Machine::default()
        };
    };

    Machine {
        unanswered: String::new(),
        // The record travels only when gunnar says there is one. A record
        // beside `record_present: false` would be a default-constructed one —
        // no version, no signature, no fields — and rendering it is exactly
        // the invention this page must not make.
        record: reality.record_present.then(|| InstallRecord {
            version: reality.record_version,
            signature: reality.record_signature,
            signature_verified: reality.record_signature_verified,
            signature_note: reality.record_signature_note,
            fields: record_fields(reality.record_fields),
        }),
        record_path: reality.record_path,
        record_absent: reality.record_absent_reason,
        filesystems: reality
            .filesystems
            .into_iter()
            .map(render_filesystem)
            .collect(),
        glance: reality
            .glance
            .into_iter()
            .map(|g| Glance { key: g.key, line: g.line, state: g.state, detail: g.detail })
            .collect(),
        placement: Some(Placement {
            data_root: reality.data_root,
            data_shape: reality.data_shape,
            data_devices: reality.data_devices,
            slow_root: reality.slow_root,
            slow_root_source: reality.slow_root_source,
            backing_device: reality.backing_device,
            backing_class: reality.backing_class,
            off_stripe: off_stripe_word(&reality.off_stripe),
            off_stripe_health: reality.off_stripe_health,
            rows: reality
                .placement
                .into_iter()
                .map(|r| PlacementRow {
                    what: r.what,
                    path: r.path,
                    requires_off_stripe: r.requires_off_stripe,
                    off_stripe: off_stripe_word(&r.off_stripe),
                    wired: r.wired,
                    note: r.note,
                })
                .collect(),
        }),
    }
}

/// The config's fields, **in key order and otherwise untouched**.
///
/// gunnar documents them as arriving in key order already; sorting here costs
/// nothing and means the page's ordering is a property of the page rather than
/// a promise it is trusting. Duplicate keys are kept — a config that carries
/// one twice is a thing an admin needs to SEE, and de-duplicating would hide
/// the exact anomaly this table exists to surface.
fn record_fields(fields: Vec<pb::InstallRecordField>) -> Vec<RecordField> {
    let mut fields: Vec<RecordField> = fields
        .into_iter()
        .map(|f| RecordField {
            key: f.key,
            value: f.value,
        })
        .collect();
    fields.sort();
    fields
}

/// One filesystem. **`measured` decides whether the numbers travel at all.**
///
/// proto3 hands a failed `statvfs` over as two zeroes, and "0 B free of 0 B"
/// on a disk that is full is the single most dangerous line this page could
/// print. gunnar carries the flag precisely so this decision is not made by
/// reading a zero.
fn render_filesystem(fs: pb::FilesystemUse) -> Filesystem {
    Filesystem {
        what: fs.what,
        path: fs.path,
        total_bytes: fs.measured.then_some(fs.total_bytes),
        free_bytes: fs.measured.then_some(fs.free_bytes),
        error: fs.error,
    }
}

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

    fn reality(reality: pb::StorageReality) -> Machine {
        render(pb::StorageInfoResponse {
            reality: Some(reality),
            ..Default::default()
        })
    }

    /// ★ **The three states of a copy stay three, and the unspecified one
    /// stays wordless.**
    ///
    /// The whole point of the page: `same_device` must never be able to reach
    /// a renderer as `elsewhere`, and a word this build has no name for must
    /// reach it as nothing rather than as the safest-looking word. gunnar's
    /// spellings are on the left and this console's on the right; the mapping
    /// is asserted here because it is the only place the two vocabularies
    /// meet.
    #[test]
    fn off_stripe_has_three_words_and_a_silence() {
        assert_eq!(off_stripe_word("off-stripe"), Some("elsewhere"));
        assert_eq!(off_stripe_word("same-device"), Some("same_device"));
        assert_eq!(off_stripe_word("absent"), Some("none"));
        // gunnar sends the empty string for a row that does not require an
        // off-stripe copy at all.
        assert_eq!(off_stripe_word(""), None);
        // A word from a gunnar newer than this build is not rounded to the
        // nearest word this build knows.
        assert_eq!(off_stripe_word("mirrored"), None);
        // And this console's own spelling is not gunnar's: if gunnar ever
        // started sending it, that would be a change to notice and not one to
        // silently accept.
        assert_eq!(off_stripe_word("same_device"), None);
    }

    /// ★ **A gunnar with no `reality` is explained, not drawn as an empty
    /// machine.**
    ///
    /// The failure mode this whole module was repointed to avoid: `reality` is
    /// an additive FIELD, so an older server answers `Ok` with it absent and
    /// nothing in the status code says so. Rendered naively that is a machine
    /// with no record, no filesystems and no placement — a measurement nobody
    /// took, drawn as a finding.
    #[test]
    fn a_gunnar_without_the_field_is_unanswered_rather_than_an_empty_machine() {
        let machine = render(pb::StorageInfoResponse {
            reality: None,
            // A real older gunnar fills the rest of the message in perfectly
            // well; it is only field 10 that is missing.
            object_backend: "packs".to_owned(),
            total_hot_bytes: 42,
            ..Default::default()
        });

        assert!(machine.unanswered.contains("reality"));
        assert!(machine.unanswered.contains("older"));
        assert_eq!(machine.record, None);
        assert!(machine.filesystems.is_empty());
        assert_eq!(machine.placement, None);
    }

    /// ★ **The two "cannot answer" states are two**, and their sentences name
    /// different servers.
    ///
    /// `Unimplemented` is a gunnar with no `Admin.StorageInfo`; a missing
    /// `reality` is a gunnar that serves it and predates field 10. They are
    /// fixed by unrelated things, and a page told only "gunnar cannot answer"
    /// could not tell an operator which.
    #[test]
    fn an_unserved_call_and_an_unreported_field_are_not_the_same_absence() {
        assert_eq!(
            unserved_words(""),
            "this Gunnar does not serve Admin.StorageInfo"
        );
        assert_eq!(unserved_words("no such method"), "no such method");
        assert!(unreported_words().contains("field 10"));
        assert_ne!(unserved_words(""), unreported_words());
    }

    /// ★ **No record means no record** — not an empty one.
    ///
    /// prost hands over the record's fields as readily empty as full, and a
    /// page given that would draw a config with no version, no signature and
    /// no keys, which reads as *the installer recorded nothing* rather than as
    /// *nobody knows*.
    #[test]
    fn an_absent_record_does_not_arrive_as_an_empty_one() {
        let machine = reality(pb::StorageReality {
            record_present: false,
            record_path: "/boot/korp/layout.conf".to_owned(),
            record_absent_reason: "no file at that path: this appliance was installed \
                                   before the record existed"
                .to_owned(),
            // gunnar may send a version and fields anyway; `record_present` is
            // what decides.
            record_version: 3,
            record_fields: vec![pb::InstallRecordField::default()],
            ..Default::default()
        });

        assert_eq!(machine.record, None);
        assert!(machine.record_absent.contains("before the record existed"));
        assert_eq!(machine.record_path, "/boot/korp/layout.conf");
    }

    /// ★ **The record's keys are carried whole, unparsed, in key order.**
    ///
    /// gunnar's own comment is the reason: *a key this build does not know is
    /// still shown, because the admin reading the page may know what it means
    /// when this binary does not*. So a key invented after this binary shipped
    /// must arrive intact, and folding the table back into disks and
    /// partitions — the shape this console once invented — would lose it.
    #[test]
    fn the_record_is_a_key_value_table_this_build_does_not_have_to_understand() {
        let machine = reality(pb::StorageReality {
            record_present: true,
            record_version: 3,
            record_signature: "INTEGRITY ONLY".to_owned(),
            record_signature_verified: false,
            record_signature_note: "no KORP_ROOT_SIGNING_KEY is enrolled on this estate"
                .to_owned(),
            record_fields: vec![
                pb::InstallRecordField {
                    key: "serialdat.dev".to_owned(),
                    value: "/dev/vda3".to_owned(),
                },
                pb::InstallRecordField {
                    key: "a.key.from.a.later.installer".to_owned(),
                    value: "whatever it means".to_owned(),
                },
                pb::InstallRecordField {
                    key: "data.raid".to_owned(),
                    value: "raid0".to_owned(),
                },
            ],
            ..Default::default()
        });

        let record = machine.record.expect("present");
        assert_eq!(record.version, 3);
        assert_eq!(record.signature, "INTEGRITY ONLY");
        assert!(!record.signature_verified);
        assert!(record.signature_note.contains("KORP_ROOT_SIGNING_KEY"));

        let keys: Vec<&str> = record.fields.iter().map(|f| f.key.as_str()).collect();
        assert_eq!(
            keys,
            vec!["a.key.from.a.later.installer", "data.raid", "serialdat.dev"]
        );
        // The key this binary has never heard of kept its value.
        assert_eq!(record.fields[0].value, "whatever it means");
    }

    /// A record whose signature verified says so in a field, not in a word the
    /// page would have to compare.
    #[test]
    fn a_verified_signature_is_a_flag_and_not_a_string_comparison() {
        let machine = reality(pb::StorageReality {
            record_present: true,
            record_signature: "verified".to_owned(),
            record_signature_verified: true,
            ..Default::default()
        });

        let record = machine.record.expect("present");
        assert!(record.signature_verified);
        assert_eq!(record.signature_note, "");
    }

    /// ★ **A filesystem that could not be measured carries no numbers at
    /// all.**
    ///
    /// proto3 would hand a failed `statvfs` over as two zeroes, and "0 B free
    /// of 0 B" on a disk that is full is the single most dangerous line this
    /// page could print.
    #[test]
    fn an_unmeasured_filesystem_carries_no_bytes_at_all() {
        let machine = reality(pb::StorageReality {
            filesystems: vec![
                pb::FilesystemUse {
                    what: "data root".to_owned(),
                    path: "/data".to_owned(),
                    measured: true,
                    total_bytes: 137_438_953_472,
                    free_bytes: 94_489_280_512,
                    error: String::new(),
                },
                pb::FilesystemUse {
                    what: "configured directory".to_owned(),
                    path: "/serialdat".to_owned(),
                    measured: false,
                    // gunnar zeroes them; the flag is what decides.
                    total_bytes: 0,
                    free_bytes: 0,
                    error: "statvfs: Input/output error (os error 5)".to_owned(),
                },
            ],
            ..Default::default()
        });

        assert_eq!(machine.filesystems[0].total_bytes, Some(137_438_953_472));
        assert_eq!(machine.filesystems[0].free_bytes, Some(94_489_280_512));
        assert_eq!(machine.filesystems[1].total_bytes, None);
        assert_eq!(machine.filesystems[1].free_bytes, None);
        assert!(machine.filesystems[1].error.contains("os error 5"));
    }

    /// Layer 3 is carried whole: the roots, how gunnar learned them, and every
    /// placement row with its own wiring verdict.
    #[test]
    fn the_placement_table_keeps_its_rows_its_wiring_and_its_failure_domains() {
        let machine = reality(pb::StorageReality {
            data_root: "/data/gunnar".to_owned(),
            slow_root: "/serialdat".to_owned(),
            slow_root_source: "named by the layout config".to_owned(),
            backing_device: "/dev/vda3".to_owned(),
            backing_class: "p3".to_owned(),
            off_stripe: "same-device".to_owned(),
            off_stripe_health: vec![
                "the roster mirror is present and shares a device with what it mirrors"
                    .to_owned(),
            ],
            placement: vec![
                pb::PlacementRow {
                    what: "metadata mirror (roster, principals, enrolled keys)".to_owned(),
                    path: "/serialdat/gunnar/mirror".to_owned(),
                    requires_off_stripe: true,
                    off_stripe: "same-device".to_owned(),
                    wired: true,
                    note: String::new(),
                },
                pb::PlacementRow {
                    what: "archives".to_owned(),
                    path: "/serialdat/gunnar/archives".to_owned(),
                    requires_off_stripe: false,
                    off_stripe: String::new(),
                    wired: false,
                    note: "no archive-out has run on this box".to_owned(),
                },
            ],
            ..Default::default()
        });

        let placement = machine.placement.expect("reported");
        assert_eq!(placement.data_root, "/data/gunnar");
        assert_eq!(placement.slow_root_source, "named by the layout config");
        assert_eq!(placement.backing_class, "p3");
        // The verdict is the worst of the three, and it arrived as such.
        assert_eq!(placement.off_stripe, Some("same_device"));
        assert_eq!(placement.off_stripe_health.len(), 1);

        assert_eq!(placement.rows[0].off_stripe, Some("same_device"));
        assert!(placement.rows[0].requires_off_stripe);
        assert!(placement.rows[0].wired);
        // A row that does not require an off-stripe copy carries no verdict
        // about one rather than the best-looking of the three.
        assert_eq!(placement.rows[1].off_stripe, None);
        assert!(!placement.rows[1].requires_off_stripe);
        assert!(!placement.rows[1].wired);
        assert!(placement.rows[1].note.contains("no archive-out"));
    }

    /// ★ **The glance lines and `/data`'s shape travel verbatim** (2026-10-04),
    /// and `/serialdat`'s disk stays `/serialdat`'s: the BFF neither re-words
    /// gunnar's verdict nor folds `backing_device` into `/data`.
    #[test]
    fn the_glance_and_the_data_shape_arrive_as_gunnar_sent_them() {
        let m = reality(pb::StorageReality {
            data_root: "/data".into(),
            data_shape: "raid0".into(),
            data_devices: vec!["/dev/vdb".into(), "/dev/vdc".into()],
            backing_device: "/dev/vda3".into(),
            backing_class: "p3".into(),
            glance: vec![pb::GlanceLine {
                key: "data".into(),
                line: "/data = raid0 over /dev/vdb, /dev/vdc".into(),
                state: "ok".into(),
                detail: "the stripe".into(),
            }],
            ..Default::default()
        });
        assert_eq!(m.glance, [Glance { key: "data".into(), line: "/data = raid0 over /dev/vdb, /dev/vdc".into(), state: "ok".into(), detail: "the stripe".into() }]);
        let p = m.placement.expect("placement");
        assert_eq!((p.data_shape.as_str(), p.data_devices.as_slice()), ("raid0", &["/dev/vdb".to_owned(), "/dev/vdc".to_owned()][..]));
        assert_eq!(p.backing_device, "/dev/vda3", "serialdat's disk is carried as serialdat's");
    }
}