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

nordisk/monetize

crates/monetize-admin/tests/site_buy_trials.rs

//! ★ **The buy trials on the ONE box's own program** (A15, moved onto `monetize_admin::linked()`
//! in v2.0 phase 1: "tests test the code that runs in production").
//!
//! The ONE box here is what `monetize-admin server` runs: the registry is
//! [`monetize_admin::linked()`] exactly, its state opened by `monetize_server::cli::open_state`
//! from the `monetize.toml` that `monetize_front::intake::apply_pull` writes out of a FEED shaped
//! as the ONE box's installer feeds it (private-monetize-ops `solo::feed_of`): the SIGNED guests
//! (`vendor.stripe.<instance>.*`, `cloud.upcloud.*`, `dns_guest.cloudflare.*`,
//! `plugin.gunnar.*`, `plugin.holger.*`), each signed in this test under a run CA fed as the
//! plugin root, the secrets by name, and the operator's fragment. The products are PULLED
//! (`[products.<id>] instance = "<site estate>"`, no endpoint): the sites enrol over the box's
//! own attach door (`monetize_front::attach`), and their boxes, played by this test, report
//! over `Fleet` (the product part: tenants, names, servable, room) and pull, verify and ack
//! the signed orders, as a pulled estate's boxes do. The box's own loops run as `serve` runs
//! them (the estate orders, the guardian, the poller, the grow batcher), only faster.
//!
//! The fakes are the EDGES only, each a separate thing the box dials as it dials the real one:
//! the fake Stripe as a PROCESS (monetize-impl `fake_stripe_serve`, its control door the
//! buyer), mock-upcloud in process (`mock_upcloud::serve`), a fake Cloudflare API and a fake
//! SMTP relay (STARTTLS under a CA fed as `secret.smtp_ca`).
//!
//! **The ONE stand-in is the installer**: real boxes do not boot here, so one extra installer
//! ([`STAND_IN`]) is registered on top of `linked()` and named by `[estate_orders] pairing`; it
//! writes a PASS verdict for what was laid, and its sale check proves nothing it reads. The
//! real pairing (`monetize-shop-pairing`, what `linked()` registers) is the fast test's
//! (`monetize-fast`).
//!
//! | trial | relay paths | end state |
//! |---|---|---|
//! | a free account | `/auth/signup/{ladder,start,status}` | the 0 kr card check, the account made |
//! | b paid plan | `/auth/signup/{ladder,start,status}` | paid, the account made |
//! | c private instance, visitor | `/auth/private/start`, `/auth/signup/status`, `/auth/private/status` | the new account made, the instance ready |
//! | d private instance, signed in | `/auth/private/start`, `/auth/private/status` | the instance ready, no e-mail sent |
//! | e grow the account | `/api/account/subscription/{bundles,buy-bundle,status}` | paid, the room granted |
//! | f grow the instance | `/auth/private/{ladder,change,status}`, `/api/account/purchases` | the change paid |
//!
//! Inputs, by environment (feature `trials`; a missing input FAILS by name, never a skip):
//! `MONETIZE_TRIAL_GUESTS` — a directory with `stripe.wasm`, `upcloud.wasm`, `cloudflare.wasm`,
//! `gunnar.wasm`, `holger.wasm` (unsigned; signed here); `MONETIZE_FAKE_STRIPE` — the
//! `fake_stripe_serve` binary. `cargo xtask trials` builds both and runs this. With
//! `MONETIZE_TRIAL_OUT=<dir>` each trial writes its verdict there (`<trial>-<product>.json`).
//! MOCK ONLY: test keys, loopback everything, `*@mock.invalid` addresses.

#![cfg(feature = "trials")]

mod common;
use common::*;

use std::collections::{BTreeMap, BTreeSet};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex};
use std::time::{Duration, Instant};

use base64::Engine as _;
use ed25519_dalek::{Signer as _, SigningKey, VerifyingKey};
use monetize::embed::signing::base64_encode;
use monetize::embed::ticket::{ticket_message, ActorTicket};
use monetize_embed::fleet::{
    fleet_call_message, verify_order, FleetCall, OrderAck, OrdersAfter, Report,
};
use monetize_server::estate_order::phase;
use monetize_server::registry::InstallerFactory;
use monetize_server::state::AppState;
use monetize_server::testing::{http_post, TestServer};
use monetize_site_buy::testkit::{Shape, TestSite};
use monetize_site_buy::Relay;
use serde_json::{json, Value};
use tower::ServiceExt as _;

const SK: &str = "sk_test_SITEbuyTRIALSneverLIVE";
const WHSEC: &str = "whsec_test_SITEbuyTRIALS";
const UPCLOUD_TOKEN: &str = "ucat_mock_trials_not_a_real_token";
const CF_TOKEN: &str = "cf_mock_trials_not_a_real_token";
const CF_ZONE: &str = "zone-trials";
/// The fake zone's own name: every site of the trials is under it.
const CF_ZONE_NAME: &str = "mock.invalid";
const ZONE: &str = "se-sto1";
const GIB: u64 = 1 << 30;

/// One ONE box at a time is built: `linked()` reads its data root from the process's
/// environment (`MONETIZE_ADMIN_DATA`).
static BUILDING: Mutex<()> = Mutex::new(());

// ── the edges: the fake Stripe (a process), the fake Cloudflare, the fake relay ─────────────

/// **The fake Cloudflare API v4** (the DNS guest's `api` on loopback): the zone named
/// ([`CF_ZONE_NAME`], which the guest asks before it writes: a name outside it is refused),
/// `dns_records` listed, made, replaced and removed, every record kept.
#[derive(Clone, Default)]
struct FakeCloudflare {
    rows: Arc<Mutex<Vec<Value>>>,
    next: Arc<std::sync::atomic::AtomicU64>,
}

impl FakeCloudflare {
    async fn serve(&self) -> u16 {
        use axum::extract::{Path as P, Query, State};
        use axum::routing::{get, put};
        async fn zone(P(z): P<String>) -> axum::Json<Value> {
            axum::Json(
                json!({"success": true, "result": {"id": z, "name": CF_ZONE_NAME}, "errors": []}),
            )
        }
        async fn list(
            State(f): State<FakeCloudflare>,
            P(_z): P<String>,
            Query(q): Query<BTreeMap<String, String>>,
        ) -> axum::Json<Value> {
            let rows: Vec<Value> = f
                .rows
                .lock()
                .unwrap()
                .iter()
                .filter(|r| {
                    ["name", "type", "comment"]
                        .iter()
                        .all(|k| q.get(*k).is_none_or(|v| r[*k] == v.as_str()))
                })
                .cloned()
                .collect();
            axum::Json(json!({"success": true, "result": rows, "errors": []}))
        }
        async fn make(
            State(f): State<FakeCloudflare>,
            P(_z): P<String>,
            axum::Json(mut v): axum::Json<Value>,
        ) -> axum::Json<Value> {
            v["id"] = json!(format!(
                "rec{}",
                f.next.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
            ));
            f.rows.lock().unwrap().push(v.clone());
            axum::Json(json!({"success": true, "result": v, "errors": []}))
        }
        async fn replace(
            State(f): State<FakeCloudflare>,
            P((_z, id)): P<(String, String)>,
            axum::Json(mut v): axum::Json<Value>,
        ) -> axum::Json<Value> {
            v["id"] = json!(id);
            let mut rows = f.rows.lock().unwrap();
            rows.retain(|r| r["id"] != id.as_str());
            rows.push(v.clone());
            axum::Json(json!({"success": true, "result": v, "errors": []}))
        }
        async fn remove(
            State(f): State<FakeCloudflare>,
            P((_z, id)): P<(String, String)>,
        ) -> axum::Json<Value> {
            f.rows.lock().unwrap().retain(|r| r["id"] != id.as_str());
            axum::Json(json!({"success": true, "result": {"id": id}, "errors": []}))
        }
        let app = axum::Router::new()
            .route("/client/v4/zones/{zone}", get(zone))
            .route("/client/v4/zones/{zone}/dns_records", get(list).post(make))
            .route(
                "/client/v4/zones/{zone}/dns_records/{id}",
                put(replace).delete(remove),
            )
            .with_state(self.clone());
        let l = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
        let port = l.local_addr().unwrap().port();
        tokio::spawn(async move {
            let _ = axum::serve(l, app).await;
        });
        port
    }
}

/// **The fake SMTP relay** (STARTTLS required, as the box's relay is): every mail kept as
/// (to, decoded body). Its certificate is for 127.0.0.1 under a CA fed as `secret.smtp_ca`.
#[derive(Clone, Default)]
struct FakeRelay {
    mails: Arc<Mutex<Vec<(String, String)>>>,
}

impl FakeRelay {
    /// Serve; answers the port and the CA's PEM.
    async fn serve(&self) -> (u16, String) {
        let _ = rustls::crypto::ring::default_provider().install_default();
        let ca = nordisk_pairing::mtls::InstallerCa::mint(
            "site-buy-trials-smtp",
            Duration::from_secs(86_400),
        )
        .unwrap();
        let door = ca
            .issue_door(std::net::Ipv4Addr::LOCALHOST, Duration::from_secs(86_400))
            .unwrap();
        use rustls::pki_types::pem::PemObject as _;
        let certs: Vec<rustls::pki_types::CertificateDer<'static>> =
            rustls::pki_types::CertificateDer::pem_slice_iter(door.cert_pem.as_bytes())
                .map(|c| c.unwrap())
                .collect();
        let key =
            rustls::pki_types::PrivateKeyDer::from_pem_slice(door.key_pem.as_bytes()).unwrap();
        let cfg = rustls::ServerConfig::builder()
            .with_no_client_auth()
            .with_single_cert(certs, key)
            .unwrap();
        let acceptor = tokio_rustls::TlsAcceptor::from(Arc::new(cfg));
        let l = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
        let port = l.local_addr().unwrap().port();
        let me = self.clone();
        tokio::spawn(async move {
            while let Ok((tcp, _)) = l.accept().await {
                let (me, acceptor) = (me.clone(), acceptor.clone());
                tokio::spawn(async move {
                    let _ = me.converse(tcp, acceptor).await;
                });
            }
        });
        (port, ca.cert_pem)
    }

