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

nordisk/gunnar-ui

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

//! **A customer renews their own subscription, themselves.**
//!
//! Until this module existed, a lapse was an operator's job: somebody with an
//! admin passkey placed the order on the tenant's behalf, by hand, every time.
//! `Transaction::renewal` and `Purchase.Start{renew}` have worked for a while —
//! the arithmetic, the pricing on the standing cap, the Retention boundary. The
//! only thing missing was that nothing but an operator could call them.
//!
//! # Why this is not a route under `/api/namespaces/{name}/`
//!
//! That is where [`crate::api::increase`] lives, and it is the right home for
//! an order an OPERATOR places on a tenant's behalf. It is the wrong home for
//! this, and the reason is written out in `monetize_site_buy::relay::operator_status` (was `increase::status`):
//!
//! > *"BOTH halves of the comparison are chosen by the caller — the reference
//! > in the query and the namespace in the path — so anybody who could name
//! > `gunnar/beta/…` could also ask for it under `/api/namespaces/beta/`."*
//!
//! A tenant surface that took a namespace in the path would have to compare it
//! against the session on every call, and **every such comparison is a place to
//! leak**: by a refusal that names what it found, by a 404 that differs from a
//! 403, by the time one takes. The rule this lane was given is that every
//! refusal a tenant can trigger must say no more than a stranger is entitled to
//! know.
//!
//! So there is **no namespace anywhere in the request** — not in the path, not
//! in a query, not in a body. It comes from the session's pinned principal and
//! from nowhere else. A tenant cannot *spell* another namespace here, so there
//! is no other-namespace request to make, no enumeration to bound and no
//! differential refusal to tune. The property is structural rather than
//! checked.
//!
//! That is `/api/account`'s own argument, and this module sits under that
//! prefix deliberately: `role_floor` puts it at `Viewer` (the tenant rung), and
//! `auth::middleware` already says why that is safe — *"every handler under
//! this prefix acts on the name in the SESSION, which no path segment, query
//! parameter or body field can change, so there is nothing to escalate to."*
//!
//! # What gunnar verifies, and why the console's word is not enough
//!
//! This console holds a **server-wide admin grant** at gunnar. If it alone
//! decided "this session may only touch namespace X", a routing mistake here
//! would be full admin over every customer on the box.
//!
//! So it does not decide. [`ticket`] asks gunnar to mint one, over a credential
//! signed with **that human's own key** — the per-user key
//! [`crate::tenant::TenantKeys`] enrolled on their own gunnar principal, the
//! same one their reads are already answered with. gunnar checks the namespace
//! against its own grant table before a ticket exists:
//!
//! ```text
//! ctx.require(&caller, Access::namespace(&ns), GrantLevel::Admin, "Billing.MintActorTicket")
//! ```
//!
//! A bug in this crate that passed the wrong namespace would be refused by the
//! appliance, because the appliance is checking the key that signed the call
//! and not the string this process sent. What it does **not** defend against is
//! a wholly compromised console — this process holds every enrolled tenant's
//! private half, as [`crate::tenant`] states plainly — but a compromised
//! console already holds a server-wide admin key, so that is no new reach.
//!
//! # The upgrade hazard, and why this module refuses rather than degrades
//!
//! proto3 drops unknown fields. A NEW console talking to an OLD monetize would
//! send an `actor_ticket` that is thrown away — **and the renewal would succeed
//! anyway, with no tenant check performed**, while this console believed the
//! tenant path was being enforced. The failure is invisible from here and looks
//! exactly like success.
//!
//! So nothing here infers enforcement from a version, a build flag or a call
//! that came back 200. the shared relay's `offered` (monetize-site-buy) reads `ProductInfo.tenant_renewal` — a bool
//! monetize sets only when it can actually verify a ticket — and when it is
//! false **the route answers as though it did not exist**. Not a disabled
//! button, not a degraded path that still charges the card. An old monetize
//! leaves the field false by omission, which is the safe direction.
//!
//! # Following an attempt across a restart
//!
//! [`crate::api::increase`] remembers every reference it mints in a
//! process-global ring, and forgets them all on restart; its `status` then 404s
//! and points the caller at monetize's own console. For an operator that is an
//! inconvenience. For a **customer who has just been charged** it is a dead end,
//! because monetize's console is not a place a tenant can reach.
//!
//! [`status`] therefore remembers nothing. A reference is
//! `<product>/<tenant>/<date>`, and the tenant is this session's own namespace
//! — so the check is re-derived from identity on every call and survives a
//! restart. The comparison `monetize_site_buy::relay::operator_status` (was `increase::status`) calls decorative is **decisive**
//! here, and the difference is exactly one thing: there, both halves came from
//! the caller; here, one half comes from the session's pinned principal, which
//! no part of the request can change.

use axum::extract::State;
use axum::Json;
use serde::Serialize;

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





/// **Whose subscription this request is about, decided before a handler exists
/// to forget.**
///
/// An extractor and not a helper, for the reason [`crate::api::account::Me`]
/// and `buy_site::GunnarSite::operator` (was `increase::Ordering`) are: a helper is something a handler can forget to
/// call, and forgetting here spends somebody else's money on somebody else's
/// account.
///
/// **The namespace is not in the request.** It is the gunnar principal the
/// session's passkey was pinned to at registration
/// (`auth::routes::bind_a_principal`), which is the one moment a name was
/// anybody's to give, and on gunnar a principal's id *is* the namespace it owns
/// (`AuthTable::owns_account`). Nothing a caller can send changes it.
#[derive(Debug, Clone)]
pub struct OwnSubscription {
    /// The session's own namespace, which is monetize's `tenant`.
    pub namespace: String,
    /// The console user, for the audit line.
    pub who: String,
    /// Whom Stripe mails the receipt (g-receipts; [`crate::monetize::Monetize::payer_for`]).
    pub payer: String,
}

impl axum::extract::FromRequestParts<AppState> for OwnSubscription {
    type Rejection = ApiError;

    async fn from_request_parts(
        parts: &mut http::request::Parts,
        state: &AppState,
    ) -> Result<OwnSubscription, ApiError> {
        let who = match parts.extensions.get::<crate::auth::middleware::Caller>() {
            Some(crate::auth::middleware::Caller::Operator(session)) => session.user.clone(),
            // **The break-glass token is not a person.** It is held by whoever
            // runs the process, it is named after nobody, and there is no
            // principal it could be the owner of — so there is no subscription
            // that is "its own". An operator with a token who wants to renew
            // somebody's plan has `/api/namespaces/{name}/increase`, which is
            // the surface for acting on a tenant's behalf. `api::account::Me`
            // refuses it for the same reason.
            Some(crate::auth::middleware::Caller::AdminToken) => {
                return Err(refuse(
                    "permissiondenied",
                    "the break-glass token is not a person and holds no plan of its own",
                ))
            }
            // Includes the open-console posture (`trunk serve` on loopback),
            // where every request runs as admin and still has no name. An
            // unnamed caller has no account, so the honest answer is the same
            // refusal rather than a guess.
            None => {
                return Err(refuse(
                    "permissiondenied",
                    "this needs a session that can be named: a subscription belongs to whoever \
                     is logged in, and nobody is",
                ))
            }
        };
        let Some(namespace) = state
            .webauthn
            .as_ref()
            .and_then(|webauthn| webauthn.principal_of(&who))
        else {
            // A passkey bound to no principal: somebody invited to look at
            // public repositories, or a credential from before the binding
            // existed. They hold no namespace, so there is nothing of theirs to
            // renew — and this console must NOT resolve a name to find one,
            // which would be GUI-001 living on in a quieter place.
            return Err(refuse(
                "notfound",
                "this sign-in belongs to no account here, so there is no \
                 plan of its own to renew",
            ));
        };
        let caller = parts.extensions.get::<crate::auth::middleware::Caller>();
        // **A member buys nothing** (owner 2026-10-07: a customer is an
        // ACCOUNT that pays; its members use its space and ask its admin for
        // more). gunnar says who is a member (`Access.WhoAmI`), and refuses a
        // member's ticket by name besides (`Billing.MintActorTicket`): this
        // only says it before a quote, an order or a read is attempted.
        let member = crate::auth::middleware::member(state, caller)
            .await
            .map_err(|why| refuse("unavailable", &why))?;
        if let Some(member) = member {
            return Err(refuse(
                "permissiondenied",
                &format!(
                    "{} A member buys nothing: {}'s room is its admin's to buy.",
                    member.members_line(),
                    member.account
                ),
            ));
        }
        let payer = state.monetize.as_ref().map(|m| m.payer_for(caller)).unwrap_or_default();
        Ok(OwnSubscription { namespace, who, payer })
    }
}

fn refuse(code: &str, message: &str) -> ApiError {
    ApiError(crate::grpc::Fail {
        code: code.to_owned(),
        message: message.to_owned(),
    })
}

/// **The caller's OWN control-plane channel**, signed with the key
/// [`crate::tenant::TenantKeys`] enrolled on their own gunnar principal.
///
/// One function because three handlers need it and every one of them would
/// otherwise be a place to reach for `state.gunnar` — this console's
/// server-wide admin channel — by accident. That substitution compiles, passes
/// every test that does not inspect the credential, and undoes the entire
/// design; `api::subscription`'s starred test exists because of it.
///
/// **There is no fallback here and there must never be one.** `api::Reader`
/// says why in the same words: the fallback IS the hole.
async fn tenant_channel(
    state: &AppState,
    who: &str,
) -> Result<crate::tenant::TenantIdentity, ApiError> {
    crate::api::person_identity(state, who)
        .await
        .map_err(|why| why.to_string())
        .and_then(|held| held.ok_or_else(|| "this sign-in holds no key at Gunnar any more".to_owned()))
        .map_err(|why| {
            tracing::warn!(
                target: crate::auth::AUDIT_TARGET,
                event = "subscription.no_tenant_credential",
                user = %who,
                reason = %why,
                "this console could not sign as the tenant, so it will not act for them"
            );
            refuse(
                "permissiondenied",
                "Gunnar could not act as your account just now; sign in again",
            )
        })
}

/// What another period would come to.
///
/// **No price and no cost**, for the reason [`crate::api::increase::Offer`]
/// gives: this console holds no currency literal and does no money arithmetic,
/// and the amount is shown by the vendor on the page the card is on.
pub use monetize_site_buy::purchase::Renewal;

/// Where the tenant is sent, and how this console follows what happens there.
pub use monetize_site_buy::purchase::{target_caps, Attempt, RoomLine, UsersLine};

// ── The plan this account is on ────────────────────────────────────────────

/// **What the appliance holds about this account's subscription.**
///
/// Read from GUNNAR and not from monetize, which is the whole point: gunnar
/// holds the last fact monetize pushed, its `Entitlement.Get` is
/// namespace-scoped, and the tenant's own key answers it — so the narrowing
/// happens on gunnar's side of the wire, where a mistake in this crate cannot
/// reach it. Asking monetize would have meant vendoring a client for
/// `Entitlement.Set` beside it and holding the answer on this console's word.
///
/// **No signature and no source.** `source` is `payment:<vendor>:<reference>`
/// — a vendor's name and a ledger key, which is operator vocabulary — and the
/// signature is monetize's and gunnar's business, not a browser's.
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct Plan {
    /// monetize's word for the plan, verbatim.
    pub plan: String,
    /// `free` | `paid` | `grace` | `suspended` | `retention`, gunnar's ladder
    /// in lower case — or `none` when gunnar holds no entitlement for the
    /// namespace at all (an account that has bought nothing).
    pub state: &'static str,
    /// When the paid period ends. Absent for a plan with no period.
    pub paid_until_unix_ms: Option<u64>,
    /// The caps the fact carries, per meter.
    pub caps: std::collections::BTreeMap<String, u64>,
}

/// **A Free account cannot push** (owner order 2026-10-18): on a console that
/// sells, a person who buys for their own account (gunnar's standing: an
/// individual or an account's admin, never a member) and whose account has no
/// plan — no fact, or gunnar's `Free` — can read and clone, not push. The
/// queue says so instead of "add your key so you can push", which was wrong
/// for them. Best-effort: anything unanswered says nothing.
pub(crate) async fn free_cannot_push(state: &AppState, caller: Option<&crate::auth::middleware::Caller>) -> bool {
    if !state.sells_here() {
        return false;
    }
    let Some(caller) = caller else {
        return false;
    };
    let Ok(Some(standing)) = crate::auth::middleware::standing(state, Some(caller)).await else {
        return false;
    };
    // Nothing a plan could change (the site's admin, a member): gunnar is asked nothing more.
    if !free_gates_push(caller.role(), &standing, true) {
        return false;
    }
    let Ok(identity) = tenant_channel(state, caller.name()).await else {
        return false;
    };
    let plan_is_free = match identity
        .gunnar
        .entitlement()
        .get(pb::GetEntitlementRequest { namespace: standing.account.clone() })
        .await
    {
        Ok(answer) => match answer.into_inner().fact {
            None => true,
            Some(fact) => plan_state(fact.state) == "free",
        },
        // gunnar holds no fact for an account nothing was ever sold for.
        Err(status) => status.code() == tonic::Code::NotFound,
    };
    free_gates_push(caller.role(), &standing, plan_is_free)
}

/// Pure: ★ ACCT-3 (owner 2026-10-29) — **does a Free plan gate this person's push?** Only a
/// person who buys for their own account (`standing`: an individual or an account's admin)
/// whose account holds no plan or gunnar's Free (`plan_is_free`) — and NEVER the site's admin
/// (`site_role`: gunnar's server-wide Admin grant, as `Access.WhoAmI` said it): a site admin is
/// never gated by an account plan. Every input is gunnar's answer; this only combines them.
pub(crate) fn free_gates_push(site_role: crate::role::Role, standing: &crate::auth::Standing, plan_is_free: bool) -> bool {
    site_role != crate::role::Role::Admin && standing.may_buy() && !standing.account.is_empty() && plan_is_free
}

/// The queue's item for [`free_cannot_push`].
pub(crate) fn free_cannot_push_item() -> crate::api::actions::Action {
    crate::api::actions::Action {
        id: "free-cannot-push",
        urgency: crate::api::actions::Urgency::Info,
        title: "A Free account cannot push".to_owned(),
        detail: "With a Free account you can sign in, read and clone, but not push. \
                 A plan gives your account room of its own to push to."
            .to_owned(),
        href: "/account#account-plan".to_owned(),
        cta: "Get room".to_owned(),
    }
}


/// gunnar's entitlement ladder as one lower-case word. An unrecognised value
/// is `unknown` rather than a guess.
/// **The money-shaped entries in the account's own åtgärder queue.**
///
/// Here rather than in [`crate::api::actions`] because the words are here: this
/// module is the one the open build does not contain, and keeping the sentences
/// about renewal and room inside it is what lets the queue itself stay free of
/// them and therefore stay scanned.
///
/// Best-effort like every other check in that queue: a source that cannot
/// answer contributes nothing. A person's whole console must not go dark
/// because the appliance was slow to answer one read.
///
/// Both thresholds are the owner's, 2026-09-18: warn at 85 % of the cap, and a
/// week before the period ends.
pub(crate) async fn actions_for(
    state: &AppState,
    user: &str,
    items: &mut Vec<crate::api::actions::Action>,
) {
    use crate::api::actions::{Action, Urgency};

    let Some(namespace) = state
        .webauthn
        .as_ref()
        .and_then(|webauthn| webauthn.principal_of(user))
    else {
        return;
    };
    let Ok(identity) = tenant_channel(state, user).await else {
        return;
    };

    // ── the subscription ────────────────────────────────────────────────────
    if let Ok(answer) = identity
        .gunnar
        .entitlement()
        .get(pb::GetEntitlementRequest { namespace: namespace.clone() })
        .await
    {
        let fact = answer.into_inner().fact.unwrap_or_default();
        let now: u64 = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)
            .map(|d| d.as_millis() as u64)
            .unwrap_or_default();
        // A namespace nothing was ever sold for has no fact, and `free` is not
        // a problem to be solved — a self-hoster and a customer between periods
        // must not be told the same thing.
        match plan_state(fact.state) {
            "grace" => items.push(Action {
                id: "plan-in-grace",
                urgency: Urgency::Urgent,
                title: "Your plan's paid time has ended and it is in its grace period".to_owned(),
                detail: "The account still works. When the grace period ends it stops, and                          renewing now is the whole of what prevents that."
                    .to_owned(),
                href: "/account".to_owned(),
                cta: "Renew".to_owned(),
            }),
            "suspended" | "retention" => items.push(Action {
                id: "plan-suspended",
                urgency: Urgency::Urgent,
                title: "This account is suspended".to_owned(),
                detail: "Its data is still held. Prolonging brings it back; there is a limit                          to how long it is kept, and it is stated on your account page."
                    .to_owned(),
                href: "/account".to_owned(),
                cta: "Renew".to_owned(),
            }),
            "paid" if fact.paid_until_unix_ms.is_some_and(|t| t > 0) => {
                const WEEK_MS: u64 = 7 * 24 * 60 * 60 * 1000;
                // Saturating: a clock that has run past the paid-until is an
                // account already in grace, which the arm above owns. Nothing
                // here may underflow into "a very long time left".
                let left = fact.paid_until_unix_ms.unwrap_or_default().saturating_sub(now);
                if left > 0 && left <= WEEK_MS {
                    items.push(Action {
                        id: "plan-due-soon",
                        urgency: Urgency::Soon,
                        title: "Your plan's paid time ends within the week".to_owned(),
                        detail: "Prolonging before it does keeps the account out of its grace                                  period entirely."
                            .to_owned(),
                        href: "/account".to_owned(),
                        cta: "Renew".to_owned(),
                    });
                }
            }
            _ => {}
        }
    }

    // ── the disk ────────────────────────────────────────────────────────────
    //
    // Against the CAP and not against the box: a tenant hits their own wall
    // first, and being told the appliance is filling up is somebody else's
    // problem printed at somebody who cannot act on it.
    if let Ok(answer) = identity
        .gunnar
        .usage()
        .read(pb::ReadUsageRequest { namespace: namespace.clone() })
        .await
    {
        let read = answer.into_inner();
        if let Some(usage) = read.usage {
            // `pack_bytes` is `Option<u64>` on the wire, and its ABSENCE is
            // "no cap declared" — never zero. A namespace with no wall has
            // nothing to be near.
            let cap = read.allowance.as_ref().and_then(|a| a.pack_bytes).unwrap_or(0);
            // No cap is not a full disk. An uncapped namespace has no wall to
            // be near, and a percentage of zero is not a number.
            if let Some(permille) = usage.pack_bytes.saturating_mul(1000).checked_div(cap) {
                if permille >= 850 {
                    items.push(Action {
                        id: "room-running-out",
                        urgency: if permille >= 950 { Urgency::Urgent } else { Urgency::Soon },
                        title: format!("Your account is {} % full", permille / 10),
                        detail: "A push is refused once the cap is reached. More room can be                                  added from your account page, and what it costs is shown there."
                            .to_owned(),
                        href: "/account".to_owned(),
                        cta: "More room".to_owned(),
                    });
                }
            }
        }
    }
}

