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

nordisk/monetize

crates/monetize-server/src/services/purchase.rs

//! `Purchase.Quote` prices an order without moving money; `Purchase.Start`
//! runs the transaction; `Purchase.Status` reads the ledger. The resume after a
//! vendor callback lives in [`crate::callback`]; both go through
//! [`resume_reference`] so there is one path from "open attempt" to "verdict".

use std::sync::Arc;

use monetize::ledger::Closed;
use monetize::{Order, Outcome, Purchase as PurchaseReq, Quote, TxError};
use monetize_pay::Market;
use monetize_product::TenantId;
use monetize_proto::purchase_server::Purchase;
use monetize_proto::{self as pb, PurchaseState};
use tonic::{Request, Response, Status};

use super::{blocking, ledger_err, product_or_not_found};
use crate::auth::Caller;
use crate::convert::{fact_to_pb, money_to_pb, resource_to_pb, row_to_pb};
use crate::state::AppState;

pub struct PurchaseService(pub Arc<AppState>);

/// What one run of the transaction came to, in wire terms.
pub struct Verdict {
    pub reference: String,
    pub state: PurchaseState,
    pub reason: String,
    pub fact: Option<monetize_product::EntitlementFact>,
}

/// Run the transaction for `purchase` and REPORT a Paid outcome as a state change
/// (the core pushes the fact itself, so this is where the row is written). The
/// door for `Purchase.Start`, where a caller is asking to BUY something.
pub fn run_and_report(
    s: &AppState,
    product: monetize_product::Served<'_>,
    vendor: monetize_pay::Vendor<'_>,
    purchase: &PurchaseReq,
) -> Result<Verdict, Status> {
    let reference = purchase.reference();
    let before = s
        .ledger
        .entitlement(product.id(), &purchase.tenant.0)
        .map_err(ledger_err)?
        .map(|f| f.state);
    // A16: the checkout returns to the site the tenant buys on, whichever instance takes the money.
    let site = s
        .registry
        .estate_of_tenant(product.id(), &purchase.tenant.0)
        .and_then(|e| s.registry.site_of_estate(&e));
    let back = crate::returns::ReturningTo::of(vendor, site.as_deref());
    let result = s.transaction(product, back.vendor()).buy(purchase);
    report_verdict(s, product, before, verdict_of(&reference, result)?)
}

/// A Paid verdict becomes a state-change row. One writer for `Start` and for a
/// resume, so the console and the testmatrix see the same row whichever door the
/// verdict came through.
fn report_verdict(
    s: &AppState,
    product: monetize_product::Served<'_>,
    before: Option<monetize_product::State>,
    v: Verdict,
) -> Result<Verdict, Status> {
    if let (PurchaseState::Paid, Some(fact)) = (v.state, &v.fact) {
        s.report_change(crate::state::StateChange {
            product: product.id().into(),
            tenant: fact.tenant.0.clone(),
            from: before,
            to: fact.state,
            source: fact.source.clone(),
            at_unix_ms: s.now(),
            pushed: true,
        });
        // An "Add users" order: the room is the tenant's now, so the users it
        // was bought for are granted — whichever door reported the payment.
        grant_paid_users(s, product, &v.reference)?;
    }
    Ok(v)
}

// ── "Add users" (owner, 2026-10-04) ─────────────────────────────────────────

/// **The users a PAID order bought room for, granted** — once: the product
/// answers a retried order with its first grant, and the ledger keeps one
/// [`monetize::Step::UsersGranted`] row per reference. A product that cannot
/// be reached leaves no row, and the next door that looks (a `Status` read,
/// the poller) tries again; the room is the tenant's either way.
///
/// **A row that cannot be read or written is an error** (`Unavailable`), never
/// a log line: the next read asks the product again, which answers the first
/// grant `unchanged`, and an unchanged answer is never invited a second time.
///
/// **A grant the product REFUSES is refused for good** (a name taken while the
/// customer paid): the payment is refunded through the vendor, the room the
/// order raised is given back, both are journaled, and the buyer is told —
/// once ([`refund_users`]).
///
/// **The ledger names no member** (G13, 5.4): the order's row holds the ask
/// without its name and address; they wait beside it ([`crate::named_users`])
/// and are forgotten once the grant's row stands. A named order whose name is
/// gone (a restore) is refused like a name taken: refunded, nobody added.
pub fn grant_paid_users(
    s: &AppState,
    product: monetize_product::Served<'_>,
    reference: &str,
) -> Result<Option<pb::UsersGrant>, Status> {
    let Some(attempt) = s.ledger.attempt(reference).map_err(ledger_err)? else {
        return Ok(None);
    };
    let Some(bare) = attempt.purchase.users.clone() else {
        return Ok(None);
    };
    if !matches!(attempt.closed, Some(Closed::Pushed { .. })) {
        return Ok(None);
    }
    if let Some(granted) = users_granted_row(s, reference).map_err(ledger_err)? {
        forget_names(s, reference);
        return Ok(Some(granted));
    }
    let ask = match s.named_users.get(reference) {
        Some(named) => monetize_product::UsersAsk {
            name: named.name,
            email: named.email,
            ..bare.clone()
        },
        None => bare.clone(),
    };
    if refund_of(s, reference).is_some() {
        return Ok(refund_users(s, product, reference, &attempt, &ask, ""));
    }
    if !bare.principal_id.is_empty() && ask.name.is_empty() {
        let why = "the name it was to add is no longer held here (monetize was restored while the order was open)";
        eprintln!("monetize-server: ALERT users.refunded {reference}: paid, and {why}: refunded");
        return Ok(refund_users(s, product, reference, &attempt, &ask, why));
    }
    let bought = sold_disk_bytes(product, &attempt.purchase.delta);
    match product.add_users(&attempt.purchase.tenant, &ask, reference) {
        Ok(answer) => {
            // The product's retry of a grant made before (its row was not
            // written then) is never invited again.
            let invited = if answer.unchanged {
                ATTEMPT_INVITED.to_owned()
            } else {
                invite_users(s, product, &attempt.purchase.tenant.0, &ask, &answer).0
            };
            let step = monetize::Step::UsersGranted {
                reference: reference.to_owned(),
                product: product.id().to_owned(),
                tenant: attempt.purchase.tenant.0.clone(),
                users: ask.without_names(),
                principal_id: ask.principal_id.clone(),
                seats: answer.seats,
                room_bytes: answer.room_bytes,
                from_unused_bytes: answer.need_bytes.saturating_sub(bought),
                bought_bytes: bought,
                invited: invited.clone(),
            };
            if let Err(e) = s.ledger.append(s.now(), step) {
                let why = format!("{reference}: the users were granted, and the ledger row could not be written: {e}; written on the next read");
                skidbladnir::functional_status("monetize-server/add-users", "grant", false, &why);
                return Err(Status::unavailable(why));
            }
            forget_names(s, reference);
            let row = users_granted_row(s, reference)
                .map_err(ledger_err)?
                .map(|g| pb::UsersGrant {
                    principal: answer.principal.clone(),
                    ..g
                });
            Ok(Some(row.unwrap_or(pb::UsersGrant {
                principal: answer.principal,
                seats: answer.seats,
                seats_open: answer.seats_open,
                room_bytes: answer.room_bytes,
                need_bytes: answer.need_bytes,
                from_unused_bytes: answer.need_bytes.saturating_sub(bought),
                bought_bytes: bought,
                granted: true,
                invited,
                ..Default::default()
            })))
        }
        Err(monetize_product::ProductError::Refused(why)) => {
            Ok(refund_users(s, product, reference, &attempt, &ask, &why))
        }
        Err(e) => {
            skidbladnir::functional_status(
                "monetize-server/add-users",
                "grant",
                false,
                &format!("{reference}: paid, and the users were NOT granted yet: {e}"),
            );
            eprintln!("monetize-server: users {reference}: paid, and the product did not grant the users yet ({e}); retried on the next read");
            Ok(None)
        }
    }
}

/// The names a paid order waited with, forgotten: its grant's row (or its
/// refund) stands. One that cannot be rewritten is said, and forgotten on the
/// next read.
fn forget_names(s: &AppState, reference: &str) {
    if let Err(e) = s.named_users.forget(reference) {
        eprintln!("monetize-server: users {reference}: the names beside the ledger could not be forgotten ({e}); again on the next read");
    }
}

/// What a grant's row says of its invite when the product answered a retry:
/// the invite went out with the first answer, whose row was not written.
const ATTEMPT_INVITED: &str = "invited when first granted";

/// Who journals this server's own refunds.
const REFUNDED_BY: &str = "monetize";

/// `(refunded in full, the operator's reason)` for an Add-users order this
/// server refunded itself, or `None`.
fn refund_of(s: &AppState, reference: &str) -> Option<(bool, String)> {
    let rows = s.ledger.rows(reference).ok()?;
    let asked = rows.iter().rev().find_map(|row| match &row.step {
        monetize::Step::RefundRequested { by, reason, .. } if by == REFUNDED_BY => {
            Some(reason.clone())
        }
        _ => None,
    })?;
    let done = rows
        .iter()
        .any(|row| matches!(&row.step, monetize::Step::Reversed { kind: monetize_pay::ReversalKind::Refunded, by, .. } if by == REFUNDED_BY));
    Some((done, asked))
}

/// What the buyer reads about a refunded Add-users order. `why` is the refusal as the
/// product filed it (both gunnar plugins: `gunnar <code>: <message>`): only gunnar's
/// `AlreadyExists` is a name taken — any other NO (a clan, a namespace gone) is said plainly,
/// never as a name taken (wiring tracer B 2026-10-08).
fn refunded_words(ask: &monetize_product::UsersAsk, why: &str) -> String {
    let taken = why.contains("AlreadyExists");
    match ask.name.as_str() {
        // A named user whose name is no longer held here (forgotten once told).
        "" if !ask.principal_id.is_empty() && taken => {
            "The user could not be added after the payment (the name was taken while you paid), so the payment was refunded in full and nothing was kept.".to_owned()
        }
        "" if !ask.principal_id.is_empty() => {
            "The user could not be added after the payment, so the payment was refunded in full and nothing was kept.".to_owned()
        }
        "" => format!(
            "The {} seat(s) could not be added after the payment, so the payment was refunded in full and nothing was kept.",
            ask.count.max(1)
        ),
        name if taken => format!(
            "{name} could not be added after the payment (the name was taken while you paid), so the payment was refunded in full and nothing was kept."
        ),
        name => format!("{name} could not be added after the payment, so the payment was refunded in full and nothing was kept."),
    }
}

/// **Refund a paid Add-users order whose users can never be granted**: the
/// vendor refund (journaled `RefundRequested` → `Reversed`, by `monetize`,
/// idempotent on the vendor's key), the room the order raised taken back off
/// the tenant's fact ([`take_back_room`], retried on every read until its
/// row stands), and the buyer told — the mail once, when the room is back. A
/// vendor that cannot be reached leaves the request written and is asked
/// again on the next read.
fn refund_users(
    s: &AppState,
    product: monetize_product::Served<'_>,
    reference: &str,
    attempt: &monetize::ledger::Attempt,
    ask: &monetize_product::UsersAsk,
    why: &str,
) -> Option<pb::UsersGrant> {
    let bought = sold_disk_bytes(product, &attempt.purchase.delta);
    // The refusal: this call's, or the one journaled when the refund was first asked for.
    let refusal = match refund_of(s, reference) {
        Some((_, asked)) if why.is_empty() => asked,
        _ => why.to_owned(),
    };
    let words = refunded_words(ask, &refusal);
    let refunded = |reason: String| pb::UsersGrant {
        room_bytes: ask.room_bytes,
        need_bytes: ask.room_bytes.saturating_mul(u64::from(ask.count.max(1))),
        bought_bytes: bought,
        refunded: true,
        reason,
        ..Default::default()
    };
    let reason = match refund_of(s, reference) {
        Some((true, asked)) => asked,
        Some((false, asked)) => {
            refund_by_vendor(s, reference, attempt, &asked)?;
            asked
        }
        None => {
            let reason = format!("Add users could not be granted after the capture: {why}");
            refund_by_vendor(s, reference, attempt, &reason)?;
            reason
        }
    };
    // The room this order raised goes back with the money: its own state,
    // retried on every read until its row stands; the buyer is told then.
    match take_back_room(s, product, reference, attempt, bought) {
        Ok(false) => {}
        Ok(true) => {
            let tenant = &attempt.purchase.tenant.0;
            let subject = format!(
                "{}: the users you paid for could not be added — refunded",
                crate::nonpay::shown(product.id())
            );
            let body = format!("{words}\n\nOrder: {reference}\n");
            let (sent, line) =
                crate::nonpay::send(s, product.id(), tenant, "users.refunded", (subject, body));
            skidbladnir::functional_status(
                "monetize-server/add-users",
                "refund",
                true,
                &format!(
                    "{reference}: refunded ({reason}); the buyer {}",
                    if sent { "was told" } else { "was NOT told" }
                ),
            );
            eprintln!("monetize-server: users {reference}: REFUNDED — {reason}; the buyer: {line}");
            forget_names(s, reference);
        }
        Err(e) => {
            skidbladnir::functional_status(
                "monetize-server/add-users",
                "refund",
                false,
                &format!("{reference}: refunded, and the room is NOT taken back yet: {e}"),
            );
            eprintln!("monetize-server: users {reference}: refunded, and the room could not be taken back ({e}); retried on the next read");
            return None;
        }
    }
    Some(refunded(words))
}