    async fn converse(
        &self,
        tcp: tokio::net::TcpStream,
        acceptor: tokio_rustls::TlsAcceptor,
    ) -> std::io::Result<()> {
        use tokio::io::{AsyncBufReadExt as _, AsyncWriteExt as _, BufReader};
        let mut plain = BufReader::new(tcp);
        plain
            .get_mut()
            .write_all(b"220 relay.mock.invalid ESMTP\r\n")
            .await?;
        loop {
            let mut line = String::new();
            if plain.read_line(&mut line).await? == 0 {
                return Ok(());
            }
            let up = line.trim().to_ascii_uppercase();
            if up.starts_with("EHLO") || up.starts_with("HELO") {
                plain
                    .get_mut()
                    .write_all(b"250-relay.mock.invalid\r\n250 STARTTLS\r\n")
                    .await?;
            } else if up == "STARTTLS" {
                plain.get_mut().write_all(b"220 go ahead\r\n").await?;
                break;
            } else if up == "QUIT" {
                plain.get_mut().write_all(b"221 bye\r\n").await?;
                return Ok(());
            } else {
                plain.get_mut().write_all(b"530 STARTTLS first\r\n").await?;
            }
        }
        let tls = acceptor.accept(plain.into_inner()).await?;
        let mut s = BufReader::new(tls);
        let (mut to, mut data, mut in_data) = (Vec::<String>::new(), String::new(), false);
        loop {
            let mut line = String::new();
            if s.read_line(&mut line).await? == 0 {
                return Ok(());
            }
            if in_data {
                if line == ".\r\n" || line == ".\n" {
                    in_data = false;
                    let body = decode_mail(&data);
                    for t in to.drain(..) {
                        self.mails.lock().unwrap().push((t, body.clone()));
                    }
                    data.clear();
                    s.get_mut().write_all(b"250 queued\r\n").await?;
                } else {
                    data.push_str(
                        line.strip_prefix('.')
                            .filter(|_| line.starts_with(".."))
                            .unwrap_or(&line),
                    );
                }
                continue;
            }
            let up = line.trim().to_ascii_uppercase();
            let answer: &[u8] = if up.starts_with("EHLO") || up.starts_with("HELO") {
                b"250-relay.mock.invalid\r\n250-AUTH PLAIN LOGIN\r\n250 8BITMIME\r\n"
            } else if up.starts_with("AUTH") {
                b"235 accepted\r\n"
            } else if up.starts_with("MAIL FROM") {
                b"250 ok\r\n"
            } else if up.starts_with("RCPT TO") {
                let addr = line.trim()[8..]
                    .trim()
                    .trim_start_matches(':')
                    .trim()
                    .trim_start_matches('<')
                    .split('>')
                    .next()
                    .unwrap_or_default()
                    .to_owned();
                to.push(addr);
                b"250 ok\r\n"
            } else if up == "DATA" {
                in_data = true;
                b"354 go on\r\n"
            } else if up == "QUIT" {
                s.get_mut().write_all(b"221 bye\r\n").await?;
                return Ok(());
            } else {
                b"250 ok\r\n"
            };
            s.get_mut().write_all(answer).await?;
        }
    }

    fn mails(&self) -> Vec<(String, String)> {
        self.mails.lock().unwrap().clone()
    }
}

/// A mail's text: its headers dropped, a quoted-printable or base64 body decoded (every part).
fn decode_mail(raw: &str) -> String {
    let raw = raw.replace("\r\n", "\n");
    let mut out = String::new();
    let mut enc = String::new();
    let mut in_head = true;
    let mut part = String::new();
    let flush = |enc: &str, part: &str, out: &mut String| {
        let text = match enc {
            "quoted-printable" => {
                let joined = part.replace("=\n", "");
                let b = joined.as_bytes();
                let mut v = Vec::new();
                let mut i = 0;
                while i < b.len() {
                    let pair = (b[i] == b'=' && i + 2 < b.len())
                        .then(|| {
                            std::str::from_utf8(&b[i + 1..i + 3])
                                .ok()
                                .and_then(|h| u8::from_str_radix(h, 16).ok())
                        })
                        .flatten();
                    match pair {
                        Some(x) => {
                            v.push(x);
                            i += 3;
                        }
                        None => {
                            v.push(b[i]);
                            i += 1;
                        }
                    }
                }
                String::from_utf8_lossy(&v).to_string()
            }
            "base64" => base64::engine::general_purpose::STANDARD
                .decode(part.split_whitespace().collect::<String>())
                .map(|b| String::from_utf8_lossy(&b).to_string())
                .unwrap_or_else(|_| part.to_owned()),
            _ => part.to_owned(),
        };
        out.push_str(&text);
        out.push('\n');
    };
    for line in raw.lines() {
        if line.starts_with("--") && !in_head {
            flush(&enc, &part, &mut out);
            part.clear();
            enc.clear();
            in_head = true;
            continue;
        }
        if in_head {
            if line.is_empty() {
                in_head = false;
            } else if let Some(v) = line
                .to_ascii_lowercase()
                .strip_prefix("content-transfer-encoding:")
            {
                enc = v.trim().to_owned();
            }
            continue;
        }
        part.push_str(line);
        part.push('\n');
    }
    flush(&enc, &part, &mut out);
    out
}

// ── the product's boxes, played by the test ─────────────────────────────────────────────────

/// **One box of a pulled estate**: it reports over `Fleet` (its health, its acks, and on a
/// site's main the product part), pulls the orders queued for it, verifies each under the
/// product's key from monetize (`monetize_pubkey`) and runs it, as a real box does.
struct TrialBox {
    product: String,
    instance: String,
    role: String,
    key: SigningKey,
    /// Send its own key on every call (a laid box pins it inside its window).
    pin: bool,
    monetize: VerifyingKey,
    health: BTreeMap<String, String>,
    last_seq: u64,
    acks: Vec<OrderAck>,
    /// The kinds it ran; `refused:<why>` for an order that did not verify.
    ran: Vec<String>,
    /// On a site's main: the product part of its report.
    site: Option<SiteMain>,
}

/// What a site's main holds of its product: its accounts and their caps.
#[derive(Default)]
struct SiteMain {
    accounts: BTreeSet<String>,
    caps: BTreeMap<String, BTreeMap<String, u64>>,
}

impl TrialBox {
    fn signed(&self, call: &str, body: String, now: u64) -> monetize_proto::FleetSigned {
        let c = FleetCall {
            product: self.product.clone(),
            instance: self.instance.clone(),
            role: self.role.clone(),
            call: call.into(),
            body,
            at_unix_ms: now,
        };
        let signature = self.key.sign(&fleet_call_message(&c)).to_bytes().to_vec();
        monetize_proto::FleetSigned {
            product: c.product,
            instance: c.instance,
            role: c.role,
            call: c.call,
            body: c.body,
            at_unix_ms: now,
            signature,
            box_key: if self.pin {
                self.key.verifying_key().as_bytes().to_vec()
            } else {
                Vec::new()
            },
        }
    }

    fn report(&mut self, now: u64) -> monetize_proto::FleetSigned {
        let product = self.site.as_ref().map(|s| {
            let room: BTreeMap<String, u64> = ["pack_bytes", "disk_bytes"]
                .iter()
                .map(|m| (m.to_string(), 300 * GIB))
                .collect();
            let pr = monetize_product::pull::ProductReport {
                tenants: s
                    .accounts
                    .iter()
                    .map(|a| monetize_product::TenantOwner {
                        tenant: monetize_product::TenantId(a.clone()),
                        person: true,
                        seller: false,
                    })
                    .collect(),
                usage: s
                    .accounts
                    .iter()
                    .map(|a| {
                        (
                            a.clone(),
                            monetize_product::Usage {
                                meters: Default::default(),
                                measured_at_unix_ms: now,
                            },
                        )
                    })
                    .collect(),
                servable: Some(monetize_product::Servable::Measured {
                    servable_bytes: 300 * GIB,
                    total_bytes: 400 * GIB,
                    growth: monetize_product::Growth::Unknown(
                        "the trial's box does not say".into(),
                    ),
                    ceilings: Default::default(),
                }),
                room,
                promised: s.caps.clone(),
                names: s.accounts.iter().cloned().collect(),
                measured_unix_ms: now,
                ..Default::default()
            };
            serde_json::to_string(&pr).unwrap()
        });
        let r = Report {
            build: "site-buy-trials".into(),
            health: self.health.clone(),
            acked: std::mem::take(&mut self.acks),
            product,
            measured_unix_ms: now,
            ..Default::default()
        };
        self.signed("report", serde_json::to_string(&r).unwrap(), now)
    }

    fn orders(&self, now: u64) -> monetize_proto::FleetSigned {
        self.signed(
            "orders",
            serde_json::to_string(&OrdersAfter {
                after: self.last_seq,
                wait_ms: 0,
            })
            .unwrap(),
            now,
        )
    }

    /// Verify and run what it pulled; the acks go with its next report.
    fn run(&mut self, orders: &[monetize_proto::FleetOrder], now: u64) {
        for o in orders
            .iter()
            .map(monetize_server::services::fleet::order_of)
        {
            if let Err(e) = verify_order(
                &o,
                &self.monetize,
                (&self.product, &self.instance, &self.role),
                now,
                self.last_seq,
            ) {
                self.ran.push(format!("refused:{e}"));
                continue;
            }
            self.last_seq = o.seq;
            let (ok, detail) = self.verb(&o.kind, &o.body);
            self.ran.push(o.kind.clone());
            self.acks.push(OrderAck {
                seq: o.seq,
                ok,
                detail: detail.clone(),
                receipt_json: json!({"verb": o.kind, "ok": ok, "detail": detail}).to_string(),
            });
        }
    }

    fn verb(&mut self, kind: &str, body: &str) -> (bool, String) {
        use monetize_product::pull::order;
        let Some(site) = self.site.as_mut() else {
            return (true, format!("the {} ran {kind}", self.role));
        };
        match kind {
            order::ADD_PRINCIPAL => {
                match serde_json::from_str::<monetize_product::pull::AddPrincipal>(body) {
                    Ok(a) => {
                        site.accounts.insert(a.username.clone());
                        (true, a.username)
                    }
                    Err(e) => (false, format!("not an add_principal: {e}")),
                }
            }
            order::ENTITLEMENT => {
                match serde_json::from_str::<monetize_embed::EntitlementFact>(body) {
                    Ok(f) => match monetize_embed::signing::verify_fact(&f, &self.monetize) {
                        Ok(()) => {
                            site.caps.insert(f.tenant.0.clone(), f.caps.clone());
                            (true, format!("{} holds {:?}", f.tenant.0, f.caps))
                        }
                        Err(e) => (
                            false,
                            format!("the fact does not verify under monetize's key: {e}"),
                        ),
                    },
                    Err(e) => (false, format!("not an entitlement fact: {e}")),
                }
            }
            other => (true, format!("the main ran {other}")),
        }
    }
}

