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

nordisk/monetize

crates/monetize-embed/src/fleet.rs

//! **The pull channel's signed forms** (5.4, G1-pull): monetize never calls INTO an
//! estate; every estate calls monetize (`Fleet.Report`, `Fleet.Orders`, `Fleet.Ask`) and
//! monetize answers with [`SignedOrder`]s the box verifies under `monetize_pubkey`.
//!
//! Two forms, each a fixed binary layout (not JSON) so the estate's verifier
//! (`gunnar_repair::order`) and this crate agree byte for byte with no canonical-JSON
//! rule to share:
//!
//! * [`order_message`]: what monetize signs for ONE order to ONE box (`role`).
//! * [`fleet_call_message`]: what a box signs with its own Ed25519 appliance key for each
//!   call it makes to monetize.
//!
//! An order is only "please run verb V with these arguments": the estate runs it through the
//! SAME function its local admin button and its boot check call, and says how it went in the
//! next [`Report`] ([`OrderAck`]).

use ed25519_dalek::{Signature, VerifyingKey};
use serde::{Deserialize, Serialize};

/// The domain tag every order signature starts with.
pub const ORDER_DOMAIN: &[u8] = b"nordisk-order-v1\0";
/// The domain tag every box's call signature starts with.
pub const CALL_DOMAIN: &[u8] = b"nordisk-fleet-call-v1\0";
/// How far a box's call time may be from monetize's clock.
pub const CALL_FRESH_MS: u64 = 5 * 60 * 1000;
/// How far ahead of the box's clock an order may be dated (the shared pump's and Gunnar's five
/// minutes).
pub const FUTURE_SKEW_MS: u64 = 5 * 60 * 1000;
/// How long `Fleet.Orders` is held open at most before it answers empty.
pub const LONG_POLL_MAX_MS: u64 = 25_000;
/// **How long a front waits on the shop's `SoldEstate.Upgrade`**: the shop's whole keep boot,
/// 2 h, the ONE constant the shop holds its call by (`monetize_product::KEEP_BOOT_WITHIN`; lane
/// G9, A7 row 9, Gunnar b74ca801). A front that gave up first would count a slow keep boot as
/// lost and ask for a Recharge while the shop still works.
pub use monetize_product::KEEP_BOOT_WITHIN;
/// **The shop's words for an Upgrade still running** (`an upgrade of <host> is already running
/// here`, an UNAVAILABLE answer): the front that hears them asks again later (REL-T2-1: the
/// Upgrade is started, then polled). The ONE box says them; the front's door reads them.
pub const UPGRADE_RUNNING: &str = "is already running here";

/// The order kinds. The body is JSON; unknown fields are ignored. The relay products' guardian
/// kinds ([`kind::GUARDIAN`], gunnar-repair's verbs) are defined here; the core's kinds are
/// `monetize_product::pull`'s one list (A28 M25), re-exported here under their old names.
pub mod kind {
    /// `{main, twin, accept_lost, epoch, case?}`: the twin (or a fresh main) pumps the twin's
    /// log into the main. The same verb the local "Recharge" button and the boot check run.
    pub const RECHARGE_FROM_TWIN: &str = "recharge_from_twin";
    /// `{primary, epoch, case?}`: the old primary may not serve past `epoch`.
    pub const FENCE_PRIMARY: &str = "fence_primary";
    /// `{twin, principal, case?}`: the primary takes the box at `twin` as its twin.
    pub const ADOPT_TWIN: &str = "adopt_twin";
    /// `{case?}`: the box reviews its twin and reports the `TwinReview`.
    pub const REVIEW_TWIN: &str = "review_twin";
    /// `{snapshot, case?}`: the money put back on a recharged main. `snapshot` is a
    /// [`crate::Snapshot`] signed by monetize's key — what monetize's books hold for the
    /// product. The box verifies it and every fact in it (`signing::verify_snapshot`), applies
    /// each fact only if newer than the one it holds (a same fact is a no-op), deletes
    /// nothing, and runs it only while it serves as the primary.
    pub const RESTATE_ENTITLEMENTS: &str = "restate_entitlements";
    /// [`super::GrowGoAhead`]: **a sold estate's paid data step** (G16-d, G1-pull row 17),
    /// queued to the estate's main AND its twin once the step's money is captured. The box
    /// verifies `go_ahead` under monetize's key (`signing::verify_estate_growth`: its estate,
    /// good until `until_unix_ms`), then grows its own data disks to `data_gib` a disk: drain,
    /// unmount, `Fleet.Ask{kind: ask::GROW_SET}` (monetize resizes them at the provider), look
    /// again, remount. The twin first — its disk holds main's whole set. A newer go-ahead
    /// supersedes an unacked older one; a growth already done is acked ok, nothing moved.
    pub use monetize_product::pull::order::GROW_GO_AHEAD;
    /// [`super::Refeed`]: **estate keys fed again to an already-laid estate** (MAIL-RELAY +
    /// NIGHT-PUBREPO, 2026-10-28), queued to the estate's main and twin when the operator asks
    /// (`EstateOrder.Refeed`). The box takes each key it knows by name ([`super::refeed`]) and
    /// refuses the order by name otherwise. The body may CARRY A SECRET (the relay's token): never
    /// logged; a newer one supersedes an unacked older one.
    pub use monetize_product::pull::order::REFEED;
    /// [`super::SignInAgain`]: **a sold estate's RESEND sign-in link** (S10, owner 2026-10-11
    /// 05:53Z), queued to the estate's main when its buyer asks (`EstateOrder.SendSignInAgain`).
    /// The order names whose passkey, which address and which console host — NO secret: the
    /// main mints the fresh invite itself (only while the account holds no passkey) and mails
    /// `https://{host}/login?invite=…&user=…` itself. The shop never holds a resend's login
    /// secret (the FIRST link stays shop-minted at install, OM-21 decision A). A newer ask
    /// supersedes an unacked older one.
    pub use monetize_product::pull::order::SIGN_IN_AGAIN;