/// The vendor refund of an Add-users order, by this server; `None` when it did
/// not land (asked again on the next read, or left for an operator).
fn refund_by_vendor(
    s: &AppState,
    reference: &str,
    attempt: &monetize::ledger::Attempt,
    reason: &str,
) -> Option<()> {
    match crate::reversal::refund_order_by(
        s,
        &attempt.handle.vendor,
        &attempt.handle.id,
        0,
        reason,
        REFUNDED_BY,
    ) {
        Ok(_) => Some(()),
        Err(crate::signup::RefundRefusal::Unavailable(e)) => {
            eprintln!("monetize-server: users {reference}: the refund is REQUESTED and the vendor did not answer ({e}); asked again on the next read");
            None
        }
        Err(e) => {
            skidbladnir::functional_status("monetize-server/add-users", "refund", false, &format!("{reference}: paid, never grantable, and the refund was REFUSED: {e:?} — an operator must give the money back"));
            eprintln!("monetize-server: users {reference}: paid, never grantable, and the refund was refused ({e:?}); an operator must act");
            None
        }
    }
}

/// **Take back the room a refunded order raised, once**: the fact loses
/// `bought` on the disk meter (source `refund:<reference>`), then the
/// [`monetize::Step::RoomTakenBack`] row is written. `Ok(true)` = written by
/// this call; `Ok(false)` = it already stood. A crash between the two finds the
/// fact already carrying the refund's source and only writes the row.
fn take_back_room(
    s: &AppState,
    product: monetize_product::Served<'_>,
    reference: &str,
    attempt: &monetize::ledger::Attempt,
    bought: u64,
) -> Result<bool, String> {
    let _order = crate::reversal::OrderLock::take(reference);
    let rows = s.ledger.rows(reference).map_err(|e| e.to_string())?;
    if rows
        .iter()
        .any(|row| matches!(row.step, monetize::Step::RoomTakenBack { .. }))
    {
        return Ok(false);
    }
    let tenant = &attempt.purchase.tenant.0;
    let meter = disk_meter(product).unwrap_or_default();
    let mut taken = 0;
    if let (false, true, Some(held)) = (
        meter.is_empty(),
        bought > 0,
        s.ledger
            .entitlement(product.id(), tenant)
            .map_err(|e| e.to_string())?,
    ) {
        taken = bought;
        let source = format!("refund:{reference}");
        if held.source != source {
            let mut fact = held.clone();
            fact.source = source;
            fact.signature = Vec::new();
            if let Some(cap) = fact.caps.get_mut(meter) {
                *cap = cap.saturating_sub(bought);
            }
            let fact = s.signer_for(product.id()).sign_fact(fact);
            if let Err(e) = s.apply_fact(product, &fact).map_err(|e| e.to_string())? {
                eprintln!("monetize-server: users {reference}: the room is taken back and the product has not heard yet ({e}); the push is retried");
            }
        }
    }
    let step = monetize::Step::RoomTakenBack {
        reference: reference.to_owned(),
        product: product.id().to_owned(),
        tenant: tenant.clone(),
        meter: meter.to_owned(),
        bytes: taken,
    };
    s.ledger.append(s.now(), step).map_err(|e| e.to_string())?;
    Ok(true)
}

/// **The new named user's invite, delivered**: the link the console redeems
/// (`<origin>/login?invite=<secret>&user=<id>`), mailed to the address the
/// admin typed — through the deployment's one customer-notice path. Answers
/// `(the mail line, the link)`; both empty when there is nobody to invite or
/// nowhere to send it. The secret is in the link and nowhere else: never on
/// a ledger row.
fn invite_users(
    s: &AppState,
    product: monetize_product::Served<'_>,
    tenant: &str,
    ask: &monetize_product::UsersAsk,
    answer: &monetize_product::UsersAnswer,
) -> (String, String) {
    if answer.principal.is_empty()
        || answer.invite_secret.is_empty()
        || ask.invite_origin.is_empty()
    {
        return (String::new(), String::new());
    }
    let link = format!(
        "{}/login?invite={}&user={}",
        ask.invite_origin.trim_end_matches('/'),
        answer.invite_secret,
        answer.principal
    );
    let to = ask.email.trim();
    if to.is_empty() {
        return (String::new(), link);
    }
    let notice = monetize_pay::CustomerNotice {
        product: product.id().to_owned(),
        tenant: tenant.to_owned(),
        to: to.to_owned(),
        kind: "users.invite".to_owned(),
        subject: format!("{}: {tenant} invited you", product.id()),
        body: format!(
            "{tenant} added you to {} as {}. Register your passkey with this link — it works once, for seven days:\n\n{link}\n",
            product.id(),
            answer.principal
        ),
    };
    let line = match s.signup_sink.notify(&notice) {
        Ok(_) => format!("mailed to {}", monetize_mail::masked(to)),
        Err(e) => format!("NOT mailed to {}: {e}", monetize_mail::masked(to)),
    };
    (line, link)
}

/// The `UsersGranted` row under `reference`, on the wire.
fn users_granted_row(
    s: &AppState,
    reference: &str,
) -> Result<Option<pb::UsersGrant>, monetize::ledger::LedgerError> {
    Ok(s.ledger
        .rows(reference)?
        .into_iter()
        .find_map(|row| match row.step {
            // No name: the row holds the member's id, the name is the estate's.
            monetize::Step::UsersGranted {
                seats,
                room_bytes,
                from_unused_bytes,
                bought_bytes,
                users,
                invited,
                ..
            } => Some(pb::UsersGrant {
                invited,
                principal: String::new(),
                seats,
                seats_open: 0,
                room_bytes,
                need_bytes: room_bytes.saturating_mul(u64::from(users.count.max(1))),
                from_unused_bytes,
                bought_bytes,
                granted: true,
                ..Default::default()
            }),
            _ => None,
        }))
}

/// The unit disk room is sold in: the price list's `disk_gib_month`.
const SOLD_IN: u64 = 1 << 30;

/// What an order SOLD on the product's disk meter (its `DiskBytes` delta).
fn sold_disk_bytes(
    product: monetize_product::Served<'_>,
    delta: &std::collections::BTreeMap<String, u64>,
) -> u64 {
    delta
        .iter()
        .filter(|(m, _)| {
            product.meters().iter().any(|meter| {
                meter.name == m.as_str()
                    && meter.backing == Some(monetize_product::Backing::DiskBytes)
            })
        })
        .map(|(_, v)| *v)
        .sum()
}