/// **The boxes' pump**: every box reports and pulls every 150 ms; a laid estate's machines
/// join as their estate is known to the guardian.
async fn pump(
    state: Arc<AppState>,
    boxes: Arc<Mutex<Vec<TrialBox>>>,
    fleet: String,
    keys: Arc<dyn Fn(&str) -> VerifyingKey + Send + Sync>,
    stop: Arc<std::sync::atomic::AtomicBool>,
) {
    let mut seed = 100u8;
    while !stop.load(std::sync::atomic::Ordering::SeqCst) {
        // A laid estate's machines, once the guardian knows the estate.
        if let Some(g) = state.fleet.guardian() {
            for run in state.estates.all() {
                let (Some(laid), Some(product)) =
                    (run.laid.as_ref(), g.store.product_of(&run.company))
                else {
                    continue;
                };
                for m in &laid.machines {
                    let mut b = boxes.lock().unwrap();
                    if b.iter()
                        .any(|x| x.instance == run.company && x.role == m.role)
                    {
                        continue;
                    }
                    seed = seed.wrapping_add(1);
                    let mut health = BTreeMap::new();
                    health.insert(
                        "serving".to_string(),
                        if m.role == "main" { "yes" } else { "no" }.to_string(),
                    );
                    health.insert("data".to_string(), "ok".to_string());
                    b.push(TrialBox {
                        product: product.clone(),
                        instance: run.company.clone(),
                        role: m.role.clone(),
                        key: SigningKey::from_bytes(&[seed; 32]),
                        pin: true,
                        monetize: keys(&product),
                        health,
                        last_seq: 0,
                        acks: Vec::new(),
                        ran: Vec::new(),
                        site: None,
                    });
                }
            }
        }
        let n = boxes.lock().unwrap().len();
        for i in 0..n {
            let rep = boxes.lock().unwrap()[i].report(now_ms());
            let Ok(mut c) = monetize_proto::fleet_client::FleetClient::connect(fleet.clone()).await
            else {
                continue;
            };
            if c.report(rep.clone()).await.is_err() {
                // Not heard (its estate not known yet): its acks go with the next report.
                if let Ok(r) = serde_json::from_str::<Report>(&rep.body) {
                    let mut b = boxes.lock().unwrap();
                    let mut back = r.acked;
                    back.append(&mut b[i].acks);
                    b[i].acks = back;
                }
                continue;
            }
            let ask = boxes.lock().unwrap()[i].orders(now_ms());
            if let Ok(a) = c.orders(ask).await {
                boxes.lock().unwrap()[i].run(&a.into_inner().orders, now_ms());
            }
        }
        tokio::time::sleep(Duration::from_millis(150)).await;
    }
}

// ── the ONE box ─────────────────────────────────────────────────────────────────────────────

fn site_id(shape: Shape) -> &'static str {
    match shape {
        Shape::Gunnar => "gunnar-mock",
        Shape::Holger => "holger-mock",
    }
}
/// The site's own Stripe account (`stripe/<instance>`).
fn instance(shape: Shape) -> &'static str {
    shape.product()
}
fn site_key(shape: Shape) -> SigningKey {
    SigningKey::from_bytes(&[if shape == Shape::Gunnar { 31u8 } else { 32u8 }; 32])
}
fn main_key(shape: Shape) -> SigningKey {
    SigningKey::from_bytes(&[if shape == Shape::Gunnar { 41u8 } else { 42u8 }; 32])
}

/// The fragment the operator feeds (`monetize.toml`): the signups, the sites, the shop's
/// estate orders, the room plans — the ONE box's shape, cut to the two trial sites.
fn fragment(media: &BTreeMap<String, String>) -> String {
    let mut t = String::new();
    for (p, meter) in [("gunnar", "pack_bytes"), ("holger", "disk_bytes")] {
        // The paid rows as the ONE box is fed them (solo.toml `[products.<p>.signup.plans]`),
        // never `[pricing.<p>.plans]`: the pulled sink signs a signup's fact from
        // `[signups.<p>.plans]` alone (`signup_pull::PulledSink::paid_on`), while the ladder
        // also sells a priced row (`signup::plan_named`) — fed that way, a paid priced row is
        // minted and paid and then REFUSED after the payment (found by this trial, 2026-10-24).
        t.push_str(&format!(
            "[signups.{p}]\ncap_meter = \"{meter}\"\nmax_sold_percent_of_capacity = 600\n\
             [signups.{p}.plans.\"{p}/account\"]\namount_minor = 0\ncurrency = \"Sek\"\ncap_bytes = 0\nperiod_days = 0\n\
             [signups.{p}.plans.\"{p}/10gb-1m\"]\namount_minor = 1000\ncurrency = \"Eur\"\ncap_bytes = 10737418240\nperiod_days = 30\n\
             [signups.{p}.plans.\"{p}/10gb-6m\"]\namount_minor = 5400\ncurrency = \"Eur\"\ncap_bytes = 10737418240\nperiod_days = 180\n"
        ));
    }
    for shape in [Shape::Gunnar, Shape::Holger] {
        let id = site_id(shape);
        t.push_str(&format!(
            "[estates.{id}]\nproduct = \"{}\"\nvendor = \"stripe/{}\"\nowner = \"ignalina\"\nsite = \"{}\"\noperator_site = true\n[estates.{id}.orders]\ndns = \"cloudflare\"\n[estates.{id}.orders.media]\n",
            shape.product(),
            instance(shape),
            shape.host()
        ));
        for (k, v) in media {
            t.push_str(&format!("\"{k}\" = \"{v}\"\n"));
        }
    }
    t.push_str(&format!(
        "[estate_orders]\nproduct = \"gunnar\"\ncloud = \"upcloud\"\nzone = \"{ZONE}\"\ncurrency = \"EUR\"\nmax_estates = 10\nmax_open = 10\npairing = \"{STAND_IN}\"\nshop_door = \"https://one.mock.invalid\"\napex = \"estates.mock.invalid\"\nspend_cap_monthly_minor = 10000000\n[estate_orders.media]\n"
    ));
    for (k, v) in media {
        t.push_str(&format!("\"{k}\" = \"{v}\"\n"));
    }
    t
}

/// **The feed**, as the ONE box's installer sends it (private-monetize-ops `solo::feed_of`).
#[allow(clippy::too_many_arguments)]
fn feed(
    dir: &Path,
    inp: &Inputs,
    stripe: &str,
    upcloud: u16,
    cf: u16,
    smtp: (u16, &str),
    media: &BTreeMap<String, String>,
) -> BTreeMap<String, String> {
    use guest_host::verify::sign::dev;
    let (ca_key, ca_der) = dev::mint_ca("site-buy-trials-plugin-root").unwrap();
    let signer = dev::new_ed25519_signer(&ca_key, &ca_der, "site-buy-trials-signing").unwrap();
    let signed =
        |name: &str| sign_into(dir, &inp.guests.join(format!("{name}.wasm")), name, &signer);
    let mut f = BTreeMap::new();
    f.insert("plugin_root.trials".to_string(), b64(&ca_der));
    let (sw, sp) = signed("stripe");
    for shape in [Shape::Gunnar, Shape::Holger] {
        let i = instance(shape);
        let env = i.to_ascii_uppercase();
        let (key, hook) = (
            format!("MONETIZE_STRIPE_{env}_SECRET_KEY"),
            format!("MONETIZE_STRIPE_{env}_WEBHOOK_SECRET"),
        );
        f.insert(format!("vendor.stripe.{i}.wasm"), b64(&sw));
        f.insert(format!("vendor.stripe.{i}.p7s"), b64(&sp));
        f.insert(
            format!("vendor.stripe.{i}.toml"),
            format!(
                "enabled = true\ncountry = \"IE\"\ngrants = [\"http\", \"hmac\", \"state\"]\nhttp_hosts = [\"{stripe}\"]\nhmac_secrets = [\"{hook}\"]\nbase_url = \"{stripe}\"\nsuccess_url = \"https://{h}/paid/{{reference}}\"\ncancel_url = \"https://{h}/cancel/{{reference}}\"\nlivemode = false\ntax_code = \"txcd_10103001\"\nwebhook_secret = \"{hook}\"\n[[http_auth]]\nhost = \"{stripe}\"\nprefix = \"Bearer \"\nsecret = \"{key}\"\n",
                h = shape.host()
            ),
        );
        f.insert(format!("secret.{key}"), SK.into());
        f.insert(format!("secret.{hook}"), WHSEC.into());
    }
    let up = format!("http://127.0.0.1:{upcloud}");
    let (uw, upp) = signed("upcloud");
    f.insert("cloud.upcloud.wasm".into(), b64(&uw));
    f.insert("cloud.upcloud.p7s".into(), b64(&upp));
    f.insert(
        "cloud.upcloud.toml".into(),
        format!("enabled = true\ncap = {{ monthly_minor = 10000000, currency = \"Eur\" }}\ncountry = \"FI\"\nzone = \"{ZONE}\"\ngrants = [\"http\", \"state\"]\nhttp_hosts = [\"{up}\"]\napi_base = \"{up}\"\n[[http_auth]]\nhost = \"{up}\"\nprefix = \"Bearer \"\nsecret = \"upcloud_token\"\n"),
    );
    f.insert("secret.upcloud_token".into(), UPCLOUD_TOKEN.into());
    let cfh = format!("http://127.0.0.1:{cf}");
    let (cw, cp) = signed("cloudflare");
    f.insert("dns_guest.cloudflare.wasm".into(), b64(&cw));
    f.insert("dns_guest.cloudflare.p7s".into(), b64(&cp));
    f.insert(
        "dns_guest.cloudflare.toml".into(),
        format!("grants = [\"http\"]\nhttp_hosts = [\"{cfh}\"]\nzone_id = \"{CF_ZONE}\"\napi = \"{cfh}/client/v4\"\n[[http_auth]]\nhost = \"{cfh}\"\nprefix = \"Bearer \"\nsecret = \"dns_cloudflare_token\"\n"),
    );
    f.insert("secret.dns_cloudflare_token".into(), CF_TOKEN.into());
    for (p, grants, bundles) in [
        ("gunnar", "[]", "[bundles.\"10gb\"]\ncap_delta = { pack_bytes = 10737418240 }\n[bundles.\"50gb\"]\ncap_delta = { pack_bytes = 53687091200 }\n[bundles.\"100gb\"]\ncap_delta = { pack_bytes = 107374182400 }\n"),
        ("holger", "[]", "[bundles.\"5gib\"]\ncap_delta = { disk_bytes = 5368709120 }\nperiod_days = 30\n[bundles.\"10gib\"]\ncap_delta = { disk_bytes = 10737418240 }\nperiod_days = 30\n"),
    ] {
        let (w, s) = signed(p);
        f.insert(format!("plugin.{p}.wasm"), b64(&w));
        f.insert(format!("plugin.{p}.p7s"), b64(&s));
        let shape = if p == "gunnar" { Shape::Gunnar } else { Shape::Holger };
        f.insert(format!("plugin.{p}.toml"), format!("vendor = \"stripe/{}\"\ninstance = \"{}\"\ngrants = {grants}\n{bundles}", instance(shape), site_id(shape)));
        f.insert(format!("plugin.{p}.prices"), "[SE]\ndisk_gib_month = 100\n[FI]\ndisk_gib_month = 100\n".into());
    }
    f.insert(
        "secret.smtp_url".into(),
        format!("smtp://trials:not-a-real-password@127.0.0.1:{}", smtp.0),
    );
    f.insert(
        "secret.smtp_from".into(),
        "ONE box <shop@mock.invalid>".into(),
    );
    f.insert("secret.smtp_ca".into(), smtp.1.to_string());
    f.insert("monetize.toml".into(), fragment(media));
    f
}