    /// **The relay products' guardian kinds** (the twin's repair verbs): not core kinds; a
    /// product whose guardian runs no twin never gets one.
    pub const GUARDIAN: [&str; 5] = [
        RECHARGE_FROM_TWIN,
        FENCE_PRIMARY,
        ADOPT_TWIN,
        REVIEW_TWIN,
        RESTATE_ENTITLEMENTS,
    ];
}

/// The `Fleet.Ask` kinds that are not a remedy: answered at once, no case opened.
/// A product's own order ([`ProductOrder`]) and the file it may carry ([`Fetch`]), MONETIZE-FIX.
pub use monetize_product::pull::{Fetch, FetchAsk, ProductOrder};

pub mod ask {
    /// `monetize_product::pull::FetchAsk` `{id}`: **the box pulls the file a product order
    /// carries** (MONETIZE-FIX); the bytes come back in `FleetAskAnswer.answer`.
    pub use monetize_product::pull::ask::FETCH;
    /// [`super::GrowSetAsk`]: **size the calling box's own data disks** at monetize's provider
    /// (G16-d, G1-pull row 18) — no more than is paid for its role, never smaller. The main
    /// sizes main's disks, the twin (its own key, `role = twin`) the twin's.
    pub use monetize_product::pull::ask::GROW_SET;
    /// [`super::FrontAsk`] `{role, done}`: **the shop boots ONE standing box once from the
    /// release's keep medium** (was `SoldEstate.Upgrade`; plan §8, A24 §5.1 row 27). Asked by
    /// the estate's front; the answer is `EstateUpgradeResponse` in `FleetAskAnswer.answer`.
    pub const UPGRADE: &str = "upgrade";
    /// [`super::FrontAsk`] `{role, seed, done}`: **the shop lays ONE lost box again** (was
    /// `SoldEstate.Recharge`, row 29); the answer is `EstateRechargeResponse`. Not the guardian's
    /// `recharge_from_twin` remedy: this one is the cloud half, asked by the front.
    pub const RECHARGE: &str = "recharge";
    /// [`super::FrontAsk`] `{done}`: **the estate takes its own installer material** (was
    /// `SoldEstate.TakeMaterial`, row 28); the answer is `EstateTakeMaterialResponse`.
    pub const MATERIAL: &str = "material";
    /// [`super::FrontAsk`] `{}`: **the front takes the open update** (was
    /// `SoldEstate.UpdateTake`, row 25); the answer is `EstateUpdateTakeResponse`.
    pub const UPDATE_TAKE: &str = "update_take";
    /// [`super::FrontAsk`] `{role, carries}`: **the front reports one box's update step** (was
    /// `SoldEstate.UpdateReport`, row 26); the answer is `EstateUpdateReportResponse`.
    pub const UPDATE_REPORT: &str = "update_report";
    /// **The front's asks** — the five `SoldEstate` calls folded into `Fleet.Ask` (plan §8,
    /// decided 2026-10-24). Answered at once, no case opened; asked only by the estate's front.
    pub const FRONT: [&str; 5] = [UPGRADE, RECHARGE, MATERIAL, UPDATE_TAKE, UPDATE_REPORT];