/// The product's disk meter: what room is sold on.
fn disk_meter(product: monetize_product::Served<'_>) -> Option<&'static str> {
    product
        .meters()
        .iter()
        .find(|m| m.backing == Some(monetize_product::Backing::DiskBytes))
        .map(|m| m.name)
}

/// **The reference of users granted with nothing bought**:
/// `<product>/<tenant>/<YYYY-MM-DD>+users:<count>x<room>[:<name>]`, the
/// grant's own — deterministic, so a retry is the same grant — and spelled
/// like every order's (`<product>/<tenant>/…`), so the tenant's scope reads
/// it as theirs.
fn users_reference(
    product: &str,
    tenant: &str,
    at_unix_ms: u64,
    ask: &monetize_product::UsersAsk,
) -> String {
    format!(
        "{product}/{tenant}/{}+users:{}",
        monetize::embed::civil::iso_date(at_unix_ms),
        ask.fingerprint()
    )
}

/// **The refusal of a short "Add users" on a server that does not sell
/// room**: what is unused, what was asked, and how much is missing.
fn users_short(
    tenant: &str,
    ask: &monetize_product::UsersAsk,
    fit: &monetize_product::UsersAnswer,
    why: &str,
) -> Status {
    let size = monetize::transaction::words::size;
    Status::failed_precondition(format!(
        "{tenant} has {} of room unused; {} user(s) × {} need {}: {} short. {why} Add room to the account, or ask for \
         fewer users or less room per user. {}",
        size(fit.unused_bytes.unwrap_or(0)),
        ask.count.max(1),
        size(fit.room_bytes),
        size(fit.need_bytes),
        size(fit.shortfall_bytes),
        monetize::transaction::words::NOTHING_CHARGED,
    ))
}

fn product_status(e: monetize_product::ProductError) -> Status {
    match e {
        monetize_product::ProductError::Refused(why) => Status::failed_precondition(why),
        monetize_product::ProductError::Unavailable(why) => Status::unavailable(why),
    }
}

/// **`Purchase.Start` with `users`** — "Add users" (owner, 2026-10-04). ONE
/// call for the console: the product is asked whether the users fit in the
/// room the account holds and has not stored or promised (and refuses a name
/// it could never create, before any money moves); if they fit they are
/// granted at once and nothing is bought; if not, EXACTLY the shortfall is
/// sold through the same quote, the same transaction and the same single
/// checkout every order gets — or, where this server sells no room, refused
/// naming what is missing. The users are granted when the order is paid
/// ([`grant_paid_users`]); a checkout that expires releases the attempt and
/// grants nothing.
fn start_users(
    s: &AppState,
    product: monetize_product::Served<'_>,
    r: &pb::StartPurchaseRequest,
    users: &pb::UsersOrder,
    market: Market,
    caller: Option<&Caller>,
    site: Option<&str>,
) -> Result<pb::StartPurchaseResponse, Status> {
    if !r.caps.is_empty() || !r.bundle.is_empty() || r.renew {
        return Err(Status::invalid_argument(
            "an \"Add users\" order names `users` and nothing else: no caps, no bundle, no renewal — the room it needs is \
             decided here, from what the account already holds",
        ));
    }
    if r.tenant.is_empty() {
        return Err(Status::invalid_argument("tenant is required"));
    }
    let ask = monetize_product::UsersAsk {
        count: users.count.max(1),
        room_bytes: users.room_bytes,
        name: users.name.trim().to_owned(),
        email: users.email.trim().to_owned(),
        invite_origin: users.invite_origin.trim().to_owned(),
        principal_id: String::new(),
    };
    // G13: the ledger knows the member by this id, never by the name.
    let ask = monetize_product::UsersAsk {
        principal_id: monetize::ledger::principal_id(product.id(), &r.tenant, &ask.name),
        ..ask
    };
    // FIRST: the ticket covers exactly this number of users at this room.
    check_actor(
        s,
        product,
        &r.tenant,
        monetize_embed::PURPOSE_ORDER,
        &ask.ticket_caps(),
        Asker {
            site,
            ticket: &r.actor_ticket,
            caller,
        },
    )?;
    let tenant = TenantId(r.tenant.clone());
    let starts = if r.starts_unix_ms == 0 {
        s.now()
    } else {
        r.starts_unix_ms
    };
    // An account with NO fact is uncapped at gunnar and fits every ask: at a selling shop it is
    // given the shop's account fact first (2026-10-08, the free-room leak), so the ask below
    // is answered against the room it really holds.
    crate::poller::account_holds_a_fact(s, product, &r.tenant).map_err(|why| {
        Status::unavailable(format!(
            "{}'s account fact could not be given, so nothing is sold now: {why}",
            r.tenant
        ))
    })?;
    let fit = product.users_fit(&tenant, &ask).map_err(product_status)?;
    let grant_of =
        |answer: &monetize_product::UsersAnswer, bought: u64, granted: bool| pb::UsersGrant {
            principal: answer.principal.clone(),
            seats: answer.seats,
            seats_open: answer.seats_open,
            room_bytes: answer.room_bytes,
            need_bytes: answer.need_bytes,
            from_unused_bytes: answer.need_bytes.saturating_sub(bought),
            bought_bytes: bought,
            granted,
            ..Default::default()
        };
    if fit.shortfall_bytes == 0 {
        // ★ The unused room covers it: granted NOW, nothing bought, no vendor.
        // The account's seats before this grant are part of its name: a retry
        // of THIS grant is the same reference (and the product answers the
        // first one), while the admin asking for the same number again is a
        // new grant — not silently the old one.
        let reference = format!(
            "{}@{}",
            users_reference(product.id(), &r.tenant, starts, &ask),
            fit.seats
        );
        let answer = product
            .add_users(&tenant, &ask, &reference)
            .map_err(product_status)?;
        // The named user's invite: the link on THIS answer (the admin is on
        // the page) and, given an address, in the user's mail.
        let (invited, invite_url) = if answer.unchanged {
            (String::new(), String::new())
        } else {
            invite_users(s, product, &r.tenant, &ask, &answer)
        };
        let step = monetize::Step::UsersGranted {
            reference: reference.clone(),
            product: product.id().to_owned(),
            tenant: r.tenant.clone(),
            users: ask.without_names(),
            principal_id: ask.principal_id.clone(),
            seats: answer.seats,
            room_bytes: answer.room_bytes,
            from_unused_bytes: answer.need_bytes,
            bought_bytes: 0,
            invited: invited.clone(),
        };
        s.ledger.append(s.now(), step).map_err(ledger_err)?;
        return Ok(pb::StartPurchaseResponse {
            reference,
            state: PurchaseState::Paid as i32,
            words: monetize::transaction::progress::USERS_FROM_UNUSED.to_owned(),
            users: Some(pb::UsersGrant {
                invite_url,
                invited,
                ..grant_of(&answer, 0, true)
            }),
            ..Default::default()
        });
    }
    // ★ Short: sell EXACTLY what the unused room cannot cover, as an order for
    // more room — the bundle path's arithmetic, on the product's disk meter.
    let meter = disk_meter(product).ok_or_else(|| {
        Status::failed_precondition(format!(
            "{} sells no room: it declares no disk meter",
            product.id()
        ))
    })?;
    let current = s
        .ledger
        .entitlement(product.id(), &r.tenant)
        .map_err(ledger_err)?
        .map(|f| f.caps)
        .unwrap_or_default();
    // In the unit room is SOLD in (a GiB-month): the price rounds a part GiB
    // up, so the customer is given every GiB they pay for.
    let buy = fit.shortfall_bytes.div_ceil(SOLD_IN) * SOLD_IN;
    let caps = target_of(&current, &[(meter.to_owned(), buy)].into_iter().collect());
    let payer = if r.payer.is_empty() {
        s.signups.email_of(product.id(), &r.tenant).ok().flatten()
    } else {
        Some(r.payer.clone())
    };
    let quote = quote_order(s, product, &r.tenant, caps, market, r.starts_unix_ms, payer)
        .map_err(quote_status)?;
    if let Err(refusal) = &quote.serve {
        eprintln!(
            "monetize-server: users for {}/{} refused: {refusal}",
            product.id(),
            r.tenant
        );
        return Err(refused_status(refusal));
    }
    let mut purchase = quote.purchase.clone();
    purchase.users = Some(ask.without_names());
    // The open, free path sells nothing: room it would hand out for nothing is
    // not room the account has. Refused, naming what is missing.
    if purchase.is_unpriced() {
        return Err(users_short(
            &r.tenant,
            &ask,
            &fit,
            "This server does not sell room.",
        ));
    }
    let Some(vendor) = s.registry.vendor_for_tenant(
        &purchase.price,
        market,
        product.id(),
        &purchase.tenant.0,
        &r.vendor,
    ) else {
        return Err(users_short(
            &r.tenant,
            &ask,
            &fit,
            "No payment can be taken here for the rest.",
        ));
    };
    let reference = purchase.reference();
    // The names wait BESIDE the ledger until the grant (G13); before any money moves.
    if !ask.name.is_empty() || !ask.email.is_empty() {
        let named = crate::named_users::Named {
            name: ask.name.clone(),
            email: ask.email.clone(),
        };
        s.named_users.keep(&reference, named).map_err(|e| {
            Status::unavailable(format!(
                "the order's names could not be kept, so nothing is sold now: {e}"
            ))
        })?;
    }
    let v = run_and_report(s, product, vendor, &purchase)?;
    let handle = s
        .ledger
        .attempt(&reference)
        .map_err(ledger_err)?
        .map(|a| a.handle);
    let redirect_url = match (&handle, v.state) {
        (Some(h), PurchaseState::Pending) => redirect_url(s, vendor, h, &reference),
        _ => String::new(),
    };
    let bought = sold_disk_bytes(product, &purchase.delta);
    let users = match v.state {
        PurchaseState::Paid => grant_paid_users(s, product, &reference)?
            .unwrap_or_else(|| grant_of(&fit, bought, false)),
        _ => grant_of(&fit, bought, false),
    };
    let (handle_vendor, handle_id) = handle.map(|h| (h.vendor, h.id)).unwrap_or_default();
    Ok(pb::StartPurchaseResponse {
        reference: v.reference,
        state: v.state as i32,
        handle_vendor,
        handle_id,
        redirect_url,
        reason: v.reason,
        fact: v.fact.as_ref().map(fact_to_pb),
        words: match v.state {
            PurchaseState::Paid => monetize::transaction::progress::QUEUED.to_owned(),
            _ => String::new(),
        },
        users: Some(users),
    })
}

/// **Where the room a paid order bought stands**, for `Status`: done. The room is the
/// tenant's at once; an order past the room is queued at the estate that grows its own set
/// (a signed `grow_room` order, [`crate::grow::queue_past_room`]), not in a queue here.
pub(crate) fn room_progress(_s: &AppState, _product: &str, _reference: &str) -> pb::RoomProgress {
    use monetize::transaction::progress;
    pb::RoomProgress {
        state: "done".to_owned(),
        words: progress::DONE.to_owned(),
    }
}

pub fn verdict_of(reference: &str, result: Result<Outcome, TxError>) -> Result<Verdict, Status> {
    let (state, reason, fact) = match result {
        Ok(Outcome::Paid { fact, .. }) => (PurchaseState::Paid, String::new(), Some(fact)),
        Ok(Outcome::Declined { reason, .. }) => (PurchaseState::Declined, reason, None),
        Ok(Outcome::Released { reason, .. }) => (PurchaseState::Released, reason, None),
        // **Not folded into `Released`.** The engine refused to claim a release
        // it could not verify, and a door that quietly upgraded the verdict
        // would undo that one call short of the operator who has to act on it.
        // The uuids travel in `reason`, because an orphan nobody can name is an
        // orphan nobody will go and free.
        Ok(Outcome::ReleasedWithOrphans {
            reason, orphans, ..
        }) => (
            PurchaseState::ReleasedWithOrphans,
            format!(
                "{reason} — the release is NOT proven: {}",
                orphans.detail.join("; ")
            ),
            None,
        ),
        Err(TxError::Stalled { cause, .. }) => (PurchaseState::Pending, cause, None),
        Err(TxError::ReserveUnavailable(e)) => {
            return Err(Status::unavailable(format!("vendor: {e}")))
        }
        Err(e @ TxError::WrongProduct { .. }) => {
            return Err(Status::invalid_argument(e.to_string()))
        }
        // An order refused before anything was spent. `failed_precondition`
        // rather than `invalid_argument`: the request was well formed and the
        // WORLD refused it — the tenant would be shrinking, the product cannot
        // deliver the caps, nobody can take the money. The console shows the
        // reason verbatim, because "the product cannot absorb this" is the
        // operator's answer to the customer.
        Err(TxError::Refused(r)) => return Err(Status::failed_precondition(r.to_string())),
        Err(TxError::Ledger(e)) => return Err(ledger_err(e)),
        // **Neither can arise from a PURCHASE**, and they are named here rather
        // than swept into a wildcard so that stays a fact somebody has to
        // re-examine. `Product` and `Cloud` belong to `super_purge`, which runs
        // no vendor and produces no `Outcome`; a purchase asks the product only
        // `can_absorb`, whose refusal is a `Refused` above. Answering
        // `internal` says exactly that: if one of these ever reaches here, the
        // transaction has changed shape and this arm is the wrong answer.
        Err(e @ (TxError::Product(_) | TxError::Cloud(_))) => {
            return Err(Status::internal(format!(
                "a purchase produced a teardown error, which it has no path to: {e}"
            )))
        }
    };
    Ok(Verdict {
        reference: reference.into(),
        state,
        reason,
        fact,
    })
}

/// How often a `Purchase.Status` read of an OPEN attempt asks the vendor
/// (see `status`): a console following an order polls every few seconds, and
/// every ask is a vendor API call.
pub const ASK_VENDOR_EVERY: std::time::Duration = std::time::Duration::from_secs(10);

/// Whether a Status read of `reference` should ask the vendor now; records the
/// ask. Bounded: entries older than an hour are dropped when the map grows.
fn ask_vendor_due(reference: &str) -> bool {
    static ASKED: std::sync::LazyLock<
        std::sync::Mutex<std::collections::HashMap<String, std::time::Instant>>,
    > = std::sync::LazyLock::new(Default::default);
    let now = std::time::Instant::now();
    let mut asked = ASKED.lock().unwrap_or_else(|p| p.into_inner());
    if asked.len() > 1024 {
        asked.retain(|_, at| now.duration_since(*at) < std::time::Duration::from_secs(3600));
    }
    match asked.get(reference) {
        Some(at) if now.duration_since(*at) < ASK_VENDOR_EVERY => false,
        _ => {
            asked.insert(reference.to_owned(), now);
            true
        }
    }
}

/// **Resume ONE open attempt from the ledger** — the vendor named in its handle,
/// the product named in its reference, and
/// [`monetize::Transaction::reconcile_reference`] on the rows. `None` when the
/// reference is unknown or already closed.
///
/// It used to call `Transaction::run` again with the purchase read back out of
/// the attempt, and that is subtly the wrong verb. `run` is "buy this": it will
/// RESERVE AGAIN if the attempt turns out to be closed, and it goes straight to
/// `resume` — which for an attempt with no `Captured` row calls `pay.capture`
/// without ever asking the vendor what it thinks. So a reservation the vendor
/// had already captured, because the callback never arrived, was captured a
/// second time: idempotent at some vendors, a second charge at others, and
/// monetize does not choose which vendor it is talking to.
///
/// `reconcile_reference` asks `pay.status` first and records what the vendor says,
/// and it cannot start a new attempt at all — no open attempt, no action. It is
/// the same code the scheduled sweep runs, narrowed to one row, so a webhook and
/// the poller finish an attempt identically.
pub fn resume_reference(s: &AppState, reference: &str) -> Result<Option<Verdict>, Status> {
    // **One resume per reference at a time** (stinkies money-webhook-504-in-growth):
    // the webhook's grant, a vendor's redelivery, the poller's tick and a
    // watching `Purchase.Status` all land here. Before the flight, a redelivery
    // that arrived while the first grant was still pushing resumed the SAME
    // open attempt and pushed the entitlement a second time (and could write a
    // close for an attempt the first had closed). The loser touches nothing and
    // answers PENDING — the holder is finishing it.
    let Some(_flight) = s.resuming.fly(reference) else {
        return Ok(Some(Verdict {
            reference: reference.to_owned(),
            state: PurchaseState::Pending,
            reason: IN_FLIGHT.to_owned(),
            fact: None,
        }));
    };
    let Some(attempt) = s.ledger.attempt(reference).map_err(ledger_err)? else {
        return Ok(None);
    };
    if !attempt.is_open() {
        return Ok(None);
    }
    let product_id = reference.split('/').next().unwrap_or_default();
    let product = product_or_not_found(s, product_id)?;
    let vendor = s
        .registry
        .find_vendor(&attempt.handle.vendor)
        .ok_or_else(|| {
            Status::failed_precondition(format!(
                "{reference} was reserved at {:?}, which is not linked into this server",
                attempt.handle.vendor
            ))
        })?;
    let before = s
        .ledger
        .entitlement(product.id(), &attempt.purchase.tenant.0)
        .map_err(ledger_err)?
        .map(|f| f.state);
    // `Ok(None)` here means the attempt closed between the two reads — the poller
    // and a webhook race by design. Nothing happened, and that is not an error.
    let outcome = match s
        .transaction(product, vendor)
        .reconcile_reference(reference)
    {
        Ok(None) => return Ok(None),
        Ok(Some(o)) => Ok(o),
        Err(e) => Err(e),
    };
    report_verdict(s, product, before, verdict_of(reference, outcome)?).map(Some)
}

/// The reason a [`resume_reference`] answers PENDING when another caller is
/// finishing the same reference right now.
pub const IN_FLIGHT: &str = "another caller is finishing this purchase right now";

/// **Where to send the customer.** The vendor's own answer first, the configured
/// template second, empty if neither has one.
///
/// The order is the whole point. `checkout_url` in monetize.toml is a template
/// over the handle and the reference, which is right for a vendor with ONE fixed
/// checkout page and cannot express a vendor that mints a URL per order — Klarna
/// returns one from create-order, a Stripe intent carries one in `next_action`,
/// and both contain a session id the vendor invented that no template of ours
/// could produce. So the vendor is asked first and is believed; the template is
/// what is left for the vendors it fits.
///
/// One writer for `Start` and for `Status` (one implementation): an operator reopening a
/// pending attempt must be offered the same link the sale did, not a second
/// opinion about it.
fn redirect_url(
    s: &AppState,
    vendor: monetize_pay::Vendor<'_>,
    handle: &monetize_pay::ChargeHandle,
    reference: &str,
) -> String {
    if let Some(url) = vendor.page_url(handle) {
        return url;
    }
    s.checkout_urls
        .read()
        .unwrap_or_else(|e| e.into_inner())
        .get(&handle.vendor)
        .map(|t| {
            t.replace("{handle}", &handle.id)
                .replace("{reference}", reference)
        })
        .unwrap_or_default()
}

/// The market a request names, or the deployment's default when it names none.
fn market_of(s: &AppState, wire: i32) -> Market {
    market_of_wire(wire).unwrap_or_else(|| {
        s.terms
            .read()
            .unwrap_or_else(|e| e.into_inner())
            .default_market
    })
}

/// Pure: the market a wire value names — `None` when it names none (or one this
/// build does not know), and the default applies. A DK order is a Danish order.
fn market_of_wire(wire: i32) -> Option<Market> {
    match pb::Market::try_from(wire) {
        Ok(pb::Market::Se) => Some(Market::Se),
        Ok(pb::Market::Fi) => Some(Market::Fi),
        Ok(pb::Market::Dk) => Some(Market::Dk),
        _ => None,
    }
}

/// **Quote an order under the deployment's terms — the one writer for `Quote`
/// and `Start`**, so what the console shows before the confirm button is what
/// `Start` runs. Nothing is reserved; the product's control plane is asked
/// once (`can_absorb`, and `servable` only for a product-scope cap).
/// **What is wrong with the REQUEST**, as opposed to what the world refuses.
/// Split out of [`quote_order`] because the two have different answers: a cap
/// naming a meter that does not exist is `invalid_argument` whoever asks, while
/// a product that cannot absorb the order is a quote with `can_serve = false`
/// that the shop window still shows.
fn check_order_args(
    product: monetize_product::Served<'_>,
    tenant: &str,
    caps: &std::collections::BTreeMap<String, u64>,
) -> Result<(), Status> {
    if tenant.is_empty() {
        return Err(Status::invalid_argument("tenant is required"));
    }
    if let Some(cap) = caps
        .keys()
        .find(|k| !product.meters().iter().any(|m| m.name == k.as_str()))
    {
        return Err(Status::invalid_argument(format!(
            "cap {cap:?} names a meter {} does not declare; it declares {:?}",
            product.id(),
            product.meters().iter().map(|m| m.name).collect::<Vec<_>>()
        )));
    }
    Ok(())
}

/// **[`quote_order`] in the deployment's default market, now** — the quote a
/// shop window row and an order make, for an integration test to hold the
/// queue (round 5.3) to. Panics on a refusal the quote itself raises (a
/// downgrade, a no-op): a test that asks one has asked the wrong thing.
pub fn quote_order_for_test(
    s: &AppState,
    product: monetize_product::Served<'_>,
    tenant: &str,
    caps: std::collections::BTreeMap<String, u64>,
) -> Quote {
    let market = s
        .terms
        .read()
        .unwrap_or_else(|e| e.into_inner())
        .default_market;
    quote_order(s, product, tenant, caps, market, 0, None)
        .unwrap_or_else(|e| panic!("the quote itself refused: {e}"))
}

pub(crate) fn quote_order(
    s: &AppState,
    product: monetize_product::Served<'_>,
    tenant: &str,
    caps: std::collections::BTreeMap<String, u64>,
    market: Market,
    starts_unix_ms: u64,
    payer: Option<String>,
) -> Result<Quote, TxError> {
    let order = Order {
        product: product.id().into(),
        tenant: TenantId(tenant.to_owned()),
        caps,
    };
    let terms = s.terms.read().unwrap_or_else(|e| e.into_inner()).clone();
    let host = terms.host(product.id());
    let terms = terms.terms(product.id(), market, &host);
    let starts = if starts_unix_ms == 0 {
        s.now()
    } else {
        starts_unix_ms
    };
    // The quote needs no vendor: nothing is reserved. `NO_VENDOR_PROVIDER` is
    // the honest stand-in — a transaction that could not pay if it tried.
    //
    // The `TxError` is handed back unmapped because the SHOP WINDOW needs it:
    // `Purchase.Bundles` turns a `Refused` into `can_serve: false` with the
    // customer's sentence rather than into a gRPC error, and it must be the
    // same quote this function makes or the window and the quote would be two
    // opinions. See [`bundles_of`].
    // The product's room, with the QUEUE past it (round 5.3, UW-4): an order past the room
    // of an estate that grows its own set when told is sold and queued there — see
    // `crate::grow::can_absorb_queued`.
    let absorb = |tenant: &monetize_product::TenantId,
                  caps: &std::collections::BTreeMap<String, u64>| {
        crate::grow::can_absorb_queued(s, product, tenant, caps)
    };
    let mut quote = s
        .transaction(product.with_room(&absorb), monetize::no_vendor())
        .quote(&order, &terms, starts, payer)?;
    // ★ The oversell ceiling (a-ceiling-s3): the sold-capacity wall the
    // signup has, for the order too — the window, the quote and Start all
    // come through here, so none of them can sell past it.
    // Only an order served from the iron ON HAND is a new promise against it;
    // one that BUYS its own iron (`Absorb::WithIron`) brings the room with it.
    if quote.serve.is_ok()
        && matches!(
            quote.purchase.absorb,
            Some(monetize_product::Absorb::OnHand)
        )
    {
        if let Err(over) = crate::oversell::admit_order(s, product, &quote.current, &order.caps) {
            // ★ Round 5.3 (owner 2026-10-08: "the customer must not know about
            // a cap! it must be queued and resized later"): where the set is
            // resized later, past the sold-capacity wall is SOLD and QUEUED —
            // the estate grows its set for what the purchases queue. Said to
            // the operator's log; the customer is offered every size.
            // Quiet here: the window quotes every row on every load; the queue
            // is said ONCE, when the order is placed (`Purchase.Start`,
            // [`queued_past_the_wall`] + `oversell::queue_note`).
            if crate::grow::queues_for_resize(s, product) {
                return Ok(quote);
            }
            crate::oversell::say_order_refused(&over.why);
            quote.serve = Err(monetize::transaction::Refusal::CannotAbsorb {
                tenant: order.tenant.0.clone(),
                reason: over.why,
                // The room the ceiling still leaves — the wall that refused
                // (cov-10): a measured room, never "we could not measure".
                shortfall: monetize::transaction::Shortfall {
                    asked: order.caps.clone(),
                    servable_bytes: Some(over.room_left_bytes),
                },
            });
        }
    }
    Ok(quote)
}

/// ★ **Why this order is QUEUED rather than served from the box** (round
/// 5.3): a served quote on the iron on hand that the oversell ceiling would
/// refuse, on a set that is resized later — the operator's reason; `None` for
/// an order the box serves now (or that buys its own iron).
pub(crate) fn queued_past_the_wall(
    s: &AppState,
    product: monetize_product::Served<'_>,
    quote: &Quote,
    caps: &std::collections::BTreeMap<String, u64>,
) -> Option<String> {
    if quote.serve.is_err()
        || !matches!(
            quote.purchase.absorb,
            Some(monetize_product::Absorb::OnHand)
        )
        || !crate::grow::queues_for_resize(s, product)
    {
        return None;
    }
    crate::oversell::admit_order(s, product, &quote.current, caps)
        .err()
        .map(|over| over.why)
}

/// **The metadata key a refusal's CUSTOMER sentence travels under.**
///
/// A gRPC `Status` carries one message, and a refused order has two readers who
/// must not be given the same words: the operator, who needs the machine named
/// (`/data`, the set, `Admin.GrowStart`), and the customer, who must never read
/// any of it (`monetize::transaction::words::NEVER_SHOWN`, owner's ruling
/// 2026-09-14). Until 2026-09-20 `Purchase.Start` had only the message, so the
/// refusal a customer saw after pressing BUY was whichever of the two the
/// server happened to send — and a console that could not tell them apart
/// substituted a sentence of its own. gunnar-ui's was *"down for
/// maintenance"*, about a store that was simply too small.
///
/// So the message stays the operator's, byte for byte, and the customer's
/// sentence rides beside it. A `-bin` key because these sentences are UTF-8 and
/// an em dash is not ASCII.
///
/// **Absence is not a licence to invent.** A reader that does not find this
/// shows the message — see `gunnar_ui_server::grpc::Fail::from`.
pub const CUSTOMER_WORDS_KEY: &str = "monetize-customer-words-bin";

/// One refusal as a `Status`: the operator's sentence in the message, the
/// customer's in [`CUSTOMER_WORDS_KEY`]. The ONE writer, so no door can send
/// one without the other.
pub(crate) fn refused_status(r: &monetize::transaction::Refusal) -> Status {
    let mut status = Status::failed_precondition(r.to_string());
    status.metadata_mut().insert_bin(
        CUSTOMER_WORDS_KEY,
        tonic::metadata::MetadataValue::from_bytes(r.customer_words().as_bytes()),
    );
    status
}

/// The quote's refusals as a `Status`, for the doors that answer one order.
pub(crate) fn quote_status(e: TxError) -> Status {
    match e {
        TxError::Refused(r) => refused_status(&r),
        TxError::WrongProduct { .. } => Status::invalid_argument(e.to_string()),
        TxError::Ledger(l) => ledger_err(l),
        other => Status::internal(other.to_string()),
    }
}

/// **Nothing is sold of a product served free** — `[products.<id>] free = true`: refused by name before
/// anything is priced, reserved or written.
fn refuse_if_free(s: &AppState, product: &str) -> Result<(), Status> {
    let free = s
        .config
        .read()
        .map(|c| c.products.get(product).is_some_and(|p| p.free))
        .unwrap_or(false);
    if free {
        return Err(Status::failed_precondition(format!(
            "nothing is sold here: {product} is served free on this deployment ([products.{product}] free = true) — no order, no renewal and no users are sold; its owner buys at the shop that sold it"
        )));
    }
    Ok(())
}

/// **Quote a RENEWAL — the one writer for `Quote` and `Start` with `renew`.**
///
/// The two guards are the anti-typo half, and they refuse rather than ignore.
/// A renewal names no caps (they come off the stored fact) and names no start
/// (the period starts where the paid one ends). A caller that sends either is
/// not asking for a renewal — it is an order-shaped request with a flag set,
/// and quietly dropping the fields it sent would charge for something other
/// than what it asked for.
fn quote_renewal(
    s: &AppState,
    product: monetize_product::Served<'_>,
    r_tenant: &str,
    caps_named: bool,
    starts_named: bool,
    market: Market,
    payer: Option<String>,
) -> Result<Quote, Status> {
    if r_tenant.is_empty() {
        return Err(Status::invalid_argument("tenant is required"));
    }
    if caps_named {
        return Err(Status::invalid_argument(
            "a renewal names no caps: it sells another period of what the tenant already holds, and the caps come off              their stored entitlement. Send caps to place an ORDER, or drop them to renew — a renewal that could be              expressed as an order for the caps a tenant happens to hold is one a client sends by mistake",
        ));
    }
    if starts_named {
        return Err(Status::invalid_argument(
            "a renewal names no start: the period starts where the paid one ends (or today, when that is past), so              that no day already bought is forfeited and no lapsed day is billed",
        ));
    }
    let terms = s.terms.read().unwrap_or_else(|e| e.into_inner()).clone();
    let host = terms.host(product.id());
    let terms = terms.terms(product.id(), market, &host);
    s.transaction(product, monetize::no_vendor())
        .renewal(&TenantId(r_tenant.to_owned()), &terms, payer)
        .map_err(|e| match e {
            // A renewal's refusals are about WHO is renewing, not about capacity,
            // and none of them is a quote worth showing: there is no period to
            // price. `failed_precondition` with the operator's reason; the
            // customer's sentence is `Refusal::customer_words`.
            TxError::Refused(r) => refused_status(&r),
            TxError::WrongProduct { .. } => Status::invalid_argument(e.to_string()),
            TxError::Ledger(l) => ledger_err(l),
            other => Status::internal(other.to_string()),
        })
}

/// **THE SHOP WINDOW: every bundle this deployment offers this tenant, priced
/// and asked about** — the read behind `Purchase.Bundles`.
///
/// Two halves, and they are deliberately different kinds of thing:
///
/// * **priced, purely** — `monetize::bundle::offer` over `[products.<id>.bundles]`
///   and the market's price list. No ledger, no control plane. A bundle this
///   deployment cannot price is not in the list at all and its refusal goes to
///   the operator's log, because an offer nobody priced is a sale at a price
///   nobody chose;
/// * **asked about, really** — the SAME `quote_order` a typed order goes
///   through, on the caps this tenant would end up with. That is what puts
///   `can_absorb`, the cloud's `can_serve` and the box's ceilings behind
///   `can_serve` here, and it is why a window row and the quote behind the
///   confirm button cannot disagree: there is one quote.
///
/// # It costs one control-plane call per bundle
///
/// MEASURED cost, stated rather than discovered: N bundles is N `can_absorb`
/// calls to ONE product (the request names one). `products.proto` warns that a
/// page asking each PRODUCT directly hangs on the slowest box in the estate;
/// this asks one box N times, with N a number an operator wrote in a config
/// file, and a shop window of four rows is four calls. A window with dozens of
/// rows is a different design problem and would need the answer cached.
///
/// # Silence is never a yes
///
/// A product that cannot be reached, or that does not measure, comes back as
/// `Refusal::CannotAbsorb` — `products/gunnar`'s `absorbs` turns
/// `Capacity::Unanswered` into exactly that — and lands here as
/// `can_serve: false` with `Refusal::customer_words`. The operator's reason
/// (which names the data set, PID 1, a fresh install) goes to the log and never
/// onto this wire.
fn bundles_of(
    s: &AppState,
    product: monetize_product::Served<'_>,
    tenant: &str,
    market: Market,
) -> Result<Vec<pb::Bundle>, Status> {
    let Some(declared) = s
        .bundles
        .read()
        .unwrap_or_else(|e| e.into_inner())
        .get(product.id())
        .cloned()
    else {
        return Ok(Vec::new());
    };
    let terms = s.terms.read().unwrap_or_else(|e| e.into_inner()).clone();
    let host = terms.host(product.id());
    let terms = terms.terms(product.id(), market, &host);
    let (offers, refused) = monetize::bundle::offers(declared.iter(), product.meters(), &terms);
    for r in &refused {
        // The operator, every time the window could have shown it. A console is
        // not always open and journald is where a deployment's own mistakes are
        // read back; the customer sees nothing at all, which is the point.
        eprintln!(
            "monetize-server: bundle not offered for {}: {}",
            product.id(),
            r.why
        );
    }
    let current = s
        .ledger
        .entitlement(product.id(), tenant)
        .map_err(ledger_err)?
        .map(|f| f.caps)
        .unwrap_or_default();
    // `offer` already refused every bundle naming a meter this product does not
    // declare, so this is the tenant's name and nothing else. Asked anyway,
    // once, so the two doors cannot drift apart on what a valid order is.
    check_order_args(product, tenant, &std::collections::BTreeMap::new())?;
    let mut out = Vec::with_capacity(offers.len());
    for o in offers {
        let caps = target_of(&current, &o.delta);
        // `starts_unix_ms = 0` is "now", the same default the console's quote
        // uses. Nothing is reserved and nothing is written.
        let (can_serve, reason) = match quote_order(s, product, tenant, caps, market, 0, None) {
            Ok(q) => match &q.serve {
                Ok(()) => (true, String::new()),
                // The OFFER's words, not an order's refusal: nobody has
                // ordered it (owner, test2 2026-10-05).
                Err(r) => {
                    eprintln!(
                        "monetize-server: bundle {:?} cannot be served for {}/{}: {r}",
                        o.id,
                        product.id(),
                        tenant
                    );
                    (false, r.offer_words())
                }
            },
            // A refusal the quote itself raised. It should not be reachable —
            // the delta is non-empty and strictly a raise, so neither
            // `NotAnIncrease` nor `Downgrade` applies — but a window row that
            // turned an unexpected refusal into a *yes* would sell it, so the
            // honest answer is the customer's sentence and a loud log line.
            Err(TxError::Refused(r)) => {
                eprintln!("monetize-server: bundle {:?} was refused while pricing the window for {}/{}: {r}", o.id, product.id(), tenant);
                (false, r.offer_words())
            }
            Err(e) => return Err(quote_status(e)),
        };
        out.push(pb::Bundle {
            id: o.id,
            label: o.label,
            // WORDS, never minor units: the console may not divide by 100 or
            // map a currency enum. Same writer as `QuoteResponse.price_words`.
            price: o.price.in_words(),
            period: o.period.name().to_owned(),
            delta: o.delta,
            can_serve,
            reason,
            // A bundle of a deployment without plans: neither is said.
            action: String::new(),
            target: Default::default(),
        });
    }
    Ok(out)
}

/// **The caps a bundle order names**: what the tenant holds, with each of the
/// bundle's meters raised by its delta.
///
/// A bundle is "10 GiB MORE", and an [`monetize::Order`] says what the tenant is
/// to be ALLOWED — so the addition happens here, once, and `delta_caps` then
/// computes exactly the bundle's delta back out of it. Saturating, because two
/// caps near `u64::MAX` must ask the product an absurd question and be told no
/// rather than wrap into a small one and be told yes.
fn target_of(
    current: &std::collections::BTreeMap<String, u64>,
    delta: &std::collections::BTreeMap<String, u64>,
) -> std::collections::BTreeMap<String, u64> {
    let raised = delta
        .iter()
        .map(|(m, d)| {
            (
                m.clone(),
                current.get(m).copied().unwrap_or(0).saturating_add(*d),
            )
        })
        .collect();
    monetize::order::target_caps(current, &raised)
}

/// **Resolve `bundle` into the caps a typed order would have named** — the ONE
/// place a bundle becomes an order, for `Quote` and for `Start`.
///
/// After this returns there is no such thing as a bundle: the rest of both
/// doors sees the caps and nothing else, which is why ordering a bundle and
/// ordering the same caps by hand reach the same transaction, the same
/// reference and the same ledger rows. There is no second way to spend money
/// in this server.
///
/// It runs BEFORE the actor ticket is checked, so the ticket is held against
/// the RESOLVED caps. A ticket covering the target caps works for either door
/// and neither can spend the other's — which would not be true if the ticket
/// were checked against an empty cap map on the bundle path.
fn caps_of_bundle(
    s: &AppState,
    product: monetize_product::Served<'_>,
    tenant: &str,
    bundle: &str,
    caps: &std::collections::BTreeMap<String, u64>,
    market: Market,
) -> Result<std::collections::BTreeMap<String, u64>, Status> {
    if !caps.is_empty() {
        return Err(Status::invalid_argument(
            "a request names a bundle OR caps, never both. A bundle IS a set of caps, and a client that sends both is a              client that disagrees with itself about what it is buying — one of them would have to win silently",
        ));
    }
    if tenant.is_empty() {
        return Err(Status::invalid_argument("tenant is required"));
    }
    let terms = s.terms.read().unwrap_or_else(|e| e.into_inner()).clone();
    let host = terms.host(product.id());
    let terms = terms.terms(product.id(), market, &host);
    let spec = s
        .bundles
        .read()
        .unwrap_or_else(|e| e.into_inner())
        .get(product.id())
        .and_then(|b| b.get(bundle))
        .cloned()
        .ok_or_else(|| {
            Status::failed_precondition(format!(
                "{:?} is not a bundle {} offers; ask Purchase.Bundles for the ones it does",
                bundle,
                product.id()
            ))
        })?;
    // Declared is not offered. The same rule that keeps an unpriceable bundle
    // out of the window keeps it from being SOLD through a stale console page,
    // and the operator's sentence goes to the log rather than to the customer.
    let offer = monetize::bundle::offer(bundle, &spec, product.meters(), &terms).map_err(|e| {
        eprintln!(
            "monetize-server: bundle {:?} was ordered and is not offered for {}: {}",
            bundle,
            product.id(),
            e.why
        );
        Status::failed_precondition(format!("{:?} is not on sale here", bundle))
    })?;
    // An account made since the poller's last tick is adopted first: the raise is resolved
    // from the fact its product already holds, as the site's ticket is (held + delta).
    crate::poller::adopt_signup(s, product.id(), tenant).map_err(Status::unavailable)?;
    let current = s
        .ledger
        .entitlement(product.id(), tenant)
        .map_err(ledger_err)?
        .map(|f| f.caps)
        .unwrap_or_default();
    Ok(target_of(&current, &offer.delta))
}

/// **What a `Quote`/`Start` asks of a product that sells PLANS**: a row by
/// id, a renewal (prolong a 1-month plan, renew a 12-month one), or a typed
/// size (the 12-month field). A bundle beside caps, or a start date, is
/// refused as on the bundle path.
fn plan_ask<'a>(
    renew: bool,
    bundle: &'a str,
    caps: &'a std::collections::BTreeMap<String, u64>,
    starts: u64,
) -> Result<crate::plans::Ask<'a>, Status> {
    if starts != 0 {
        return Err(Status::invalid_argument(
            "a plan names no start: it starts today, or where the paid one ends",
        ));
    }
    match (renew, bundle.is_empty(), caps.is_empty()) {
        (true, true, true) => Ok(crate::plans::Ask::Renew),
        (true, _, _) => Err(Status::invalid_argument(
            "a renewal names no bundle and no caps",
        )),
        (false, false, true) => Ok(crate::plans::Ask::Row(bundle)),
        (false, false, false) => Err(Status::invalid_argument(
            "a request names a bundle OR caps, never both — one of them would have to win silently",
        )),
        (false, true, _) => Ok(crate::plans::Ask::Typed(caps)),
    }
}