/// **One site, attached to the ONE box** (its own attach door): its bearer and its relay.
struct Site {
    bearer: String,
}

/// **The ONE box** — `monetize-admin server`'s program over the fed config — its edges, and
/// the sites' boxes.
struct Rig {
    state: std::mem::ManuallyDrop<Arc<AppState>>,
    server: Option<TestServer>,
    loops: Vec<tokio::task::JoinHandle<()>>,
    stop: Arc<std::sync::atomic::AtomicBool>,
    boxes: Arc<Mutex<Vec<TrialBox>>>,
    fake: FakeStripe,
    relay_mail: FakeRelay,
    sites: BTreeMap<&'static str, Site>,
    dir: PathBuf,
}

/// The guardian's tick, the jera duty `serve` starts (P4b), held by a task of the rig's loops:
/// the loops' abort drops the task, and its guard stops the duty.
fn guardian_tick(state: &Arc<AppState>) -> tokio::task::JoinHandle<()> {
    struct Stops(Arc<monetize_server::jobs::Job>);
    impl Drop for Stops {
        fn drop(&mut self) {
            if !self.0.stop(Duration::from_secs(2)) {
                eprintln!("trials: the guardian tick was still in a look at the rig's stop");
            }
        }
    }
    let tick = Stops(
        monetize_server::fleet::start(state, Duration::from_millis(250))
            .unwrap_or_else(|e| panic!("the guardian ticks: {e}")),
    );
    tokio::spawn(async move {
        let _held = tick;
        std::future::pending::<()>().await
    })
}

async fn rig(name: &str) -> Rig {
    let inp = inputs();
    let dir = PathBuf::from(env!("CARGO_TARGET_TMPDIR"))
        .join(format!("site-buy-trials-{name}-{}", std::process::id()));
    let _ = std::fs::remove_dir_all(&dir);
    std::fs::create_dir_all(dir.join("guests")).unwrap();
    let root = dir.join("data");
    let fake = FakeStripe::start(&inp.fake_stripe, SK, WHSEC);
    let mock = mock_upcloud::Mock::recording(mock_upcloud::estate::Estate::new(
        mock_upcloud::Clock::new(1_000_000),
        mock_upcloud::Faults::none(),
        11,
    ));
    // The release media the shop lays sold estates from: storages at the mock, by kind.
    let media: BTreeMap<String, String> = {
        let mut e = mock.estate.lock().unwrap();
        [
            "front",
            "gunnar",
            "holger",
            "holger-front",
            "front-keep",
            "gunnar-keep",
            "holger-keep",
            "holger-front-keep",
        ]
        .iter()
        .map(|k| {
            (
                k.to_string(),
                e.create_storage(&format!("{k}-r1"), 1, "maxiops", ZONE, Vec::new())
                    .unwrap(),
            )
        })
        .collect()
    };
    let upcloud = mock_upcloud::serve(mock.clone(), "127.0.0.1:0")
        .await
        .unwrap()
        .0;
    let cf = FakeCloudflare::default().serve().await;
    let relay_mail = FakeRelay::default();
    let (smtp_port, smtp_ca) = relay_mail.serve().await;
    let feed = feed(
        &dir.join("guests"),
        &inp,
        &fake.base(),
        upcloud,
        cf,
        (smtp_port, &smtp_ca),
        &media,
    );
    let r2 = root.clone();
    let state = tokio::task::spawn_blocking(move || {
        let _one = BUILDING.lock().unwrap_or_else(|e| e.into_inner());
        // As PID 1 does: monetize's token and key, then the feed taken in.
        monetize_front::intake::prepare(&r2).unwrap();
        let refused = monetize_front::intake::apply_pull(&r2, &feed).unwrap();
        assert!(
            refused.is_empty(),
            "the ONE box refused part of the feed: {refused:#?}"
        );
        let path = r2.join(monetize_front::intake::CONFIG_REL);
        let cfg = monetize_server::config::Config::load(&path).unwrap_or_else(|e| {
            panic!(
                "{}: {e}\n{}",
                path.display(),
                std::fs::read_to_string(&path).unwrap_or_default()
            )
        });
        std::env::set_var(monetize_admin::DATA_ENV, &r2);
        let mut linked = monetize_admin::linked();
        // THE ONE STAND-IN (see the module doc).
        linked.installer(InstallerFactory {
            name: STAND_IN,
            build: stand_in,
        });
        let state = monetize_server::cli::open_state(&cfg, &linked)
            .unwrap_or_else(|e| panic!("the ONE box does not open: {e:#}"));
        Arc::new(state)
    })
    .await
    .unwrap();
    let token = std::fs::read_to_string(root.join(monetize_front::intake::TOKEN_REL))
        .unwrap()
        .trim()
        .to_owned();
    let server = TestServer::spawn(state.clone(), &token).await;
    // The loops `serve` starts, ticking faster.
    monetize_server::grow::arm(&state);
    monetize_server::plans::arm(&state);
    let mut loops = vec![
        tokio::spawn(monetize_server::estate_order::run(
            state.clone(),
            Duration::from_millis(200),
        )),
        guardian_tick(&state),
        tokio::spawn(monetize_server::poller::run(
            state.clone(),
            Duration::from_secs(2),
        )),
    ];
    // The sites enrol at the box's attach door and name their main.
    let central = monetize_front::attach::Central {
        root: root.clone(),
        plugin_door: format!("127.0.0.1:{}", server.addr.port()),
    };
    let boxes: Arc<Mutex<Vec<TrialBox>>> = Arc::default();
    let mut sites = BTreeMap::new();
    let signer = monetize_front::intake::signer(&root).unwrap();
    for shape in [Shape::Gunnar, Shape::Holger] {
        let (estate, product) = (site_id(shape), shape.product());
        let token = monetize_front::attach::mint_token(
            &central,
            estate,
            product,
            Duration::from_secs(3600),
        )
        .unwrap();
        let (csr, _key) = nordisk_pairing::mtls::box_request().unwrap();
        let owner = ssh_key::PrivateKey::from(ssh_key::private::Ed25519Keypair::from_seed(
            &[if shape == Shape::Gunnar { 51u8 } else { 52u8 }; 32],
        ));
        let req = plugin_door_wire::attach::EnrolRequest {
            v: plugin_door_wire::attach::VERSION,
            token,
            estate: estate.into(),
            product: product.into(),
            box_name: "main".into(),
            csr_pem: csr,
            endpoint: format!("{}:443", shape.host()),
            owner_key: owner.public_key().to_openssh().unwrap(),
            estate_ca_pem: String::new(),
            nonce: format!("{estate}-enrol-0123456789"),
            at_unix_ms: now_ms() as i64,
            owner_sig: String::new(),
        }
        .sign(&owner)
        .unwrap();
        let (st, reply) = monetize_front::attach::enrol_answer(
            central.clone(),
            serde_json::to_vec(&req).unwrap().into(),
        )
        .await;
        assert_eq!(st.as_u16(), 200, "{estate} enrols: {}", reply.0);
        let bearer = reply.0["estate_bearer"].as_str().unwrap().to_owned();
        let pubkey = reply.0["monetize_pubkey"].as_str().unwrap().to_owned();
        assert_eq!(
            pubkey,
            hex(&monetize::Keyring::derive(&signer, product).public_key()),
            "the key the estate verifies orders with is its product's"
        );
        let notice = plugin_door_wire::attach::InstalledNotice {
            v: plugin_door_wire::attach::VERSION,
            estate: estate.into(),
            product: product.into(),
            roles: vec!["main".into()],
            nonce: format!("{estate}-installed-0123456789"),
            at_unix_ms: now_ms() as i64,
            ticket_key: hex(site_key(shape).verifying_key().as_bytes()),
            fleet_keys: [(
                "main".to_string(),
                hex(main_key(shape).verifying_key().as_bytes()),
            )]
            .into(),
            owner_sig: String::new(),
        }
        .sign(&owner)
        .unwrap();
        let (st, said) = monetize_front::attach::installed_answer(
            central.clone(),
            serde_json::to_vec(&notice).unwrap().into(),
        )
        .await;
        assert_eq!(st.as_u16(), 200, "{estate}'s install notice: {}", said.0);
        let mut health = BTreeMap::new();
        for (k, v) in [
            ("serving", "yes"),
            ("data", "ok"),
            ("serves_at", "127.0.0.1"),
            ("twin", "paired"),
        ] {
            health.insert(k.to_string(), v.to_string());
        }
        boxes.lock().unwrap().push(TrialBox {
            product: product.into(),
            instance: estate.into(),
            role: "main".into(),
            key: main_key(shape),
            pin: false,
            monetize: VerifyingKey::from_bytes(
                &monetize::Keyring::derive(&signer, product).public_key(),
            )
            .unwrap(),
            health,
            last_seq: 0,
            acks: Vec::new(),
            ran: Vec::new(),
            site: Some(SiteMain::default()),
        });
        sites.insert(product, Site { bearer });
    }
    let stop = Arc::new(std::sync::atomic::AtomicBool::new(false));
    let s2 = signer.clone();
    let keys: Arc<dyn Fn(&str) -> VerifyingKey + Send + Sync> = Arc::new(move |p: &str| {
        VerifyingKey::from_bytes(&monetize::Keyring::derive(&s2, p).public_key()).unwrap()
    });
    loops.push(tokio::spawn(pump(
        state.clone(),
        boxes.clone(),
        server.endpoint(),
        keys,
        stop.clone(),
    )));
    let r = Rig {
        state: std::mem::ManuallyDrop::new(state),
        server: Some(server),
        loops,
        stop,
        boxes,
        fake,
        relay_mail,
        sites,
        dir,
    };
    // The guardian takes the enrolments (its tick) and hears each main's first report.
    let until = Instant::now() + Duration::from_secs(30);
    for shape in [Shape::Gunnar, Shape::Holger] {
        loop {
            let heard = r
                .state
                .fleet
                .guardian()
                .and_then(|g| g.store.box_record(site_id(shape), "main"))
                .is_some_and(|b| b.heard_unix_ms > 0);
            if heard {
                break;
            }
            assert!(
                Instant::now() < until,
                "{}'s main was not heard in 30 s: {:?}",
                site_id(shape),
                r.boxes
                    .lock()
                    .unwrap()
                    .iter()
                    .map(|b| (&b.instance, &b.ran))
                    .collect::<Vec<_>>()
            );
            tokio::time::sleep(Duration::from_millis(100)).await;
        }
    }
    r
}