    /// Pure: **is `kind` one of the front's asks** ([`FRONT`])?
    pub fn is_front(kind: &str) -> bool {
        FRONT.contains(&kind)
    }
}

/// The calls a box makes ([`FleetCall::call`]).
pub mod call {
    pub const REPORT: &str = "report";
    pub const ORDERS: &str = "orders";
    pub const ASK: &str = "ask";
}

/// **One order to one box**, signed by the product's monetize key.
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
pub struct SignedOrder {
    /// Per instance, strictly rising; the box refuses any `seq` at or below the last it ran.
    pub seq: u64,
    pub product: String,
    pub instance: String,
    /// The box the order is for: `main` | `twin` | `front`. Signed, so an order for the twin
    /// is never run by the main.
    pub role: String,
    pub kind: String,
    /// JSON text.
    pub body: String,
    pub issued_unix_ms: u64,
    pub not_after_unix_ms: u64,
    /// 64-byte Ed25519 over [`order_message`].
    #[serde(default)]
    pub signature: Vec<u8>,
}

/// Why a box refuses an order.
#[derive(Clone, PartialEq, Eq, Debug, thiserror::Error)]
pub enum OrderRefusal {
    #[error("the order is not signed by monetize")]
    Signature,
    #[error("order {seq} is not newer than {last}")]
    Replayed { seq: u64, last: u64 },
    #[error("order {0} has expired")]
    Expired(u64),
    #[error("order {0} is for {1}, not this box")]
    NotForMe(u64, String),
    #[error("order {0} is dated more than five minutes ahead of this box's clock")]
    Ahead(u64),
}

fn field(out: &mut Vec<u8>, bytes: &[u8]) {
    out.extend_from_slice(&(bytes.len() as u32).to_be_bytes());
    out.extend_from_slice(bytes);
}

/// The bytes an order's signature covers: [`ORDER_DOMAIN`] ‖ seq ‖ issued ‖ not_after (u64 BE)
/// ‖ then product, instance, role, kind, body, each as u32 BE length ‖ bytes.
pub fn order_message(o: &SignedOrder) -> Vec<u8> {
    let mut out = ORDER_DOMAIN.to_vec();
    out.extend_from_slice(&o.seq.to_be_bytes());
    out.extend_from_slice(&o.issued_unix_ms.to_be_bytes());
    out.extend_from_slice(&o.not_after_unix_ms.to_be_bytes());
    for f in [&o.product, &o.instance, &o.role, &o.kind, &o.body] {
        field(&mut out, f.as_bytes());
    }
    out
}

/// **The box's check**, as strict as the shared pump's (`monetize_estate_side::pump::check`):
/// signed under `key` with STRICT Ed25519 (no small-order key or `R`), checked first, so a
/// forged order is always [`OrderRefusal::Signature`] and never moves the box's sequence; then
/// for `(product, instance, role)`, newer than `last_seq`, inside its window at `now_unix_ms`
/// (`not_after` 0 = none), and dated no more than [`FUTURE_SKEW_MS`] ahead of the box's clock.
pub fn verify_order(
    o: &SignedOrder,
    key: &VerifyingKey,
    me: (&str, &str, &str),
    now_unix_ms: u64,
    last_seq: u64,
) -> Result<(), OrderRefusal> {
    let (product, instance, role) = me;
    if !check(key, &order_message(o), &o.signature) {
        return Err(OrderRefusal::Signature);
    }
    if o.product != product || o.instance != instance || o.role != role {
        return Err(OrderRefusal::NotForMe(o.seq, o.role.clone()));
    }
    if o.seq <= last_seq {
        return Err(OrderRefusal::Replayed {
            seq: o.seq,
            last: last_seq,
        });
    }
    if o.not_after_unix_ms != 0 && now_unix_ms > o.not_after_unix_ms {
        return Err(OrderRefusal::Expired(o.seq));
    }
    if o.issued_unix_ms > now_unix_ms.saturating_add(FUTURE_SKEW_MS) {
        return Err(OrderRefusal::Ahead(o.seq));
    }
    Ok(())
}