fn plan_state(wire: i32) -> &'static str {
    match pb::EntitlementState::try_from(wire) {
        Ok(pb::EntitlementState::Free) => "free",
        Ok(pb::EntitlementState::Paid) => "paid",
        Ok(pb::EntitlementState::Grace) => "grace",
        Ok(pb::EntitlementState::Suspended) => "suspended",
        Ok(pb::EntitlementState::Retention) => "retention",
        _ => "unknown",
    }
}

/// `GET /api/account/plan` — the subscription state of the caller's own
/// account.
///
/// Signed with the caller's own credential, so gunnar decides. **Not gated on
/// the shared relay's `offered` (monetize-site-buy)**: what plan somebody is on is a fact about their account that
/// gunnar holds whether or not this monetize can sell them another period, and
/// a customer whose renewal path is unavailable still has the right to see that
/// their plan has lapsed — that is precisely when they most need to.
pub async fn plan(own: OwnSubscription, State(state): State<AppState>) -> ApiResult<Plan> {
    let identity = tenant_channel(&state, &own.who).await?;
    let answer = identity
        .gunnar
        .entitlement()
        .get(pb::GetEntitlementRequest {
            namespace: own.namespace.clone(),
        })
        .await
        .map_err(ApiError::from)?
        .into_inner();
    // **No fact is not an error.** A namespace monetize has never pushed for —
    // a self-hoster, or an account created before it was sold anything — has no
    // entitlement, and answering 404 would make the pane look broken for the
    // most ordinary case there is. Nor is it `unknown` (owner, test2,
    // 2026-10-05: "Plan unknown" read like a fault): gunnar SAID there is
    // none, and the answer carries that as the word `none`.
    let Some(fact) = answer.fact else {
        return Ok(Json(Plan {
            plan: String::new(),
            state: "none",
            paid_until_unix_ms: None,
            caps: Default::default(),
        }));
    };
    Ok(Json(Plan {
        plan: fact.plan,
        state: plan_state(fact.state),
        paid_until_unix_ms: fact.paid_until_unix_ms,
        caps: fact.caps.into_iter().collect(),
    }))
}


// ── What this account holds, and room for more ─────────────────────────────

/// `GET /api/account/storage` — what the caller's own namespace holds and is
/// allowed.
///
/// Delegates to [`crate::api::usage::render`] rather than counting anything
/// here: the Room table on the namespace page and this pane must never be able
/// to disagree about what a byte is, and two renderers is how they would.
///
/// **Not gated on the shared relay's `offered` (monetize-site-buy)**, for [`plan`]'s reason: what a tenant stores is
/// gunnar's answer about their own disk, true on a community appliance that
/// sells nothing at all.
pub async fn storage(
    own: OwnSubscription,
    State(state): State<AppState>,
) -> ApiResult<crate::api::usage::Usage> {
    let identity = tenant_channel(&state, &own.who).await?;
    let answer = identity
        .gunnar
        .usage()
        .read(pb::ReadUsageRequest {
            namespace: own.namespace.clone(),
        })
        .await
        .map_err(ApiError::from)?
        .into_inner();
    // The same refusal `api::usage::read` makes, and for the same reason:
    // rendering an entire namespace as zeroes is the one answer a person
    // reading their own disk must never be given by mistake.
    let usage = answer.usage.ok_or_else(|| {
        refuse(
            "internal",
            "Gunnar answered without your account's figures, so there is nothing to show \
             yet; try again in a moment",
        )
    })?;
    Ok(Json(crate::api::usage::render(
        usage,
        answer.allowance.unwrap_or_default(),
        // gunnar's own `remaining` (thin layer, owner 2026-10-04).
        answer.remaining,
        // **No box.** `Admin.Capacity` is the appliance's own disk — total,
        // free, servable — and not a tenant's business.
        Err("the server's own disk is not shown to an account".to_owned()),
    )))
}



// ── What this account has already been sold ────────────────────────────────

/// One past purchase, folded to its outcome.
///
/// **No price, and that is this console's rule rather than monetize's.**
/// `PurchaseAttempt.price` is deliberately present on the wire — monetize
/// documents it as what the customer was charged, and a customer's own money is
/// theirs to see. This console still drops it, for the reason
/// [`crate::api::increase`] gives about the quote: `Money { minor, Currency }`
/// is minor units and an enum, and turning that into a rendered amount needs a
/// division by 100 and a map from `CURRENCY_EUR` to a symbol — money arithmetic
/// and a currency literal, which are exactly what this console may not contain.
///
/// So a row says WHAT was bought and WHEN, and the amounts live where the card
/// was. If a price is ever to appear here, monetize must send it as words, the
/// same conclusion `increase` reached.
///
/// **And no `cost`.** That is the provider's margin and is not on the wire at
/// all; `the_providers_cost_never_reaches_a_customer` guards the sibling route
/// on the bytes.
pub use monetize_site_buy::purchase::Past;