/// **No vendor takes this order's money**: the price in major units with its
/// currency (`110.00 SEK`), never the öre count.
fn no_vendor_words(
    price: monetize_pay::Money,
    market: Market,
    said: &str,
    asked: &str,
    serving: &[&str],
) -> String {
    format!("this order costs {} in {market:?}; {said} (asked: {asked:?}), and no vendor here takes that money; serving: {serving:?}", price.in_words())
}

#[cfg(test)]
mod no_vendor_words_tests {
    #[test]
    fn the_refusal_names_the_price_in_major_units() {
        let w = super::no_vendor_words(
            monetize_pay::Money {
                minor: 11_000,
                currency: monetize_pay::Currency::Sek,
            },
            monetize_pay::Market::Se,
            "no route",
            "stripe/x",
            &[],
        );
        assert!(w.contains("costs 110.00 SEK in Se"), "{w}");
        assert!(!w.contains("11000"), "{w}");
    }
}

/// **Sell a quoted purchase**: the vendor for its price and market, the
/// transaction, and the answer `Start` gives — the tail every door shares.
fn sell(
    s: &AppState,
    product: monetize_product::Served<'_>,
    purchase: &PurchaseReq,
    market: Market,
    vendor_name: &str,
) -> Result<pb::StartPurchaseResponse, Status> {
    let vendor = s
        .registry
        .vendor_for_tenant(
            &purchase.price,
            market,
            product.id(),
            &purchase.tenant.0,
            vendor_name,
        )
        .ok_or_else(|| {
            Status::not_found(no_vendor_words(
                purchase.price,
                market,
                &s.registry.route_said(product.id()),
                vendor_name,
                &s.registry.vendor_names(),
            ))
        })?;
    let reference = purchase.reference();
    let v = run_and_report(s, product, vendor, purchase)?;
    let handle = s
        .ledger
        .attempt(&reference)
        .map_err(ledger_err)?
        .map(|a| a.handle);
    let redirect_url = match (&handle, v.state) {
        (Some(h), PurchaseState::Pending) => redirect_url(s, vendor, h, &reference),
        _ => String::new(),
    };
    let (handle_vendor, handle_id) = handle.map(|h| (h.vendor, h.id)).unwrap_or_default();
    Ok(pb::StartPurchaseResponse {
        reference: v.reference,
        state: v.state as i32,
        handle_vendor,
        handle_id,
        redirect_url,
        reason: v.reason,
        fact: v.fact.as_ref().map(fact_to_pb),
        words: match v.state {
            PurchaseState::Paid => purchase.granted_words().to_owned(),
            _ => String::new(),
        },
        users: None,
    })
}