/// **One call from a box to monetize**, signed by the box's own appliance key.
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
pub struct FleetCall {
    pub product: String,
    pub instance: String,
    pub role: String,
    /// [`call::REPORT`] | [`call::ORDERS`] | [`call::ASK`].
    pub call: String,
    /// JSON text: a [`Report`], an [`OrdersAfter`] or an [`Ask`].
    pub body: String,
    pub at_unix_ms: u64,
}

/// Why monetize refuses a box's call.
#[derive(Clone, PartialEq, Eq, Debug, thiserror::Error)]
pub enum CallRefusal {
    #[error("the call is not signed by the box's key")]
    Signature,
    #[error("the call's time is too far from monetize's clock")]
    Stale,
}

/// The bytes a box's call signature covers: [`CALL_DOMAIN`] ‖ at (u64 BE) ‖ then product,
/// instance, role, call, body, each as u32 BE length ‖ bytes.
pub fn fleet_call_message(c: &FleetCall) -> Vec<u8> {
    let mut out = CALL_DOMAIN.to_vec();
    out.extend_from_slice(&c.at_unix_ms.to_be_bytes());
    for f in [&c.product, &c.instance, &c.role, &c.call, &c.body] {
        field(&mut out, f.as_bytes());
    }
    out
}

/// Verify a box's call under its appliance `key`, fresh at `now_unix_ms`.
pub fn verify_fleet_call(
    c: &FleetCall,
    signature: &[u8],
    key: &VerifyingKey,
    now_unix_ms: u64,
) -> Result<(), CallRefusal> {
    if !check(key, &fleet_call_message(c), signature) {
        return Err(CallRefusal::Signature);
    }
    if c.at_unix_ms.abs_diff(now_unix_ms) > CALL_FRESH_MS {
        return Err(CallRefusal::Stale);
    }
    Ok(())
}

/// STRICT Ed25519 (`verify_strict`): a small-order key or `R` never verifies (T16, A28 M11).
fn check(key: &VerifyingKey, msg: &[u8], sig: &[u8]) -> bool {
    Signature::from_slice(sig)
        .map(|s| key.verify_strict(msg, &s).is_ok())
        .unwrap_or(false)
}

/// What a box says ran (or did not) — sent back in its next [`Report`].
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct OrderAck {
    pub seq: u64,
    pub ok: bool,
    pub detail: String,
    /// gunnar_repair's `Receipt` / `TwinReview`, JSON text; empty when none.
    pub receipt_json: String,
}

/// **The box's heartbeat** (`Fleet.Report` body). Its arrival time is the liveness signal.
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct Report {
    pub build: String,
    /// The box's own health words, flat: `serving` (`yes` | `no` | `fenced`), `data` (`ok` |
    /// `lost` | `diverged`), `serves_at` (`host:port`), `twin` (`paired` | `silent` | …),
    /// `epoch`. Unknown words are kept and shown.
    pub health: std::collections::BTreeMap<String, String>,
    pub acked: Vec<OrderAck>,
    /// The product's twin review (gunnar: `gunnar_repair::TwinReview`), JSON text, when it
    /// made one.
    pub twin_review: Option<String>,
    /// **The product's own state** (G1 pull: tenants and owners, usage, servable, the paid
    /// door, the room a raise would find), JSON text of `monetize_product::pull::ProductReport`.
    /// Sent by the box that serves tenants (the main); what monetize used to dial it for.
    pub product: Option<String>,
    pub measured_unix_ms: u64,
}

/// `Fleet.Orders` body: orders after `after`, held up to `wait_ms` (≤ [`LONG_POLL_MAX_MS`]).
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct OrdersAfter {
    pub after: u64,
    pub wait_ms: u64,
}

/// Body of a [`kind::GROW_GO_AHEAD`] order.
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct GrowGoAhead {
    /// The [`crate::signing::EstateGrowth`] JSON, signed by monetize's key.
    pub go_ahead: String,
    /// GB a data disk THIS box's role is paid to (main: the step; twin: main's whole set).
    pub data_gib: u64,
}

/// Body of a [`kind::SIGN_IN_AGAIN`] order. Never a secret.
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct SignInAgain {
    /// The account whose first passkey the invite enrols (the order's account).
    pub account: String,
    /// The order's address: where the estate mails the link.
    pub to: String,
    /// The console's relying-party host the link points at (`<company>.<apex>`).
    pub host: String,
    /// How long the invite lives.
    pub ttl_secs: u64,
}