impl Rig {
    fn addr(&self) -> std::net::SocketAddr {
        self.server.as_ref().unwrap().addr
    }

    /// The accounts a site's main holds (what its product made from the box's orders).
    fn accounts(&self, shape: Shape) -> Vec<String> {
        self.boxes
            .lock()
            .unwrap()
            .iter()
            .find(|b| b.instance == site_id(shape))
            .and_then(|b| b.site.as_ref())
            .map(|s| s.accounts.iter().cloned().collect())
            .unwrap_or_default()
    }

    /// **The site's relay** over this ONE box, with the bearer its enrolment gave it and its
    /// tickets signed with the site's own key (delivered to the box by its install notice).
    fn site(&self, shape: Shape) -> Arc<Relay<TestSite>> {
        let key = site_key(shape);
        let product = shape.product();
        let n = Arc::new(std::sync::atomic::AtomicU64::new(0));
        let bearer = self.sites[product].bearer.clone();
        let boxes = self.boxes.clone();
        let estate = site_id(shape);
        let holds = Arc::new(move |u: &str| {
            boxes.lock().unwrap().iter().any(|b| {
                b.instance == estate && b.site.as_ref().is_some_and(|s| s.accounts.contains(u))
            })
        });
        // The room an account holds is the PRODUCT's word (the real site asks its own
        // product, never the ONE box's `Entitlement.Get`, which a site's bearer does not
        // open — ST-13): what the site's main applied from the pulled entitlement orders.
        let boxes2 = self.boxes.clone();
        let held = Arc::new(move |tenant: &str| {
            boxes2
                .lock()
                .unwrap()
                .iter()
                .find(|b| b.instance == estate)
                .and_then(|b| b.site.as_ref())
                .and_then(|s| s.caps.get(tenant).cloned())
                .unwrap_or_default()
        });
        let site = TestSite::at(shape, &format!("http://{}", self.addr()), &bearer, holds)
            .with_held(held)
            .with_minter(Arc::new(move |buyer, purpose, caps| {
                let nonce = format!(
                    "{}-{}",
                    purpose,
                    n.fetch_add(1, std::sync::atomic::Ordering::SeqCst)
                );
                let mut t = ActorTicket::unsigned(
                    product,
                    product,
                    buyer.tenant(),
                    purpose,
                    nonce,
                    now_ms() as i64,
                    300_000,
                );
                if !caps.is_empty() {
                    t = t.covering(caps.clone());
                }
                t.signature = base64_encode(&key.sign(&ticket_message(&t)).to_bytes());
                serde_json::to_vec(&t).unwrap()
            }));
        let link = monetize_site_buy::ShopLink::connect_lazy(
            &monetize_site_buy::Door {
                url: format!("http://{}", self.addr()),
                ..Default::default()
            },
            &bearer,
            product,
        )
        .unwrap();
        Arc::new(Relay::new(site, link))
    }

    /// The buyer at the fake Stripe's page (`pay`, `check-card/<fp>`), and Stripe's signed event
    /// delivered to the ONE box's `/callback/stripe/<instance>`.
    fn buyer_does(&self, shape: Shape, what: &str, cs: &str) -> Result<(u16, String), String> {
        let (st, ev) = self.fake.control("POST", &format!("/{what}"));
        if st != 200 {
            return Err(format!(
                "the fake Stripe's page refused {what} for {cs}: {st} {ev}"
            ));
        }
        let headers = vec![
            (
                "Stripe-Signature".to_string(),
                ev["signature"].as_str().unwrap_or_default().to_owned(),
            ),
            ("Content-Type".to_string(), "application/json".to_string()),
        ];
        http_post(
            self.addr(),
            &format!("/callback/stripe/{}", instance(shape)),
            &headers,
            ev["body"].as_str().unwrap_or_default().as_bytes(),
        )
        .map_err(|e| e.to_string())
    }

    fn pay(&self, shape: Shape, cs: &str) -> Result<(u16, String), String> {
        self.buyer_does(shape, &format!("pay/{cs}"), cs)
    }

    /// Until the order of `company` is `want` or no longer open (90 s): the box's own loops
    /// drive it, the laid boxes report as they come up.
    async fn order_until(&self, company: &str, want: &str) -> String {
        let until = Instant::now() + Duration::from_secs(90);
        loop {
            let p = self
                .state
                .estates
                .get(company)
                .map(|r| r.phase)
                .unwrap_or_default();
            if p == want || (!p.is_empty() && !phase::is_open(&p)) || Instant::now() > until {
                return p;
            }
            tokio::time::sleep(Duration::from_millis(100)).await;
        }
    }

    fn history(&self, company: &str) -> String {
        self.state
            .estates
            .get(company)
            .map(|r| {
                format!(
                    "why: {}; {}",
                    r.why,
                    r.history
                        .iter()
                        .map(|t| format!("{}: {}", t.phase, t.note))
                        .collect::<Vec<_>>()
                        .join(" | ")
                )
            })
            .unwrap_or_else(|| "no order".into())
    }

    async fn stop(mut self) {
        self.stop.store(true, std::sync::atomic::Ordering::SeqCst);
        for l in self.loops.drain(..) {
            l.abort();
        }
        if let Some(s) = self.server.take() {
            s.stop().await;
        }
    }
}

impl Drop for Rig {
    fn drop(&mut self) {
        self.stop.store(true, std::sync::atomic::Ordering::SeqCst);
        for l in self.loops.drain(..) {
            l.abort();
        }
        // SAFETY: taken once, here, and never touched again. The state's blocking clients are
        // dropped off the runtime.
        let state = unsafe { std::mem::ManuallyDrop::take(&mut self.state) };
        let server = self.server.take();
        let _ = std::thread::spawn(move || drop((server, state))).join();
        let _ = std::fs::remove_dir_all(&self.dir);
    }
}

async fn ask(
    relay: &Arc<Relay<TestSite>>,
    shape: Shape,
    method: &str,
    uri: &str,
    who: Option<&str>,
    body: Option<Value>,
) -> (u16, Value) {
    let mut req = axum::http::Request::builder()
        .method(method)
        .uri(uri)
        .header("accept-language", "fi-FI")
        .header("x-forwarded-for", "203.0.113.11");
    if let Some(u) = who {
        let (name, value) = shape.session(u);
        req = req.header(name, value);
    }
    let req = match body {
        Some(b) => req
            .header("content-type", "application/json")
            .body(axum::body::Body::from(b.to_string()))
            .unwrap(),
        None => req.body(axum::body::Body::empty()).unwrap(),
    };
    let res = monetize_site_buy::router(relay.clone())
        .oneshot(req)
        .await
        .unwrap();
    let status = res.status().as_u16();
    let bytes = axum::body::to_bytes(res.into_body(), 1 << 20)
        .await
        .unwrap();
    (
        status,
        serde_json::from_slice(&bytes).unwrap_or(Value::Null),
    )
}

/// One trial's verdict, written where the runner gathers it.
fn record(trial: &str, shape: Shape, pass: bool, detail: &str, secs: f64) {
    if let Some(dir) = std::env::var_os("MONETIZE_TRIAL_OUT") {
        let dir = PathBuf::from(dir);
        let _ = std::fs::create_dir_all(&dir);
        let name = format!("{trial}-{}", shape.product());
        let v = json!({"name": name, "trial": trial, "site": shape.word(), "where": "linked", "pass": pass, "detail": detail, "secs": (secs * 10.0).round() / 10.0, "at_unix": now_ms() / 1000});
        let _ = std::fs::write(
            dir.join(format!("{name}.json")),
            serde_json::to_vec_pretty(&v).unwrap(),
        );
    }
}

/// Run `body`, record its verdict, then fail the test as it failed.
async fn trial<F>(name: &str, shape: Shape, body: F)
where
    F: std::future::Future<Output = Result<String, String>>,
{
    let t = Instant::now();
    let verdict = body.await;
    let secs = t.elapsed().as_secs_f64();
    match &verdict {
        Ok(detail) => record(name, shape, true, detail, secs),
        Err(why) => record(name, shape, false, why, secs),
    }
    if let Err(why) = verdict {
        panic!("{name} ({}): {why}", shape.word());
    }
}

fn check(cond: bool, why: impl Into<String>) -> Result<(), String> {
    if cond {
        Ok(())
    } else {
        Err(why.into())
    }
}

/// The signup's state as the welcome page polls it, until `want` (bounded).
async fn poll_signup(
    relay: &Arc<Relay<TestSite>>,
    shape: Shape,
    session: &str,
    want: &str,
) -> Value {
    let until = Instant::now() + Duration::from_secs(30);
    loop {
        let (_, s) = ask(
            relay,
            shape,
            "GET",
            &format!("/auth/signup/status?session={session}"),
            None,
            None,
        )
        .await;
        if s["state"] == want || Instant::now() > until {
            return s;
        }
        tokio::time::sleep(Duration::from_millis(100)).await;
    }
}

fn session_of(url: &str) -> String {
    url.rsplit('/')
        .next()
        .unwrap_or_default()
        .split('#')
        .next()
        .unwrap_or_default()
        .split('?')
        .next()
        .unwrap_or_default()
        .to_owned()
}