/// **Your purchases** (one shop, owner 2026-10-07), moved into the shared buy flow
/// (monetize-site-buy `purchase`, A12): what this account bought at this shop — its private
/// Gunnars first (Grow, Renew), then its room here; for an account WITHOUT room here, the owner's
/// two lines for its Storage page ("Your Gunnar is <host>", "Want space here on <this host> too?
/// Buy 10GB/month") — never an empty bar or "0 B".
pub use monetize_site_buy::purchase::{Instance, Line, Purchases, RoomBought};

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

    use std::sync::{Arc, Mutex};

    use tower::ServiceExt as _;

    use crate::mpb::products_server::{Products as ProductsService, ProductsServer};
    use crate::mpb::purchase_server::{Purchase as PurchaseService, PurchaseServer};
    use crate::mpb::estate_order_server::{EstateOrder as EstateOrderService, EstateOrderServer};
    use crate::pb::access_server::{Access as AccessService, AccessServer};
    use crate::pb::billing_server::{Billing as BillingService, BillingServer};
    use crate::pb::entitlement_server::{Entitlement as EntitlementService, EntitlementServer};

    /// The bearer the fake monetize insists on.
    const BEARER: &str = "the-monetize-bearer";

    /// **The seed of the console's OWN key** — the server-wide admin
    /// credential. Its fingerprint is what the starred test asserts a ticket
    /// request did NOT carry.
    const CONSOLE_SEED: [u8; 32] = [7u8; 32];

    /// **The provider's cost, and nothing like the price.** A leak of `cost`
    /// under any name puts these exact digits in the body.
    const COST_MINOR: u64 = 133_700;
    const PRICE_MINOR: u64 = 1_000;

    /// **monetize's rendered amount**, and deliberately not a formatting of
    /// `PRICE_MINOR`. If the console ever formats the number itself the two
    /// will differ, and the assertions can tell which one reached the browser.
    const PRICE_WORDS: &str = "49.99 EUR";

    /// The vendor's own checkout page, a session id no template here could mint.
    const CHECKOUT_URL: &str = "https://checkout.stripe.com/c/pay/cs_test_renew_9z8y";

    /// One call that reached the fake gunnar: what was asked, and **which key
    /// signed it**.
    #[derive(Debug, Clone, PartialEq, Eq)]
    pub(crate) struct Signed {
        pub(crate) what: String,
        pub(crate) fingerprint: String,
        pub(crate) namespace: String,
        pub(crate) purpose: String,
        /// The caps the ticket was minted to COVER. Empty for a renewal, and
        /// for an order this is the thing that stops a blank cheque.
        caps: std::collections::BTreeMap<String, u64>,
    }

    #[derive(Clone, Default)]
    pub(crate) struct FakeGunnar {
        pub(crate) calls: Arc<Mutex<Vec<Signed>>>,
        /// gunnar refuses to vouch, the way it does for a namespace the
        /// caller's key does not hold.
        refuse_ticket: bool,
        /// gunnar holds NO entitlement for the namespace: `Entitlement.Get`
        /// answers no fact, as it does for an account that has bought nothing.
        no_fact: bool,
        /// Set: the namespaces this gunnar holds. A ticket for any other is
        /// `NOT_FOUND`, as gunnar answers a sign-in with no account of its own (the
        /// kit's or the operator's machine sign-in, i54a run32 A3).
        namespaces: Option<Vec<String>>,
    }

    impl FakeGunnar {
        /// The fingerprint out of the `gunnar-sshsig-v2` credential, which is
        /// the only way a test can see WHICH of the console's keys made a call.
        fn fingerprint_of(request: &tonic::Request<impl Sized>) -> String {
            request
                .metadata()
                .get(crate::signer::CREDENTIAL_METADATA_KEY)
                .and_then(|v| v.to_str().ok())
                .and_then(|header| header.split_whitespace().nth(1))
                .unwrap_or("<none>")
                .to_owned()
        }
    }

    #[tonic::async_trait]
    impl BillingService for FakeGunnar {
        async fn mint_actor_ticket(
            &self,
            request: tonic::Request<pb::MintActorTicketRequest>,
        ) -> Result<tonic::Response<pb::MintActorTicketResponse>, tonic::Status> {
            let fingerprint = FakeGunnar::fingerprint_of(&request);
            let asked = request.into_inner();
            self.calls.lock().expect("the call log").push(Signed {
                what: "Billing.MintActorTicket".to_owned(),
                fingerprint,
                namespace: asked.namespace.clone(),
                purpose: asked.purpose.clone(),
                caps: asked.caps.clone().into_iter().collect(),
            });
            if self.refuse_ticket {
                return Err(tonic::Status::permission_denied(format!(
                    "principal has no admin grant on namespace:{}",
                    asked.namespace
                )));
            }
            if self.namespaces.as_ref().is_some_and(|held| !held.contains(&asked.namespace)) {
                return Err(tonic::Status::not_found(format!("no namespace {:?} on this server", asked.namespace)));
            }
            Ok(tonic::Response::new(pb::MintActorTicketResponse {
                // Opaque here on purpose: whether these bytes VERIFY is
                // monetize's question and is answered by `monetize-embed`'s own
                // tests. What this console must get right is which key it asked
                // with, which namespace it named, and that it relays the answer
                // unaltered.
                ticket: b"{\"v\":1,\"a-real-ticket-is-signed-json\":true}".to_vec(),
                expires_unix_ms: 0,
            }))
        }

        async fn appliance_identity(
            &self,
            _request: tonic::Request<pb::ApplianceIdentityRequest>,
        ) -> Result<tonic::Response<pb::ApplianceIdentityResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }
    }

    /// `Access.AddKey` is the one call `TenantKeys::ensure` makes, and it is
    /// made with the CONSOLE's admin key — correctly so: enrolling a key on a
    /// principal is administration. The ticket that follows must not be.
    /// **What the appliance says this account is allowed today.**
    ///
    /// Two meters, and only one of them is what the bundle raises — see
    /// `HELD_CACHE`. A console that minted its ticket from the delta alone
    /// would be refused by a real monetize and would pass a one-meter fixture.
    #[tonic::async_trait]
    impl EntitlementService for FakeGunnar {
        async fn get(
            &self,
            request: tonic::Request<pb::GetEntitlementRequest>,
        ) -> Result<tonic::Response<pb::GetEntitlementResponse>, tonic::Status> {
            let asked = request.into_inner();
            if self.no_fact {
                return Ok(tonic::Response::new(pb::GetEntitlementResponse { fact: None }));
            }
            Ok(tonic::Response::new(pb::GetEntitlementResponse {
                fact: Some(pb::EntitlementFact {
                    namespace: asked.namespace,
                    plan: "standard".to_owned(),
                    state: pb::EntitlementState::Paid as i32,
                    caps: [
                        ("pack_bytes".to_owned(), HELD_PACK),
                        ("cache_bytes".to_owned(), HELD_CACHE),
                    ]
                    .into(),
                    ..Default::default()
                }),
            }))
        }
    }

    #[tonic::async_trait]
    impl AccessService for FakeGunnar {
        /// Every tenant here buys for their own account: an individual.
        async fn who_am_i(
            &self,
            _r: tonic::Request<pb::WhoAmIRequest>,
        ) -> Result<tonic::Response<pb::WhoAmIResponse>, tonic::Status> {
            Ok(tonic::Response::new(pb::WhoAmIResponse { account_role: "individual".to_owned(), ..Default::default() }))
        }

        async fn add_key(
            &self,
            request: tonic::Request<pb::AddKeyRequest>,
        ) -> Result<tonic::Response<pb::AddKeyResponse>, tonic::Status> {
            let fingerprint = FakeGunnar::fingerprint_of(&request);
            let asked = request.into_inner();
            self.calls.lock().expect("the call log").push(Signed {
                what: "Access.AddKey".to_owned(),
                fingerprint,
                namespace: asked.principal_id,
                purpose: String::new(),
                caps: Default::default(),
            });
            Ok(tonic::Response::new(pb::AddKeyResponse::default()))
        }

        async fn revoke_key(
            &self,
            _r: tonic::Request<pb::RevokeKeyRequest>,
        ) -> Result<tonic::Response<pb::RevokeKeyResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }

        async fn list_keys(
            &self,
            _r: tonic::Request<pb::ListKeysRequest>,
        ) -> Result<tonic::Response<pb::ListKeysResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }

        async fn add_principal(
            &self,
            _r: tonic::Request<pb::AddPrincipalRequest>,
        ) -> Result<tonic::Response<pb::AddPrincipalResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }

        async fn list_principals(
            &self,
            _r: tonic::Request<pb::ListPrincipalsRequest>,
        ) -> Result<tonic::Response<pb::ListPrincipalsResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }

        async fn remove_principal(
            &self,
            _r: tonic::Request<pb::RemovePrincipalRequest>,
        ) -> Result<tonic::Response<pb::RemovePrincipalResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }

        async fn rename_principal(
            &self,
            _r: tonic::Request<pb::RenamePrincipalRequest>,
        ) -> Result<tonic::Response<pb::RenamePrincipalResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }

        async fn grant(
            &self,
            _r: tonic::Request<pb::GrantRequest>,
        ) -> Result<tonic::Response<pb::GrantResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }

        async fn revoke(
            &self,
            _r: tonic::Request<pb::RevokeRequest>,
        ) -> Result<tonic::Response<pb::RevokeResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }

        async fn list_grants(
            &self,
            _r: tonic::Request<pb::ListGrantsRequest>,
        ) -> Result<tonic::Response<pb::ListGrantsResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }

        async fn add_group_member(
            &self,
            _r: tonic::Request<pb::AddGroupMemberRequest>,
        ) -> Result<tonic::Response<pb::AddGroupMemberResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }

        async fn remove_group_member(
            &self,
            _r: tonic::Request<pb::RemoveGroupMemberRequest>,
        ) -> Result<tonic::Response<pb::RemoveGroupMemberResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }

        async fn list_group_members(
            &self,
            _r: tonic::Request<pb::ListGroupMembersRequest>,
        ) -> Result<tonic::Response<pb::ListGroupMembersResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }

        async fn list_group_membership_events(
            &self,
            _r: tonic::Request<pb::ListGroupMembershipEventsRequest>,
        ) -> Result<tonic::Response<pb::ListGroupMembershipEventsResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not this test's"))
        }
    }

    /// What monetize was asked, so a refusal that had already reached it can be
    /// told from one that had not.
    #[derive(Debug, Clone, PartialEq, Eq)]
    struct Asked {
        what: String,
        tenant: String,
        renew: bool,
        ticket_len: usize,
        caps_named: bool,
        caps: std::collections::BTreeMap<String, u64>,
        /// **The bundle id the request carried**, empty for a typed order. On
        /// the wire it and `caps` are mutually exclusive and monetize refuses a
        /// request that sets both, so `caps_named` beside this is what proves
        /// the console sent one shape and not one and a half.
        bundle: String,
    }

    /// Every `Purchase.Start{users}` any fake monetize heard: `(tenant, users)` (tests run at once,
    /// so each one reads its own tenant's rows).
    static USERS_ASKED: Mutex<Vec<(String, mpb::UsersOrder)>> = Mutex::new(Vec::new());

    /// ★ A32-25 (the guard): **this console starts no `Purchase.Start{users}` of its own**; "Add
    /// users" is monetize-site-buy's door (`relay::add_users`), called from `account_admin`.
    #[test]
    fn this_console_starts_no_users_purchase_of_its_own() {
        let here = include_str!("subscription.rs");
        // Spelled apart, so this test's own text is not what it looks for.
        let own = [concat!("users: ", "Some("), concat!("pub(crate) async fn ", "add_users("), concat!("async fn ", "order_ticket(")];
        for gone in own {
            assert!(!here.contains(gone), "api/subscription.rs still carries `{gone}`: \"Add users\" is the shared buy flow's door");
        }
        assert!(include_str!("account_admin.rs").contains(concat!("monetize_site_buy::relay::", "add_users(")), "account_admin calls the shared door");
    }

    /// ★ A32-25: **"Add users" buys through the shared buy flow's door** (monetize-site-buy
    /// `relay::add_users`), not a `Purchase.Start` of this console's own: `POST
    /// /api/account/employees` on a console that sells room starts monetize's `Purchase.Start`
    /// with `users` for the account named, the room they bring, the invite redeemed at this
    /// console's origin, under an ORDER ticket this console minted as the person for exactly
    /// `users` and `user_room_bytes`; the checkout comes back as `checkout_url`.
    #[tokio::test]
    async fn add_users_goes_through_the_shared_buy_flows_door() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/api/account/employees", Some(&session), r#"{"account":"alice","count":2,"room_gib":1}"#).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let answer: serde_json::Value = serde_json::from_str(&body).expect("json");
        assert_eq!((answer["state"].as_str(), answer["reference"].as_str()), (Some("pending"), Some("gunnar/alice/2026-09-17")), "{answer}");
        assert!(answer["checkout_url"].as_str().is_some_and(|u| u.starts_with("https://")), "{answer}");
        let users: Vec<mpb::UsersOrder> = USERS_ASKED.lock().unwrap().iter().filter(|(t, _)| t == "alice").map(|(_, u)| u.clone()).collect();
        assert_eq!(users, vec![mpb::UsersOrder { count: 2, room_bytes: 1 << 30, name: String::new(), email: String::new(), invite_origin: "https://console.example".to_owned() }]);
        let minted = rig.minted_for();
        let order = minted.iter().find(|m| m.purpose == "order").unwrap_or_else(|| panic!("no order ticket: {minted:?}"));
        assert_eq!(order.caps, std::collections::BTreeMap::from([("users".to_owned(), 2), ("user_room_bytes".to_owned(), 1 << 30)]));
        assert_ne!(order.fingerprint, rig.console_fingerprint, "minted as the person, never with the console's admin key");
    }

    #[derive(Clone)]
    struct FakeMonetize {
        asked: Arc<Mutex<Vec<Asked>>>,
        /// `ProductInfo.tenant_renewal` — whether this monetize verifies
        /// tickets at all. **False is an OLD monetize**, and the whole point of
        /// the flag.
        tenant_renewal: bool,
        /// What `Purchase.Quote` refuses with, when it refuses. `None` quotes.
        quote_refuses: Option<(tonic::Code, String)>,
        /// The customer's sentence monetize puts beside a refusal
        /// (`monetize-customer-words-bin`), when it sends one.
        quote_refusal_words: Option<String>,
        /// `Purchase.Status` answers a PAID PROLONG: its `Reserved` row the
        /// way monetize serialises a plan purchase (`purchase.plan.verb`,
        /// an empty `delta`) and the granted fact's new end.
        prolonged: bool,
        /// `Purchase.Status` answers PENDING with no `Captured` row (an order
        /// nobody has paid) instead of PAID. The customer's cancel case.
        unpaid: bool,
        /// Every `Purchase.Abandon`: `(reference, reason)`.
        abandoned: Arc<Mutex<Vec<(String, String)>>>,
        /// Every `Purchase.Cancel` monetize ACCEPTED: `(reference, reason)`.
        cancelled: Arc<Mutex<Vec<(String, String)>>>,
        /// `Purchase.Bundles` says the window is still being read (no rows).
        reading: bool,
        /// `Purchase.Bundles` answers as a deployment that sells PLANS
        /// (2026-10-05): the gauge, a prolong row (pressable or past its
        /// horizon) and a 12-month upgrade.
        plans: Option<bool>,
        /// `EstateOrder.Purchases` answers a room line beside the instance
        /// (an account that bought room here too); else none (an account
        /// without room here, one shop 2026-10-07).
        has_room: bool,
        /// The vendor link `Purchase.Start` and an unpaid `Purchase.Status`
        /// answer with.
        checkout_url: &'static str,
    }

    /// **The window's one offer.** The id is opaque and deliberately not a
    /// description of the delta, so a console that parsed it would get the size
    /// wrong rather than merely be rude.
    const BUNDLE_ID: &str = "the-usual";
    /// monetize's sentence on a prolong past its horizon (`plan::words::ahead_limit`).
    const AHEAD_WORDS: &str = "This account is already paid 3 months ahead, the most a 1-month plan can be prolonged. For longer, choose a 12-month plan. Nothing has been charged.";
    const BUNDLE_LABEL: &str = "10.0 GiB more room";
    /// The end a paid prolong's granted fact carries: 2026-12-05.
    const PROLONGED_UNTIL: u64 = 1_796_428_800_000;
    const BUNDLE_PRICE_WORDS: &str = "220.00 SEK";
    /// The window's one row monetize CANNOT serve, and the sentence it carried
    /// on 2026-09-20 (`monetize::transaction::words::CANNOT_ADD_ROOM`).
    const DEAD_BUNDLE_ID: &str = "100gb";
    const DEAD_BUNDLE_WORDS: &str = "We cannot add more space to your account right now while we carry \
                                     out maintenance. Nothing has been charged — please try again later.";
    /// What the offer RAISES, and what the account already HOLDS.
    ///
    /// `held_cache` is the load-bearing fixture: it is a meter the bundle does
    /// not touch, and monetize's own resolution keeps it in the target caps. A
    /// ticket minted without it is one `verify_ticket` refuses, because that
    /// comparison is `!=` over the whole map.
    const BUNDLE_DELTA: u64 = 10_737_418_240;
    pub(crate) const HELD_PACK: u64 = 10_737_418_240;
    const HELD_CACHE: u64 = 1_073_741_824;

    impl FakeMonetize {
        /// monetize 3b44e7d's tenant scope: with a tenant named, only that
        /// tenant's attempt is answered — one uniform NOT_FOUND otherwise.
        fn owned_by(reference: &str, tenant: &str) -> Result<(), tonic::Status> {
            let owner = reference
                .split_once('/')
                .and_then(|(_, rest)| rest.rsplit_once('/'))
                .map(|(owner, _)| owner)
                .unwrap_or_default();
            if !tenant.is_empty() && owner != tenant {
                return Err(tonic::Status::not_found(
                    "this tenant has no purchase by that reference",
                ));
            }
            Ok(())
        }

        fn verifying() -> FakeMonetize {
            FakeMonetize {
                asked: Default::default(),
                tenant_renewal: true,
                quote_refuses: None,
                quote_refusal_words: None,
                prolonged: false,
                unpaid: false,
                abandoned: Default::default(),
                cancelled: Default::default(),
                reading: false,
                plans: None,
                has_room: false,
                checkout_url: CHECKOUT_URL,
            }
        }

        /// A monetize that REFUSES the quote, with the code and words it would
        /// really use. `failed_precondition` is what every `TxError::Refused`
        /// becomes in `monetize_server::services::purchase`.
        fn refusing_the_quote(code: tonic::Code, why: &str) -> FakeMonetize {
            FakeMonetize { quote_refuses: Some((code, why.to_owned())), ..FakeMonetize::verifying() }
        }

        /// A refusal the way monetize's `refused_status` sends one: the
        /// operator's reason in the message, the customer's sentence beside it.
        fn refusing_the_quote_with_words(code: tonic::Code, why: &str, words: &str) -> FakeMonetize {
            FakeMonetize { quote_refusal_words: Some(words.to_owned()), ..FakeMonetize::refusing_the_quote(code, why) }
        }

        fn old() -> FakeMonetize {
            FakeMonetize {
                asked: Default::default(),
                tenant_renewal: false,
                quote_refuses: None,
                quote_refusal_words: None,
                prolonged: false,
                unpaid: false,
                abandoned: Default::default(),
                cancelled: Default::default(),
                reading: false,
                plans: None,
                has_room: false,
                checkout_url: CHECKOUT_URL,
            }
        }

        fn bearer_ok(&self, request: &tonic::Request<impl Sized>) -> Result<(), tonic::Status> {
            let offered = request
                .metadata()
                .get("authorization")
                .and_then(|v| v.to_str().ok())
                .unwrap_or_default();
            if offered != format!("Bearer {BEARER}") {
                return Err(tonic::Status::unauthenticated(format!(
                    "monetize was offered {offered:?}"
                )));
            }
            Ok(())
        }
    }

    /// **`EstateOrder`, as far as a private Gunnar's order goes** (one shop,
    /// 2026-10-07): `Start` is recorded — the account it names, the ticket's
    /// length (the bytes are the fake gunnar's constant), the company in
    /// `bundle` — and answers where to pay, or monetize's sentence for a
    /// taken name. The rest is not these tests'.
    #[tonic::async_trait]
    impl EstateOrderService for FakeMonetize {
        async fn start(&self, request: tonic::Request<mpb::EstateOrderStartRequest>) -> Result<tonic::Response<mpb::EstateOrderStartResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            let r = request.into_inner();
            self.asked.lock().expect("the ask log").push(Asked {
                what: "EstateOrder.Start".to_owned(),
                tenant: r.account.clone(),
                renew: false,
                ticket_len: r.actor_ticket.len(),
                caps_named: false,
                caps: Default::default(),
                bundle: r.company.clone(),
            });
            if r.company == "taken" {
                return Err(tonic::Status::already_exists("taken.gunnar.rs is taken"));
            }
            Ok(tonic::Response::new(mpb::EstateOrderStartResponse {
                reference: format!("estate/{}", r.company),
                checkout_url: "https://checkout.fake-stripe.test/c/pay/cs_test_estate".to_owned(),
                state: "waiting_for_payment".to_owned(),
                words: "Waiting for your payment.".to_owned(),
                price_words: "792.00 EUR".to_owned(),
            }))
        }
        async fn status(&self, _r: tonic::Request<mpb::EstateOrderStatusRequest>) -> Result<tonic::Response<mpb::EstateOrderStatusResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not these tests'"))
        }
        async fn renew(&self, _r: tonic::Request<mpb::EstateOrderRenewRequest>) -> Result<tonic::Response<mpb::EstateOrderRenewResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not these tests'"))
        }
        /// One shop 4: a step for an instance, on its account's ticket — recorded
        /// (the company in `bundle`, main's data in `caps`); someone else's
        /// instance (`bolt`) is monetize's one sentence.
        async fn change_plan(&self, request: tonic::Request<mpb::EstateOrderChangePlanRequest>) -> Result<tonic::Response<mpb::EstateOrderChangePlanResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            let r = request.into_inner();
            let sizes = r.sizes.unwrap_or_default();
            self.asked.lock().expect("the ask log").push(Asked {
                what: "EstateOrder.ChangePlan".to_owned(),
                tenant: String::new(),
                renew: false,
                ticket_len: r.actor_ticket.len(),
                caps_named: false,
                caps: std::collections::BTreeMap::from([("main_data_gib".to_owned(), sizes.main_data_gib)]),
                bundle: r.company.clone(),
            });
            if r.company == "bolt" {
                return Err(tonic::Status::unauthenticated("that instance is not your account's"));
            }
            Ok(tonic::Response::new(mpb::EstateOrderChangePlanResponse {
                reference: format!("estate/{}/change-1", r.company),
                checkout_url: "https://checkout.fake-stripe.test/c/pay/cs_test_change".to_owned(),
                status: "waiting_for_payment".to_owned(),
                words: "main's data disks grow from 10 to 30 GB each and the twin's to 120 GB, once paid. 44.00 EUR is held now.".to_owned(),
                price_words: "44.00 EUR".to_owned(),
                twin_plan: "STARTER-1xCPU-4GB".to_owned(),
            }))
        }
        /// One shop 4: an instance's ladder, on its account's ticket.
        async fn ladder(&self, request: tonic::Request<mpb::EstateOrderLadderRequest>) -> Result<tonic::Response<mpb::EstateOrderLadderResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            let r = request.into_inner();
            self.asked.lock().expect("the ask log").push(Asked {
                what: "EstateOrder.Ladder".to_owned(),
                tenant: String::new(),
                renew: false,
                ticket_len: r.actor_ticket.len(),
                caps_named: false,
                caps: Default::default(),
                bundle: r.company.clone(),
            });
            let step = |name: &str, data: u64| mpb::EstateLadderStep {
                name: name.into(),
                sizes: Some(mpb::EstateSizes { front_plan: "STARTER-2xCPU-4GB".into(), main_plan: "STARTER-4xCPU-8GB".into(), main_data_gib: data, ..Default::default() }),
                resources_words: format!("7 cores · 16 GB RAM · {} GB data", 4 * data),
                monthly_words: "132.00 EUR a month".into(),
                available: true,
                ..Default::default()
            };
            Ok(tonic::Response::new(mpb::EstateOrderLadderResponse { steps: vec![step("Mini", 10), step("Small", 30)], start: 0, laid: true, current: 0, floor: 0, apex: "gunnar.rs".into(), term_months: 6 }))
        }
        async fn notice(&self, _r: tonic::Request<mpb::EstateNoticeRequest>) -> Result<tonic::Response<mpb::EstateNoticeResponse>, tonic::Status> {
            Ok(tonic::Response::new(mpb::EstateNoticeResponse::default()))
        }
        async fn sells(&self, _r: tonic::Request<mpb::EstateOrderSellsRequest>) -> Result<tonic::Response<mpb::EstateOrderSellsResponse>, tonic::Status> {
            Ok(tonic::Response::new(mpb::EstateOrderSellsResponse { estates: true }))
        }
        async fn cancel(&self, _r: tonic::Request<mpb::EstateOrderCancelRequest>) -> Result<tonic::Response<mpb::EstateOrderCancelResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not these tests'"))
        }
        async fn send_sign_in_again(&self, _r: tonic::Request<mpb::EstateOrderSignInAgainRequest>) -> Result<tonic::Response<mpb::EstateOrderSignInAgainResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not these tests'"))
        }
        /// S8: a lost front made again from its daily backup, on its account's ticket —
        /// recorded; someone else's instance (`bolt`) is monetize's one sentence.
        async fn restore_front(&self, request: tonic::Request<mpb::EstateOrderRestoreFrontRequest>) -> Result<tonic::Response<mpb::EstateOrderRestoreFrontResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            let r = request.into_inner();
            self.asked.lock().expect("the ask log").push(Asked {
                what: "EstateOrder.RestoreFront".to_owned(),
                tenant: String::new(),
                renew: false,
                ticket_len: r.actor_ticket.len(),
                caps_named: false,
                caps: Default::default(),
                bundle: r.company.clone(),
            });
            if r.company == "bolt" {
                return Err(tonic::Status::unauthenticated("that instance is not your account's"));
            }
            Ok(tonic::Response::new(mpb::EstateOrderRestoreFrontResponse { words: "acme.gunnar.rs's front is restored from its backup of last night, with its keys".to_owned(), moved: false, public_ipv4: "198.51.100.7".to_owned() }))
        }
        async fn settle(&self, _r: tonic::Request<mpb::EstateOrderSettleRequest>) -> Result<tonic::Response<mpb::EstateOrderSettleResponse>, tonic::Status> {
            Err(tonic::Status::unimplemented("not these tests'"))
        }
        /// TERMINATE (2026-10-12): recorded (the company in `bundle`, the typed name in
        /// `tenant`); ended at once, no backup (A32-27: the wire carries none).
        async fn terminate(&self, request: tonic::Request<mpb::EstateOrderTerminateRequest>) -> Result<tonic::Response<mpb::EstateOrderTerminateResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            let r = request.into_inner();
            self.asked.lock().expect("the ask log").push(Asked {
                what: "EstateOrder.Terminate".to_owned(),
                tenant: r.confirm.clone(),
                renew: false,
                ticket_len: r.actor_ticket.len(),
                caps_named: false,
                caps: Default::default(),
                bundle: r.company.clone(),
            });
            Ok(tonic::Response::new(mpb::EstateOrderTerminateResponse { words: format!("{}.gunnar.rs is terminated: its machines, disks and DNS records are gone.", r.company), done: true }))
        }
        async fn purchases(&self, request: tonic::Request<mpb::EstateOrderPurchasesRequest>) -> Result<tonic::Response<mpb::EstateOrderPurchasesResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            let r = request.into_inner();
            self.asked.lock().expect("the ask log").push(Asked {
                what: "EstateOrder.Purchases".to_owned(),
                tenant: r.account.clone(),
                renew: false,
                ticket_len: r.actor_ticket.len(),
                caps_named: false,
                caps: Default::default(),
                bundle: String::new(),
            });
            // Round 5.2: `erik` is an account monetize knows nothing of; `alma` an
            // account at this shop that bought nothing yet.
            let (bought, account_here) = match r.account.as_str() {
                "erik" => (false, false),
                "alma" => (false, true),
                _ => (true, false),
            };
            Ok(tonic::Response::new(mpb::EstateOrderPurchasesResponse {
                account_here,
                estates: if !bought { Vec::new() } else { vec![mpb::EstatePurchase {
                    company: "acme".into(),
                    host: "acme.gunnar.rs".into(),
                    url: "https://acme.gunnar.rs".into(),
                    state: "ready".into(),
                    words: "Your Gunnar is ready at https://acme.gunnar.rs; it is paid until 2027-04-07.".into(),
                    step: "Mini".into(),
                    resources_words: "7 cores · 16 GB RAM · 40 GB data".into(),
                    monthly_words: "132.00 EUR a month".into(),
                    paid_until: "2027-04-07".into(),
                    repair_words: String::new(),
                }] },
                rooms: if self.has_room { vec![mpb::RoomPurchase { state: "paid".into(), paid_until: "2026-11-07".into(), cap_bytes: 10_737_418_240 }] } else { Vec::new() },
            }))
        }
    }

    #[tonic::async_trait]
    impl ProductsService for FakeMonetize {
        async fn list(
            &self,
            request: tonic::Request<mpb::ListProductsRequest>,
        ) -> Result<tonic::Response<mpb::ListProductsResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            Ok(tonic::Response::new(mpb::ListProductsResponse {
                products: vec![mpb::ProductInfo {
                    id: "gunnar".to_owned(),
                    meters: Vec::new(),
                    reachable: None,
                    tenant_renewal: self.tenant_renewal,
                    metered_door: None,
                }],
                ..Default::default()
            }))
        }
    }

    #[tonic::async_trait]
    impl PurchaseService for FakeMonetize {
        async fn quote(
            &self,
            request: tonic::Request<mpb::QuoteRequest>,
        ) -> Result<tonic::Response<mpb::QuoteResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            if let Some((code, why)) = &self.quote_refuses {
                let mut refused = tonic::Status::new(*code, why.clone());
                if let Some(words) = &self.quote_refusal_words {
                    refused
                        .metadata_mut()
                        .insert_bin(crate::grpc::CUSTOMER_WORDS_KEY, tonic::metadata::MetadataValue::from_bytes(words.as_bytes()));
                }
                return Err(refused);
            }
            let asked = request.into_inner();
            self.asked.lock().expect("the ask log").push(Asked {
                what: "Purchase.Quote".to_owned(),
                tenant: asked.tenant.clone(),
                renew: asked.renew,
                ticket_len: asked.actor_ticket.len(),
                caps_named: !asked.caps.is_empty(),
                caps: asked.caps.clone().into_iter().collect(),
                bundle: asked.bundle.clone(),
            });
            Ok(tonic::Response::new(mpb::QuoteResponse {
                reference: format!("gunnar/{}/2026-09-17", asked.tenant),
                can_serve: true,
                period: "year".to_owned(),
                // Monetize's rendered amount. Distinct from the raw
                // PRICE_MINOR digits so a test can tell "the console carried
                // monetize's words" from "the console formatted the number
                // itself" — the second is the thing it may not do.
                price_words: PRICE_WORDS.to_owned(),
                caps: [("pack_bytes".to_owned(), 10_737_418_240u64)].into(),
                ..Default::default()
            }))
        }

        async fn start(
            &self,
            request: tonic::Request<mpb::StartPurchaseRequest>,
        ) -> Result<tonic::Response<mpb::StartPurchaseResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            let asked = request.into_inner();
            if let Some(users) = asked.users.clone() {
                USERS_ASKED.lock().expect("the users log").push((asked.tenant.clone(), users));
            }
            self.asked.lock().expect("the ask log").push(Asked {
                what: "Purchase.Start".to_owned(),
                tenant: asked.tenant.clone(),
                renew: asked.renew,
                ticket_len: asked.actor_ticket.len(),
                caps_named: !asked.caps.is_empty(),
                caps: asked.caps.clone().into_iter().collect(),
                bundle: asked.bundle.clone(),
            });
            Ok(tonic::Response::new(mpb::StartPurchaseResponse {
                reference: format!("gunnar/{}/2026-09-17", asked.tenant),
                state: mpb::PurchaseState::Pending as i32,
                redirect_url: self.checkout_url.to_owned(),
                reason: "waiting for the customer at the vendor".to_owned(),
                ..Default::default()
            }))
        }

        /// **The shop window.** One offer, so a test can name the whole of it.
        async fn bundles(
            &self,
            request: tonic::Request<mpb::ListBundlesRequest>,
        ) -> Result<tonic::Response<mpb::ListBundlesResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            let asked = request.into_inner();
            self.asked.lock().expect("the ask log").push(Asked {
                what: "Purchase.Bundles".to_owned(),
                tenant: asked.tenant.clone(),
                renew: false,
                ticket_len: asked.actor_ticket.len(),
                caps_named: false,
                caps: Default::default(),
                bundle: String::new(),
            });
            if self.reading {
                return Ok(tonic::Response::new(mpb::ListBundlesResponse { bundles: Vec::new(), reading: true, ..Default::default() }));
            }
            if let Some(prolong_ok) = self.plans {
                return Ok(tonic::Response::new(mpb::ListBundlesResponse {
                    reading: false,
                    bundles: vec![
                        mpb::Bundle {
                            id: "prolong-1m".to_owned(),
                            label: "Prolong 1 month (10 GiB)".to_owned(),
                            price: "13.60 EUR".to_owned(),
                            period: "month".to_owned(),
                            can_serve: prolong_ok,
                            reason: if prolong_ok { String::new() } else { AHEAD_WORDS.to_owned() },
                            action: "prolong".to_owned(),
                            ..Default::default()
                        },
                        mpb::Bundle {
                            id: "100gb-12m".to_owned(),
                            label: "Upgrade to 100 GiB · 12 months".to_owned(),
                            price: "420.00 EUR".to_owned(),
                            delta: [("pack_bytes".to_owned(), 100 * BUNDLE_DELTA - HELD_PACK)].into(),
                            can_serve: true,
                            action: "upgrade".to_owned(),
                            target: [("pack_bytes".to_owned(), 100 * BUNDLE_DELTA), ("cache_bytes".to_owned(), HELD_CACHE)].into(),
                            ..Default::default()
                        },
                    ],
                    plan: Some(mpb::PlanStatus {
                        state: "paid".to_owned(),
                        period: "month".to_owned(),
                        label: "10 GiB · 1 month".to_owned(),
                        cap_bytes: HELD_PACK,
                        days_left: 6,
                        days_total: 30,
                        ends_words: "Paid until 2026-11-05 — 6 days left".to_owned(),
                        price_words: "13.60 EUR per month".to_owned(),
                        banner: "Your paid time ends on 2026-11-05 — in 6 days.".to_owned(),
                        banner_action: "prolong-1m".to_owned(),
                        banner_tone: "warn".to_owned(),
                        ..Default::default()
                    }),
                }));
            }
            Ok(tonic::Response::new(mpb::ListBundlesResponse {
                reading: false,
                bundles: vec![mpb::Bundle {
                    id: BUNDLE_ID.to_owned(),
                    label: BUNDLE_LABEL.to_owned(),
                    // WORDS, and nothing like a formatting of `PRICE_MINOR`:
                    // if this console ever renders an amount itself, the two
                    // differ and the assertion says which one reached the
                    // browser.
                    price: BUNDLE_PRICE_WORDS.to_owned(),
                    period: "month".to_owned(),
                    delta: [("pack_bytes".to_owned(), BUNDLE_DELTA)].into(),
                    can_serve: true,
                    reason: String::new(), ..Default::default()
                },
                // **The row the owner read for five days**, as monetize sent it
                // on 2026-09-20: a real id, a real price, `can_serve: false`,
                // and under it the masked sentence. It must not reach the pane.
                mpb::Bundle {
                    id: DEAD_BUNDLE_ID.to_owned(),
                    label: "100.0 GiB more room".to_owned(),
                    price: "1000.00 SEK".to_owned(),
                    period: "month".to_owned(),
                    delta: [("pack_bytes".to_owned(), 10 * BUNDLE_DELTA)].into(),
                    can_serve: false,
                    reason: DEAD_BUNDLE_WORDS.to_owned(), ..Default::default()
                }], ..Default::default()
            }))
        }

        async fn status(
            &self,
            request: tonic::Request<mpb::PurchaseStatusRequest>,
        ) -> Result<tonic::Response<mpb::PurchaseStatusResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            let asked = request.into_inner();
            self.asked.lock().expect("the ask log").push(Asked {
                what: "Purchase.Status".to_owned(),
                tenant: asked.tenant.clone(),
                renew: false,
                ticket_len: asked.actor_ticket.len(),
                caps_named: false,
                caps: Default::default(),
                bundle: String::new(),
            });
            Self::owned_by(&asked.reference, &asked.tenant)?;
            if self.prolonged {
                // `serde_json::to_string(&Step::Reserved { .. })`, as
                // monetize-server's `row_to_pb` writes it, cut to the fields
                // that matter here.
                let reserved = format!(
                    "{{\"Reserved\":{{\"reference\":\"{}\",\"purchase\":{{\"product\":\"gunnar\",\"caps\":{{\"pack_bytes\":{HELD_PACK}}},\"delta\":{{}},\"price\":{{\"minor\":{PRICE_MINOR}}},\"cost\":{{\"minor\":0}},\"plan\":{{\"verb\":\"prolong\",\"period\":\"Month\",\"size_bytes\":{HELD_PACK}}}}}}}}}",
                    asked.reference
                );
                return Ok(tonic::Response::new(mpb::PurchaseStatusResponse {
                    fact: Some(mpb::EntitlementFact {
                        caps: [("pack_bytes".to_owned(), HELD_PACK)].into(),
                        paid_until_unix_ms: Some(PROLONGED_UNTIL),
                        ..Default::default()
                    }),
                    reference: asked.reference.clone(),
                    state: mpb::PurchaseState::Paid as i32,
                    phase: mpb::PurchasePhase::Done as i32,
                    rows: vec![mpb::LedgerRow { reference: asked.reference, seq: 1, at_unix_ms: 0, kind: "Reserved".to_owned(), json: reserved }],
                    // monetize's grow queue line, which it sends for a paid
                    // prolong too; the page decides not to draw it.
                    room: Some(mpb::RoomProgress { state: "queued".to_owned(), words: "Paid · queued for today's batch".to_owned() }),
                    ..Default::default()
                }));
            }
            if self.unpaid {
                return Ok(tonic::Response::new(mpb::PurchaseStatusResponse {
                    reference: asked.reference,
                    state: mpb::PurchaseState::Pending as i32,
                    phase: mpb::PurchasePhase::WaitingForPayment as i32,
                    cancellable: true,
                    reason: "the customer has not paid yet; nothing is provisioned against a \
                             link nobody has used"
                        .to_owned(),
                    rows: vec![mpb::LedgerRow {
                        reference: "gunnar/alice/2026-09-17".to_owned(),
                        seq: 1,
                        at_unix_ms: 0,
                        kind: "Reserved".to_owned(),
                        json: "{}".to_owned(),
                    }],
                    redirect_url: self.checkout_url.to_owned(),
                    ..Default::default()
                }));
            }
            Ok(tonic::Response::new(mpb::PurchaseStatusResponse {
                // The granted fact, as a paid attempt carries it.
                fact: Some(mpb::EntitlementFact {
                    caps: [("pack_bytes".to_owned(), HELD_PACK + BUNDLE_DELTA)].into(),
                    ..Default::default()
                }),
                reference: asked.reference,
                state: mpb::PurchaseState::Paid as i32,
                phase: mpb::PurchasePhase::Done as i32,
                // **The ledger steps, exactly as monetize sends them**, and a
                // `Reserved` step serialises the whole `Purchase` — `cost`
                // included. `Purchase.Status` is gated by no ticket at
                // monetize, so the promise that a customer never sees the
                // provider's margin lives in THIS console. A fake that sent no
                // rows would let a handler that forwarded them pass.
                rows: vec![mpb::LedgerRow {
                    reference: "gunnar/alice/2026-09-17".to_owned(),
                    seq: 1,
                    at_unix_ms: 0,
                    kind: "Reserved".to_owned(),
                    json: format!(
                        "{{\"purchase\":{{\"price\":{{\"minor\":{PRICE_MINOR}}},\"cost\":{{\"minor\":{COST_MINOR}}}}}}}"
                    ),
                }],
                ..Default::default()
            }))
        }

        async fn abandon(
            &self,
            request: tonic::Request<mpb::AbandonPurchaseRequest>,
        ) -> Result<tonic::Response<mpb::AbandonPurchaseResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            let asked = request.into_inner();
            Self::owned_by(&asked.reference, &asked.tenant)?;
            // monetize's `abandon_attempt`: a REFUND of a captured attempt.
            // Nothing captured, nothing to refund — refused.
            if self.unpaid {
                return Err(tonic::Status::failed_precondition(
                    "nothing was captured on this attempt, so there is nothing to refund",
                ));
            }
            self.abandoned
                .lock()
                .expect("the abandon log")
                .push((asked.reference.clone(), asked.reason));
            Ok(tonic::Response::new(mpb::AbandonPurchaseResponse {
                reference: asked.reference,
                released: Vec::new(),
            }))
        }

        async fn cancel(
            &self,
            request: tonic::Request<mpb::CancelPurchaseRequest>,
        ) -> Result<tonic::Response<mpb::CancelPurchaseResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            let asked = request.into_inner();
            self.asked.lock().expect("the ask log").push(Asked {
                what: "Purchase.Cancel".to_owned(),
                tenant: asked.tenant.clone(),
                renew: false,
                ticket_len: asked.actor_ticket.len(),
                caps_named: false,
                caps: Default::default(),
                bundle: String::new(),
            });
            Self::owned_by(&asked.reference, &asked.tenant)?;
            // monetize's Cancel: an order with nothing captured is closed; a
            // paid one is refused (that is Abandon's, with its refund).
            if !self.unpaid {
                return Err(tonic::Status::failed_precondition(
                    "the money for this order was captured; it is not cancelled here",
                ));
            }
            self.cancelled
                .lock()
                .expect("the cancel log")
                .push((asked.reference.clone(), asked.reason.clone()));
            Ok(tonic::Response::new(mpb::CancelPurchaseResponse {
                reference: asked.reference,
                already_closed: false,
                state: mpb::PurchaseState::Released as i32,
                phase: mpb::PurchasePhase::Cancelled as i32,
                reason: asked.reason,
                released: Vec::new(),
            }))
        }

        async fn history(
            &self,
            request: tonic::Request<mpb::PurchaseHistoryRequest>,
        ) -> Result<tonic::Response<mpb::PurchaseHistoryResponse>, tonic::Status> {
            self.bearer_ok(&request)?;
            let asked = request.into_inner();
            self.asked.lock().expect("the ask log").push(Asked {
                what: "Purchase.History".to_owned(),
                tenant: asked.tenant.clone(),
                renew: false,
                ticket_len: asked.actor_ticket.len(),
                caps_named: false,
                caps: Default::default(),
                bundle: String::new(),
            });
            Ok(tonic::Response::new(mpb::PurchaseHistoryResponse {
                attempts: vec![mpb::PurchaseAttempt {
                    reference: format!("gunnar/{}/2026-09-01", asked.tenant),
                    outcome: "sold".to_owned(),
                    at_unix_ms: 1_756_000_000_000,
                    started_unix_ms: 1_755_000_000_000,
                    caps: [("pack_bytes".to_owned(), 10_737_418_240u64)].into(),
                    delta: [("pack_bytes".to_owned(), 10_737_418_240u64)].into(),
                    // **The price monetize is willing to show a customer.** The
                    // console must still drop it: `Money` is minor units and a
                    // currency enum, and rendering it is the arithmetic and the
                    // literal this console may not contain.
                    price: Some(mpb::Money {
                        minor: PRICE_MINOR,
                        currency: mpb::Currency::Eur as i32,
                    }),
                    steps: 6,
                    price_words: PRICE_WORDS.to_owned(),
                }],
            }))
        }
    }

    struct Rig {
        router: axum::Router,
        gunnar_calls: Arc<Mutex<Vec<Signed>>>,
        monetize_asked: Arc<Mutex<Vec<Asked>>>,
        webauthn: Arc<crate::auth::Webauthn>,
        /// The console's own admin fingerprint, for the starred test.
        console_fingerprint: String,
    }

    /// Stand a gunnar and a monetize up on loopback and point a console at
    /// both, with a real passkey subsystem so sessions are the real thing.
    async fn rig(gunnar: FakeGunnar, monetize: FakeMonetize) -> Rig {
        let g_listener = tokio::net::TcpListener::bind("127.0.0.1:0")
            .await
            .expect("a loopback port");
        let g_addr = g_listener.local_addr().expect("its address");
        let gunnar_calls = gunnar.calls.clone();
        tokio::spawn(async move {
            tonic::transport::Server::builder()
                .add_service(BillingServer::new(gunnar.clone()))
                .add_service(EntitlementServer::new(gunnar.clone()))
                .add_service(AccessServer::new(gunnar))
                .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(g_listener))
                .await
        });

        let m_listener = tokio::net::TcpListener::bind("127.0.0.1:0")
            .await
            .expect("a loopback port");
        let m_addr = m_listener.local_addr().expect("its address");
        let monetize_asked = monetize.asked.clone();
        tokio::spawn(async move {
            tonic::transport::Server::builder()
                .add_service(ProductsServer::new(monetize.clone()))
                .add_service(EstateOrderServer::new(monetize.clone()))
                .add_service(PurchaseServer::new(monetize))
                // Signup.Plans: what an account is (the Storage buy line's size, round 5.3.1).
                .add_service(crate::mpb::signup_server::SignupServer::new(crate::auth::signup::tests::FakeMonetize::default()))
                .serve_with_incoming(tokio_stream::wrappers::TcpListenerStream::new(m_listener))
                .await
        });

        let dir = tempfile::tempdir().expect("a temp dir").keep();
        let store = crate::state::StateStore::open(dir.join("state.redb")).expect("a store");
        let webauthn = Arc::new(
            crate::auth::Webauthn::new(
                crate::auth::RelyingParty {
                    rp_id: "console.example".to_owned(),
                    origin: "https://console.example".to_owned(),
                    rp_name: "gunnar".to_owned(),
                },
                store.clone(),
            )
            .expect("a subsystem"),
        );
        let signer = Arc::new(
            crate::signer::Signer::new(ssh_key::PrivateKey::from(
                ssh_key::private::Ed25519Keypair::from_seed(&CONSOLE_SEED),
            ))
            .expect("a fixed seed makes a signer"),
        );
        let console_fingerprint = signer.fingerprint().to_owned();
        let endpoint = format!("http://{g_addr}");
        let router = crate::serve::router(Arc::new(crate::app::App {
            webauthn: Some(webauthn.clone()),
            admin_token: None,
            monetize: Some(
                crate::monetize::Monetize::connect_lazy(&format!("http://{m_addr}"), BEARER, "gunnar")
                    .expect("a lazy channel"),
            ),
            events: crate::sse::EventHub::detached(),
            gunnar: crate::grpc::Gunnar::connect_lazy(&endpoint, signer).expect("a lazy handle"),
            twin: None,
            guest: None,
            reviewers: Arc::new(crate::reviewer::ReviewerKeys::new(
                endpoint.clone(),
                store.clone(),
            )),
            tenants: Arc::new(crate::tenant::TenantKeys::new(endpoint, store)),
            forges: Default::default(),
            imports: Default::default(),
            forge_apps: Default::default(),
            ui_dir: None,
            caches: crate::api::Caches::default(),
            objects: Default::default(),
            readmes: Default::default(),
        }));
        Rig {
            router,
            gunnar_calls,
            monetize_asked,
            webauthn,
            console_fingerprint,
        }
    }

    impl Rig {
        /// A logged-in tenant: a planted passkey at the VIEWER rung — the rung
        /// a paying customer actually lands on — pinned to their own gunnar
        /// principal, which on gunnar is their namespace.
        fn tenant(&self, user: &str, principal: &str) -> String {
            self.webauthn
                .plant_credential_for_tests(user, crate::role::Role::Viewer);
            self.webauthn
                .bind_principal(&format!("planted-{user}-viewer"), principal, 0)
                .expect("the planted credential pins");
            self.webauthn
                .make_session(user, crate::role::Role::Viewer, true)
        }

        /// A logged-in person with a passkey bound to NO principal.
        fn unbound(&self, user: &str) -> String {
            self.webauthn
                .plant_credential_for_tests(user, crate::role::Role::Viewer);
            self.webauthn
                .make_session(user, crate::role::Role::Viewer, true)
        }

        fn minted_for(&self) -> Vec<Signed> {
            self.gunnar_calls
                .lock()
                .expect("the call log")
                .iter()
                .filter(|c| c.what == "Billing.MintActorTicket")
                .cloned()
                .collect()
        }

        fn purchase_calls(&self) -> Vec<Asked> {
            self.monetize_asked
                .lock()
                .expect("the ask log")
                .iter()
                .filter(|a| a.what.starts_with("Purchase."))
                .cloned()
                .collect()
        }
    }

    async fn request(
        router: axum::Router,
        method: http::Method,
        uri: &str,
        cookie: Option<&str>,
    ) -> (http::StatusCode, String) {
        request_body(router, method, uri, cookie, "{}").await
    }

    async fn request_body(
        router: axum::Router,
        method: http::Method,
        uri: &str,
        cookie: Option<&str>,
        body: &str,
    ) -> (http::StatusCode, String) {
        let mut builder = http::Request::builder()
            .method(method)
            .uri(uri)
            .header(http::header::CONTENT_TYPE, "application/json")
            .header(http::header::ORIGIN, "https://console.example");
        if let Some(cookie) = cookie {
            builder = builder.header(
                http::header::COOKIE,
                format!("{}={cookie}", crate::auth::SESSION_COOKIE),
            );
        }
        let response = router
            .oneshot(
                builder
                    .body(axum::body::Body::from(body.to_owned()))
                    .expect("a request"),
            )
            .await
            .expect("the router answers");
        let status = response.status();
        let bytes = axum::body::to_bytes(response.into_body(), 1 << 20)
            .await
            .expect("a body");
        (status, String::from_utf8_lossy(&bytes).into_owned())
    }

    // ── the security properties ────────────────────────────────────────────

    /// ★ **The ticket is asked for with the TENANT's key, never the console's.**
    ///
    /// This is the whole design in one assertion. This console holds a
    /// server-wide admin grant at gunnar; a ticket requested with THAT key
    /// would be minted for any namespace the console cared to name, and every
    /// other test here would still pass. What makes gunnar the enforcer rather
    /// than this crate is that the credential on the `MintActorTicket` call is
    /// the one `TenantKeys` enrolled on the tenant's own principal — so gunnar
    /// is deciding from the key that signed the call.
    ///
    /// Asserted on the FINGERPRINT in the `gunnar-sshsig-v2` credential, which
    /// is the only thing that can tell the two apart from outside this process.
    /// An edit that "simplified" `ticket()` to use `state.gunnar` would compile
    /// and would fail exactly here.
    #[tokio::test]
    async fn the_ticket_is_asked_for_over_the_tenants_own_key_and_not_the_consoles() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");

        let (status, body) = request(
            rig.router.clone(),
            http::Method::GET,
            "/api/account/subscription",
            Some(&session),
        )
        .await;
        assert_eq!(status, http::StatusCode::OK, "{body}");

        let minted = rig.minted_for();
        assert_eq!(minted.len(), 1, "exactly one ticket per call: {minted:?}");
        assert_ne!(
            minted[0].fingerprint, rig.console_fingerprint,
            "the ticket was asked for with the CONSOLE's server-wide admin key. gunnar would \
             then be vouching for whatever namespace this process named, and the appliance \
             would have stopped being the thing that decides."
        );
        assert_eq!(minted[0].namespace, "alice");
        assert_eq!(minted[0].purpose, "renew");
    }

    /// ★ **The namespace is the session's own, and nothing in the request can
    /// change it.**
    ///
    /// There is no path segment, query parameter or body field for it by
    /// construction — this test spends its effort trying to supply one anyway,
    /// because the day somebody adds a convenience parameter this is what
    /// catches it.
    #[tokio::test]
    async fn no_request_field_can_name_another_namespace() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");

        let (status, body) = request(
            rig.router.clone(),
            http::Method::POST,
            "/api/account/subscription/renew?namespace=beta&tenant=beta&name=beta",
            Some(&session),
        )
        .await;

        assert_eq!(status, http::StatusCode::OK, "{body}");
        let minted = rig.minted_for();
        assert_eq!(minted[0].namespace, "alice", "a query string chose the namespace");
        let bought = rig.purchase_calls();
        assert_eq!(bought[0].tenant, "alice", "a query string chose the tenant");
    }

    /// ★ **An old monetize means the route is not offered — and nothing is
    /// bought.**
    ///
    /// proto3 drops unknown fields, so a new console against an old monetize
    /// would send an `actor_ticket` that is thrown away and the renewal would
    /// go through **unchecked**, looking exactly like success from here. The
    /// console must therefore never infer enforcement from a 200.
    ///
    /// The second assertion is the one that matters: no `Purchase` call at all.
    /// A route that refused only after the order had been placed would have
    /// charged the card it was trying to protect.
    #[tokio::test]
    async fn an_old_monetize_is_not_offered_the_route_and_sells_nothing() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::old()).await;
        let session = rig.tenant("alice", "alice");

        for (method, uri) in [
            (http::Method::GET, "/api/account/subscription"),
            (http::Method::POST, "/api/account/subscription/renew"),
            (
                http::Method::GET,
                "/api/account/subscription/status?reference=gunnar/alice/2026-09-17",
            ),
        ] {
            let (status, body) =
                request(rig.router.clone(), method.clone(), uri, Some(&session)).await;
            assert_eq!(
                status,
                http::StatusCode::NOT_IMPLEMENTED,
                "{method} {uri} was offered by a monetize that does not verify tickets: {body}"
            );
        }
        assert!(
            rig.purchase_calls().is_empty(),
            "an unenforced monetize was asked to sell something: {:?}",
            rig.purchase_calls()
        );
        assert!(
            rig.minted_for().is_empty(),
            "a ticket was minted for a monetize that cannot check one"
        );
    }

    /// ★ **An account door's refusal is the console's `{code, message}`** (A28 H19, P4b): the
    /// web reads that shape (`gunnar-ui-web` `api::Fail`: the message shown, the code deciding
    /// the summary, a step-up's retry and absence), so it holds wherever the door is answered —
    /// here or by the shared router. A sign-in pinned to no principal: `notfound`. A monetize
    /// that does not verify tenant tickets: `unimplemented` with its sentence, on every door
    /// that would read or spend on a ticket.
    #[tokio::test]
    async fn an_account_doors_refusal_is_the_consoles_code_and_message() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let nobody = rig.unbound("nobody");
        let (status, body) = request(rig.router.clone(), http::Method::GET, "/api/account/subscription", Some(&nobody)).await;
        let j: serde_json::Value = serde_json::from_str(&body).expect("JSON");
        assert_eq!((status, j["code"].as_str()), (http::StatusCode::NOT_FOUND, Some("notfound")), "{body}");
        assert!(j["message"].as_str().is_some_and(|m| !m.is_empty()), "{body}");

        let rig = rig_old().await;
        let session = rig.tenant("alice", "alice");
        for (method, uri, sent) in [
            (http::Method::GET, "/api/account/subscription", "{}"),
            (http::Method::POST, "/api/account/subscription/renew", "{}"),
            (http::Method::GET, "/api/account/subscription/status?reference=gunnar/alice/2026-09-17", "{}"),
            (http::Method::POST, "/api/account/subscription/cancel", r#"{"reference":"gunnar/alice/2026-09-17"}"#),
            (http::Method::GET, "/api/account/subscription/bundles", "{}"),
            (http::Method::POST, "/api/account/subscription/buy-bundle", r#"{"bundle":"b1"}"#),
            (http::Method::GET, "/api/account/subscription/history", "{}"),
        ] {
            let (status, body) = request_body(rig.router.clone(), method.clone(), uri, Some(&session), sent).await;
            let j: serde_json::Value = serde_json::from_str(&body).unwrap_or_default();
            assert_eq!((status, j["code"].as_str()), (http::StatusCode::NOT_IMPLEMENTED, Some("unimplemented")), "{method} {uri}: {body}");
            assert_eq!(j["message"].as_str(), Some(monetize_site_buy::relay::RENEWAL_NOT_VERIFIED), "{method} {uri}");
        }
        assert!(rig.purchase_calls().is_empty() && rig.minted_for().is_empty(), "nothing asked of a monetize that cannot check a ticket");
    }

    /// ★ A28 H19 (P4b): **the account's own doors are the shared buy flow's ROUTER**
    /// (`monetize_site_buy::router_of`, its `account` and `orders` groups): the quote, Prolong,
    /// the status poll, Cancel order, the window, its grow, the history and Your purchases.
    /// What stays here is what only Gunnar answers (the plan, the disk, the typed order, Add
    /// users, the queue's lines).
    /// ★ g-reds 4b: **the typed order `POST /api/account/subscription/buy` has no door.** The
    /// shared crate has no typed order, and nothing calls this one: not gunnar-ui-web (its
    /// pages buy by a window bundle, `…/buy-bundle`), not uitest, not a doc, not gunnar's CLI.
    /// A tenant's typed size was a second way to spend money that no page offered.
    #[tokio::test]
    async fn the_typed_buy_has_no_door() {
        let here = include_str!("subscription.rs");
        let serve = include_str!("../serve.rs");
        assert_eq!(here.matches(&["pub async fn ", "buy", "("].concat()).count(), 0, "no typed-buy handler here");
        assert_eq!(serve.matches(&["api::subscription::", "buy", ")"].concat()).count(), 0, "no typed-buy route by hand");
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/api/account/subscription/buy", Some(&session), r#"{"meter":"pack_bytes","cap":21474836480}"#).await;
        assert_eq!(status, http::StatusCode::NOT_FOUND, "{body}");
        assert!(rig.purchase_calls().is_empty() && rig.minted_for().is_empty(), "nothing was asked of monetize or gunnar");
    }

    #[test]
    fn the_account_doors_are_the_shared_routers() {
        let here = include_str!("subscription.rs");
        let serve = include_str!("../serve.rs");
        for door in ["offer", "renew", "status", "cancel", "bundles", "buy_bundle", "purchases", "history"] {
            assert_eq!(here.matches(&["pub async fn ", door, "("].concat()).count(), 0, "{door} is the shared router's, not a handler here");
            assert_eq!(serve.matches(&["api::subscription::", door, ")"].concat()).count(), 0, "{door}: no route by hand");
        }
        assert!(serve.contains("account: true"), "serve.rs mounts the shared account doors");
    }

    async fn rig_old() -> Rig {
        rig(FakeGunnar::default(), FakeMonetize::old()).await
    }

    /// ★ **A vendor link the browser may not be sent to never reaches it**
    /// (stinky #19): monetize's `redirect_url` becomes the pay button's href
    /// and `location.assign`'s argument, so it is checked as the paid signup
    /// and the private order check theirs — https, a host, no credentials —
    /// and anything else is a 502, never the link.
    #[tokio::test]
    async fn a_checkout_link_that_is_not_https_never_reaches_the_browser() {
        for bad in ["http://checkout.example/pay", "javascript:alert(1)", "https://someone@checkout.example/pay"] {
            let rig = rig(FakeGunnar::default(), FakeMonetize { checkout_url: bad, unpaid: true, ..FakeMonetize::verifying() }).await;
            let session = rig.tenant("alice", "alice");
            for (method, uri) in [
                (http::Method::POST, "/api/account/subscription/renew"),
                (http::Method::GET, "/api/account/subscription/status?reference=gunnar%2Falice%2F2026-09-17"),
            ] {
                let (status, body) = request(rig.router.clone(), method, uri, Some(&session)).await;
                assert_eq!(status, http::StatusCode::BAD_GATEWAY, "{bad} at {uri}: {body}");
                assert!(!body.contains(bad), "{bad} at {uri}: {body}");
            }
        }
    }

    /// A renewal names no caps, says `renew`, and carries the ticket.
    #[tokio::test]
    async fn a_renewal_names_no_caps_and_carries_the_ticket() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");

        let (status, body) = request(
            rig.router.clone(),
            http::Method::POST,
            "/api/account/subscription/renew",
            Some(&session),
        )
        .await;

        assert_eq!(status, http::StatusCode::OK, "{body}");
        assert!(body.contains(CHECKOUT_URL), "the vendor's own link: {body}");
        let bought = rig.purchase_calls();
        assert_eq!(bought.len(), 1, "{bought:?}");
        assert!(bought[0].renew, "a renewal must say so");
        assert!(
            !bought[0].caps_named,
            "a renewal names no caps — the caps come off the stored fact, and sending them \
             would be this console inventing an upgrade"
        );
        assert!(
            bought[0].ticket_len > 0,
            "the order carried no ticket, so monetize could not tell this from an operator's"
        );
    }

    /// ★ **A viewer renews their own subscription.**
    ///
    /// The floor here is the opposite of `api::increase`'s, deliberately:
    /// there, a viewer and even an operator are refused, because that surface
    /// is an operator acting on somebody else's behalf. Here the viewer rung IS
    /// the tenant rung — it is what a paid signup lands on — and a customer who
    /// could not renew their own plan is the whole defect this lane exists to
    /// fix.
    #[tokio::test]
    async fn a_viewer_renews_their_own_subscription() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("vera", "vera");

        let (status, body) = request(
            rig.router.clone(),
            http::Method::POST,
            "/api/account/subscription/renew",
            Some(&session),
        )
        .await;

        assert_eq!(
            status,
            http::StatusCode::OK,
            "a viewer could not renew their own subscription: {body}"
        );
    }

    /// **The commonest state on the box is not an error.** A tenant who has
    /// never bought anything holds no entitlement, so there is no period to
    /// extend, and monetize says so as a `TxError::Refused` — which it codes
    /// `failed_precondition`.
    ///
    /// MEASURED 2026-09-19: the owner's own account got a red box reading "The
    /// request failed." over "nothing to renew for rickard: this server holds
    /// no entitlement for them", on the page whose job is to sell them their
    /// first subscription. Nothing had failed; they were being alarmed at for
    /// not being a subscriber yet. It leaves as an ANSWER now — `can_serve`
    /// false and monetize's sentence — which the page draws as a plain line.
    #[tokio::test]
    async fn a_tenant_with_no_subscription_is_told_so_and_not_shown_a_failure() {
        let why = "nothing to renew for vera: this server holds no entitlement for them";
        let rig = rig(
            FakeGunnar::default(),
            FakeMonetize::refusing_the_quote(tonic::Code::FailedPrecondition, why),
        )
        .await;
        let session = rig.tenant("vera", "vera");

        let (status, body) = request(
            rig.router.clone(),
            http::Method::GET,
            "/api/account/subscription",
            Some(&session),
        )
        .await;

        assert_eq!(status, http::StatusCode::OK, "a refusal was dressed as a failure: {body}");
        let seen: serde_json::Value = serde_json::from_str(&body).expect("an answer, not an error page");
        assert_eq!(seen["can_serve"], serde_json::json!(false), "{body}");
        assert_eq!(seen["reason"], serde_json::json!(why), "monetize's words were reworded: {body}");
        // Nothing is invented to fill the gap: no period, no amount, no
        // reference. A renewal that cannot happen has none of them.
        assert_eq!(seen["period"], serde_json::json!(""), "{body}");
        assert_eq!(seen["price_words"], serde_json::json!(""), "{body}");
        assert_eq!(seen["reference"], serde_json::json!(""), "{body}");
    }

    /// **An account that has bought nothing reads "none", not "unknown"**
    /// (owner, test2, 2026-10-05: "Plan unknown — Subscription: Renewing is
    /// not available right now" on his own fresh account read like a fault).
    /// gunnar SAYS there is nothing: `Entitlement.Get` answers no fact. That
    /// answer is carried as the word `none`; `unknown` stays for a ladder word
    /// this console does not recognise.
    #[tokio::test]
    async fn a_namespace_gunnar_holds_no_entitlement_for_reads_none_not_unknown() {
        let rig = rig(FakeGunnar { no_fact: true, ..Default::default() }, FakeMonetize::verifying()).await;
        let session = rig.tenant("vera", "vera");
        let (status, body) = request(rig.router.clone(), http::Method::GET, "/api/account/plan", Some(&session)).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let seen: serde_json::Value = serde_json::from_str(&body).expect("a plan");
        assert_eq!(seen["state"], serde_json::json!("none"), "no entitlement is not an unknown one: {body}");
        assert_eq!(seen["plan"], serde_json::json!(""), "{body}");
        assert_eq!(seen["paid_until_unix_ms"], serde_json::Value::Null, "{body}");
    }

    /// **Nothing bought, so nothing to renew — said as that.** monetize
    /// refuses the renewal (`NothingToRenew`, failed_precondition, with its
    /// customer sentence "We cannot renew this account automatically …
    /// contact us") and gunnar holds no entitlement: the answer carries
    /// `nothing_to_renew`, and the page sends the person to More room
    /// instead of telling them to contact anyone.
    #[tokio::test]
    async fn a_tenant_who_has_bought_nothing_is_told_there_is_nothing_to_renew() {
        let rig = rig(
            FakeGunnar { no_fact: true, ..Default::default() },
            FakeMonetize::refusing_the_quote_with_words(
                tonic::Code::FailedPrecondition,
                "nothing to renew for vera: this server holds no entitlement for them",
                "We cannot renew this account automatically. Nothing has been charged — please contact us and we will set it right.",
            ),
        )
        .await;
        let session = rig.tenant("vera", "vera");
        let (status, body) = request(rig.router.clone(), http::Method::GET, "/api/account/subscription", Some(&session)).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let seen: serde_json::Value = serde_json::from_str(&body).expect("an answer");
        assert_eq!(seen["can_serve"], serde_json::json!(false), "{body}");
        assert_eq!(seen["nothing_to_renew"], serde_json::json!(true), "an account with no entitlement was not told it has nothing to renew: {body}");
    }

    /// **And a real refusal keeps its own words.** The same refusal for a
    /// tenant gunnar DOES hold a plan for is not "nothing bought": the answer
    /// says `nothing_to_renew: false` and carries monetize's customer
    /// sentence as `words`, which the page shows as it arrived — never a
    /// sentence composed here, and never the operator's `reason`.
    #[tokio::test]
    async fn a_refusal_for_a_tenant_who_holds_a_plan_shows_monetizes_own_words() {
        let words = "We cannot renew this account automatically. Nothing has been charged — please contact us and we will set it right.";
        let why = "vera is past retention (95 days after the paid period ended)";
        let rig = rig(FakeGunnar::default(), FakeMonetize::refusing_the_quote_with_words(tonic::Code::FailedPrecondition, why, words)).await;
        let session = rig.tenant("vera", "vera");
        let (status, body) = request(rig.router.clone(), http::Method::GET, "/api/account/subscription", Some(&session)).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let seen: serde_json::Value = serde_json::from_str(&body).expect("an answer");
        assert_eq!(seen["nothing_to_renew"], serde_json::json!(false), "a held plan was called nothing: {body}");
        assert_eq!(seen["words"], serde_json::json!(words), "monetize's customer sentence was not carried: {body}");
        assert_eq!(seen["reason"], serde_json::json!(why), "{body}");
    }

    /// ★ **A paid prolong's status names it a prolong, with its new end**
    /// (owner, test2, 2026-10-05: the page back from Stripe after a prolong
    /// said "Room added … the disk is enlarged in today's batch"). Both are
    /// monetize's facts: the verb off the order's own `Reserved` row, the
    /// end off the granted fact. Nothing is computed here.
    #[tokio::test]
    async fn a_paid_prolongs_status_names_the_prolong_and_the_new_end() {
        let rig = rig(FakeGunnar::default(), FakeMonetize { prolonged: true, ..FakeMonetize::verifying() }).await;
        let session = rig.tenant("alice", "alice");
        let (status, body) = request(
            rig.router.clone(),
            http::Method::GET,
            "/api/account/subscription/status?reference=gunnar%2Falice%2F2026-11-05%2Bpack_bytes%3D10%2Bplan%3Amonth",
            Some(&session),
        )
        .await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let seen: serde_json::Value = serde_json::from_str(&body).expect("an attempt");
        assert_eq!(seen["action"], serde_json::json!("prolong"), "{body}");
        assert_eq!(seen["paid_until_unix_ms"], serde_json::json!(PROLONGED_UNTIL), "{body}");
        // A32-29: and that day in words, the server's (the console draws them as they are).
        assert_eq!(seen["paid_until_words"], serde_json::json!(monetize_site_buy::purchase::date_words(PROLONGED_UNTIL)), "{body}");
    }

    /// And an order for room alone (no plan on its `Reserved` row, a delta)
    /// names no action, so its page stays the room page it always was.
    #[tokio::test]
    async fn a_room_orders_status_names_no_action() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");
        let (status, body) = request(rig.router.clone(), http::Method::GET, "/api/account/subscription/status?reference=gunnar%2Falice%2F2026-09-17", Some(&session)).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let seen: serde_json::Value = serde_json::from_str(&body).expect("an attempt");
        assert!(seen.get("action").is_none(), "a room order was given an action: {body}");
    }

    /// The Account page's button is a renewal by construction (the renew
    /// endpoint), and a plan row bought from the window carries the row's
    /// own verb — so the panel drawn before the vendor is reached already
    /// has the right steps.
    #[tokio::test]
    async fn an_order_placed_here_says_what_it_does_to_the_plan() {
        let plain = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = plain.tenant("vera", "vera");
        let (status, body) = request(plain.router.clone(), http::Method::POST, "/api/account/subscription/renew", Some(&session)).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let seen: serde_json::Value = serde_json::from_str(&body).expect("an attempt");
        assert_eq!(seen["action"], serde_json::json!("renew"), "{body}");

        let plans = rig(FakeGunnar::default(), FakeMonetize { plans: Some(true), ..FakeMonetize::verifying() }).await;
        let session = plans.tenant("alice", "alice");
        for (row, action) in [("prolong-1m", "prolong"), ("100gb-12m", "upgrade")] {
            let (status, body) = request_body(
                plans.router.clone(),
                http::Method::POST,
                "/api/account/subscription/buy-bundle",
                Some(&session),
                &format!(r#"{{"bundle":"{row}"}}"#),
            )
            .await;
            assert_eq!(status, http::StatusCode::OK, "{body}");
            let seen: serde_json::Value = serde_json::from_str(&body).expect("an attempt");
            assert_eq!(seen["action"], serde_json::json!(action), "{row}: {body}");
        }
    }

    /// **And the other half: a real fault is still a fault.** The rule is about
    /// refusals, which are policy, and not about a channel that broke or a
    /// credential that was rejected. Dressing one of those as "you have no
    /// subscription" would hide an outage behind a sentence about billing.
    #[tokio::test]
    async fn a_monetize_that_is_actually_broken_still_reads_as_broken() {
        for (code, why) in [
            (tonic::Code::Unavailable, "the ledger is not open"),
            (tonic::Code::Unauthenticated, "this bearer is not ours"),
            (tonic::Code::Internal, "a panic while pricing"),
        ] {
            let rig = rig(FakeGunnar::default(), FakeMonetize::refusing_the_quote(code, why)).await;
            let session = rig.tenant("vera", "vera");

            let (status, body) = request(
                rig.router.clone(),
                http::Method::GET,
                "/api/account/subscription",
                Some(&session),
            )
            .await;

            assert_ne!(status, http::StatusCode::OK, "{code} was served as an answer: {body}");
        }
    }

    /// gunnar refusing to vouch is the end of it — nothing is bought.
    #[tokio::test]
    async fn a_refusal_to_vouch_buys_nothing() {
        let rig = rig(
            FakeGunnar {
                refuse_ticket: true,
                ..Default::default()
            },
            FakeMonetize::verifying(),
        )
        .await;
        let session = rig.tenant("alice", "alice");

        let (status, body) = request(
            rig.router.clone(),
            http::Method::POST,
            "/api/account/subscription/renew",
            Some(&session),
        )
        .await;

        assert_eq!(status, http::StatusCode::FORBIDDEN, "{body}");
        assert!(
            rig.purchase_calls().is_empty(),
            "the appliance would not vouch and an order was placed anyway"
        );
    }

    /// ★ **A reference from another account is refused, and the refusal says
    /// nothing about it.**
    ///
    /// A reference is `<product>/<tenant>/<date>` — three guessable parts. A
    /// tenant who could learn from the refusal whether one exists, or whose it
    /// is, would have an oracle over every attempt on the box. The message must
    /// name only the caller's own account.
    ///
    /// Since 2026-10-04 the refusal is monetize's: the console asks with the
    /// session's own namespace and the appliance's ticket, and monetize answers
    /// only that tenant's attempts.
    #[tokio::test]
    async fn a_reference_from_another_account_is_refused_and_names_nothing() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");

        let (status, body) = request(
            rig.router.clone(),
            http::Method::GET,
            "/api/account/subscription/status?reference=gunnar%2Fbeta%2F2026-09-17",
            Some(&session),
        )
        .await;

        assert_eq!(status, http::StatusCode::NOT_FOUND, "{body}");
        assert!(
            !body.contains("beta"),
            "the refusal repeats the namespace that was probed for: {body}"
        );
        // ★ monetize decides (thin layer, owner 2026-10-04): asked with the
        // session's OWN namespace and the appliance's read ticket, and it is
        // monetize's uniform NOT_FOUND that comes back.
        let asked = rig.purchase_calls();
        assert_eq!(asked.len(), 1, "{asked:?}");
        assert_eq!(asked[0].what, "Purchase.Status");
        assert_eq!(asked[0].tenant, "alice", "the status was not scoped to the session's account");
        assert!(asked[0].ticket_len > 0, "the status carried no ticket");
    }

    /// And the caller's OWN reference is followed, so the check above is a
    /// scope and not a route that always refuses. It survives a restart
    /// because it remembers nothing: the tenant half of the comparison is
    /// re-derived from the session's principal on every call.
    #[tokio::test]
    async fn the_accounts_own_attempt_is_followed_without_anything_being_remembered() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");

        // Never placed through this router — nothing here has a ring, and that
        // is the point: `api::increase` would 404 this after a restart and send
        // a just-charged customer to a console they cannot reach.
        let (status, body) = request(
            rig.router.clone(),
            http::Method::GET,
            "/api/account/subscription/status?reference=gunnar%2Falice%2F2026-09-17",
            Some(&session),
        )
        .await;

        assert_eq!(status, http::StatusCode::OK, "{body}");
        assert!(body.contains("\"state\":\"paid\""), "{body}");
    }

    /// A passkey bound to no principal holds no namespace, so there is nothing
    /// of its own to renew — and this console must not resolve a name to find
    /// one, which is GUI-001.
    #[tokio::test]
    async fn a_session_bound_to_no_principal_has_nothing_to_renew() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.unbound("nobody");

        let (status, body) = request(
            rig.router.clone(),
            http::Method::GET,
            "/api/account/subscription",
            Some(&session),
        )
        .await;

        assert_eq!(status, http::StatusCode::NOT_FOUND, "{body}");
        assert!(rig.minted_for().is_empty());
        assert!(rig.purchase_calls().is_empty());
    }

    /// A renewal ticket still names no caps, which is what gunnar refuses an
    /// order ticket for having none of — the two paths must not converge.
    #[tokio::test]
    async fn a_renewal_ticket_still_names_no_caps() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");

        let (status, _) = request(
            rig.router.clone(),
            http::Method::POST,
            "/api/account/subscription/renew",
            Some(&session),
        )
        .await;

        assert_eq!(status, http::StatusCode::OK);
        let minted = rig.minted_for();
        assert_eq!(minted[0].purpose, "renew");
        assert!(
            minted[0].caps.is_empty(),
            "a renewal ticket carried caps, which gunnar refuses and monetize refuses again"
        );
    }

    /// ★ **The provider's cost never reaches a customer's browser, even though
    /// monetize hands it to this console.**
    ///
    /// `PurchaseStatusResponse.rows` carries each ledger step's raw JSON, and a
    /// `Reserved` step serialises the whole `Purchase` — `cost` and all. That
    /// is monetize's shape and it is not wrong there: `Purchase.Status` is an
    /// operator verb gated by no ticket. What it means is that the promise a
    /// customer never sees the provider's MARGIN is kept **here**, by this
    /// handler building `Attempt` field by field and never forwarding `rows`.
    ///
    /// Asserted on the bytes rather than the struct, the way
    /// `increase::the_offer_carries_no_cost` is: a field added to `Attempt`
    /// tomorrow, or a handler that serialised the whole message because it was
    /// easier, both fail here. The struct's shape is a claim; the body is the
    /// evidence.
    #[tokio::test]
    async fn the_providers_cost_never_reaches_a_customer() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");

        let (status, body) = request(
            rig.router.clone(),
            http::Method::GET,
            "/api/account/subscription/status?reference=gunnar%2Falice%2F2026-09-17",
            Some(&session),
        )
        .await;

        assert_eq!(status, http::StatusCode::OK, "{body}");
        assert!(
            !body.contains(&COST_MINOR.to_string()),
            "the provider's cost reached the customer's browser: {body}"
        );
        assert!(
            !body.to_lowercase().contains("cost"),
            "the response names a cost: {body}"
        );
        assert!(
            !body.contains("Reserved") && !body.contains("\"rows\""),
            "the raw ledger steps were forwarded to a customer; they are the operator's \
             vocabulary and they carry the margin: {body}"
        );
    }

    /// ★ **A history is read with a READ ticket, and the amount is monetize's
    /// WORDS — never a number this console formatted.**
    ///
    /// Two properties in one test because they fail independently.
    ///
    /// The ticket must be a `read`: a ticket is single-use, so listing a
    /// history with a renewal ticket would burn the one the customer came to
    /// renew with — and it would make the appliance vouch for a verb nobody was
    /// performing.
    ///
    /// The RAW price must not reach the browser, and this one is subtle
    /// because monetize is not wrong to send it: `PurchaseAttempt.price` is
    /// what the customer was charged, and their own money is theirs to see.
    /// The console cannot render `Money { minor, currency }` — that needs the
    /// division by 100 and the currency symbol it may not contain — so
    /// monetize now also sends `price_words`, and this carries that verbatim
    /// while still dropping the machine's number.
    ///
    /// **The fixture makes the two tellable apart on purpose.** `PRICE_WORDS`
    /// is `"49.99 EUR"` and `PRICE_MINOR` is `1_000`; a console that formatted
    /// the number itself would produce `10.00`, not `49.99`, so "carried
    /// monetize's words" and "did the arithmetic anyway" cannot both pass.
    ///
    /// This assertion was `!body.contains("price")` until `price_words`
    /// existed, which a legitimate field name now trips. Narrowed to the raw
    /// minor units rather than deleted, and strengthened in exchange: the words
    /// must be PRESENT and must be monetize's exact string.
    #[tokio::test]
    async fn a_history_is_read_with_a_read_ticket_and_the_amount_is_monetizes_words() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");

        let (status, body) = request(
            rig.router.clone(),
            http::Method::GET,
            "/api/account/subscription/history",
            Some(&session),
        )
        .await;

        assert_eq!(status, http::StatusCode::OK, "{body}");
        assert!(body.contains("\"steps\":6"), "a fold, not a log: {body}");
        assert!(body.contains("sold"), "{body}");

        let minted = rig.minted_for();
        assert_eq!(minted.len(), 1, "one ticket per call: {minted:?}");
        assert_eq!(
            minted[0].purpose, "read",
            "a history was listed with a {:?} ticket; a ticket is single-use, so that burns \
             the one the customer came to renew with",
            minted[0].purpose
        );
        assert!(
            minted[0].caps.is_empty(),
            "a read buys nothing, so its ticket covers no amount"
        );
        assert_ne!(
            minted[0].fingerprint, rig.console_fingerprint,
            "the read ticket was asked for with the CONSOLE's server-wide admin key"
        );

        assert!(
            !body.contains(&PRICE_MINOR.to_string()),
            "the machine's raw Money amount reached the browser; this console cannot render \
             one without the arithmetic and the currency literal it may not contain: {body}"
        );
        assert!(
            !body.to_lowercase().contains("cost"),
            "the provider's margin reached the customer: {body}"
        );
        assert!(
            body.contains(PRICE_WORDS),
            "monetize's own rendered amount did not reach the customer, so the pane can tell \
             them what they hold but not what it cost: {body}"
        );
    }

    // ── the window and the button ──────────────────────────────────────────

    /// **The meters the account already holds and the bundle does not touch
    /// stay in the target**, because monetize's own resolution keeps them and
    /// the ticket comparison is over the whole map.
    #[test]
    fn a_target_keeps_the_meters_the_bundle_does_not_raise() {
        let held = std::collections::BTreeMap::from([
            ("pack_bytes".to_owned(), 10u64),
            ("cache_bytes".to_owned(), 5u64),
        ]);
        let delta = std::collections::BTreeMap::from([("pack_bytes".to_owned(), 3u64)]);
        assert_eq!(
            target_caps(&held, &delta),
            std::collections::BTreeMap::from([
                ("pack_bytes".to_owned(), 13u64),
                ("cache_bytes".to_owned(), 5u64),
            ])
        );
    }

    /// An account nothing was ever sold for holds no caps, and every meter the
    /// bundle names starts from nothing rather than from a guess.
    #[test]
    fn a_meter_the_account_does_not_hold_yet_starts_from_nothing() {
        let delta = std::collections::BTreeMap::from([("pack_bytes".to_owned(), 7u64)]);
        assert_eq!(
            target_caps(&Default::default(), &delta),
            std::collections::BTreeMap::from([("pack_bytes".to_owned(), 7u64)])
        );
    }

    /// **Saturating, as monetize's is.** A cap near the ceiling must ask the
    /// product an absurd question and be told no, rather than wrap into a small
    /// one and be told yes.
    #[test]
    fn a_target_that_would_overflow_saturates_instead_of_wrapping() {
        let held = std::collections::BTreeMap::from([("pack_bytes".to_owned(), u64::MAX - 1)]);
        let delta = std::collections::BTreeMap::from([("pack_bytes".to_owned(), 1_000u64)]);
        assert_eq!(target_caps(&held, &delta)["pack_bytes"], u64::MAX);
    }

    /// ★ **The ticket covers the caps monetize will resolve the bundle to, and
    /// that is every meter the account holds — not just the one being raised.**
    ///
    /// monetize resolves a bundle into caps BEFORE it checks the ticket, and
    /// `monetize_embed::verify_ticket` compares the ticket's caps to the
    /// order's with `!=` over the whole map. The account here holds
    /// `cache_bytes` that the bundle does not touch; a ticket minted from the
    /// delta alone, or from the raised meter alone, is refused by a real
    /// monetize with a sentence about meter counts that nobody could act on.
    /// [`target_caps`] is the arithmetic and this is the claim it exists for.
    #[tokio::test]
    async fn a_bundle_ticket_covers_every_cap_the_order_will_resolve_to() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");

        let (status, body) = request_body(
            rig.router.clone(),
            http::Method::POST,
            "/api/account/subscription/buy-bundle",
            Some(&session),
            &format!("{{\"bundle\":\"{BUNDLE_ID}\"}}"),
        )
        .await;

        assert_eq!(status, http::StatusCode::OK, "{body}");
        let minted = rig.minted_for();
        let order = minted
            .iter()
            .find(|m| m.purpose == "order")
            .unwrap_or_else(|| panic!("no order ticket was minted: {minted:?}"));
        assert_eq!(
            order.caps,
            std::collections::BTreeMap::from([
                ("pack_bytes".to_owned(), HELD_PACK + BUNDLE_DELTA),
                ("cache_bytes".to_owned(), HELD_CACHE),
            ]),
            "the appliance vouched for caps monetize will not resolve this bundle to, so the              order is refused at the far side"
        );
        assert_ne!(
            order.fingerprint, rig.console_fingerprint,
            "the order ticket was asked for with the CONSOLE's server-wide admin key"
        );
        // The window is read with a READ ticket, never the order's: a ticket is
        // single-use, and spending the order's on a listing would leave nothing
        // to buy with.
        assert!(
            minted.iter().any(|m| m.purpose == "read" && m.caps.is_empty()),
            "the window was not read with a read ticket naming no caps: {minted:?}"
        );

        let bought: Vec<Asked> = rig
            .purchase_calls()
            .into_iter()
            .filter(|a| a.what == "Purchase.Start")
            .collect();
        assert_eq!(bought.len(), 1, "{bought:?}");
        assert_eq!(bought[0].bundle, BUNDLE_ID, "the id was not echoed back");
        assert!(
            !bought[0].caps_named,
            "the order named a bundle AND caps; monetize refuses that rather than letting one              of them win silently"
        );
        assert!(!bought[0].renew, "an order is not a renewal");
        assert!(bought[0].ticket_len > 0, "the order carried no ticket");
    }

    /// The window is monetize's words, carried, and read with a ticket that
    /// buys nothing.
    #[tokio::test]
    async fn the_window_is_read_with_a_read_ticket_and_is_monetizes_own_words() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");

        let (status, body) = request(
            rig.router.clone(),
            http::Method::GET,
            "/api/account/subscription/bundles",
            Some(&session),
        )
        .await;

        assert_eq!(status, http::StatusCode::OK, "{body}");
        assert!(body.contains(BUNDLE_ID), "{body}");
        assert!(body.contains(BUNDLE_LABEL), "the label was reworded: {body}");
        assert!(
            body.contains(BUNDLE_PRICE_WORDS),
            "monetize's rendered amount did not reach the customer, and this console cannot              compose one: {body}"
        );
        assert!(
            !body.contains(&PRICE_MINOR.to_string()),
            "a raw Money amount reached the browser: {body}"
        );
        // ★ The row monetize cannot serve is not in the tenant's window either:
        // not its id, not its price, and not the masked sentence. Owner's
        // ruling 2026-09-20 — see `api::increase::Window`.
        for dead in [DEAD_BUNDLE_ID, "1000.00 SEK", DEAD_BUNDLE_WORDS, "maintenance"] {
            assert!(!body.contains(dead), "a dead card reached the tenant ({dead:?}): {body}");
        }
        assert!(body.contains("\"withheld\":1"), "{body}");
        let minted = rig.minted_for();
        assert_eq!(minted.len(), 1, "one ticket per call: {minted:?}");
        assert_eq!(minted[0].purpose, "read", "a window buys nothing");
        assert!(minted[0].caps.is_empty(), "a read covers no amount");
    }

    /// ★ **The tenant's own window, while monetize is still reading it, says
    /// `pending`** with this server's two lines and no rows — the shape the
    /// console draws a spinner for and asks again, never the typed order
    /// (test2, 2026-10-05). Still read with a read ticket, and nothing else.
    #[tokio::test]
    async fn the_tenants_window_while_monetize_reads_it_is_pending() {
        let rig = rig(FakeGunnar::default(), FakeMonetize { reading: true, ..FakeMonetize::verifying() }).await;
        let session = rig.tenant("alice", "alice");

        let (status, body) = request(rig.router.clone(), http::Method::GET, "/api/account/subscription/bundles", Some(&session)).await;

        assert_eq!(status, http::StatusCode::OK, "{body}");
        let w: serde_json::Value = serde_json::from_str(&body).expect("json");
        assert_eq!(w["pending"], crate::api::increase::AWAITING_PROVIDER, "{body}");
        assert_eq!(w["late"], crate::api::increase::PROVIDER_LATE, "{body}");
        assert_eq!(w["offers"], serde_json::json!([]), "{body}");
        assert_eq!(w["withheld"], 0, "{body}");
        let minted = rig.minted_for();
        assert_eq!(minted.len(), 1, "{minted:?}");
        assert_eq!(minted[0].purpose, "read");
    }

    /// ★ **A deployment that sells PLANS: the gauge reaches the page, and a
    /// prolong row past its horizon is KEPT with monetize's sentence** — it is
    /// the customer's way on ("choose a 12-month plan"), not a size the box
    /// cannot hold (2026-10-05).
    #[tokio::test]
    async fn the_tenants_window_carries_the_plan_and_keeps_a_refused_plan_row() {
        let rig = rig(FakeGunnar::default(), FakeMonetize { plans: Some(false), ..FakeMonetize::verifying() }).await;
        let session = rig.tenant("alice", "alice");
        let (status, body) = request(rig.router.clone(), http::Method::GET, "/api/account/subscription/bundles", Some(&session)).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let w: serde_json::Value = serde_json::from_str(&body).expect("json");
        assert_eq!(w["plan"]["label"], "10 GiB · 1 month", "{body}");
        assert_eq!(w["plan"]["days_left"], 6);
        assert_eq!(w["plan"]["banner_action"], "prolong-1m");
        assert_eq!(w["offers"][0]["id"], "prolong-1m");
        assert_eq!(w["offers"][0]["can_serve"], false);
        assert_eq!(w["offers"][0]["reason"], AHEAD_WORDS);
        assert_eq!(w["offers"][0]["action"], "prolong");
        assert_eq!(w["offers"][1]["action"], "upgrade");
        assert_eq!(w["withheld"], 0, "a plan row is never withheld: {body}");
    }

    /// ★ **A prolong row is a RENEWAL: the renew ticket, no caps** — and an
    /// upgrade row an ORDER over the caps monetize said it ends at.
    #[tokio::test]
    async fn a_prolong_row_is_bought_with_a_renew_ticket_and_an_upgrade_with_monetizes_target() {
        let rig = rig(FakeGunnar::default(), FakeMonetize { plans: Some(true), ..FakeMonetize::verifying() }).await;
        let session = rig.tenant("alice", "alice");
        let (status, body) =
            request_body(rig.router.clone(), http::Method::POST, "/api/account/subscription/buy-bundle", Some(&session), r#"{"bundle":"prolong-1m"}"#).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let minted = rig.minted_for();
        let last = minted.last().expect("a ticket");
        assert_eq!((last.purpose.as_str(), last.caps.len()), ("renew", 0), "{minted:?}");
        let (status, body) =
            request_body(rig.router.clone(), http::Method::POST, "/api/account/subscription/buy-bundle", Some(&session), r#"{"bundle":"100gb-12m"}"#).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let minted = rig.minted_for();
        let last = minted.last().expect("a ticket");
        assert_eq!(last.purpose, "order");
        assert_eq!(last.caps.get("pack_bytes"), Some(&(100 * BUNDLE_DELTA)), "the ticket covers monetize's target: {:?}", last.caps);
        assert_eq!(last.caps.get("cache_bytes"), Some(&HELD_CACHE));
    }

    /// ★ **A bundle the window does not offer spends nothing.**
    ///
    /// A stale page is the ordinary way to press a button for an offer that has
    /// been withdrawn. The refusal happens before the order ticket is minted,
    /// so nothing was vouched for and `Purchase.Start` was never dialled.
    #[tokio::test]
    async fn a_bundle_the_window_does_not_offer_spends_nothing() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");

        let (status, body) = request_body(
            rig.router.clone(),
            http::Method::POST,
            "/api/account/subscription/buy-bundle",
            Some(&session),
            r#"{"bundle":"one-nobody-declared"}"#,
        )
        .await;

        assert_ne!(status, http::StatusCode::OK, "{body}");
        assert!(
            !rig.minted_for().iter().any(|m| m.purpose == "order"),
            "the appliance vouched for an order that was about to be refused"
        );
        assert!(
            !rig.purchase_calls()
                .iter()
                .any(|a| a.what == "Purchase.Start"),
            "monetize was asked to sell something this console could not name"
        );
    }

    /// A stranger reaches nothing, and no credential of this console's is spent
    /// answering them.
    #[tokio::test]
    async fn an_anonymous_visitor_reaches_no_renewal_route() {
        for (method, uri) in [
            (http::Method::GET, "/api/account/subscription"),
            (http::Method::POST, "/api/account/subscription/renew"),
            (http::Method::GET, "/api/account/subscription/bundles"),
            (http::Method::POST, "/api/account/subscription/buy-bundle"),
            (
                http::Method::GET,
                "/api/account/subscription/status?reference=gunnar/alice/2026-09-17",
            ),
        ] {
            let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
            let (status, body) =
                request(rig.router.clone(), method.clone(), uri, None).await;
            assert_eq!(
                status,
                http::StatusCode::UNAUTHORIZED,
                "{method} {uri} answered a stranger: {body}"
            );
            assert!(rig.minted_for().is_empty());
            assert!(rig.purchase_calls().is_empty());
        }
    }

    /// **"You have 10 GiB → 20 GiB after payment"**, out of the numbers the
    /// order was made against: the fact the appliance read and the target the
    /// ticket covers — for the raised meter only.
    #[tokio::test]
    async fn a_bundle_order_carries_before_and_after_for_the_meter_it_raises() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");
        let (status, body) = request_body(
            rig.router.clone(),
            http::Method::POST,
            "/api/account/subscription/buy-bundle",
            Some(&session),
            &format!("{{\"bundle\":\"{BUNDLE_ID}\"}}"),
        )
        .await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let a: serde_json::Value = serde_json::from_str(&body).expect("json");
        assert_eq!(a["before"]["pack_bytes"], HELD_PACK);
        assert_eq!(a["after"]["pack_bytes"], HELD_PACK + BUNDLE_DELTA);
        assert!(a["before"].get("cache_bytes").is_none(), "a meter the order does not raise is not its news: {body}");
        assert_eq!(a["captured"], false);
    }

    /// A paid attempt, followed after the return from the vendor, carries the
    /// caps the account now holds — "Done – you now have 20 GiB".
    #[tokio::test]
    async fn a_paid_attempt_carries_the_caps_it_granted() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");
        let (status, body) = request(
            rig.router.clone(),
            http::Method::GET,
            "/api/account/subscription/status?reference=gunnar%2Falice%2F2026-09-17",
            Some(&session),
        )
        .await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let a: serde_json::Value = serde_json::from_str(&body).expect("json");
        assert_eq!(a["state"], "paid");
        assert_eq!(a["after"]["pack_bytes"], HELD_PACK + BUNDLE_DELTA);
    }

    /// **"Cancel order"**: an order nobody has paid is closed on the ledger
    /// with the customer's reason; a paid one is not the customer's to cancel
    /// here; another account's reference names nothing and closes nothing.
    #[tokio::test]
    async fn an_unpaid_order_is_cancelled_and_a_paid_one_is_not() {
        let unpaid = FakeMonetize { unpaid: true, ..FakeMonetize::verifying() };
        // ★ monetize's Cancel closes it (thin layer, owner 2026-10-04). Red
        // before: the console sent `Abandon` — a REFUND of a captured
        // attempt, which monetize refuses for an unpaid one — so the button
        // could never succeed.
        let closed = unpaid.cancelled.clone();
        let unpaid_rig = rig(FakeGunnar::default(), unpaid).await;
        let session = unpaid_rig.tenant("alice", "alice");
        let body = r#"{"reference":"gunnar/alice/2026-09-17"}"#;
        let (status, answer) = request_body(unpaid_rig.router.clone(), http::Method::POST, "/api/account/subscription/cancel", Some(&session), body).await;
        assert_eq!(status, http::StatusCode::OK, "{answer}");
        assert!(answer.contains("\"state\":\"released\""), "{answer}");
        assert_eq!(
            *closed.lock().unwrap(),
            vec![("gunnar/alice/2026-09-17".to_owned(), monetize_site_buy::relay::CANCELLED_BY_CUSTOMER.to_owned())]
        );

        // Somebody else's order: refused naming nothing, nothing closed.
        let (status, answer) = request_body(unpaid_rig.router.clone(), http::Method::POST, "/api/account/subscription/cancel", Some(&session), r#"{"reference":"gunnar/beta/2026-09-17"}"#).await;
        assert_eq!(status, http::StatusCode::NOT_FOUND, "{answer}");
        assert!(!answer.contains("beta"), "{answer}");
        assert_eq!(closed.lock().unwrap().len(), 1);

        // Paid: not the customer's button.
        let paid = FakeMonetize::verifying();
        let paid_closed = paid.abandoned.clone();
        let paid_cancelled = paid.cancelled.clone();
        let paid_rig = rig(FakeGunnar::default(), paid).await;
        let session = paid_rig.tenant("alice", "alice");
        let (status, answer) = request_body(paid_rig.router.clone(), http::Method::POST, "/api/account/subscription/cancel", Some(&session), body).await;
        // The shared door's status for monetize's FAILED_PRECONDITION (`rules::http_status_of`,
        // Holger's too): 409, where this console's own door said 400 (A28 H19, P4b). The words
        // are monetize's, unchanged, and the web shows them either way.
        assert_eq!(status, http::StatusCode::CONFLICT, "{answer}");
        assert!(answer.contains("\"code\":\"failedprecondition\"") && answer.contains("captured"), "{answer}");
        assert!(paid_closed.lock().unwrap().is_empty(), "a paid order was abandoned by the customer");
        assert!(paid_cancelled.lock().unwrap().is_empty(), "monetize closed a paid order");
    }

    // ── a private Gunnar, ordered by a PROVEN account (one shop, 2026-10-07) ──

    /// The bytes the fake gunnar mints for every ticket.
    const MINTED: &[u8] = b"{\"v\":1,\"a-real-ticket-is-signed-json\":true}";

    fn estate_starts(rig: &Rig) -> Vec<Asked> {
        rig.monetize_asked.lock().expect("the ask log").iter().filter(|a| a.what == "EstateOrder.Start").cloned().collect()
    }

    /// ★ **A private Gunnar is ordered by its PROVEN account** (one shop, owner
    /// 2026-10-07): the signed-in person's own account — whatever the form
    /// names — and an `estate` ticket gunnar minted for it over the PERSON's
    /// own key (never the console's), relayed to monetize's `Start` untouched;
    /// where to pay comes back, or monetize's sentence.
    #[tokio::test]
    async fn a_private_gunnar_is_ordered_with_the_accounts_estate_ticket_over_its_own_key() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/start", Some(&session), r#"{"company":"acme","email":"a@example.com","account":"mallory"}"#).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let j: serde_json::Value = serde_json::from_str(&body).expect("JSON");
        assert!(j["url"].as_str().is_some_and(|u| u.starts_with("https://")), "{j}");
        let minted = rig.minted_for();
        assert_eq!(minted.len(), 1, "{minted:?}");
        assert_eq!((minted[0].namespace.as_str(), minted[0].purpose.as_str()), ("alice", "estate"), "the person's own account, the estate verb");
        assert!(minted[0].caps.is_empty(), "an estate ticket names no caps");
        assert_ne!(minted[0].fingerprint, rig.console_fingerprint, "over the person's own key, never the console's");
        let started = estate_starts(&rig);
        assert_eq!(started.len(), 1);
        assert_eq!((started[0].tenant.as_str(), started[0].bundle.as_str()), ("alice", "acme"), "the session's account, not the form's");
        assert_eq!(started[0].ticket_len, MINTED.len(), "the ticket relayed as minted");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/start", Some(&session), r#"{"company":"taken","email":"a@example.com"}"#).await;
        assert_eq!(status, http::StatusCode::CONFLICT, "{body}");
        assert!(body.contains("taken.gunnar.rs is taken"), "monetize's sentence, whole: {body}");
        // ★ The e-mail is not changed in the buy (owner 2026-10-22): signed in, the page sends
        // none — the order is the account's, on its ticket, and monetize mails the account's own.
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/start", Some(&session), r#"{"company":"bolt"}"#).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let started = estate_starts(&rig);
        assert_eq!((started.len(), started[2].tenant.as_str(), started[2].ticket_len), (3, "alice", MINTED.len()), "the account's own order, on its ticket");
    }

    /// ★ **An instance is grown by its PROVEN account** (one shop 4, owner
    /// 2026-10-07): "Grow" on the sign-up page reads the instance's ladder
    /// and asks a step on the signed-in account's `estate` ticket (minted over
    /// the person's own key, relayed untouched); where to pay comes back, with
    /// monetize's words. Someone else's instance: monetize's sentence, 403.
    /// Nobody signed in: sign in first — nothing is dialled.
    #[tokio::test]
    async fn an_instance_is_grown_on_its_accounts_estate_ticket() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");
        let asked = |what: &str| rig.monetize_asked.lock().expect("the ask log").iter().filter(|a| a.what == what).cloned().collect::<Vec<Asked>>();
        let (status, body) = request(rig.router.clone(), http::Method::GET, "/auth/private/ladder?company=acme", Some(&session)).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let j: serde_json::Value = serde_json::from_str(&body).expect("JSON");
        assert_eq!((j["laid"].as_bool(), j["current"].as_u64(), j["steps"].as_array().map(Vec::len)), (Some(true), Some(0), Some(2)), "{j}");
        // The site's kept new-estate ladder (LADDER-2) reads on its own clock, with no company and
        // no ticket; the instance's ladder is the request's.
        let ladders: Vec<Asked> = asked("EstateOrder.Ladder").into_iter().filter(|a| !a.bundle.is_empty()).collect();
        assert_eq!((ladders[0].bundle.as_str(), ladders[0].ticket_len), ("acme", MINTED.len()), "the instance, on the account's ticket");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/change", Some(&session), r#"{"company":"acme","main_data_gib":30}"#).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let j: serde_json::Value = serde_json::from_str(&body).expect("JSON");
        assert!(j["url"].as_str().is_some_and(|u| u.starts_with("https://")), "{j}");
        assert!(j["words"].as_str().is_some_and(|w| w.contains("main's data disks grow from 10 to 30 GB")), "monetize's words: {j}");
        let changes = asked("EstateOrder.ChangePlan");
        assert_eq!((changes[0].bundle.as_str(), changes[0].ticket_len, changes[0].caps.get("main_data_gib")), ("acme", MINTED.len(), Some(&30)));
        let minted = rig.minted_for();
        assert!(minted.iter().all(|m| m.namespace == "alice" && m.purpose == "estate" && m.fingerprint != rig.console_fingerprint), "{minted:?}");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/change", Some(&session), r#"{"company":"bolt","main_data_gib":30}"#).await;
        assert_eq!(status, http::StatusCode::FORBIDDEN, "{body}");
        assert!(body.contains("not your account's"), "monetize's sentence: {body}");
        let before = asked("EstateOrder.ChangePlan").len();
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/change", None, r#"{"company":"acme","main_data_gib":30}"#).await;
        assert_eq!(status, http::StatusCode::UNAUTHORIZED, "{body}");
        assert!(body.contains("Sign in"), "{body}");
        let (status, _) = request(rig.router.clone(), http::Method::GET, "/auth/private/ladder?company=acme", None).await;
        assert_eq!(status, http::StatusCode::UNAUTHORIZED);
        assert_eq!(asked("EstateOrder.ChangePlan").len(), before, "nothing dialled for nobody");
    }

    /// ★ **"Restore front" on an instance's row** (S8, RESUME 5.4 #5): a sold estate whose front
    /// was lost is made again from the front's daily backup with its keys — monetize's
    /// `EstateOrder.RestoreFront`, on the signed-in account's own `estate` ticket (minted over
    /// the person's key), relayed untouched; monetize's words come back. Someone else's
    /// instance: monetize's sentence, 403. Nobody signed in: nothing is dialled.
    #[tokio::test]
    async fn a_lost_front_is_restored_on_its_accounts_estate_ticket() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");
        let asked = |what: &str| rig.monetize_asked.lock().expect("the ask log").iter().filter(|a| a.what == what).cloned().collect::<Vec<Asked>>();
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/restore-front", Some(&session), r#"{"company":"acme"}"#).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let j: serde_json::Value = serde_json::from_str(&body).expect("JSON");
        assert!(j["words"].as_str().is_some_and(|w| w.contains("restored from its backup")), "monetize's words: {j}");
        assert_eq!((j["moved"].as_bool(), j["public_ipv4"].as_str()), (Some(false), Some("198.51.100.7")), "{j}");
        let asks = asked("EstateOrder.RestoreFront");
        assert_eq!((asks.len(), asks[0].bundle.as_str(), asks[0].ticket_len), (1, "acme", MINTED.len()), "the instance, on the account's ticket");
        let minted = rig.minted_for();
        assert!(minted.iter().all(|m| m.namespace == "alice" && m.purpose == "estate" && m.fingerprint != rig.console_fingerprint), "{minted:?}");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/restore-front", Some(&session), r#"{"company":"bolt"}"#).await;
        assert_eq!(status, http::StatusCode::FORBIDDEN, "{body}");
        assert!(body.contains("not your account's"), "{body}");
        let (status, _) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/restore-front", Some(&session), r#"{"company":"../x"}"#).await;
        assert_eq!(status, http::StatusCode::BAD_REQUEST);
        let before = asked("EstateOrder.RestoreFront").len();
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/restore-front", None, r#"{"company":"acme"}"#).await;
        assert_eq!(status, http::StatusCode::UNAUTHORIZED, "{body}");
        assert_eq!(asked("EstateOrder.RestoreFront").len(), before, "nothing dialled for nobody");
    }

    /// ★ **Your purchases lead with the instance** (one shop, owner
    /// 2026-10-07): the account's own — gunnar mints its `estate` ticket over
    /// the PERSON's key, monetize answers on it — its private Gunnar first
    /// (name, address, step and what is laid, the month, the paid period,
    /// Grow, Open). An account WITHOUT room here gets the owner's two lines for
    /// its Storage page — "Your Gunnar is acme.gunnar.rs", linked, and "Want
    /// space here on <this host> too? Buy 10GB/month" — and no room line.
    #[tokio::test]
    async fn your_purchases_lead_with_the_instance_on_the_accounts_own_ticket() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");
        let (status, body) = request(rig.router.clone(), http::Method::GET, "/api/account/purchases", Some(&session)).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let j: serde_json::Value = serde_json::from_str(&body).expect("JSON");
        let acme = &j["estates"][0];
        assert_eq!((acme["company"].as_str(), acme["url"].as_str(), acme["step"].as_str(), acme["paid_until"].as_str()), (Some("acme"), Some("https://acme.gunnar.rs"), Some("Mini"), Some("2027-04-07")), "{j}");
        assert_eq!(acme["grow_url"], "/signup?plan=grow&instance=acme", "{j}");
        assert_eq!(acme["renew_url"], "/signup?plan=private&renew=acme", "renew or stop renewing (A52/A51): {j}");
        assert_eq!(j["rooms"].as_array().map(Vec::len), Some(0), "{j}");
        assert_eq!(j["storage_lines"][0]["words"], "Your Gunnar is acme.gunnar.rs", "{j}");
        assert_eq!(j["storage_lines"][0]["url"], "https://acme.gunnar.rs", "{j}");
        assert_eq!(j["buy"]["words"], "Want space here on console.example too? Buy 10GB/month", "{j}");
        assert_eq!(j["buy"]["url"], "/signup?plan=10gb", "{j}");
        // A ZERO, never a size that ends in one ("40 GB data" is a size).
        let zero = |needle: &str| body.match_indices(needle).any(|(i, _)| !body[..i].ends_with(|c: char| c.is_ascii_digit()));
        for never in ["0 B", "0 GB"] {
            assert!(!zero(never), "{never:?} in {body}");
        }
        assert!(!body.contains("free"), "\"free\" in {body}");
        let minted = rig.minted_for();
        assert_eq!((minted[0].namespace.as_str(), minted[0].purpose.as_str()), ("alice", "estate"));
        assert_ne!(minted[0].fingerprint, rig.console_fingerprint, "over the person's own key");
        let asked: Vec<Asked> = rig.monetize_asked.lock().unwrap().iter().filter(|a| a.what == "EstateOrder.Purchases").cloned().collect();
        assert_eq!((asked[0].tenant.as_str(), asked[0].ticket_len), ("alice", MINTED.len()));
        // An account that bought room here too: its room is a line, and no
        // Storage lines take its room's place.
        let rig = rig_with_room().await;
        let session = rig.tenant("carol", "carol");
        let (status, body) = request(rig.router.clone(), http::Method::GET, "/api/account/purchases", Some(&session)).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let j: serde_json::Value = serde_json::from_str(&body).expect("JSON");
        assert_eq!(j["rooms"][0]["cap_bytes"], 10_737_418_240u64, "{j}");
        assert_eq!(j["storage_lines"].as_array().map(Vec::len), Some(0), "{j}");
        assert!(j["buy"].is_null(), "{j}");
        // Nobody signed in has no purchases.
        let (status, _) = request(rig.router.clone(), http::Method::GET, "/api/account/purchases", None).await;
        assert_eq!(status, http::StatusCode::UNAUTHORIZED);
    }

    /// ★ **Only an account monetize KNOWS to hold no room here is shown what it holds
    /// elsewhere** (round 5.2, the UI matrix): an account at this shop that bought nothing
    /// yet gets the way to room here; an account monetize knows nothing of — its room is
    /// Gunnar's own, as on a box where the operator gave it — gets no Storage lines and no
    /// offer, so its Storage page keeps its room.
    #[tokio::test]
    async fn only_an_account_monetize_knows_without_room_is_shown_what_it_holds_elsewhere() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let alma = rig.tenant("alma", "alma");
        let (status, body) = request(rig.router.clone(), http::Method::GET, "/api/account/purchases", Some(&alma)).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let j: serde_json::Value = serde_json::from_str(&body).expect("JSON");
        assert_eq!(j["estates"].as_array().map(Vec::len), Some(0), "{j}");
        assert_eq!(j["buy"]["words"], "Want space here on console.example too? Buy 10GB/month", "an account at this shop: {j}");
        let erik = rig.tenant("erik", "erik");
        let (status, body) = request(rig.router.clone(), http::Method::GET, "/api/account/purchases", Some(&erik)).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let j: serde_json::Value = serde_json::from_str(&body).expect("JSON");
        assert_eq!(j["storage_lines"].as_array().map(Vec::len), Some(0), "{j}");
        assert!(j["buy"].is_null(), "nothing known of erik: his Storage keeps his room: {j}");
    }

    async fn rig_with_room() -> Rig {
        rig(FakeGunnar::default(), FakeMonetize { has_room: true, ..FakeMonetize::verifying() }).await
    }

    /// ★ **gunnar refusing to vouch orders nothing** (a member of an account,
    /// a name the box holds no namespace for): ONE plain sentence — gunnar's
    /// own names principals and grants and stays in the log (wiring trace B,
    /// private.rs raw refusal) — and monetize is never asked to hold anything.
    #[tokio::test]
    async fn a_refusal_to_vouch_orders_no_private_gunnar() {
        let rig = rig(FakeGunnar { refuse_ticket: true, ..FakeGunnar::default() }, FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/start", Some(&session), r#"{"company":"acme","email":"a@example.com"}"#).await;
        assert_eq!(status, http::StatusCode::FORBIDDEN, "{body}");
        assert!(body.contains(crate::auth::private::ONLY_THE_ADMIN_BUYS), "the plain sentence: {body}");
        assert!(!body.contains("grant") && !body.contains("namespace") && !body.contains("principal"), "never gunnar's own words: {body}");
        assert!(estate_starts(&rig).is_empty(), "nothing was ordered");
    }

    /// ★ **i54a run32 A3, at the routes**: a private Gunnar is bought by an ACCOUNT — a
    /// sign-in with a namespace of its own. The kit's (or the operator's) machine sign-in
    /// holds none: gunnar answers the `estate` ticket `NOT_FOUND`, and the page says there is
    /// no account to buy for (404) — never the admin sentence (403) the mock met — and
    /// monetize is never asked. The same console, signed in as the account, orders.
    #[tokio::test]
    async fn a_private_gunnar_is_bought_by_an_account_with_a_namespace_never_a_bare_sign_in() {
        let held = FakeGunnar { namespaces: Some(vec!["a3buyer".to_owned()]), ..FakeGunnar::default() };
        let rig = rig(held, FakeMonetize::verifying()).await;
        let kit = rig.tenant("kit-claude", "kit-claude");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/start", Some(&kit), r#"{"company":"acme","email":"a@example.com"}"#).await;
        assert_eq!(status, http::StatusCode::NOT_FOUND, "{body}");
        assert!(body.contains(crate::auth::private::NO_ACCOUNT_TO_BUY_FOR), "no account to buy for: {body}");
        assert!(!body.contains("admin") && !body.contains("namespace"), "{body}");
        assert!(estate_starts(&rig).is_empty(), "nothing was ordered for a sign-in with no account");
        let buyer = rig.tenant("a3buyer", "a3buyer");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/start", Some(&buyer), r#"{"company":"acme","email":"a@example.com"}"#).await;
        assert_eq!(status, http::StatusCode::OK, "the account orders: {body}");
        let started = estate_starts(&rig);
        assert_eq!((started.len(), started[0].tenant.as_str()), (1, "a3buyer"), "{started:?}");
    }

    // ── TERMINATE a private Gunnar (owner 2026-10-12): admin only, a fresh login, the name typed back ──

    fn terminates(rig: &Rig) -> Vec<Asked> {
        rig.monetize_asked.lock().expect("the ask log").iter().filter(|a| a.what == "EstateOrder.Terminate").cloned().collect()
    }

    /// A tenant whose login is NOT user-verified recently: not stepped up.
    fn stale_tenant(rig: &Rig, user: &str) -> String {
        rig.webauthn.plant_credential_for_tests(user, crate::role::Role::Viewer);
        rig.webauthn.bind_principal(&format!("planted-{user}-viewer"), user, 0).expect("the planted credential pins");
        rig.webauthn.make_session(user, crate::role::Role::Viewer, false)
    }

    /// ★ **The account's admin, freshly logged in, types the name back**: the instance is ended
    /// with no backup (owner 2026-10-22; A32-27: no backup word on the wire), an older page's
    /// `backup` word changing nothing — each call on the account's own `estate` ticket.
    #[tokio::test]
    async fn the_admin_terminates_a_private_gunnar_with_no_backup() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/terminate", Some(&session), r#"{"company":"acme","confirm":"acme"}"#).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let j: serde_json::Value = serde_json::from_str(&body).expect("JSON");
        assert_eq!(j["done"].as_bool(), Some(true), "{j}");
        assert!(j.get("backup_offered").is_none() && j.get("backups").is_none(), "{j}");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/terminate", Some(&session), r#"{"company":"acme","confirm":"acme","backup":"skip"}"#).await;
        assert_eq!(status, http::StatusCode::OK, "{body}");
        let j: serde_json::Value = serde_json::from_str(&body).expect("JSON");
        assert_eq!(j["done"].as_bool(), Some(true), "{j}");
        let asked = terminates(&rig);
        assert_eq!(asked.len(), 2, "{asked:?}");
        assert!(asked.iter().all(|a| a.bundle == "acme" && a.tenant == "acme" && a.ticket_len > 0), "the company, the typed name and the account's ticket: {asked:?}");
        let minted = rig.minted_for();
        assert!(minted.iter().all(|m| m.namespace == "alice" && m.purpose == "estate"), "{minted:?}");
    }

    /// ★ **The wrong name typed back ends nothing** — refused here, monetize never asked.
    #[tokio::test]
    async fn a_terminate_with_the_wrong_name_typed_back_is_refused() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");
        for typed in ["acne", "", "bolt"] {
            let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/terminate", Some(&session), &format!(r#"{{"company":"acme","confirm":"{typed}","backup":"skip"}}"#)).await;
            assert_eq!(status, http::StatusCode::BAD_REQUEST, "{typed:?}: {body}");
            assert!(body.contains("acme") && body.contains("Nothing was ended"), "{body}");
        }
        assert!(terminates(&rig).is_empty(), "monetize was never asked");
    }

    /// ★ **Admin only**: a sign-in gunnar will not vouch for as the account's admin (a member),
    /// and nobody signed in, terminate nothing.
    #[tokio::test]
    async fn a_non_admin_terminates_nothing() {
        let rig = rig(FakeGunnar { refuse_ticket: true, ..FakeGunnar::default() }, FakeMonetize::verifying()).await;
        let session = rig.tenant("alice", "alice");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/terminate", Some(&session), r#"{"company":"acme","confirm":"acme","backup":"skip"}"#).await;
        assert_eq!(status, http::StatusCode::FORBIDDEN, "{body}");
        assert!(body.contains(crate::auth::private::ONLY_THE_ADMIN_BUYS), "{body}");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/terminate", None, r#"{"company":"acme","confirm":"acme","backup":"skip"}"#).await;
        assert_eq!(status, http::StatusCode::UNAUTHORIZED, "{body}");
        assert!(terminates(&rig).is_empty(), "monetize was never asked");
    }

    /// ★ **A recent fresh login**: a session whose user-verified login is not recent is asked to
    /// log in again, before anything is minted or asked.
    #[tokio::test]
    async fn a_terminate_needs_a_fresh_login() {
        let rig = rig(FakeGunnar::default(), FakeMonetize::verifying()).await;
        let session = stale_tenant(&rig, "alice");
        let (status, body) = request_body(rig.router.clone(), http::Method::POST, "/auth/private/terminate", Some(&session), r#"{"company":"acme","confirm":"acme","backup":"skip"}"#).await;
        assert_eq!(status, http::StatusCode::FORBIDDEN, "{body}");
        assert!(body.contains("fresh touch of your key"), "{body}");
        assert!(body.contains(&format!("\"code\":\"{}\"", crate::auth::STEP_UP_CODE)), "machine-readable: {body}");
        assert!(terminates(&rig).is_empty() && rig.minted_for().is_empty(), "nothing minted or asked");
    }


    /// ★ ACCT-3 (owner 2026-10-29): **the site's admin is never told "A Free account cannot
    /// push"** — gunnar.rs's own admin read it on his Account page. A site admin on a Free
    /// account pushes (gunnar-core `EntitlementState::Free.allows_write()`, and his
    /// server-wide grant); a person without that grant who buys for a Free account is still
    /// told, and a member never is (his account's admin buys).
    #[test]
    fn a_site_admin_on_free_is_never_gated_and_a_free_buyer_still_is() {
        use crate::auth::Standing;
        use crate::role::Role;
        let individual = Standing { account: "alma".into(), role: "individual".into(), admin: String::new() };
        let account_admin = Standing { account: "acme".into(), role: "admin".into(), admin: "alma".into() };
        let member = Standing { account: "acme".into(), role: "employee".into(), admin: "alma".into() };
        assert!(!free_gates_push(Role::Admin, &individual, true), "the site's admin on Free pushes");
        assert!(!free_gates_push(Role::Admin, &account_admin, true), "the site's admin who also runs an account pushes");
        for site_role in [Role::Viewer, Role::Operator] {
            assert!(free_gates_push(site_role, &individual, true), "{site_role}: a Free individual is still told");
            assert!(free_gates_push(site_role, &account_admin, true), "{site_role}: a Free account's admin is still told");
            assert!(!free_gates_push(site_role, &individual, false), "{site_role}: a plan pushes");
            assert!(!free_gates_push(site_role, &member, true), "{site_role}: a member is never told; his admin buys");
        }
    }
}