/// **The estate keys a [`kind::REFEED`] order may carry**, in the words of the feed a box is
/// laid with: the mains' mail relay (`secret.smtp_url`, `secret.smtp_from`, and `secret.smtp_ca`
/// for a relay on a private CA; monetize-mail `FEED_SMTP_*`) and a site's public repositories
/// (`public_repositories`, comma-separated). A box takes the ones it knows and refuses any
/// other by name.
pub mod refeed {
    pub const SMTP_URL: &str = "secret.smtp_url";
    pub const SMTP_FROM: &str = "secret.smtp_from";
    pub const SMTP_CA: &str = "secret.smtp_ca";
    pub const PUBLIC_REPOSITORIES: &str = "public_repositories";
    /// The site's public-site switch, `on` | `off` (GRS-PUBLIC 2026-10-28; the lay's own front
    /// feed word, monetize-shop-pairing `contract::FEED_PUBLIC_SITE`).
    pub const PUBLIC_SITE: &str = "console_public_site";
    /// Every key a refeed may carry.
    pub const KNOWN: [&str; 5] = [
        SMTP_URL,
        SMTP_FROM,
        SMTP_CA,
        PUBLIC_REPOSITORIES,
        PUBLIC_SITE,
    ];
    /// The keys whose values are secrets (never shown).
    pub fn is_secret(key: &str) -> bool {
        key.starts_with("secret.")
    }
}

/// Body of a [`kind::REFEED`] order (MAIL-RELAY + NIGHT-PUBREPO, 2026-10-28): the estate keys
/// fed again, key → value. **A `secret.` value is a secret**: the `Debug` names the keys only.
#[derive(Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct Refeed {
    pub keys: std::collections::BTreeMap<String, String>,
}

impl std::fmt::Debug for Refeed {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("Refeed")
            .field("keys", &self.keys.keys().collect::<Vec<_>>())
            .finish()
    }
}

/// `Fleet.Ask` body of [`ask::GROW_SET`]: the box's own data disks to `gib` a disk. No
/// `members` = every laid data disk of the calling box; `gib` 0 = what its role is paid to.
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct GrowSetAsk {
    pub members: Vec<String>,
    pub gib: u64,
}

/// **The body of a front's ask** ([`ask::FRONT`]): the fields the old `SoldEstate` request
/// carried, less the company and the signature — the `FleetSigned` call names the estate
/// (`instance`) and the box (`role = front`) and is signed by the front's key. `role` is the
/// box the ask is about (`main` | `twin`; for `update_report`, the box whose step it is);
/// `carries` is the update report's `<outcome>\n<words>`.
#[derive(Clone, PartialEq, Eq, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct FrontAsk {
    #[serde(skip_serializing_if = "String::is_empty")]
    pub role: String,
    #[serde(skip_serializing_if = "std::ops::Not::not")]
    pub done: bool,
    #[serde(skip_serializing_if = "String::is_empty")]
    pub seed: String,
    #[serde(skip_serializing_if = "String::is_empty")]
    pub carries: String,
}

/// `Fleet.Ask` body: a request from the estate (`new_twin`, `new_server`, `recharge`, …).
#[derive(Clone, PartialEq, Debug, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct Ask {
    pub kind: String,
    pub body: serde_json::Value,
}

#[cfg(test)]
mod tests {
    use super::*;
    use ed25519_dalek::{Signer as _, SigningKey};

    /// A28 M25: the core kinds are defined once, in `monetize_product::pull`; the kinds here
    /// are that list's, and the rest of [`kind`] are the relay products' guardian kinds.
    #[test]
    fn the_core_kinds_here_are_monetize_products_one_list() {
        use monetize_product::pull;
        assert_eq!(kind::GROW_GO_AHEAD, pull::order::GROW_GO_AHEAD);
        assert_eq!(kind::SIGN_IN_AGAIN, pull::order::SIGN_IN_AGAIN);
        assert_eq!(kind::REFEED, pull::order::REFEED);
        assert_eq!(ask::GROW_SET, pull::ask::GROW_SET);
        for k in kind::GUARDIAN {
            assert!(!pull::is_core(k), "{k} is a guardian kind, not a core one");
        }
        assert_eq!(
            kind::GUARDIAN,
            [
                kind::RECHARGE_FROM_TWIN,
                kind::FENCE_PRIMARY,
                kind::ADOPT_TWIN,
                kind::REVIEW_TWIN,
                kind::RESTATE_ENTITLEMENTS
            ]
        );
    }