/// **A visitor's free account through the site** (`<product>/account`, the page's own row):
/// the start, Stripe's 0 kr card check, the event, the welcome page. Answers the session.
async fn make_account(
    r: &Rig,
    relay: &Arc<Relay<TestSite>>,
    shape: Shape,
    user: &str,
) -> Result<String, String> {
    let (st, start) = ask(relay, shape, "POST", "/auth/signup/start", None, Some(json!({"username": user, "email": format!("{user}@mock.invalid"), "plan": format!("{}/account", shape.product()), "next": "/"}))).await;
    check(st == 200, format!("the start: {st} {start}"))?;
    let url = start["url"].as_str().unwrap_or_default().to_owned();
    let cs = session_of(&url);
    check(
        r.fake.minted(&cs),
        format!("the checkout is the fake Stripe's: {url}"),
    )?;
    let (code, said) = r.buyer_does(shape, &format!("check-card/{cs}/fp_trial_{user}"), &cs)?;
    check(code == 200, format!("the event: {code} {said}"))?;
    let s = poll_signup(relay, shape, &cs, "created").await;
    check(s["state"] == "created", format!("the welcome page: {s}"))?;
    check(
        s["invite_url"]
            .as_str()
            .is_some_and(|u| u.starts_with("/login?signup=")),
        format!("the passkey link on the site: {s}"),
    )?;
    Ok(cs)
}

async fn free_account(shape: Shape) -> Result<String, String> {
    let r = rig(&format!("a-{}", shape.product())).await;
    let relay = r.site(shape);
    let (st, plans) = ask(&relay, shape, "GET", "/auth/signup/ladder", None, None).await;
    check(st == 200, format!("the plans: {st} {plans}"))?;
    let made = make_account(&r, &relay, shape, "freya").await;
    let accounts = r.accounts(shape);
    let held = made
        .as_deref()
        .map(|cs| r.fake.session(cs)["mode"].clone())
        .unwrap_or_default();
    r.stop().await;
    let cs = made?;
    // The pulled shape: the account is made by the site's main from its signed add_principal.
    check(
        accounts == ["freya"],
        format!("one account made, on the site's main: {accounts:?}"),
    )?;
    Ok(format!(
        "0 kr card check {cs} (mode {held}); account freya made on {}'s main; welcome on {}",
        site_id(shape),
        shape.host()
    ))
}

async fn paid_plan(shape: Shape) -> Result<String, String> {
    let r = rig(&format!("b-{}", shape.product())).await;
    let relay = r.site(shape);
    let (_, plans) = ask(&relay, shape, "GET", "/auth/signup/ladder", None, None).await;
    let paid = plans["plans"]
        .as_array()
        .and_then(|p| {
            p.iter()
                .find(|x| x["id"].as_str().is_some_and(|i| i.contains("10gb")))
        })
        .cloned()
        .ok_or(format!("no paid row: {plans}"))?;
    let (st, start) = ask(&relay, shape, "POST", "/auth/signup/start", None, Some(json!({"username": "paula", "email": "paula@mock.invalid", "plan": paid["id"], "next": "/"}))).await;
    check(st == 200, format!("the start: {st} {start}"))?;
    let cs = session_of(start["url"].as_str().unwrap_or_default());
    let pending = poll_signup(&relay, shape, &cs, "pending").await;
    check(
        r.accounts(shape).is_empty(),
        format!("no account before the payment: {pending}"),
    )?;
    let (code, said) = r.pay(shape, &cs)?;
    check(code == 200, format!("the event: {code} {said}"))?;
    let s = poll_signup(&relay, shape, &cs, "created").await;
    let accounts = r.accounts(shape);
    let session = r.fake.session(&cs);
    r.stop().await;
    check(
        s["state"] == "created" && s["username"] == "paula",
        format!("the welcome page: {s}"),
    )?;
    check(
        accounts == ["paula"],
        format!("the account on the site's main: {accounts:?}"),
    )?;
    Ok(format!(
        "{} paid at the fake Stripe ({cs}, {} {}); account paula made",
        paid["price_words"].as_str().unwrap_or(""),
        session["amount_total"],
        session["currency"]
    ))
}

/// The private ladder's first step, as the order's body.
fn first_step(ladder: &Value) -> Value {
    ladder["steps"][0]["sizes"].clone()
}

async fn private_visitor(shape: Shape) -> Result<String, String> {
    let r = rig(&format!("c-{}", shape.product())).await;
    let relay = r.site(shape);
    // As a page reads it (LADDER-2): a ladder not read yet is said by name, and looked at again.
    let mut asked = 0;
    let (st, ladder) = loop {
        let (st, ladder) = ask(&relay, shape, "GET", "/auth/private/ladder", None, None).await;
        asked += 1;
        if !(st == 503 && ladder["not_read"] == true) || asked >= 60 {
            break (st, ladder);
        }
        tokio::time::sleep(std::time::Duration::from_millis(500)).await;
    };
    check(st == 200, format!("the ladder: {st} {ladder}"))?;
    let step = first_step(&ladder);
    let body = json!({"company": "acme", "account": "vera", "email": "vera@mock.invalid", "front_plan": step["front_plan"], "main_plan": step["main_plan"], "main_data_gib": step["main_data_gib"]});
    let (st, start) = ask(
        &relay,
        shape,
        "POST",
        "/auth/private/start",
        None,
        Some(body),
    )
    .await;
    check(st == 200, format!("the order: {st} {start}"))?;
    let cs = session_of(start["url"].as_str().unwrap_or_default());
    let paid = r.pay(shape, &cs);
    let p = r.order_until("acme", phase::CAPTURED).await;
    let (_, watch) = ask(
        &relay,
        shape,
        "GET",
        "/auth/private/status?company=acme",
        None,
        None,
    )
    .await;
    // Pay once: the new account's sign-in link is MAILED (the shop's own account session, not
    // Stripe's), through the box's relay; the welcome page it opens is on the site.
    let until = Instant::now() + Duration::from_secs(20);
    let mut link = String::new();
    while link.is_empty() && Instant::now() < until {
        link = r
            .relay_mail
            .mails()
            .iter()
            .find(|(to, _)| to == "vera@mock.invalid")
            .and_then(|(_, body)| {
                body.split_whitespace()
                    .find(|w| w.contains("/welcome?session="))
                    .map(str::to_owned)
            })
            .unwrap_or_default();
        if link.is_empty() {
            tokio::time::sleep(Duration::from_millis(200)).await;
        }
    }
    let session = link
        .split("session=")
        .nth(1)
        .unwrap_or_default()
        .split(['&', ' ', '"', '>'])
        .next()
        .unwrap_or_default()
        .to_owned();
    let welcome = if session.is_empty() {
        json!({"error": format!("no sign-in link mailed to vera: {:?}", r.relay_mail.mails())})
    } else {
        poll_signup(&relay, shape, &session, "created").await
    };
    let made = r.accounts(shape);
    let history = r.history("acme");
    r.stop().await;
    check(
        paid.as_ref().is_ok_and(|(c, _)| *c == 200),
        format!("the event: {paid:?}"),
    )?;
    check(
        p == phase::CAPTURED,
        format!("laid and captured: {p}; {watch}; {history}"),
    )?;
    check(watch["state"] == "ready", format!("the watch: {watch}"))?;
    check(
        link.starts_with(&format!("{}/welcome?session=", shape.origin())),
        format!("the mailed link is on the site: {link:?}"),
    )?;
    check(
        welcome["state"] == "created",
        format!("the welcome page: {welcome}"),
    )?;
    check(
        made.iter().any(|u| u == "vera"),
        format!("the new account on the site's main: {made:?}"),
    )?;
    Ok(format!("paid once ({cs}); account vera made; acme laid on the UpCloud mock through the signed guest, ready"))
}

async fn private_signed_in(shape: Shape) -> Result<String, String> {
    let r = rig(&format!("d-{}", shape.product())).await;
    let relay = r.site(shape);
    make_account(&r, &relay, shape, "sigrid").await?;
    let (_, ladder) = ask(&relay, shape, "GET", "/auth/private/ladder", None, None).await;
    let step = first_step(&ladder);
    let body = json!({"company": "beta", "email": "other@mock.invalid", "front_plan": step["front_plan"], "main_plan": step["main_plan"], "main_data_gib": step["main_data_gib"]});
    let (st, start) = ask(
        &relay,
        shape,
        "POST",
        "/auth/private/start",
        Some("sigrid"),
        Some(body),
    )
    .await;
    check(st == 200, format!("the order: {st} {start}"))?;
    let cs = session_of(start["url"].as_str().unwrap_or_default());
    // What reached Stripe for this page, as the fake serves the session and its create form.
    let asked = r.fake.session(&cs).to_string();
    let paid = r.pay(shape, &cs);
    let p = r.order_until("beta", phase::CAPTURED).await;
    let (_, watch) = ask(
        &relay,
        shape,
        "GET",
        "/auth/private/status?company=beta",
        Some("sigrid"),
        None,
    )
    .await;
    let mails = r.relay_mail.mails();
    let history = r.history("beta");
    r.stop().await;
    check(
        paid.as_ref().is_ok_and(|(c, _)| *c == 200),
        format!("the event: {paid:?}"),
    )?;
    check(
        !asked.contains("other%40mock.invalid") && !asked.contains("other@mock.invalid"),
        format!("the page's address never reached Stripe: {asked}"),
    )?;
    check(
        p == phase::CAPTURED,
        format!("laid and captured: {p}; {watch}; {history}"),
    )?;
    check(watch["state"] == "ready", format!("the watch: {watch}"))?;
    check(
        !mails.iter().any(|(to, _)| to.contains("other@")),
        format!("no mail to the page's address: {mails:?}"),
    )?;
    let to: Vec<&String> = mails.iter().map(|(t, _)| t).collect();
    Ok(format!(
        "sigrid's own order, its estate ticket; beta laid, ready; mails only to {to:?}"
    ))
}