/// **Who knocks**, as the door saw it: the calling site (its estate's bearer),
/// the actor ticket the request carried, and the door's own word for the caller.
/// The three travel together into [`check_actor`].
#[derive(Clone, Copy)]
struct Asker<'a> {
    site: Option<&'a str>,
    ticket: &'a [u8],
    caller: Option<&'a Caller>,
}

/// **Who is asking — the ONE gate on the tenant path, for `Quote` and for
/// `Start`.**
///
/// monetize authenticates exactly one caller on its gRPC surface (a shared
/// bearer, and an empty one means open — `crate::auth`), so nothing else in
/// this file can tell the product's console from the product's operator, let
/// alone one browser session from another. An actor ticket is the product's own
/// appliance saying that the human driving this call holds `tenant`, and the
/// PLUGIN checks it: it is the half that holds the appliance's key, and
/// `monetize-embed` (which owns the ticket) depends on `monetize-product`, so
/// the seam carries opaque bytes.
///
/// Three rules, and every one of them is load-bearing:
///
/// * **An empty ticket is the caller the DOOR vouched for, and nobody else.**
///   Through the bearer (or the control signature) it is the operator, as it
///   always was. Through no door at all it is REFUSED: an empty ticket must never mean
///   "the operator" by its own say-so, or every in-process caller is one.
/// * **A ticket with `renew = false` is REFUSED**, not ignored. A ticket
///   authorises one verb; an order is new caps, new money and new iron, and the
///   appliance vouched for none of it. Silently dropping the field would work
///   today and is exactly how a widening sneaks in later.
/// * **It is called before anything else**, so a refusal has nothing to unwind:
///   nothing priced, nothing reserved, no row appended, no vendor dialled.
///
/// A `ProductError` is a refusal too — an appliance that cannot be asked has
/// not said yes — and the two are kept apart on the wire only so an operator
/// can tell a wrong ticket from a plugin that is down.
fn check_actor(
    s: &AppState,
    product: monetize_product::Served<'_>,
    tenant: &str,
    purpose: &str,
    caps: &std::collections::BTreeMap<String, u64>,
    asker: Asker<'_>,
) -> Result<(), Status> {
    let Asker {
        site,
        ticket,
        caller,
    } = asker;
    if ticket.is_empty() {
        // No ticket means nobody is claiming to be the tenant, which is what an
        // operator ordering on a customer's behalf is — when the bearer says it
        // is the operator. The product is not asked, so a deployment with no
        // appliance key is not broken by this gate existing.
        // ★ S5 (prod audit 2026-10-12): a SITE's own bearer is that site's operator door, as
        // the service bearer was the estate monetize's: its console orders on its own
        // accounts' behalf (the tenant is already scoped to the site, `scope_tenant`).
        if site.is_some_and(|e| !e.trim().is_empty()) {
            return Ok(());
        }
        return match caller {
            Some(Caller::Door) => Ok(()),
            _ => Err(Status::permission_denied(
                "no actor ticket, and this request did not come through the operator's door: an empty ticket is nobody",
            )),
        };
    }
    // **The verb the REQUEST is, named by the CALLER, not derived from a
    // flag here.** It was a `renew: bool` until `PURPOSE_READ` existed, and a
    // bool cannot say three things — the moment there was a third verb the
    // mapping would have had to guess which one "not renew" meant. The
    // ticket's own word is checked against this inside the product, where the
    // signature is; naming it here is what stops any one verb's ticket being
    // spent on another.
    // A renewal names no caps on the wire, and `quote_renewal` has already
    // refused one that did. Passing the order's caps straight through means a
    // ticket that covered a different amount is refused by the comparison in
    // `verify_ticket` rather than by anything written here.
    // ★ ST-3: from a SITE, under that site's own key ([`crate::site_ticket::may_act`]).
    match crate::site_ticket::may_act(s, product, site, tenant, purpose, caps, ticket) {
        Ok(monetize_product::ActorVerdict::Allowed) => Ok(()),
        Ok(monetize_product::ActorVerdict::Refused(why)) => Err(Status::permission_denied(why)),
        // The product could not answer. NOT an allow, and not a
        // `permission_denied` either: the caller may well be entitled and the
        // honest answer is "ask again".
        Err(monetize_product::ProductError::Unavailable(why)) => Err(Status::unavailable(format!(
            "{} cannot be asked who you are right now, so this request cannot be authorised: {why}",
            product.id()
        ))),
        Err(monetize_product::ProductError::Refused(why)) => Err(Status::permission_denied(why)),
    }
}

/// **The SITE a call comes from** — its estate's own bearer ([`crate::auth::CallerEstate`]).
fn site_of<T>(req: &Request<T>) -> Option<String> {
    req.extensions()
        .get::<crate::auth::CallerEstate>()
        .map(|e| e.0.clone())
}

/// ★ ST-4: **the request's tenant, as the calling site's account** — `@<estate>/<name>`
/// away from the product's home ([`crate::site_ticket::tenant_on`]); another site's account
/// is refused before anything is read. No calling site: as given.
fn scope_tenant(
    s: &AppState,
    product: &str,
    site: Option<&str>,
    tenant: &mut String,
) -> Result<(), Status> {
    if tenant.is_empty() {
        return Ok(());
    }
    *tenant = crate::site_ticket::tenant_on(s, product, site, tenant)
        .map_err(Status::permission_denied)?;
    Ok(())
}

/// **The one sentence a scoped caller gets for a reference that is not its
/// tenant's — and for one that names nothing at all.** The same words both
/// ways, and no reference or owner in them: a refusal that told "exists, not
/// yours" from "does not exist" would be a read-only enumeration of every
/// order on the server, which is what the scope exists to prevent.
pub const NOT_THIS_TENANTS: &str = "this tenant has no purchase by that reference";

/// **Who is asking about ONE order** — `Status`, `Abandon` and `Cancel`.
///
/// Three paths, decided before the ledger is read (see
/// `PurchaseStatusRequest.tenant` in the proto):
///
/// * `tenant` empty — the operator, unscoped, and only through the bearer's
///   door ([`Caller::Door`]). A ticket here is a client that confused two
///   paths: a ticket names a tenant.
/// * `tenant` set, no ticket — the operator (it holds the bearer), scoped.
/// * `tenant` set, a ticket — the tenant, scoped, and the appliance's word for
///   it ([`check_actor`], the same gate `Quote`, `Bundles` and `History` pass).
enum OrderScope {
    Operator,
    Tenant { product: String, tenant: String },
}