    /// ★ Plan §8 (the SoldEstate → Fleet fold): the front's five asks are named once, none of
    /// them is a guardian remedy or `grow_set`, and their body round-trips through the `Ask`
    /// JSON with only the fields it carries.
    #[test]
    fn the_fronts_asks_are_the_five_soldestate_calls_and_their_body_round_trips() {
        assert_eq!(
            ask::FRONT,
            [
                "upgrade",
                "recharge",
                "material",
                "update_take",
                "update_report"
            ]
        );
        for k in ask::FRONT {
            assert!(ask::is_front(k));
        }
        for k in [
            ask::GROW_SET,
            kind::RECHARGE_FROM_TWIN,
            kind::REVIEW_TWIN,
            "new_twin",
            "new_server",
            "",
        ] {
            assert!(!ask::is_front(k), "{k}");
        }
        // The ONE box's own door, not a product's kind: none is one of the core's 8 (A28 M25).
        for k in ask::FRONT {
            assert!(!monetize_product::pull::is_core(k), "{k}");
        }
        let a = FrontAsk {
            role: "main".into(),
            seed: "SEED".into(),
            ..Default::default()
        };
        let text = serde_json::to_string(&Ask {
            kind: ask::RECHARGE.into(),
            body: serde_json::to_value(&a).unwrap(),
        })
        .unwrap();
        assert_eq!(
            text,
            r#"{"kind":"recharge","body":{"role":"main","seed":"SEED"}}"#
        );
        let back: Ask = serde_json::from_str(&text).unwrap();
        assert_eq!(serde_json::from_value::<FrontAsk>(back.body).unwrap(), a);
        assert_eq!(
            serde_json::from_value::<FrontAsk>(serde_json::json!({})).unwrap(),
            FrontAsk::default(),
            "an empty body is the update take's"
        );
    }

    /// ★ Lane G9, A7 row 9 (Gunnar b74ca801): a front waits on the shop's whole keep boot, 2 h,
    /// the one constant the shop's cloud crate holds its Upgrade call by.
    #[test]
    fn a_front_waits_on_the_shops_whole_keep_boot() {
        assert_eq!(KEEP_BOOT_WITHIN, std::time::Duration::from_secs(2 * 3600));
        assert_eq!(KEEP_BOOT_WITHIN, monetize_product::KEEP_BOOT_WITHIN);
    }

    const GOLDEN_MESSAGE_HEX: &str = "6e6f726469736b2d6f726465722d7631000000000000000003000001a3185c5000000001a3186a0ba00000000667756e6e61720000000461636d65000000047477696e0000001272656368617267655f66726f6d5f7477696e000000517b226163636570745f6c6f7374223a66616c73652c2265706f6368223a352c226d61696e223a2231302e362e302e31303a3530303531222c227477696e223a2231302e362e302e31323a3530303531227d";
    const GOLDEN_SIGNATURE_HEX: &str = "d4a3233158d9a3fbfa42f9aa80fd2ca420666ec2fe9f7fbf1a61abab533c09f6dab60c67367bc771a1d819d1e6bed28c59d6d56187a4748ba9b4b9988d13d50a";

    fn key() -> SigningKey {
        SigningKey::from_bytes(&[7u8; 32])
    }

    fn order() -> SignedOrder {
        SignedOrder {
            seq: 3,
            product: "gunnar".into(),
            instance: "acme".into(),
            role: "twin".into(),
            kind: kind::RECHARGE_FROM_TWIN.into(),
            body: r#"{"accept_lost":false,"epoch":5,"main":"10.6.0.10:50051","twin":"10.6.0.12:50051"}"#.into(),
            issued_unix_ms: 1_800_000_000_000,
            not_after_unix_ms: 1_800_000_900_000,
            signature: Vec::new(),
        }
    }

    fn signed() -> SignedOrder {
        let mut o = order();
        o.signature = key().sign(&order_message(&o)).to_bytes().to_vec();
        o
    }