async fn grow_account(shape: Shape) -> Result<String, String> {
    let r = rig(&format!("e-{}", shape.product())).await;
    let relay = r.site(shape);
    make_account(&r, &relay, shape, "gro").await?;
    // The pulled shape: the account's fact reaches the site's main as a signed order after the
    // account is made. Until the main applied it, the site's held caps ({}) and the ONE box's
    // ledger (the account fact's 1-byte cap) differ, and a raise's ticket (held + delta) is
    // REFUSED as `WHO_NOT_CONFIRMED` — seen in this trial's first runs (2026-10-24). A real
    // site's page reads the window after its product holds the account, so the buyer waits here.
    let until = Instant::now() + Duration::from_secs(20);
    while Instant::now() < until
        && r.boxes
            .lock()
            .unwrap()
            .iter()
            .find(|b| b.instance == site_id(shape))
            .and_then(|b| b.site.as_ref())
            .is_none_or(|s| !s.caps.contains_key("gro"))
    {
        tokio::time::sleep(Duration::from_millis(100)).await;
    }
    let (st, window) = ask(
        &relay,
        shape,
        "GET",
        "/api/account/subscription/bundles",
        Some("gro"),
        None,
    )
    .await;
    check(st == 200, format!("the window: {st} {window}"))?;
    // ★ Cheapest first (owner, gunnar.rs 2026-10-27: "Grow your plan" opened on 100 GB): the
    // ids sort as text ("100gb" before "10gb", "10gib" before "5gib"); the window does not.
    let ids: Vec<&str> = window["offers"]
        .as_array()
        .into_iter()
        .flatten()
        .filter_map(|o| o["id"].as_str())
        .collect();
    let cheapest = match shape {
        Shape::Gunnar => "10gb",
        Shape::Holger => "5gib",
    };
    check(
        ids.first() == Some(&cheapest),
        format!("the window opens on the cheapest row ({cheapest}): {ids:?}"),
    )?;
    let offer = window["offers"]
        .as_array()
        .and_then(|o| o.first())
        .cloned()
        .ok_or(format!("no offer: {window}"))?;
    let (st, buy) = ask(
        &relay,
        shape,
        "POST",
        "/api/account/subscription/buy-bundle",
        Some("gro"),
        Some(json!({"bundle": offer["id"]})),
    )
    .await;
    // A refused ticket is `WHO_NOT_CONFIRMED` to the buyer; for the finding, both sides' view
    // of what the account holds (the ticket covers held + delta on the site; the ONE box
    // computes it from its ledger).
    let ledger = r
        .state
        .ledger
        .entitlement(shape.product(), "gro")
        .ok()
        .flatten()
        .map(|f| f.caps);
    let on_main = r
        .boxes
        .lock()
        .unwrap()
        .iter()
        .find(|b| b.instance == site_id(shape))
        .and_then(|b| b.site.as_ref())
        .and_then(|s| s.caps.get("gro").cloned());
    // ★ FINDING (2026-10-24, red on the real program): the ONE box resolves a bundle against
    // its LEDGER alone (`services::purchase::caps_of_bundle`), which holds nothing for a free
    // account, while the site's product holds the account's signed fact
    // (`signup::account_fact`, NO_ROOM_CAP = 1 byte; `Entitlement.Get` falls back to it too).
    // The site's ticket covers held + delta (1 B + 10 GiB), the box checks 10 GiB, and the
    // raise is refused (WHO_NOT_CONFIRMED). The vetra trial read the ledger for the site's
    // held caps and so never met it.
    check(
        st == 200,
        format!("the buy: {st} {buy}; FINDING: the ONE box resolves the bundle against its ledger ({ledger:?} for gro) while the site's main holds the account's fact {on_main:?}, so the site's ticket (held + delta) and the box's caps differ; the offer: {offer}"),
    )?;
    let reference = buy["reference"].as_str().unwrap_or_default().to_owned();
    let cs = session_of(buy["url"].as_str().unwrap_or_default());
    let (code, said) = r.pay(shape, &cs)?;
    check(code == 200, format!("the event: {code} {said}"))?;
    let until = Instant::now() + Duration::from_secs(30);
    let mut done = Value::Null;
    while Instant::now() < until {
        done = ask(
            &relay,
            shape,
            "GET",
            &format!(
                "/api/account/subscription/status?reference={}",
                monetize_site_buy::rules::query_value(&reference)
            ),
            Some("gro"),
            None,
        )
        .await
        .1;
        if done["state"] == "paid" {
            break;
        }
        tokio::time::sleep(Duration::from_millis(100)).await;
    }
    r.stop().await;
    check(
        done["state"] == "paid",
        format!("the way back: {done}; the buy: {buy}; the offer: {offer}"),
    )?;
    Ok(format!(
        "{} bought ({reference}), paid, granted {}",
        offer["label"], done["after"]
    ))
}

async fn grow_instance(shape: Shape) -> Result<String, String> {
    let r = rig(&format!("f-{}", shape.product())).await;
    let relay = r.site(shape);
    make_account(&r, &relay, shape, "gus").await?;
    let (_, ladder) = ask(&relay, shape, "GET", "/auth/private/ladder", None, None).await;
    let step = first_step(&ladder);
    let (st, start) = ask(&relay, shape, "POST", "/auth/private/start", Some("gus"), Some(json!({"company": "gamma", "front_plan": step["front_plan"], "main_plan": step["main_plan"], "main_data_gib": step["main_data_gib"]}))).await;
    check(st == 200, format!("the order: {st} {start}"))?;
    let cs = session_of(start["url"].as_str().unwrap_or_default());
    r.pay(shape, &cs)?;
    let p = r.order_until("gamma", phase::CAPTURED).await;
    check(
        p == phase::CAPTURED,
        format!("the instance first: {p}; {}", r.history("gamma")),
    )?;
    let (st, grown) = ask(
        &relay,
        shape,
        "GET",
        "/auth/private/ladder?company=gamma",
        Some("gus"),
        None,
    )
    .await;
    check(st == 200, format!("its ladder: {st} {grown}"))?;
    let next = grown["steps"]
        .as_array()
        .and_then(|s| {
            s.iter()
                .skip(grown["current"].as_u64().unwrap_or(0) as usize + 1)
                .find(|x| x["available"] == true)
        })
        .cloned()
        .ok_or(format!("no bigger step: {grown}"))?;
    let sizes = &next["sizes"];
    let (st, change) = ask(&relay, shape, "POST", "/auth/private/change", Some("gus"), Some(json!({"company": "gamma", "front_plan": sizes["front_plan"], "main_plan": sizes["main_plan"], "main_data_gib": sizes["main_data_gib"]}))).await;
    check(st == 200, format!("the change: {st} {change}"))?;
    let url = change["url"].as_str().unwrap_or_default().to_owned();
    if !url.is_empty() {
        r.pay(shape, &session_of(&url))?;
    }
    // The change followed until the watch names it and two looks agree (the old trial waited
    // for the order to leave the open phases, bounded at 90 s; the box's own loop drives it).
    let until = Instant::now() + Duration::from_secs(90);
    let mut watch = Value::Null;
    let mut last = String::new();
    while Instant::now() < until {
        watch = ask(
            &relay,
            shape,
            "GET",
            "/auth/private/status?company=gamma",
            Some("gus"),
            None,
        )
        .await
        .1;
        let now = watch["change_status"]
            .as_str()
            .unwrap_or_default()
            .to_owned();
        if !now.is_empty() && now == last {
            break;
        }
        last = now;
        tokio::time::sleep(Duration::from_millis(500)).await;
    }
    let (_, mine) = ask(
        &relay,
        shape,
        "GET",
        "/api/account/purchases",
        Some("gus"),
        None,
    )
    .await;
    r.stop().await;
    check(
        mine["estates"]
            .as_array()
            .is_some_and(|e| e.iter().any(|x| x["company"] == "gamma")),
        format!("Your purchases list it: {mine}"),
    )?;
    check(
        !watch["change_status"]
            .as_str()
            .unwrap_or_default()
            .is_empty(),
        format!("the change is followed: {watch}"),
    )?;
    Ok(format!(
        "gamma: {} → {} ({}), change {}",
        grown["steps"][grown["current"].as_u64().unwrap_or(0) as usize]["name"],
        next["name"],
        change["reference"],
        watch["change_status"]
    ))
}