fn order_scope(
    s: &AppState,
    site: Option<&str>,
    product: &str,
    tenant: &str,
    ticket: &[u8],
    purpose: &str,
    caller: Option<&Caller>,
) -> Result<OrderScope, Status> {
    if tenant.is_empty() {
        if !ticket.is_empty() {
            return Err(Status::invalid_argument(
                "an actor ticket names a tenant, so name it in `tenant` (and `product`) beside the ticket",
            ));
        }
        if caller != Some(&Caller::Door) {
            return Err(Status::permission_denied(
                "an unscoped read of any order is the operator's, through the bearer's door",
            ));
        }
        return Ok(OrderScope::Operator);
    }
    if product.is_empty() {
        return Err(Status::invalid_argument(
            "`product` is required with `tenant`",
        ));
    }
    let p = product_or_not_found(s, product)?;
    let mut tenant = tenant.to_owned();
    scope_tenant(s, p.id(), site, &mut tenant)?;
    // FIRST, before a single key is read out of the ledger: a refusal must cost
    // nothing and learn nothing. No caps — none of these verbs buys anything.
    check_actor(
        s,
        p,
        &tenant,
        purpose,
        &std::collections::BTreeMap::new(),
        Asker {
            site,
            ticket,
            caller,
        },
    )?;
    Ok(OrderScope::Tenant {
        product: product.to_owned(),
        tenant,
    })
}

impl OrderScope {
    /// May this caller see `reference` at all? The owner is read off the
    /// ledger's own copy of the purchase (the `Reserved` row) — never off a
    /// prefix of the reference, because `team` must not reach `team/sub`.
    fn admits(&self, s: &AppState, reference: &str) -> Result<(), Status> {
        let OrderScope::Tenant { product, tenant } = self else {
            return Ok(());
        };
        match owner_of(s, reference)? {
            Some((p, t)) if p == *product && t == *tenant => Ok(()),
            _ => Err(Status::not_found(NOT_THIS_TENANTS)),
        }
    }
}

/// `(product, tenant)` of the order behind `reference`, or `None` when the
/// ledger has nothing under it.
///
/// An attempt carries its purchase, which is authoritative. A reference with
/// rows and NO attempt was declined at reserve, and its own name is then the
/// only record of whose it was: `<product>/<tenant>/<date>+<caps>`, where the
/// tenant is everything between the FIRST slash and the LAST — an exact
/// equality on that is not a prefix match, so `team/sub` still is not `team`.
fn owner_of(s: &AppState, reference: &str) -> Result<Option<(String, String)>, Status> {
    if let Some(a) = s.ledger.attempt(reference).map_err(ledger_err)? {
        return Ok(Some((
            a.purchase.product.clone(),
            a.purchase.tenant.0.clone(),
        )));
    }
    if s.ledger.rows(reference).map_err(ledger_err)?.is_empty() {
        return Ok(None);
    }
    Ok(owner_named_by(reference))
}

/// `(product, tenant)` as a reference spells them.
pub fn owner_named_by(reference: &str) -> Option<(String, String)> {
    let (product, rest) = reference.split_once('/')?;
    let (tenant, _when) = rest.rsplit_once('/')?;
    (!product.is_empty() && !tenant.is_empty()).then(|| (product.to_owned(), tenant.to_owned()))
}

/// **Where an order is, in the customer's terms** — `PurchasePhase`, from the
/// ledger's own attempt. One writer, so `Status` and `Cancel` cannot answer two
/// different words for the same row (and the console derives none).
pub fn phase_of(
    attempt: Option<&monetize::ledger::Attempt>,
    rows: &[monetize::ledger::Row],
) -> pb::PurchasePhase {
    match attempt {
        None => match rows.last().map(|r| &r.step) {
            Some(monetize::Step::Declined { .. }) => pb::PurchasePhase::Declined,
            _ => pb::PurchasePhase::Unspecified,
        },
        Some(a) => match &a.closed {
            None if a.captured.is_some() => pb::PurchasePhase::PaidAdding,
            None => pb::PurchasePhase::WaitingForPayment,
            Some(Closed::Pushed { .. }) => pb::PurchasePhase::Done,
            Some(Closed::Released { .. }) if a.captured.is_some() => pb::PurchasePhase::Refunded,
            Some(Closed::Released { .. }) => pb::PurchasePhase::Cancelled,
        },
    }
}

/// Would `Cancel` end this attempt now — open, and nothing captured as far as
/// the ledger knows (`Cancel` asks the vendor again before it acts).
pub fn cancellable(attempt: Option<&monetize::ledger::Attempt>) -> bool {
    attempt.is_some_and(|a| a.is_open() && a.captured.is_none())
}

/// Would `Abandon` end this attempt now — open, and its money captured: the
/// two things `monetize::abandon_attempt` requires.
pub fn abandonable(attempt: Option<&monetize::ledger::Attempt>) -> bool {
    attempt.is_some_and(|a| {
        a.is_open()
            && matches!(
                a.captured,
                Some(monetize_pay::ChargeStatus::Captured { .. })
            )
    })
}

/// **The most attempts one `Purchase.History` answer may carry.**
///
/// A caller names a `limit` and the server obeys it only up to here. An
/// unbounded history is a disk read whoever holds a ticket gets to size, and a
/// page is a page: a hundred attempts is more than a tenant buying every month
/// accumulates in eight years.
pub const HISTORY_CEILING: u32 = 100;

/// **The most of a tenant's references one call will FOLD**, before the answer
/// is clamped. The bound on the read rather than on the reply — the clamp above
/// makes the response small, this makes the work small.
///
/// The tail is kept, not the head: references sort as
/// `<product>/<tenant>/<YYYY-MM-DD>+<caps>`, so lexicographic order is date
/// order, and the last ones are the recent ones. A tenant with more than this
/// many attempts sees their most recent thousand folded and never their first.
const HISTORY_SCAN_CEILING: usize = 1_000;

/// `limit` as the server will honour it: 0 means the ceiling, and anything
/// larger is the ceiling. Pure, so the clamp is provable without a ledger.
pub fn clamp_limit(limit: u32) -> usize {
    if limit == 0 {
        HISTORY_CEILING as usize
    } else {
        limit.min(HISTORY_CEILING) as usize
    }
}

/// **One tenant's attempts, folded, newest first** — the read behind
/// `Purchase.History`, with the gate already passed.
///
/// # It reuses `Sale::fold`, and there is no second folder
///
/// `monetize::ledger::Sale::fold` is the fold `Ledger.Sales` uses, and it fits
/// here without a change: it is PURE — `(reference, at, rows) -> Option<Sale>`
/// — so the only thing `Sales` has that this does not is where the rows come
/// from. `Sales` discovers references off the time index (recent activity
/// across every tenant); this one takes them off the reference prefix (one
/// tenant's whole history, however old). Same fold, different door, and
/// `PurchaseAttempt` is then a SUBSET of the `Sale` — the customer's own half
/// of it, with `cost`, `fee`, `vendor`, `cloud`, `market` and the tax rate left
/// behind rather than nulled out.
///
/// # Why the tenant is compared again after the scan
///
/// `references_with_prefix("<product>/<tenant>/")` is a STRING prefix, and a
/// gunnar namespace may itself contain a slash (`team/sub`), so the scan for
/// `gunnar/team/` also returns every reference of `gunnar/team/sub`. A prefix is
/// not an equality. The fold reads the tenant off the `Reserved` row's own copy
/// of the purchase — which is the authoritative name, not a substring of a key
/// — and the result is filtered on it exactly.
fn history_of(
    s: &AppState,
    product: &str,
    tenant: &str,
    limit: u32,
) -> Result<Vec<pb::PurchaseAttempt>, Status> {
    let mut references = s
        .ledger
        .references_with_prefix(&format!("{product}/{tenant}/"))
        .map_err(ledger_err)?;
    // The bound on the READ. The scan is ordered, and a reference sorts as
    // `<product>/<tenant>/<YYYY-MM-DD>+<caps>`, so the tail is the recent end:
    // a tenant with more attempts than this sees their newest and never their
    // first, which is the same trade `Ledger::recent_sales` already makes.
    if references.len() > HISTORY_SCAN_CEILING {
        references.drain(..references.len() - HISTORY_SCAN_CEILING);
    }
    let mut folded: Vec<monetize::ledger::Sale> = Vec::with_capacity(references.len());
    for reference in &references {
        let rows = s.ledger.rows(reference).map_err(ledger_err)?;
        // `at_unix_ms = 0`: the fold takes the attempt's own last row, which is
        // the honest instant here. `Sales` passes the time index's key instead,
        // because THERE the ordering key and the row must not disagree.
        if let Some(sale) = monetize::ledger::Sale::fold(reference, 0, &rows) {
            if sale.tenant == tenant {
                folded.push(sale);
            }
        }
    }
    // Newest first, by the attempt's last row — the same order `Sales` answers
    // in, and the same meaning: a give-back on a year-old purchase floats it up,
    // because that is when that purchase last moved.
    folded.sort_by_key(|a| std::cmp::Reverse(a.at_unix_ms));
    folded.truncate(clamp_limit(limit));
    Ok(folded.iter().map(attempt_to_pb).collect())
}

/// **The customer's half of a folded attempt.**
///
/// Field by field, never a blanket conversion from [`monetize::ledger::Sale`]:
/// `Sale` carries `cost`, `fee`, `vendor` and `cloud`, and the first version of
/// gunnar-ui's quote renderer passed a whole message through and put the
/// provider's cost in a browser. What is dropped is dropped HERE, where a new
/// field on `Sale` cannot arrive on the wire by default.
fn attempt_to_pb(s: &monetize::ledger::Sale) -> pb::PurchaseAttempt {
    pb::PurchaseAttempt {
        reference: s.reference.clone(),
        outcome: s.outcome.name().into(),
        // **The amount the customer can actually read.** `price` stays for the
        // operator console, which formats its own; this is the string a
        // customer-facing console renders verbatim because it may not format
        // one. One writer, so this and the quote cannot disagree.
        price_words: s.price.in_words(),
        at_unix_ms: s.at_unix_ms,
        started_unix_ms: s.started_unix_ms,
        caps: s.caps.clone(),
        delta: s.delta.clone(),
        // **The customer's own money and nothing beside it.** `price` is what
        // they were charged, which `QuoteResponse.price` already answers a
        // ticket-gated call with. `cost` is the provider's and `fee` is the
        // vendor's; together with `price` either one is a margin, and a margin
        // is not the customer's business.
        price: Some(money_to_pb(s.price)),
        steps: s.steps as u32,
    }
}

fn quote_to_pb(q: &Quote) -> pb::QuoteResponse {
    let p = &q.purchase;
    let (can_serve, reason, words) = match &q.serve {
        Ok(()) => (true, String::new(), String::new()),
        Err(r) => (false, r.to_string(), r.customer_words().to_owned()),
    };
    pb::QuoteResponse {
        reference: p.reference(),
        price: Some(money_to_pb(p.price)),
        // The same string `attempt_to_pb` puts on a history row, from the same
        // writer — so what a customer is quoted and what they later see they
        // were charged are formatted once, not twice.
        price_words: p.price.in_words(),
        cost: Some(money_to_pb(p.cost)),
        current: q.current.clone(),
        caps: p.caps.clone(),
        delta: p.delta.clone(),
        resources: p.resources.iter().map(resource_to_pb).collect(),
        can_serve,
        reason,
        period: p.policy.period.name().into(),
        words,
    }
}

#[tonic::async_trait]
impl Purchase for PurchaseService {
    /// What the order would come to. Pure: nothing reserved, nothing written.
    /// A downgrade or a no-op is `failed_precondition` — there is no quote for
    /// nothing — while a refusal by the product, the cloud or a ceiling is a
    /// quote with `can_serve = false` and the reason, because the price of what
    /// was refused is still what the operator wants to see.
    async fn quote(
        &self,
        req: Request<pb::QuoteRequest>,
    ) -> Result<Response<pb::QuoteResponse>, Status> {
        let caller = req.extensions().get::<Caller>().cloned();
        let site = site_of(&req);
        let r = req.into_inner();
        blocking(&self.0, move |s| {
            let site = site.as_deref();
            let mut r = r;
            let product = product_or_not_found(s, &r.product)?;
            scope_tenant(s, product.id(), site, &mut r.tenant)?;
            let market = market_of(s, r.market);
            // ★ A product that sells PLANS (`[pricing.<id>]`): the row, the
            // ticket, then the rule's price off the cached basis.
            if let Some(cfg) = s.plans.config(product.id()) {
                let sel = crate::plans::select(s, &cfg, product.id(), &r.tenant, plan_ask(r.renew, &r.bundle, &r.caps, r.starts_unix_ms)?)?;
                check_actor(s, product, &r.tenant, sel.purpose, &sel.ticket_caps, Asker { site, ticket: &r.actor_ticket, caller: caller.as_ref() })?;
                let q = crate::plans::quote(s, product, &cfg, &sel, market, None, false)?;
                return Ok(Response::new(quote_to_pb(&q)));
            }
            // **A BUNDLE BECOMES CAPS HERE, and then there is no bundle.**
            // Everything below sees the caps a typed order would have named, so
            // the two doors share the quote, the reference and the ledger rows.
            //
            // It reads the tenant's standing caps before the ticket is checked,
            // which is deliberate and is not a widening: nothing is priced,
            // written, reserved or dialled, and no byte of it leaves this
            // function unless the ticket then passes. The alternative — check
            // the ticket against an EMPTY cap map on this path — would let one
            // bundle's ticket buy another's.
            let caps = if r.bundle.is_empty() {
                r.caps.clone()
            } else {
                if r.renew {
                    return Err(Status::invalid_argument(
                        "a renewal names no bundle: it sells another period of what the tenant already holds, and a \
                         bundle is a RAISE. Send the bundle to order more room, or drop it to renew",
                    ));
                }
                caps_of_bundle(s, product, &r.tenant, &r.bundle, &r.caps, market)?
            };
            // Before the price is computed and before the product's control
            // plane is touched: a quote names a tenant's standing caps and what
            // they cost, which is not a thing a stranger may read.
            check_actor(s, product, &r.tenant, if r.renew { monetize_embed::PURPOSE_RENEW } else { monetize_embed::PURPOSE_ORDER }, &caps, Asker { site, ticket: &r.actor_ticket, caller: caller.as_ref() })?;
            let q = if r.renew {
                quote_renewal(s, product, &r.tenant, !r.caps.is_empty(), r.starts_unix_ms != 0, market, None)?
            } else {
                {
                    check_order_args(product, &r.tenant, &caps)?;
                    quote_order(s, product, &r.tenant, caps, market, r.starts_unix_ms, None).map_err(quote_status)?
                }
            };
            Ok(Response::new(quote_to_pb(&q)))
        })
        .await
    }