    /// The golden vector gunnar-repair pastes into its own test: same order, same bytes.
    #[test]
    fn the_order_message_is_the_agreed_binary_layout() {
        let m = order_message(&order());
        assert!(m.starts_with(ORDER_DOMAIN));
        let mut want = ORDER_DOMAIN.to_vec();
        want.extend_from_slice(&3u64.to_be_bytes());
        want.extend_from_slice(&1_800_000_000_000u64.to_be_bytes());
        want.extend_from_slice(&1_800_000_900_000u64.to_be_bytes());
        for f in [
            "gunnar",
            "acme",
            "twin",
            kind::RECHARGE_FROM_TWIN,
            &order().body,
        ] {
            want.extend_from_slice(&(f.len() as u32).to_be_bytes());
            want.extend_from_slice(f.as_bytes());
        }
        assert_eq!(m, want);
        let sig = key().sign(&m).to_bytes();
        let hex: String = sig.iter().map(|b| format!("{b:02x}")).collect();
        assert_eq!(
            hex, GOLDEN_SIGNATURE_HEX,
            "the golden vector moved: tell gunnar_repair::order"
        );
        let mhex: String = m.iter().map(|b| format!("{b:02x}")).collect();
        assert_eq!(mhex, GOLDEN_MESSAGE_HEX);
    }

    #[test]
    fn a_box_runs_only_a_fresh_order_signed_for_it() {
        let pk = key().verifying_key();
        let me = ("gunnar", "acme", "twin");
        let now = 1_800_000_100_000;
        assert_eq!(verify_order(&signed(), &pk, me, now, 2), Ok(()));
        assert_eq!(
            verify_order(&signed(), &pk, me, now, 3),
            Err(OrderRefusal::Replayed { seq: 3, last: 3 })
        );
        assert_eq!(
            verify_order(&signed(), &pk, me, 1_800_000_900_001, 0),
            Err(OrderRefusal::Expired(3))
        );
        assert_eq!(
            verify_order(&signed(), &pk, ("gunnar", "acme", "main"), now, 0),
            Err(OrderRefusal::NotForMe(3, "twin".into()))
        );
        let mut forged = signed();
        forged.role = "main".into();
        assert_eq!(
            verify_order(&forged, &pk, ("gunnar", "acme", "main"), now, 0),
            Err(OrderRefusal::Signature)
        );
        let other = SigningKey::from_bytes(&[9u8; 32]).verifying_key();
        assert_eq!(
            verify_order(&signed(), &other, me, now, 0),
            Err(OrderRefusal::Signature)
        );
    }

    /// ★ **T16 (A28 M11): this check is as strict as the shared pump's** (`monetize_estate_side::
    /// pump::check`, P4c). Under a small-order key (the identity point) the all-zero signature
    /// verifies ANY message with plain `verify`; a strict check refuses it, and a real key's
    /// signature still passes.
    #[test]
    fn a_weak_key_with_the_all_zero_signature_signs_no_order() {
        let (weak, zero) = weak_key_and_zero_signature();
        let mut o = order();
        o.signature = zero;
        let now = 1_800_000_100_000;
        assert_eq!(
            verify_order(&o, &weak, ("gunnar", "acme", "twin"), now, 0),
            Err(OrderRefusal::Signature),
            "a weak key verifies nothing"
        );
        assert_eq!(
            verify_order(
                &signed(),
                &key().verifying_key(),
                ("gunnar", "acme", "twin"),
                now,
                0
            ),
            Ok(())
        );
    }

    /// ★ The same weak key never vouches for a box's call either.
    #[test]
    fn a_weak_box_key_with_the_all_zero_signature_signs_no_call() {
        let (weak, zero) = weak_key_and_zero_signature();
        let c = FleetCall {
            product: "gunnar".into(),
            instance: "acme".into(),
            role: "main".into(),
            call: call::REPORT.into(),
            body: "{}".into(),
            at_unix_ms: 1_800_000_000_000,
        };
        assert_eq!(
            verify_fleet_call(&c, &zero, &weak, 1_800_000_000_000),
            Err(CallRefusal::Signature)
        );
    }

    /// The identity point as a key, and the signature (R = identity, s = 0) that plain `verify`
    /// accepts for every message under it.
    fn weak_key_and_zero_signature() -> (VerifyingKey, Vec<u8>) {
        let mut identity = [0u8; 32];
        identity[0] = 1;
        let weak = VerifyingKey::from_bytes(&identity).expect("the identity point decompresses");
        let mut zero = vec![0u8; 64];
        zero[0] = 1;
        (weak, zero)
    }