/// ★ **The owner's walk** (T-OWNERFLOW, owner order 2026-10-26: the purchase the owner made by
/// hand on test2.gunnar.rs, alica then rickardtest, as one test on the ONE box's own program):
///
/// 1. a NEW visitor on the root site signs up for a PAID account plan through the site's relay:
///    one checkout at the fake Stripe, paid once, the welcome page reads `created`, the account is
///    made by the SITE's main, and the site's main holds the plan's room (the console's "plan
///    shown = what was paid": alica's console said Free, ALICA-4);
/// 2. that account, SIGNED IN, orders a private instance: the order body carries no e-mail and no
///    account (the form knows the account), the order is the account's and mails the account's
///    own address (e-mail asked once), paid once;
/// 3. the instance is laid at the UpCloud mock, installed, captured; the watch says `ready`; the
///    ready mail (through the box's relay) names the address, the first admin = the buyer, the
///    one-time link (once, 7 days), where the product serves (Gunnar: its git address) and the
///    paid-until date;
/// 4. the ONE box's Accounts page lists the instance on that account, beside the plan.
///
/// Every step is the product's own door; the console's passkey and the instance's own pages are
/// the product repos' browser tests (gunnar-ui, holger-ui; see ~/plan/T-OWNERFLOW.md).
async fn owner_walk(shape: Shape) -> Result<String, String> {
    let r = rig(&format!("g-{}", shape.product())).await;
    let relay = r.site(shape);
    let product = shape.product();
    // ── 1. the account plan, a new visitor ──
    let (st, plans) = ask(&relay, shape, "GET", "/auth/signup/ladder", None, None).await;
    check(st == 200, format!("the plans: {st} {plans}"))?;
    let paid = plans["plans"]
        .as_array()
        .and_then(|p| {
            p.iter()
                .find(|x| x["id"].as_str().is_some_and(|i| i.ends_with("/10gb-1m")))
        })
        .cloned()
        .ok_or(format!("no 1-month paid row: {plans}"))?;
    let (st, start) = ask(&relay, shape, "POST", "/auth/signup/start", None, Some(json!({"username": "alica", "email": "alica@mock.invalid", "plan": paid["id"], "next": "/"}))).await;
    check(st == 200, format!("the plan's start: {st} {start}"))?;
    let plan_cs = session_of(start["url"].as_str().unwrap_or_default());
    check(
        r.fake.minted(&plan_cs),
        format!("the plan's checkout is the fake Stripe's: {start}"),
    )?;
    let (code, said) = r.pay(shape, &plan_cs)?;
    check(code == 200, format!("the plan's event: {code} {said}"))?;
    let welcome = poll_signup(&relay, shape, &plan_cs, "created").await;
    check(
        welcome["state"] == "created" && welcome["username"] == "alica",
        format!("the welcome page after paying: {welcome}"),
    )?;
    check(
        r.accounts(shape).iter().any(|a| a == "alica"),
        format!("the account on the site's main: {:?}", r.accounts(shape)),
    )?;
    let meter = if shape == Shape::Gunnar {
        "pack_bytes"
    } else {
        "disk_bytes"
    };
    let until = Instant::now() + Duration::from_secs(30);
    let held = loop {
        let held = r
            .boxes
            .lock()
            .unwrap()
            .iter()
            .find(|b| b.instance == site_id(shape))
            .and_then(|b| b.site.as_ref())
            .and_then(|s| s.caps.get("alica").cloned())
            .unwrap_or_default();
        if held.get(meter).copied() == Some(10 * GIB) || Instant::now() > until {
            break held;
        }
        tokio::time::sleep(Duration::from_millis(100)).await;
    };
    check(
        held.get(meter).copied() == Some(10 * GIB),
        format!("the site's main holds what was paid (10 GiB {meter}) for alica: {held:?}"),
    )?;

    // ── 2. a private instance, signed in: the form knows the account, no e-mail asked ──
    let (st, ladder) = ask(
        &relay,
        shape,
        "GET",
        "/auth/private/ladder",
        Some("alica"),
        None,
    )
    .await;
    check(
        st == 200,
        format!("the private ladder, signed in: {st} {ladder}"),
    )?;
    let step = first_step(&ladder);
    let body = json!({"company": "rickardtest", "front_plan": step["front_plan"], "main_plan": step["main_plan"], "main_data_gib": step["main_data_gib"]});
    let (st, order) = ask(
        &relay,
        shape,
        "POST",
        "/auth/private/start",
        Some("alica"),
        Some(body),
    )
    .await;
    check(
        st == 200,
        format!("the signed-in order with no e-mail and no account in it: {st} {order}"),
    )?;
    check(
        order["price_words"].as_str().is_some_and(|w| !w.is_empty()),
        format!("the order names its price: {order}"),
    )?;
    let cs = session_of(order["url"].as_str().unwrap_or_default());
    check(
        cs != plan_cs && r.fake.minted(&cs),
        format!("the instance's own checkout: {order}"),
    )?;
    let run = r
        .state
        .estates
        .get("rickardtest")
        .ok_or("no run for rickardtest")?;
    check(
        run.account == "alica",
        format!("the order is the signed-in account's: {:?}", run.account),
    )?;
    check(
        run.email == "alica@mock.invalid",
        format!("the order mails the account's own address: {:?}", run.email),
    )?;
    let (code, said) = r.pay(shape, &cs)?;
    check(code == 200, format!("the instance's event: {code} {said}"))?;

    // ── 3. laid, installed, captured; the watch; the ready mail ──
    let p = r.order_until("rickardtest", phase::CAPTURED).await;
    let (_, watch) = ask(
        &relay,
        shape,
        "GET",
        "/auth/private/status?company=rickardtest",
        Some("alica"),
        None,
    )
    .await;
    check(
        p == phase::CAPTURED,
        format!(
            "laid and captured: {p}; {watch}; {}",
            r.history("rickardtest")
        ),
    )?;
    check(watch["state"] == "ready", format!("the watch: {watch}"))?;
    let run = r.state.estates.get("rickardtest").ok_or("the run went")?;
    // The instance's own name, under the site it was bought on.
    let host = format!("rickardtest.{}", shape.host());
    let until = Instant::now() + Duration::from_secs(20);
    let mut ready: Vec<String> = Vec::new();
    while ready.is_empty() && Instant::now() < until {
        ready = r
            .relay_mail
            .mails()
            .into_iter()
            .filter(|(to, body)| to == "alica@mock.invalid" && body.contains("/login?invite="))
            .map(|(_, b)| b)
            .collect();
        if ready.is_empty() {
            tokio::time::sleep(Duration::from_millis(200)).await;
        }
    }
    let mails: Vec<String> = r
        .relay_mail
        .mails()
        .iter()
        .map(|(t, b)| {
            format!(
                "{t}: {}",
                b.split_whitespace()
                    .take(12)
                    .filter(|w| !w.contains("invite="))
                    .collect::<Vec<_>>()
                    .join(" ")
            )
        })
        .collect();
    check(
        ready.len() == 1,
        format!("ONE ready mail with the one-time link to alica: {mails:?}"),
    )?;
    let mail = ready[0].clone();
    // The one-time link is a secret, even a test's: never in a failure's words.
    let shown = mail
        .split_whitespace()
        .map(|w| {
            if w.contains("invite=") {
                "<the one-time link>"
            } else {
                w
            }
        })
        .collect::<Vec<_>>()
        .join(" ");
    let want: Vec<String> = vec![
        format!("{host} is installed and running"),
        "its first admin is alica".to_string(),
        format!("https://{host}/login?invite="),
        "&user=alica".to_string(),
        "it works once, for 7 days".to_string(),
        format!(
            "paid until {}",
            monetize_server::estate_order::iso_date(run.paid_until_ms)
        ),
        if shape == Shape::Gunnar {
            format!("git is at git.{host}.")
        } else {
            format!("served from https://{host}.")
        },
    ];
    for w in &want {
        check(
            mail.contains(w.as_str()),
            format!("the ready mail says {w:?}: {shown}"),
        )?;
    }
    check(
        mail.matches("/login?invite=").count() == 1,
        format!("the one-time link once: {shown}"),
    )?;

    // ── 4. the ONE box's Accounts page: the plan and the instance, on alica's account ──
    let token = std::fs::read_to_string(r.dir.join("data").join(monetize_front::intake::TOKEN_REL))
        .map_err(|e| e.to_string())?
        .trim()
        .to_owned();
    let channel = tonic::transport::Channel::from_shared(format!("http://{}", r.addr()))
        .map_err(|e| e.to_string())?
        .connect()
        .await
        .map_err(|e| e.to_string())?;
    let mut accounts = monetize_proto::accounts_client::AccountsClient::new(channel);
    fn authed<T>(token: &str, m: T) -> tonic::Request<T> {
        let mut q = tonic::Request::new(m);
        q.metadata_mut()
            .insert("authorization", format!("Bearer {token}").parse().unwrap());
        q
    }
    let listed = accounts
        .list(authed(
            &token,
            monetize_proto::ListAccountsRequest {
                product: product.into(),
                limit: 100,
            },
        ))
        .await
        .map_err(|e| format!("Accounts.List: {e}"))?
        .into_inner()
        .accounts;
    let acct = listed
        .iter()
        .find(|a| a.tenant == "alica" || a.tenant.ends_with("/alica"))
        .cloned()
        .ok_or(format!("alica is not on the Accounts page: {listed:?}"))?;
    if acct.instances != 1 {
        let other = if shape == Shape::Gunnar {
            "holger"
        } else {
            "gunnar"
        };
        let theirs = accounts
            .list(authed(
                &token,
                monetize_proto::ListAccountsRequest {
                    product: other.into(),
                    limit: 100,
                },
            ))
            .await
            .map(|a| a.into_inner().accounts)
            .unwrap_or_default();
        let ledger = r
            .state
            .ledger
            .instances(product)
            .map(|v| v.len())
            .unwrap_or(0);
        let ledger_other = r
            .state
            .ledger
            .instances(other)
            .map(|v| {
                v.iter()
                    .map(|i| format!("{}:{}", i.company, i.tenant))
                    .collect::<Vec<_>>()
            })
            .unwrap_or_default();
        return Err(format!("one instance on alica's {product} account: {acct:?}; {product} ledger instances {ledger}; {other} ledger instances {ledger_other:?}; {other}'s accounts {theirs:?}"));
    }
    let rows = accounts
        .rows(authed(
            &token,
            monetize_proto::AccountRowsRequest {
                product: product.into(),
                tenant: acct.tenant.clone(),
            },
        ))
        .await
        .map_err(|e| format!("Accounts.Rows: {e}"))?
        .into_inner();
    check(
        rows.rows
            .iter()
            .any(|x| x.kind == "instance" && x.id.contains("rickardtest")),
        format!("the instance is a row on alica's account: {:?}", rows.rows),
    )?;
    let names: Vec<String> = listed
        .iter()
        .map(|a| format!("{} (rows {}, instances {})", a.tenant, a.rows, a.instances))
        .collect();
    check(
        rows.rows
            .iter()
            .any(|x| x.kind == "purchase" || x.kind == "subscription"),
        format!(
            "the plan is a row on alica's account {}: {:?}; the {product} accounts: {names:?}",
            acct.tenant, rows.rows
        ),
    )?;
    check(
        listed
            .iter()
            .filter(|a| a.tenant == "alica" || a.tenant.ends_with("/alica"))
            .count()
            == 1,
        format!("ONE account for alica on the Accounts page: {names:?}"),
    )?;
    r.stop().await;
    Ok(format!("alica paid once for {} ({plan_cs}), made on {}'s main holding 10 GiB; rickardtest ordered signed in (no e-mail asked), paid once ({cs}), laid and ready; the ready mail names {host}, alica, the 7-day link, paid until {}; Accounts lists both", paid["id"], site_id(shape), monetize_server::estate_order::iso_date(run.paid_until_ms)))
}

macro_rules! trials {
    ($($fn_:ident => $name:literal),* $(,)?) => {$(
        mod $fn_ {
            #[tokio::test(flavor = "multi_thread", worker_threads = 4)]
            async fn gunnar() {
                super::trial($name, super::Shape::Gunnar, super::$fn_(super::Shape::Gunnar)).await
            }
            #[tokio::test(flavor = "multi_thread", worker_threads = 4)]
            async fn holger() {
                super::trial($name, super::Shape::Holger, super::$fn_(super::Shape::Holger)).await
            }
        }
    )*};
}

trials!(
    free_account => "a-free-account",
    paid_plan => "b-paid-plan",
    private_visitor => "c-private-visitor",
    private_signed_in => "d-private-signed-in",
    grow_account => "e-grow-account",
    grow_instance => "f-grow-instance",
    owner_walk => "g-owner-walk",
);

/// ★ MHUNT-2 (OX-MONHUNT 2026-10-28, `cargo xtask trial buy` on oden): `free_account::gunnar`
/// failed with "the fake Stripe did not listen on 36485/44091 in 20 s" — its child had exited
/// with "Address already in use": the port [`free_port`] named was taken before the child bound
/// it. Here the first port named is held by a socket that never answers: the fake must still
/// come up, on other ports, and answer its own control door.
#[test]
fn the_fake_stripe_comes_up_on_new_ports_when_the_one_it_was_given_is_taken() {
    let inp = inputs();
    let taken = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
    let held = taken.local_addr().unwrap().port();
    let mut first = true;
    let mut pick = || {
        if std::mem::take(&mut first) {
            held
        } else {
            free_port()
        }
    };
    let fake = FakeStripe::start_on(&inp.fake_stripe, SK, WHSEC, &mut pick);
    assert_ne!(
        fake.api, held,
        "the fake never took the held port: it came up on another"
    );
    assert_ne!(
        fake.control("GET", "/seen/cs_none").0,
        0,
        "its control door answers"
    );
    drop(taken);
}