    /// **What this tenant can buy, priced.** Empty on a deployment that
    /// declared no bundles — not an error: the console falls back to the typed
    /// order, which is untouched by any of this.
    async fn bundles(
        &self,
        req: Request<pb::ListBundlesRequest>,
    ) -> Result<Response<pb::ListBundlesResponse>, Status> {
        let caller = req.extensions().get::<Caller>().cloned();
        let site = site_of(&req);
        let r = req.into_inner();
        let me = Arc::clone(&self.0);
        blocking(&self.0, move |s| {
            let site = site.as_deref();
            let mut r = r;
            let product = product_or_not_found(s, &r.product)?;
            scope_tenant(s, product.id(), site, &mut r.tenant)?;
            if r.tenant.is_empty() {
                return Err(Status::invalid_argument("tenant is required"));
            }
            // The same gate `Quote` has, and for the same reason: every price
            // below is on the delta over what THIS tenant holds, so an ungated
            // window would read a customer's standing caps back out of a price.
            // `PURPOSE_READ` and no caps — this call buys nothing and must not
            // be able to spend an order ticket.
            check_actor(
                s,
                product,
                &r.tenant,
                monetize_embed::PURPOSE_READ,
                &std::collections::BTreeMap::new(),
                Asker {
                    site,
                    ticket: &r.actor_ticket,
                    caller: caller.as_ref(),
                },
            )?;
            let market = market_of(s, r.market);
            // ★ A product that sells PLANS: the rule's rows and the plan's gauge.
            if let Some(cfg) = s.plans.config(product.id()) {
                return crate::plans::window(&me, product, &cfg, &r.tenant, market)
                    .map(Response::new);
            }
            Ok(Response::new(pb::ListBundlesResponse {
                bundles: bundles_of(s, product, &r.tenant, market)?,
                reading: false,
                plan: None,
            }))
        })
        .await
    }

    /// **Sell an order.** The same quote `Quote` makes, then the refusals it
    /// found, then the vendor for the price — nobody at price 0, the named one,
    /// or the only one serving the market — then `buy`.
    async fn start(
        &self,
        req: Request<pb::StartPurchaseRequest>,
    ) -> Result<Response<pb::StartPurchaseResponse>, Status> {
        let caller = req.extensions().get::<Caller>().cloned();
        let site = site_of(&req);
        let r = req.into_inner();
        blocking(&self.0, move |s| {
            let site = site.as_deref();
            let mut r = r;
            let product = product_or_not_found(s, &r.product)?;
            scope_tenant(s, product.id(), site, &mut r.tenant)?;
            // ★ A product served FREE sells nothing (wiring tracer B 2026-10-08): a sold estate's own
            // monetize (`[products.<id>] free = true`, fed as `plugin.<id>.free`) grants no order, no
            // renewal and no users — its owner buys at the shop that sold it.
            refuse_if_free(s, product.id())?;
            let market = market_of(s, r.market);
            // **"Add users"** is its own resolution into an order (or into no
            // order at all, when the unused room covers it).
            if let Some(users) = &r.users {
                return start_users(s, product, &r, users, market, caller.as_ref(), site).map(Response::new);
            }
            // ★ A product that sells PLANS (`[pricing.<id>]`, owner 2026-10-05):
            // the row is resolved, the ticket checked against it, and the
            // provider's price read NOW — a price under the floor at it is
            // refused before anything moves. Then the same transaction.
            if let Some(cfg) = s.plans.config(product.id()) {
                let sel = crate::plans::select(s, &cfg, product.id(), &r.tenant, plan_ask(r.renew, &r.bundle, &r.caps, r.starts_unix_ms)?)?;
                check_actor(s, product, &r.tenant, sel.purpose, &sel.ticket_caps, Asker { site, ticket: &r.actor_ticket, caller: caller.as_ref() })?;
                let payer = if r.payer.is_empty() { s.signups.email_of(product.id(), &r.tenant).ok().flatten() } else { Some(r.payer.clone()) };
                let quote = crate::plans::quote(s, product, &cfg, &sel, market, payer, true)?;
                return sell(s, product, &quote.purchase, market, &r.vendor).map(Response::new);
            }
            // **A BUNDLE BECOMES CAPS HERE, and then there is no bundle.**
            // Everything below sees the caps a typed order would have named, so
            // the two doors share the quote, the reference and the ledger rows.
            //
            // It reads the tenant's standing caps before the ticket is checked,
            // which is deliberate and is not a widening: nothing is priced,
            // written, reserved or dialled, and no byte of it leaves this
            // function unless the ticket then passes. The alternative — check
            // the ticket against an EMPTY cap map on this path — would let one
            // bundle's ticket buy another's.
            let caps = if r.bundle.is_empty() {
                r.caps.clone()
            } else {
                if r.renew {
                    return Err(Status::invalid_argument(
                        "a renewal names no bundle: it sells another period of what the tenant already holds, and a \
                         bundle is a RAISE. Send the bundle to order more room, or drop it to renew",
                    ));
                }
                caps_of_bundle(s, product, &r.tenant, &r.bundle, &r.caps, market)?
            };
            // FIRST, before the idempotency read, before the quote, before the
            // vendor: a refusal here must leave the ledger exactly as it found
            // it. See `check_actor`.
            check_actor(s, product, &r.tenant, if r.renew { monetize_embed::PURPOSE_RENEW } else { monetize_embed::PURPOSE_ORDER }, &caps, Asker { site, ticket: &r.actor_ticket, caller: caller.as_ref() })?;
            // **Who pays, when the caller named nobody**: the address the
            // tenant signed up with, so the vendor's page does not ask a
            // logged-in customer for it again (owner 2026-09-28: Stripe asked
            // for "E-postadress" on test2). A store error is not a refusal: the
            // page then asks, as it always did.
            let payer = if r.payer.is_empty() { s.signups.email_of(product.id(), &r.tenant).ok().flatten() } else { Some(r.payer.clone()) };
            // A retry of an order already filled: the quote would compute the
            // delta against caps the tenant now HOLDS and refuse it as a no-op,
            // but the reference it names is the attempt that filled it, and
            // that is the answer — the console that asks twice is the one
            // whose first request timed out after the money moved.
            //
            // A RENEWAL needs none of this: its quote never refuses, so the
            // request reaches `buy`, which short-circuits a filled reference on
            // its own.
            if !r.renew && !r.tenant.is_empty() {
                let starts = if r.starts_unix_ms == 0 { s.now() } else { r.starts_unix_ms };
                let order = Order { product: product.id().into(), tenant: TenantId(r.tenant.clone()), caps: caps.clone() };
                if let Some(filled) = s.transaction(product, monetize::no_vendor()).already_filled(&order, starts).map_err(|e| Status::internal(e.to_string()))? {
                    let Outcome::Paid { reference, fact } = filled else { unreachable!("already_filled answers Paid or nothing") };
                    return Ok(Response::new(pb::StartPurchaseResponse {
                        reference,
                        state: PurchaseState::Paid as i32,
                        handle_vendor: String::new(),
                        handle_id: String::new(),
                        redirect_url: String::new(),
                        reason: String::new(),
                        fact: Some(fact_to_pb(&fact)),
                        // An order that was already filled is still a granted
                        // order, and the customer asking again is usually the
                        // one who did not see the first answer. This branch is
                        // guarded by `!r.renew`, so it is an order by
                        // construction and never a renewal.
                        words: monetize::transaction::words::ORDER_GRANTED.to_owned(),
                        users: None,
                    }));
                }
            }
            let quote = if r.renew {
                quote_renewal(s, product, &r.tenant, !r.caps.is_empty(), r.starts_unix_ms != 0, market, payer)?
            } else {
                {
                    check_order_args(product, &r.tenant, &caps)?;
                    quote_order(s, product, &r.tenant, caps.clone(), market, r.starts_unix_ms, payer).map_err(quote_status)?
                }
            };
            if let Err(refusal) = &quote.serve {
                // The operator's reason to the log as well as to the caller: a
                // capacity refusal is something an operator has to act on (enlarge
                // a set, extend a filesystem), and the console is not always open.
                eprintln!("monetize-server: purchase refused for {}/{}: {refusal}", product.id(), r.tenant);
                // **THE REFUSAL A CUSTOMER MEETS AFTER PRESSING BUY.** The
                // window said this could be served and by the time the button
                // was pressed it could not — the store filled, a floor moved,
                // the appliance answered differently. That person has just
                // committed to a charge, so the one thing they must not be
                // handed is a sentence with the reason taken out of it.
                // `refused_status` sends the operator's words AND the
                // customer's; the console picks the one for its reader.
                return Err(refused_status(refusal));
            }
            let purchase = &quote.purchase;
            let vendor = s.registry.vendor_for_tenant(&purchase.price, market, product.id(), &purchase.tenant.0, &r.vendor).ok_or_else(|| {
                Status::not_found(no_vendor_words(purchase.price, market, &s.registry.route_said(product.id()), &r.vendor, &s.registry.vendor_names()))
            })?;
            let reference = purchase.reference();
            // ★ Round 5.3: an order past the room is QUEUED — said once, as INFO,
            // with its reference and the reason (never a refusal's WARN).
            if !r.renew {
                if let Some(why) = queued_past_the_wall(s, product, &quote, &caps) {
                    if let Some(line) = crate::oversell::queue_note(&reference, &format!("{}/{}", product.id(), r.tenant), &why) {
                        eprintln!("{line}");
                    }
                }
                // ★ UW-4: past the room of an estate that grows its own set when told.
                if let Some(line) = crate::grow::queue_past_room(s, product, &purchase.tenant, &caps) {
                    eprintln!("{line}");
                }
            }
            let v = run_and_report(s, product, vendor, purchase)?;
            let handle = s.ledger.attempt(&reference).map_err(ledger_err)?.map(|a| a.handle);
            // Only while the customer still has somewhere to go: a PAID or
            // DECLINED attempt with a checkout link on it is an invitation to
            // pay twice.
            let redirect_url = match (&handle, v.state) {
                (Some(h), PurchaseState::Pending) => redirect_url(s, vendor, h, &reference),
                _ => String::new(),
            };
            let (handle_vendor, handle_id) = handle.map(|h| (h.vendor, h.id)).unwrap_or_default();
            Ok(Response::new(pb::StartPurchaseResponse {
                reference: v.reference,
                state: v.state as i32,
                handle_vendor,
                handle_id,
                redirect_url,
                reason: v.reason,
                fact: v.fact.as_ref().map(fact_to_pb),
                // **Only when it was actually granted.** A PENDING attempt has
                // not raised anything yet — the customer is still at the
                // vendor — and a sentence saying the room is already theirs
                // would be the one untruth this field exists to prevent.
                words: match v.state {
                    PurchaseState::Paid => purchase.granted_words().to_owned(),
                    _ => String::new(),
                },
                users: None,
            }))
        })
        .await
    }