    /// ★ Every signed field is covered: one tampered field, a flipped signature bit, a short or
    /// missing signature, or another key is refused as not monetize's.
    #[test]
    fn a_tampered_order_is_not_monetizes() {
        let pk = key().verifying_key();
        let me = ("gunnar", "acme", "twin");
        let now = 1_800_000_100_000;
        type Tamper = Box<dyn Fn(&mut SignedOrder)>;
        let tampered: Vec<(&str, Tamper)> = vec![
            ("seq", Box::new(|o| o.seq += 1)),
            ("kind", Box::new(|o| o.kind = kind::FENCE_PRIMARY.into())),
            ("body", Box::new(|o| o.body = "{}".into())),
            ("issued", Box::new(|o| o.issued_unix_ms -= 1)),
            ("not_after", Box::new(|o| o.not_after_unix_ms += 1)),
            ("bit", Box::new(|o| o.signature[5] ^= 1)),
            ("short", Box::new(|o| o.signature.truncate(63))),
            ("none", Box::new(|o| o.signature.clear())),
        ];
        for (what, f) in tampered {
            let mut o = signed();
            f(&mut o);
            assert_eq!(
                verify_order(&o, &pk, me, now, 0),
                Err(OrderRefusal::Signature),
                "{what}"
            );
        }
    }

    /// ★ The signature is checked FIRST: a forged order addressed to another box is forged (it
    /// never moves the box's sequence), not "not for me".
    #[test]
    fn a_forged_order_for_another_box_is_forged_not_misaddressed() {
        let mut o = signed();
        o.role = "main".into();
        assert_eq!(
            verify_order(
                &o,
                &key().verifying_key(),
                ("gunnar", "acme", "twin"),
                1_800_000_100_000,
                0
            ),
            Err(OrderRefusal::Signature)
        );
    }

    /// ★ `not_after` 0 is no window (as the shared pump reads it), not "expired at the epoch".
    #[test]
    fn an_order_with_no_window_does_not_expire() {
        let mut o = order();
        o.not_after_unix_ms = 0;
        o.signature = key().sign(&order_message(&o)).to_bytes().to_vec();
        assert_eq!(
            verify_order(
                &o,
                &key().verifying_key(),
                ("gunnar", "acme", "twin"),
                1_900_000_000_000,
                0
            ),
            Ok(())
        );
    }

    /// ★ An order dated more than [`FUTURE_SKEW_MS`] ahead of the box's clock is refused by
    /// name; five minutes of skew is fine.
    #[test]
    fn an_order_dated_ahead_of_the_box_clock_is_refused() {
        let pk = key().verifying_key();
        let me = ("gunnar", "acme", "twin");
        let issued = order().issued_unix_ms;
        assert_eq!(
            verify_order(&signed(), &pk, me, issued - FUTURE_SKEW_MS, 0),
            Ok(()),
            "five minutes of skew"
        );
        assert_eq!(
            verify_order(&signed(), &pk, me, issued - FUTURE_SKEW_MS - 1, 0),
            Err(OrderRefusal::Ahead(3))
        );
    }

    #[test]
    fn a_call_is_signed_by_the_box_and_fresh() {
        let box_key = SigningKey::from_bytes(&[3u8; 32]);
        let c = FleetCall {
            product: "gunnar".into(),
            instance: "acme".into(),
            role: "main".into(),
            call: call::REPORT.into(),
            body: "{}".into(),
            at_unix_ms: 1_800_000_000_000,
        };
        let m = fleet_call_message(&c);
        assert!(m.starts_with(CALL_DOMAIN));
        let sig = box_key.sign(&m).to_bytes();
        let pk = box_key.verifying_key();
        assert_eq!(verify_fleet_call(&c, &sig, &pk, 1_800_000_060_000), Ok(()));
        assert_eq!(
            verify_fleet_call(&c, &sig, &pk, 1_800_000_000_000 + CALL_FRESH_MS + 1),
            Err(CallRefusal::Stale)
        );
        let mut moved = c.clone();
        moved.role = "twin".into();
        assert_eq!(
            verify_fleet_call(&moved, &sig, &pk, 1_800_000_000_000),
            Err(CallRefusal::Signature)
        );
        assert_eq!(
            verify_fleet_call(&c, &sig[..10], &pk, 1_800_000_000_000),
            Err(CallRefusal::Signature)
        );
    }
}