    async fn status(
        &self,
        req: Request<pb::PurchaseStatusRequest>,
    ) -> Result<Response<pb::PurchaseStatusResponse>, Status> {
        let caller = req.extensions().get::<Caller>().cloned();
        let site = site_of(&req);
        let r = req.into_inner();
        blocking(&self.0, move |s| {
            let site = site.as_deref();
            // **Whose order, first** — before the vendor is asked on anybody's
            // behalf and before a row is read. A `read` ticket: this buys
            // nothing and must not be able to spend another verb's.
            order_scope(s, site, &r.product, &r.tenant, &r.actor_ticket, monetize_embed::PURPOSE_READ, caller.as_ref())?.admits(s, &r.reference)?;
            // **Somebody is watching this order: ask the vendor now**, at most
            // every `ASK_VENDOR_EVERY` per reference, instead of leaving it to
            // the webhook or the poller's next pass. MEASURED on the KVM mock
            // 2026-09-28 (functest): a paid order whose webhook never came was
            // captured by the poller alone, 300 s after the payment — and for
            // those five minutes the customer back from the vendor's page was
            // shown `pending`, with the pay button. The same reconcile the
            // poller runs (`resume_reference`); a failure here is said and the
            // read goes on with what the ledger holds.
            if ask_vendor_due(&r.reference) {
                match resume_reference(s, &r.reference) {
                    Ok(Some(v)) if v.state != PurchaseState::Pending => eprintln!("monetize-server: status {}: the vendor was asked while the customer watched: {:?}", r.reference, v.state),
                    Ok(_) => {}
                    Err(e) => eprintln!("monetize-server: status {}: asking the vendor: {}", r.reference, e.message()),
                }
            }
            let rows = s.ledger.rows(&r.reference).map_err(ledger_err)?;
            let attempt = s.ledger.attempt(&r.reference).map_err(ledger_err)?;
            let (state, reason, fact) = match (&attempt, rows.last()) {
                (None, None) => (PurchaseState::Unknown, String::new(), None),
                (None, Some(last)) => match &last.step {
                    monetize::Step::Declined { reason, .. } => (PurchaseState::Declined, reason.clone(), None),
                    _ => (PurchaseState::Unknown, String::new(), None),
                },
                (Some(a), _) => match &a.closed {
                    None => (PurchaseState::Pending, if a.captured.is_some() { "captured, entitlement not yet pushed".into() } else { "reserved, awaiting the vendor".into() }, None),
                    Some(Closed::Released { reason }) => (PurchaseState::Released, reason.clone(), None),
                    Some(Closed::Pushed { fact }) => (PurchaseState::Paid, String::new(), Some(fact.clone())),
                },
            };
            // The link, still live, for an attempt that is still open. Asked of
            // the vendor on every read (see the proto): a session that has
            // expired at the vendor must stop being offered, and a vendor that
            // is no longer linked into this server has nothing to say.
            let redirect = match (&attempt, state) {
                (Some(a), PurchaseState::Pending) => s
                    .registry
                    .find_vendor(&a.handle.vendor)
                    .map(|v| redirect_url(s, v, &a.handle, &r.reference))
                    .unwrap_or_default(),
                _ => String::new(),
            };
            // "Add users": the grant (retried here if the paid order's grant
            // did not land), or the one waiting for its order; and, for a paid
            // order, where the room it bought stands in the grow queue.
            let product_id = r.reference.split('/').next().unwrap_or_default();
            let free_grant = if attempt.is_none() { users_granted_row(s, &r.reference).map_err(ledger_err)? } else { None };
            let (users, room) = if let Some(granted) = free_grant.clone() {
                // Granted from unused room: there is nothing to enlarge.
                (Some(granted), Some(pb::RoomProgress { state: "done".into(), words: monetize::transaction::progress::USERS_FROM_UNUSED.into() }))
            } else {
                let users = match (&attempt, state) {
                    (Some(a), PurchaseState::Paid) if a.purchase.users.is_some() => match s.registry.find_product(product_id) {
                        Some(p) => grant_paid_users(s, p, &r.reference)?,
                        None => None,
                    },
                    (Some(a), _) => a.purchase.users.as_ref().map(|ask| {
                        // A checkout that ended unpaid adds nobody: its names go.
                        if matches!(a.closed, Some(Closed::Released { .. })) {
                            forget_names(s, &r.reference);
                        }
                        pb::UsersGrant {
                        room_bytes: ask.room_bytes,
                        need_bytes: ask.room_bytes.saturating_mul(u64::from(ask.count.max(1))),
                        granted: false,
                        ..Default::default()
                        }
                    }),
                    _ => None,
                };
                let room = (state == PurchaseState::Paid).then(|| room_progress(s, product_id, &r.reference));
                (users, room)
            };
            let state = if free_grant.is_some() { PurchaseState::Paid } else { state };
            Ok(Response::new(pb::PurchaseStatusResponse {
                reference: r.reference,
                state: state as i32,
                reason,
                fact: fact.as_ref().map(fact_to_pb),
                rows: rows.iter().map(row_to_pb).collect(),
                redirect_url: redirect,
                users,
                room,
                cancellable: cancellable(attempt.as_ref()),
                abandonable: abandonable(attempt.as_ref()),
                phase: if free_grant.is_some() { pb::PurchasePhase::Done } else { phase_of(attempt.as_ref(), &rows) } as i32,
            }))
        })
        .await
    }

    /// **One tenant's own purchase history, folded.** See the proto for why it
    /// lives on `Purchase` and not on `Ledger`, and [`history_of`] for the read.
    async fn history(
        &self,
        req: Request<pb::PurchaseHistoryRequest>,
    ) -> Result<Response<pb::PurchaseHistoryResponse>, Status> {
        let caller = req.extensions().get::<Caller>().cloned();
        let site = site_of(&req);
        let r = req.into_inner();
        blocking(&self.0, move |s| {
            let site = site.as_deref();
            let mut r = r;
            let product = product_or_not_found(s, &r.product)?;
            scope_tenant(s, product.id(), site, &mut r.tenant)?;
            // FIRST, before a single key is read out of the ledger. A history
            // names what a tenant bought and for how much; a refusal must cost
            // nothing and must learn nothing.
            //
            // **`PURPOSE_READ`, and it names no caps.** A read buys nothing,
            // so there is no amount for its ticket to cover.
            //
            // This was a RENEWAL ticket for one commit — strictly narrower than
            // what that ticket authorises, so nothing could be done with it
            // that could not have been done anyway. It was still wrong: a
            // ticket is single-use, so listing a history burned the one the
            // customer would have renewed with, and the appliance was vouching
            // for a verb the caller was not performing. The same `check_actor`
            // is reused verbatim, so the operator path, the refusal words and
            // the "before anything" ordering are one piece of code on all four
            // calls.
            check_actor(
                s,
                product,
                &r.tenant,
                monetize_embed::PURPOSE_READ,
                &std::collections::BTreeMap::new(),
                Asker {
                    site,
                    ticket: &r.actor_ticket,
                    caller: caller.as_ref(),
                },
            )?;
            if r.tenant.is_empty() {
                return Err(Status::invalid_argument("tenant is required"));
            }
            Ok(Response::new(pb::PurchaseHistoryResponse {
                attempts: history_of(s, product.id(), &r.tenant, r.limit)?,
            }))
        })
        .await
    }

    /// Refund what was drawn, give back what was bought, close the attempt. See
    /// the proto for why this exists and why it is not idempotent.
    async fn abandon(
        &self,
        req: Request<pb::AbandonPurchaseRequest>,
    ) -> Result<Response<pb::AbandonPurchaseResponse>, Status> {
        let caller = req.extensions().get::<Caller>().cloned();
        let site = site_of(&req);
        let r = req.into_inner();
        blocking(&self.0, move |s| {
            let site = site.as_deref();
            if r.reason.trim().is_empty() {
                return Err(Status::invalid_argument("abandon needs a reason: a refund nobody can account for is not one worth making"));
            }
            // **Whose order** — a `cancel` ticket on the tenant path: ending
            // one's own open order, which for captured money is this refund.
            order_scope(s, site, &r.product, &r.tenant, &r.actor_ticket, monetize_embed::PURPOSE_CANCEL, caller.as_ref())?.admits(s, &r.reference)?;
            let attempt = s
                .ledger
                .attempt(&r.reference)
                .map_err(ledger_err)?
                .ok_or_else(|| Status::not_found(format!("no attempt was ever made for {}", r.reference)))?;
            let vendor = s.registry.find_vendor(&attempt.handle.vendor).ok_or_else(|| {
                Status::failed_precondition(format!(
                    "{} was reserved at {:?}, which is not linked into this server — the refund must be made where the money was taken",
                    r.reference, attempt.handle.vendor
                ))
            })?;
            let out = monetize::abandon_attempt(vendor.payment(), s.registry.cloud_for_transactions(), &s.ledger, s.now(), &r.reference, &r.reason)
                .map_err(|e| Status::failed_precondition(e.to_string()))?;
            skidbladnir::functional_status(
                "monetize-server/purchase",
                "abandon",
                true,
                &format!("{} refunded and closed, {} resource(s) released: {}", r.reference, out.destroyed.len(), r.reason),
            );
            Ok(Response::new(pb::AbandonPurchaseResponse {
                reference: r.reference,
                released: out.destroyed.iter().map(|id| format!("{}:{}", id.provider, id.id)).collect(),
            }))
        })
        .await
    }

    /// **Cancel an order nobody has paid for** — see the proto, and
    /// [`monetize::Transaction::cancel_reference`] for why the vendor is asked
    /// first and a payment always wins.
    async fn cancel(
        &self,
        req: Request<pb::CancelPurchaseRequest>,
    ) -> Result<Response<pb::CancelPurchaseResponse>, Status> {
        let caller = req.extensions().get::<Caller>().cloned();
        let site = site_of(&req);
        let r = req.into_inner();
        blocking(&self.0, move |s| {
            let site = site.as_deref();
            if r.reason.trim().is_empty() {
                return Err(Status::invalid_argument("cancel needs a reason: it is written into the ledger's Released row"));
            }
            order_scope(s, site, &r.product, &r.tenant, &r.actor_ticket, monetize_embed::PURPOSE_CANCEL, caller.as_ref())?.admits(s, &r.reference)?;
            let attempt = s
                .ledger
                .attempt(&r.reference)
                .map_err(ledger_err)?
                .ok_or_else(|| Status::not_found(format!("no order was ever placed under {}", r.reference)))?;
            let product = product_or_not_found(s, &attempt.purchase.product)?;
            let vendor = s.registry.find_vendor(&attempt.handle.vendor).ok_or_else(|| {
                Status::failed_precondition(format!(
                    "{} was reserved at {:?}, which is not linked into this server — the hold must be let go where it was taken",
                    r.reference, attempt.handle.vendor
                ))
            })?;
            // **One closer per reference at a time**, the same flight a webhook,
            // the poller and a watching `Status` take: a cancel racing the grant
            // of the same order must not write a close beside it.
            let flight = s
                .resuming
                .fly(&r.reference)
                .ok_or_else(|| Status::unavailable(format!("{}; ask again in a moment", IN_FLIGHT)))?;
            let done = s.transaction(product, vendor).cancel_reference(&r.reference, &r.reason);
            drop(flight);
            let (already_closed, state) = match done {
                Ok(monetize::Cancelled::Closed(o)) if matches!(*o, Outcome::ReleasedWithOrphans { .. }) => (false, PurchaseState::ReleasedWithOrphans),
                Ok(monetize::Cancelled::Closed(_)) => (false, PurchaseState::Released),
                Ok(monetize::Cancelled::AlreadyClosed) => (true, PurchaseState::Released),
                Err(monetize::CancelError::Paid { .. }) => {
                    // The capture is written down; finish the order as paid now
                    // rather than at the poller's next pass. A failure here is
                    // said and changes nothing about the answer.
                    if let Err(e) = resume_reference(s, &r.reference) {
                        eprintln!("monetize-server: cancel {}: finishing the paid order: {}", r.reference, e.message());
                    }
                    return Err(Status::failed_precondition(format!(
                        "{} has been paid, so it cannot be cancelled: it finishes as paid, and ending it now is a refund (Abandon)",
                        r.reference
                    )));
                }
                Err(e @ monetize::CancelError::Granted { .. }) => return Err(Status::failed_precondition(e.to_string())),
                Err(e @ monetize::CancelError::NoAttempt { .. }) => return Err(Status::not_found(e.to_string())),
                Err(monetize::CancelError::Tx(e)) => return Err(Status::unavailable(e.to_string())),
            };
            let rows = s.ledger.rows(&r.reference).map_err(ledger_err)?;
            let attempt = s.ledger.attempt(&r.reference).map_err(ledger_err)?;
            let reason = match attempt.as_ref().and_then(|a| a.closed.as_ref()) {
                Some(Closed::Released { reason }) => reason.clone(),
                _ => String::new(),
            };
            let released = rows
                .iter()
                .filter_map(|row| match &row.step {
                    monetize::Step::Destroyed { id, .. } => Some(format!("{}:{}", id.provider, id.id)),
                    _ => None,
                })
                .collect();
            if !already_closed {
                skidbladnir::functional_status("monetize-server/purchase", "cancel", true, &format!("{} cancelled: {}", r.reference, r.reason));
            }
            Ok(Response::new(pb::CancelPurchaseResponse {
                reference: r.reference,
                already_closed,
                state: state as i32,
                phase: phase_of(attempt.as_ref(), &rows) as i32,
                reason,
                released,
            }))
        })
        .await
    }
}

#[cfg(test)]
mod market_tests {
    /// ★ An order that names DK is priced in DK (DKK, 25 %) — never silently in
    /// the deployment's default market (owner 2026-09-28: holger sells in DK).
    #[test]
    fn an_order_naming_dk_is_a_danish_order() {
        use monetize_proto as pb;
        assert_eq!(
            super::market_of_wire(pb::Market::Dk as i32),
            Some(monetize_pay::Market::Dk)
        );
        assert_eq!(
            super::market_of_wire(pb::Market::Fi as i32),
            Some(monetize_pay::Market::Fi)
        );
        assert_eq!(
            super::market_of_wire(pb::Market::Unspecified as i32),
            None,
            "unnamed: the default applies"
        );
    }
}

#[cfg(test)]
mod site_operator_tests {
    //! ★ prod audit 2026-10-12 (S5): **a site's own console orders for its own account**.
    //! Through the ONE box the console presents its estate's bearer, which marks the call
    //! [`crate::auth::CallerEstate`] and never [`Caller::Door`]; the console's "more room"
    //! Quote/Start/Bundles carry no actor ticket (an operator ordering on a tenant's behalf,
    //! gunnar-ui `api::increase`), so every one was PERMISSION_DENIED live. The site's bearer is
    //! that site's operator door — scoped to the site's own accounts by `scope_tenant` — while
    //! an empty ticket through no door at all is still nobody.

    use monetize_proto as pb;
    use monetize_proto::purchase_server::Purchase as _;
    use tonic::Request;

    use super::*;

    fn state() -> Arc<AppState> {
        Arc::new(AppState::in_memory(
            crate::registry::Registry::new().product(monetize::testing::MockProduct::gunnar()),
        ))
    }

    fn quote(tenant: &str) -> pb::QuoteRequest {
        pb::QuoteRequest {
            product: "gunnar".into(),
            tenant: tenant.into(),
            caps: [("pack_bytes".to_string(), 10u64 << 30)].into(),
            ..Default::default()
        }
    }

    #[tokio::test]
    async fn a_sites_console_quotes_for_its_own_account_with_no_ticket() {
        let s = PurchaseService(state());
        let mut req = Request::new(quote("alice"));
        req.extensions_mut()
            .insert(crate::auth::CallerEstate("test2-gunnar-rs".into()));
        if let Err(e) = s.quote(req).await {
            assert_ne!(
                e.code(),
                tonic::Code::PermissionDenied,
                "the site's own console is its operator: {e:?}"
            );
        }
        let nobody = s
            .quote(Request::new(quote("alice")))
            .await
            .expect_err("an empty ticket through no door is nobody");
        assert_eq!(nobody.code(), tonic::Code::PermissionDenied, "{nobody:?}");
        let mut other = Request::new(quote("@other-site/alice"));
        other
            .extensions_mut()
            .insert(crate::auth::CallerEstate("test2-gunnar-rs".into()));
        assert_eq!(
            s.quote(other)
                .await
                .expect_err("another site's account")
                .code(),
            tonic::Code::PermissionDenied
        );
    }
}