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/estate_order/sold.rs

//! **A sold estate grows through its shop** (one shop, 2026-10-07).
//!
//! A private Gunnar sold here holds no cloud token: its disks are this shop's,
//! at this shop's provider account. Its data grows in three moves, and the
//! estate makes the last two.
//!
//! **G16-d (ONE monetize, G1-pull rows 17-18, 2026-10-10):** no estate runs a
//! monetize of its own, so nothing on the estate polls for its go-ahead. The
//! go-ahead is a SIGNED ORDER the estate's boxes pull, and each box asks for
//! its own disks over the same Fleet channel, with its own key:
//!
//! ```text
//!   the buyer pays a data step (ChangePlan, `change`) ──▶ captured
//!     ──▶ grant(): monetize SIGNS a go-ahead {estate, main GB a disk, until}
//!     ──▶ queued: order `grow_go_ahead{go_ahead, data_gib}` to the estate's
//!         main (main's paid size) and twin (main's whole set), good until
//!         the end of the paid period; a newer step supersedes an unacked one
//!   each box pulls it (Fleet.Orders) ──▶ verifies it under monetize's key
//!     ──▶ its own growth runs (drain, unmount — the twin first)
//!   its growth's cloud step ──▶ Fleet.Ask{grow_set, {members?, gib?}}
//!     ──▶ here (grow_own): the caller's fleet key and ROLE, its own LAID data
//!         disks only, no more than its role is paid, never smaller
//!         ──▶ grow_set at the provider (detach, resize, attach)
//!     ──▶ the sizes read back into the run: the renewal prices what is laid
//! ```
//!
//! The estate's own monetize once called `SoldEstate.GrowGoAhead`/`GrowSet`; no estate runs a
//! monetize, and both RPCs went in v2.0 P2 (T12 12.3, A28 H7). What stays is the live pulled
//! path above: the `grow_go_ahead` order, `Fleet.Ask{grow_set}` and the boxes' own executors.

use std::collections::BTreeSet;
use std::sync::Mutex;

use monetize::sign::{verify_estate_call, EstateCall, VerifyingKey};
use monetize_cloud::grow::{DataSet, GrowOutcome, SetSurvey, VolumeId};
use monetize_cloud::{CloudError, ServerId};

use monetize_embed::fleet::{kind, GrowGoAhead};
use monetize_guardian::Guardian;

use super::{iso_date, phase, EstateOrderConfig, EstateRun, EstateSizes, Transition};
use crate::state::AppState;

/// The one sentence a call that does not verify is answered with — an
/// unknown estate, an estate with no key, a wrong key, a stale call.
pub const NOT_SIGNED: &str = "the call is not signed by that estate's key";

/// The call words ([`EstateCall::call`]).
/// F4 (2026-10-09): lay ONE lost box of the estate again (the cloud half of a recharge).
pub const CALL_RECHARGE: &str = "recharge";
/// F4 (2026-10-09): upgrade ONE standing box in place from the release's keep medium.
pub const CALL_UPGRADE: &str = "upgrade";
/// F4 (2026-10-10): the estate TAKES its installer material from the shop (the pull; the shop
/// used to PUT it into the front's door — monetize never dials an estate).
pub const CALL_TAKE_MATERIAL: &str = "take-material";
/// How long after the buyer was told the shop holds a sold estate's installer material for it
/// to take ([`take_material`]) before the hand-off forgets it anyway.
pub const MATERIAL_TAKE_WITHIN_MS: u64 = 24 * 3600 * 1000;

/// **The go-ahead as the run keeps it**: the newest paid data step.
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct Growth {
    /// GB a data disk on main, as paid.
    pub main_data_gib: u64,
    /// Good until then: the end of the period it was paid in.
    pub until_ms: u64,
    /// The change it was paid on (`estate/<company>/change-<n>`).
    pub reference: String,
    pub granted_at_ms: u64,
    /// The signed JSON (`monetize_embed::signing::EstateGrowth`), as handed out.
    pub go_ahead: String,
}

/// Why a sold estate's call was not done.
#[derive(Debug, PartialEq, Eq)]
pub enum SoldRefusal {
    /// [`NOT_SIGNED`].
    NotSigned,
    /// Refused by name: the estate's own disks, sizes and money only.
    Refused(String),
    /// Transient: another growth of the same estate runs, the provider did not
    /// answer. Nothing was changed by this call.
    Unavailable(String),
}

/// **Who asks a sold estate's call, and how it was proven** (plan §8: SoldEstate folded into
/// Fleet, the ONE box serving both doors for one release).
#[derive(Clone, Copy, Debug)]
pub enum Caller<'a> {
    /// The old `SoldEstate` door: the call is an `EstateCall` signed by the estate's client key,
    /// verified here.
    Signed { at_ms: i64, signature: &'a [u8] },
    /// `Fleet.Ask` (a front's ask, [`monetize_embed::fleet::ask::FRONT`]): the Fleet door has
    /// already proven the call is the estate's front's ([`crate::fleet::front_ask`]).
    Fleet,
}

impl Caller<'_> {
    /// The run the call is about, once the call is proven: refused [`SoldRefusal::NotSigned`]
    /// (one sentence that names no estate) for an unknown, gone or never-laid estate either way.
    pub(super) fn run(
        &self,
        run: Option<&EstateRun>,
        call: &EstateCall,
        now: u64,
    ) -> Result<EstateRun, SoldRefusal> {
        match self {
            Caller::Signed { at_ms, signature } => verify(
                run,
                &EstateCall {
                    at_unix_ms: *at_ms,
                    ..call.clone()
                },
                signature,
                now,
            ),
            Caller::Fleet => run
                .filter(|r| !phase::is_gone(&r.phase) && r.laid.is_some())
                .cloned()
                .ok_or(SoldRefusal::NotSigned),
        }
    }
}

/// One data disk, as the estate is told it.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct DiskLine {
    pub member: String,
    /// `main` | `twin`.
    pub role: String,
    pub gib: u64,
    /// The size it may be grown to: what is paid.
    pub paid_gib: u64,
    pub server: String,
    pub state: String,
    pub attached: bool,
    pub address: String,
}

/// What a sold estate is told while the shop makes room for a paid growth
/// (A54): it asks again on its tick; no cap is named.
pub const GROWTH_WAITS: &str = "the shop is preparing this growth; ask again later";

/// [`grow_own`]'s answer.
#[derive(Clone, Debug)]
pub struct GrowSetAnswer {
    pub disks: Vec<DiskLine>,
    pub outcome: GrowOutcome,
    pub words: String,
}

/// **Sign and keep the go-ahead** for `gib` a disk on main: called once the
/// data step's money is captured. Good until the end of the paid period.
pub fn grant(state: &AppState, run: &mut EstateRun, gib: u64, reference: &str, now: u64) {
    let until = run.paid_until_ms;
    let product = match crate::fleet::run_product(state, run) {
        Ok(p) => p,
        Err(why) => {
            run.history.push(Transition {
                phase: String::new(),
                at_ms: now,
                note: format!(
                    "the growth go-ahead could not be signed for {}: {why}",
                    run.company
                ),
            });
            return;
        }
    };
    let bytes = state.signer_for(&product).sign_estate_growth(
        &run.company,
        gib,
        until as i64,
        reference,
        now as i64,
    );
    run.growth = Some(Growth {
        main_data_gib: gib,
        until_ms: until,
        reference: reference.to_string(),
        granted_at_ms: now,
        go_ahead: String::from_utf8(bytes).unwrap_or_default(),
    });
    run.history.push(Transition {
        phase: String::new(),
        at_ms: now,
        note: format!("the growth go-ahead is signed for {}: main's data to {gib} GB a disk, paid order {reference}, good until {}", run.company, iso_date(until)),
    });
    let note = match queue_go_ahead(state, run, now) {
        Ok(roles) => format!(
            "the go-ahead ({reference}) is queued for {}'s {} to pull",
            run.company,
            roles.join(" and ")
        ),
        Err(e) => {
            let words = format!(
                "the go-ahead ({reference}) was NOT queued for {}'s boxes: {e}",
                run.company
            );
            eprintln!("monetize-server: ALERT sold-estate.grow {words}");
            skidbladnir::functional_status(
                "monetize-server/sold-estate",
                "grow-go-ahead",
                false,
                &words,
            );
            words
        }
    };
    run.history.push(Transition {
        phase: String::new(),
        at_ms: now,
        note,
    });
}

/// **A captured renewal, as a signed order the estate pulls** (money-flow l): the paid step —
/// main's data at what is paid — is signed again for the NEW period and queued for the main
/// and the twin like any go-ahead ([`grant`]), so the boxes learn the term they are paid to
/// and a paid data step no longer lapses at the old end. A box already at size moves nothing.
/// An estate the fleet does not hold as sold (no guardian, another product) has nothing to
/// pull; that is noted, not alerted.
pub fn renewed(state: &AppState, run: &mut EstateRun, reference: &str, now: u64) {
    let held = crate::fleet::run_product(state, run)
        .ok()
        .is_some_and(|product| {
            state.fleet.guardian().is_some_and(|g| {
                g.store.product_of(run.fleet_name()).as_deref() == Some(product.as_str())
            })
        });
    if !held {
        run.history.push(Transition { phase: String::new(), at_ms: now, note: format!("renewal {reference}: no order is queued — the fleet does not hold {} as a sold estate", run.company) });
        return;
    }
    let gib = paid_main_gib(run, now);
    grant(state, run, gib, reference, now);
}

/// **The go-ahead as orders the estate pulls** (G16-d): one `grow_go_ahead` for each laid
/// box with data (main, twin), carrying what THAT role may grow to, signed by monetize's
/// key on the guardian's store, good until the go-ahead is. An unacked older one for the
/// same box is dropped. The roles queued.
fn queue_go_ahead(state: &AppState, run: &EstateRun, now: u64) -> Result<Vec<String>, String> {
    let g = state
        .fleet
        .guardian()
        .ok_or("the fleet store is not open")?;
    let cfg = state.estates.cfg.as_ref().ok_or("no [estate_orders]")?;
    let growth = run.growth.as_ref().ok_or("no go-ahead is signed")?;
    let product = crate::fleet::run_product(state, run)?;
    let product = product.as_str();
    if g.store.product_of(run.fleet_name()).as_deref() != Some(product) {
        return Err(format!(
            "the fleet does not know {} as a sold estate",
            run.company
        ));
    }
    let ttl = growth.until_ms.saturating_sub(now);
    let mut roles = Vec::new();
    for role in data_roles(cfg).iter().map(|d| d.role.as_str()) {
        if !run
            .laid
            .as_ref()
            .and_then(|l| l.machine(role))
            .is_some_and(|m| m.disks.len() > 1)
        {
            continue;
        }
        let body = serde_json::to_string(&GrowGoAhead {
            go_ahead: growth.go_ahead.clone(),
            data_gib: paid_gib_for(cfg, run, role, now),
        })
        .map_err(|e| e.to_string())?;
        let order = Guardian::order(
            product,
            &run.company,
            role,
            kind::GROW_GO_AHEAD,
            body,
            now,
            ttl,
        );
        g.queue_order(order, |o| o.kind == kind::GROW_GO_AHEAD && o.role == role)
            .map_err(|e| e.to_string())?;
        roles.push(role.to_string());
    }
    if roles.is_empty() {
        return Err("no laid box has a data disk".into());
    }
    Ok(roles)
}

/// **What main's data is paid to**, GB a disk: the run's price holds it (a
/// paid step's change sets it, the laid sizes read back raise it), or an open
/// go-ahead's when that is more.
pub fn paid_main_gib(run: &EstateRun, now: u64) -> u64 {
    let open = run
        .growth
        .as_ref()
        .filter(|g| g.until_ms > now)
        .map(|g| g.main_data_gib)
        .unwrap_or(0);
    run.quote.sizes.main_data_gib.max(open)
}

/// What a data disk of `role` may be grown to: main's paid size, or — the
/// twin's disk holding main's whole set — the twin's disk at that size.
fn paid_gib_for(cfg: &EstateOrderConfig, run: &EstateRun, role: &str, now: u64) -> u64 {
    let main = paid_main_gib(run, now);
    if !data_roles(cfg)
        .iter()
        .any(|d| d.role == role && d.mirrors_primary)
    {
        return main;
    }
    let sizes = EstateSizes {
        main_data_gib: main,
        ..run.quote.sizes.clone()
    };
    let Ok(plan) = super::lifecycle::lay_plan_of(cfg, &run.company, &sizes, &run.quote.twin_plan)
    else {
        return 0;
    };
    plan.machines
        .iter()
        .find(|m| m.role == role)
        .and_then(|m| m.disks.get(1))
        .map(|d| d.gib)
        .unwrap_or(0)
}

/// **The machines whose data a bought set grows** — the product's lifecycle's
/// ([`super::lifecycle::Lifecycle::data_roles`]), the primary first; none for a product
/// with no lifecycle.
fn data_roles(cfg: &EstateOrderConfig) -> Vec<super::lifecycle::DataRole> {
    super::lifecycle::of(cfg)
        .map(|l| l.data_roles())
        .unwrap_or_default()
}

/// Every data disk of the estate as recorded (main's and the twin's), each
/// with what it may be grown to.
fn recorded(cfg: &EstateOrderConfig, run: &EstateRun, now: u64) -> Vec<DiskLine> {
    let Some(laid) = run.laid.as_ref() else {
        return Vec::new();
    };
    let mut out = Vec::new();
    for role in data_roles(cfg).iter().map(|d| d.role.clone()) {
        let role = role.as_str();
        let Some(m) = laid.machine(role) else {
            continue;
        };
        let paid = paid_gib_for(cfg, run, role, now);
        for d in m.disks.iter().skip(1) {
            out.push(DiskLine {
                member: d.id.clone(),
                role: role.into(),
                gib: d.gib,
                paid_gib: paid,
                server: m.server.clone(),
                state: String::new(),
                attached: true,
                address: d.address.clone(),
            });
        }
    }
    out
}

/// The call verified under the run's client key, or [`SoldRefusal::NotSigned`].
pub(super) fn verify(
    run: Option<&EstateRun>,
    call: &EstateCall,
    signature: &[u8],
    now: u64,
) -> Result<EstateRun, SoldRefusal> {
    let run = run
        .filter(|r| !phase::is_gone(&r.phase) && r.laid.is_some())
        .ok_or(SoldRefusal::NotSigned)?;
    let key = client_key_of(run).ok_or(SoldRefusal::NotSigned)?;
    verify_estate_call(call, signature, &key, now as i64).map_err(|_| SoldRefusal::NotSigned)?;
    Ok(run.clone())
}

/// **The estate's client key** (the custody minted it at install; its public half on the run):
/// what its front signs with, on the old door and on `Fleet.Ask`. None: none kept, or no key.
pub fn client_key_of(run: &EstateRun) -> Option<VerifyingKey> {
    unhex32(&run.client_key).and_then(|k| VerifyingKey::from_bytes(&k).ok())
}

/// **The box that drives `run`'s update and asks the shop for its boxes** (the lifecycle's
/// `front_role`, on the site it was bought on): `front` for Gunnar and Holger.
pub fn front_role_of(state: &AppState, run: &EstateRun) -> String {
    let Some(cfg) = state.estates.cfg.as_ref() else {
        return "front".into();
    };
    let terms = super::terms_of(state, cfg, run).unwrap_or_else(|_| cfg.clone());
    super::lifecycle::of(&terms)
        .map(|l| l.update_plan().front_role)
        .unwrap_or_else(|_| "front".into())
}

fn unhex32(s: &str) -> Option<[u8; 32]> {
    let s = s.trim();
    if s.len() != 64 {
        return None;
    }
    let v: Option<Vec<u8>> = (0..64)
        .step_by(2)
        .map(|i| u8::from_str_radix(&s[i..i + 2], 16).ok())
        .collect();
    v?.try_into().ok()
}

/// The named members, all of ONE machine's laid data disks: its role.
fn one_machine(
    company: &str,
    lines: &[DiskLine],
    members: &[String],
) -> Result<(String, String), SoldRefusal> {
    let mut role: Option<(String, String)> = None;
    for m in members {
        let line = lines.iter().find(|l| &l.member == m).ok_or_else(|| {
            SoldRefusal::Refused(format!("{m} is not one of {company}'s laid data disks"))
        })?;
        match &role {
            None => role = Some((line.role.clone(), line.server.clone())),
            Some((r, _)) if *r != line.role => return Err(SoldRefusal::Refused(format!("the disks named are on two machines of {company} (main and twin): one call sizes one machine's"))),
            Some(_) => {}
        }
    }
    role.ok_or_else(|| SoldRefusal::Refused("no disk is named".into()))
}

/// The set to grow, under the product the box sells (OM-13: `[estate_orders] product`, never a
/// hard-coded "gunnar"), booked as `<product><suffix>` ([`super::lifecycle::DataRole::set_suffix`]:
/// the twin's `<product>-twin`).
pub(super) fn set_of_as(
    product: &str,
    suffix: &str,
    server: &str,
    members: &[String],
    gib: u64,
) -> DataSet {
    DataSet {
        product: format!("{product}{suffix}"),
        server: ServerId(server.to_string()),
        members: members.iter().map(|m| VolumeId(m.clone())).collect(),
        target_gib: gib,
    }
}

fn surveyed(lines: &[DiskLine], survey: &SetSurvey) -> Vec<DiskLine> {
    survey
        .volumes
        .iter()
        .filter_map(|v| {
            let mut l = lines.iter().find(|l| l.member == v.id.0)?.clone();
            l.gib = v.gib;
            l.state = v.state.clone();
            l.attached = v.attached;
            l.address = v.address.clone().unwrap_or_default();
            Some(l)
        })
        .collect()
}

/// One growth of one estate's disks at a time, here.
static GROWING: Mutex<BTreeSet<String>> = Mutex::new(BTreeSet::new());

struct Growing(String);

impl Drop for Growing {
    fn drop(&mut self) {
        GROWING
            .lock()
            .unwrap_or_else(|p| p.into_inner())
            .remove(&self.0);
    }
}

static RECHARGING: Mutex<BTreeSet<String>> = Mutex::new(BTreeSet::new());

struct Recharging(String);

impl Drop for Recharging {
    fn drop(&mut self) {
        RECHARGING
            .lock()
            .unwrap_or_else(|p| p.into_inner())
            .remove(&self.0);
    }
}

/// [`recharge`]'s answer: the machine as laid again (its new server and addresses).
#[derive(Clone, Debug)]
pub struct RechargeAnswer {
    pub machine: monetize_cloud::lay::LaidMachine,
    pub words: String,
}

/// **`SoldEstate.Recharge`: the cloud half of a recharge** (F4, the owner 2026-10-09). A sold
/// estate whose `main` or `twin` is LOST asks its shop to lay that ONE box again: the shop's
/// account holds its machines, the estate holds no cloud token. The estate re-admits the box
/// itself (its front, from the installer material in its own sealed slot); the shop lays it
/// from the release medium with `seed` as its user_data and answers where it stands.
///
/// Refused by name: a role that is not `main` or `twin`, an estate not delivered, and a box
/// that still STANDS at the provider (a standing box is upgraded, never laid again). `done`:
/// the box was re-admitted — the shop gives its release clone back and turns its metadata
/// off, as after the first hand-off. Signed by the estate's client key, the seed inside the
/// signed call.
pub fn recharge(
    state: &AppState,
    company: &str,
    role: &str,
    seed: &str,
    done: bool,
    at_ms: i64,
    signature: &[u8],
) -> Result<RechargeAnswer, SoldRefusal> {
    recharge_as(
        state,
        company,
        role,
        seed,
        done,
        Caller::Signed { at_ms, signature },
    )
}

/// [`recharge`], asked by `by` (the old door's signed call, or the front's `Fleet.Ask{recharge}`).
pub fn recharge_as(
    state: &AppState,
    company: &str,
    role: &str,
    seed: &str,
    done: bool,
    by: Caller<'_>,
) -> Result<RechargeAnswer, SoldRefusal> {
    let cfg = state.estates.cfg.as_ref().ok_or(SoldRefusal::NotSigned)?;
    let now = state.now();
    let carries = if done {
        String::new()
    } else {
        seed.to_string()
    };
    let call = EstateCall {
        v: 1,
        call: CALL_RECHARGE.into(),
        estate: company.to_string(),
        members: vec![role.to_string()],
        gib: u64::from(done),
        at_unix_ms: 0,
        carries,
    };
    let run = by.run(state.estates.get(company).as_ref(), &call, now)?;
    // ★ ST-5: named on the site the estate was bought on.
    let site_terms = super::terms_of(state, cfg, &run).unwrap_or_else(|_| cfg.clone());
    let cfg = &site_terms;
    let host = cfg.host_of(company);
    let again = super::lifecycle::of(cfg)
        .map_err(SoldRefusal::Refused)?
        .update_plan()
        .upgraded_by_shop;
    if !again.iter().any(|r| r == role) {
        return Err(SoldRefusal::Refused(format!(
            "{role:?} is not a box the shop lays again: {}",
            again.join(" or ")
        )));
    }
    if !phase::is_term(&run.phase) {
        return Err(SoldRefusal::Refused(format!(
            "{host} is not delivered ({}): nothing is laid again",
            run.phase
        )));
    }
    // An adopted site's machines are its kit's: a lost box is laid again by the kit.
    if super::adopt::is_adopted(&run) {
        return Err(SoldRefusal::Refused(super::adopt::not_laid_here(
            &run,
            &format!("laying its {role} again"),
        )));
    }
    let laid = run
        .laid
        .clone()
        .ok_or_else(|| SoldRefusal::Refused(format!("{host} has nothing laid")))?;
    let was = laid
        .machine(role)
        .cloned()
        .ok_or_else(|| SoldRefusal::Refused(format!("{host} has no {role} laid")))?;
    let cloud = state.registry.find_cloud(&cfg.cloud).ok_or_else(|| {
        SoldRefusal::Unavailable(format!("the shop's cloud {:?} is not linked", cfg.cloud))
    })?;
    let journal = state
        .estates
        .journal(company)
        .map_err(|e| SoldRefusal::Unavailable(format!("the lay journal: {e}")))?;
    {
        let mut g = RECHARGING.lock().unwrap_or_else(|p| p.into_inner());
        if !g.insert(company.to_string()) {
            return Err(SoldRefusal::Unavailable(format!(
                "a recharge of {host} is already running here"
            )));
        }
    }
    let _recharging = Recharging(company.to_string());
    if done {
        let only = monetize_cloud::lay::LaidEstate {
            machines: vec![was.clone()],
            ..laid.clone()
        };
        let gone = monetize_cloud::ask::forget_media(&cloud, &only, &journal).map_err(|e| {
            SoldRefusal::Unavailable(format!(
                "the release clone of {role} was not given back yet: {e}"
            ))
        })?;
        let mut words = format!(
            "{host}'s {role} is re-admitted: its release clone given back ({}), its metadata off",
            if gone.is_empty() {
                "none was left".into()
            } else {
                gone.join(", ")
            }
        );
        // RA5-37: a main's kept relay (the `mail_relay` refeed) lived on the lost box alone, and
        // the new one was re-admitted from its first lay's material: it is fed the relay of its
        // own product again, as `site refeed` feeds it.
        if role == "main" {
            match super::refeed::feed(
                state,
                company,
                &[super::refeed::group::MAIL_RELAY.to_string()],
            ) {
                Ok(asked) => words.push_str(&format!("; fed again: {}", asked.words)),
                Err(why) => words.push_str(&format!("; its mail relay was not fed again ({why})")),
            }
        }
        note(state, cfg, company, &words, now);
        return Ok(RechargeAnswer {
            machine: was,
            words,
        });
    }
    if seed.trim().is_empty() {
        return Err(SoldRefusal::Refused(
            "a box is laid again with its seed: none was sent".into(),
        ));
    }
    let id = monetize_cloud::ResourceId {
        provider: cloud.name().into(),
        id: was.server.clone(),
    };
    match monetize_cloud::ask::status(&cloud, &id) {
        Ok(monetize_cloud::ResourceStatus::Gone) | Err(CloudError::UnknownResource(_)) => {}
        // Down, not gone (CODE RED audit 4): started from its disk, never laid again.
        Ok(monetize_cloud::ResourceStatus::Stopped) => {
            let red = format!("recharge:{company}:{role}");
            if let Err(e) = monetize_cloud::ask::set_power(&cloud, &id, true) {
                let words = e.to_string();
                super::code_red::raise(state, &red, &host, role, &format!("the {role} is stopped at the provider and would not start"), &words, &format!("start {host}'s {role} from its disk at the provider, or ask the recharge again"));
                return Err(SoldRefusal::Unavailable(format!("{host}'s {role} is stopped at the provider and its start was refused: {words}")));
            }
            super::code_red::clear(state, &red);
            let words = format!("{host}'s {role} was stopped at the provider: started from its disk (nothing laid again)");
            note(state, cfg, company, &words, now);
            return Ok(RechargeAnswer { machine: was, words });
        }
        Ok(st) => return Err(SoldRefusal::Refused(format!("{host}'s {role} still stands at the provider ({st:?}): a standing box is upgraded, never laid again"))),
        Err(e) => return Err(SoldRefusal::Unavailable(format!("the provider could not say whether {host}'s {role} stands: {e}"))),
    }
    // The run's whole plan — the standing boxes are ADOPTED by their labels, nothing laid for
    // them — with the release's medium and the seed for THIS role only.
    let life = super::lifecycle::of(cfg).map_err(SoldRefusal::Refused)?;
    let mut plan = super::lifecycle::plan_of(
        life.as_ref(),
        cfg,
        company,
        &run.quote.sizes,
        &run.quote.twin_plan,
    )
    .map_err(SoldRefusal::Refused)?;
    for line in super::dress_plan(state, cfg, life.as_ref(), &mut plan, now)
        .map_err(SoldRefusal::Unavailable)?
    {
        if line.starts_with(&format!("{role}:")) {
            eprintln!("monetize-server: estate order {company}: {line}");
        }
    }
    for m in plan.machines.iter_mut() {
        if m.role == role {
            m.user_data = monetize_cloud::lay::UserData(seed.to_string());
        } else {
            m.medium.clear();
            m.medium_object = None;
            m.template.clear();
        }
    }
    let relaid = monetize_cloud::Cloud::lay(&cloud, &plan, &journal).map_err(|e| match e {
        CloudError::Refused(w) => SoldRefusal::Refused(format!(
            "the provider refused to lay {host}'s {role} again: {w}"
        )),
        other => SoldRefusal::Unavailable(format!("the provider: {other}")),
    })?;
    let now_m = relaid
        .machines
        .into_iter()
        .find(|m| m.role == role)
        .ok_or_else(|| SoldRefusal::Unavailable(format!("the provider laid no {role}")))?;
    let mut words = format!(
        "{host}'s {role} was laid again (it was gone at the provider): {} at {} / {}",
        now_m.server, now_m.public_ipv4, now_m.utility_ipv4
    );
    // MONETIZE-V2-REFEED-FLEET: the new box calls home with a NEW fleet key, named by nobody.
    // The lost box's key is forgotten and a pin window opened, as the guardian's own re-lay
    // does: the new box pins its key on its first call (every product, a Gunnar main as any).
    // The box stands either way: a failure here is said, never a refusal (that lays it twice).
    if let Some(g) = state.fleet.guardian() {
        let fleet = run.fleet_name();
        match g
            .store
            .forget_box(fleet, role)
            .and_then(|()| g.store.open_pin(fleet, role, now + g.cfg.pin_window_ms))
        {
            Ok(()) => words.push_str("; its key is pinned on its first call home"),
            Err(e) => {
                eprintln!("monetize-server: ALERT estate-orders.pin {company}: the new {role} was laid, but its pin window was not opened ({e}): `site open-pin` opens it");
                words.push_str(&format!("; its pin window was NOT opened ({e}): the operator opens it with `site open-pin`"));
            }
        }
    }
    {
        let Ok(_pen) = state.estates.pen_for_a_call(cfg, company) else {
            return Err(SoldRefusal::Unavailable(format!(
                "{host} is being worked on; ask again"
            )));
        };
        if let Some(mut r) = state.estates.get(company) {
            if let Some(l) = r.laid.as_mut() {
                if let Some(m) = l.machines.iter_mut().find(|m| m.role == role) {
                    *m = now_m.clone();
                }
            }
            r.history.push(Transition {
                phase: String::new(),
                at_ms: now,
                note: words.clone(),
            });
            // The box stands at the provider now: it is answered either way (a refusal would
            // lay it a second time), and an unwritten run is said loud for the operator.
            if let Err(e) = super::save(state, &r) {
                eprintln!("monetize-server: ALERT estate-orders.unwritten {}: {words}, but the run could not be written ({e}): its laid {role} is not named in run.json", r.reference);
            }
        }
    }
    eprintln!("monetize-server/sold-estate: {words}");
    Ok(RechargeAnswer {
        machine: now_m,
        words,
    })
}

/// One upgrade running here ([`super::EstateOrders::upgrading`]): its company, let go on drop.
struct Upgrading<'a>(
    &'a std::sync::Mutex<std::collections::BTreeSet<String>>,
    String,
);

impl Drop for Upgrading<'_> {
    fn drop(&mut self) {
        self.0
            .lock()
            .unwrap_or_else(|p| p.into_inner())
            .remove(&self.1);
    }
}

/// [`upgrade`]'s answer: whether the box was booted from the keep medium now (`false`: it
/// already runs this release, or `done` was recorded), and the machine as it stands.
#[derive(Clone, Debug)]
pub struct UpgradeAnswer {
    pub upgraded: bool,
    pub machine: monetize_cloud::lay::LaidMachine,
    pub words: String,
}

/// **`SoldEstate.Upgrade`: the cloud half of an in-place upgrade** (F4, 2026-10-09). A sold
/// estate's front asks its shop to boot ONE standing box (`main` or `twin`) once from the
/// release's KEEP medium ([`super::KEEP_MEDIUM`]): its system rewritten, its `/data` kept, the
/// box powered off by the medium and started again from its disk
/// ([`monetize_cloud::Cloud::keep_boot`]). The front re-admits it (`readmit_kept`)
/// and then calls `done`: the shop records that the box runs this release.
///
/// Answered `upgraded = false` (nothing done) when the box already runs this release. Refused by
/// name: another role, an estate not delivered, no update open on this box (F-U-02: the
/// operator's `UpdateEstate` alone opens one), a box that does NOT stand (a lost box is laid
/// again — `Recharge`), a release with no keep medium. Signed by the estate's client key.
pub fn upgrade(
    state: &AppState,
    company: &str,
    role: &str,
    done: bool,
    at_ms: i64,
    signature: &[u8],
) -> Result<UpgradeAnswer, SoldRefusal> {
    upgrade_as(
        state,
        company,
        role,
        done,
        Caller::Signed { at_ms, signature },
    )
}

/// [`upgrade`], asked by `by` (the old door's signed call, or the front's `Fleet.Ask{upgrade}`).
pub fn upgrade_as(
    state: &AppState,
    company: &str,
    role: &str,
    done: bool,
    by: Caller<'_>,
) -> Result<UpgradeAnswer, SoldRefusal> {
    let cfg = state.estates.cfg.as_ref().ok_or(SoldRefusal::NotSigned)?;
    let now = state.now();
    let call = EstateCall {
        v: 1,
        call: CALL_UPGRADE.into(),
        estate: company.to_string(),
        members: vec![role.to_string()],
        gib: u64::from(done),
        at_unix_ms: 0,
        carries: String::new(),
    };
    let run = by.run(state.estates.get(company).as_ref(), &call, now)?;
    // ★ ST-5: named on the site the estate was bought on.
    let site_terms = super::terms_of(state, cfg, &run).unwrap_or_else(|_| cfg.clone());
    // While an update is open, a box is upgraded to the release it was OPENED with (2026-10-17).
    let site_terms = match run.update.as_ref().filter(|u| u.is_open()) {
        Some(u) => super::update::as_opened(&site_terms, u),
        None => site_terms,
    };
    let cfg = &site_terms;
    let host = cfg.host_of(company);
    let plan = super::lifecycle::of(cfg)
        .map_err(SoldRefusal::Refused)?
        .update_plan();
    if !plan.upgraded_by_shop.iter().any(|r| r == role) {
        return Err(SoldRefusal::Refused(format!(
            "{role:?} is not a box the shop upgrades: {} (the {} upgrades last, by itself)",
            plan.upgraded_by_shop.join(" or "),
            plan.front_role
        )));
    }
    // F-U-02 (A17): only while the operator's update is on this very box (its data kept).
    super::update::upgrade_admits(&run, &host, role).map_err(SoldRefusal::Refused)?;
    let laid = run
        .laid
        .clone()
        .ok_or_else(|| SoldRefusal::Refused(format!("{host} has nothing laid")))?;
    let was = laid
        .machine(role)
        .cloned()
        .ok_or_else(|| SoldRefusal::Refused(format!("{host} has no {role} laid")))?;
    let release = super::release_id(cfg, &plan.app_medium);
    if done {
        let words = format!(
            "{host}'s {role} is re-admitted after its upgrade: it runs release {}",
            short(&release)
        );
        let Ok(_pen) = state.estates.pen_for_a_call(cfg, company) else {
            return Err(SoldRefusal::Unavailable(format!(
                "{host} is being worked on; ask again"
            )));
        };
        if let Some(mut r) = state.estates.get(company) {
            r.release_of.insert(role.to_string(), release.clone());
            r.history.push(Transition {
                phase: String::new(),
                at_ms: now,
                note: words.clone(),
            });
            super::save(state, &r).map_err(|e| {
                SoldRefusal::Unavailable(format!("the run was not saved: {e}; ask done again"))
            })?;
        }
        eprintln!("monetize-server/sold-estate: {words}");
        return Ok(UpgradeAnswer {
            upgraded: false,
            machine: was,
            words,
        });
    }
    if !release.is_empty() && run.release_of.get(role) == Some(&release) {
        return Ok(UpgradeAnswer {
            upgraded: false,
            words: format!(
                "{host}'s {role} already runs release {}: nothing to upgrade",
                short(&release)
            ),
            machine: was,
        });
    }
    let (now_m, words) = keep_boot_box(state, cfg, company, role, &laid, &plan.keep_medium, now)?;
    // ★ F-U-07 (A17): the box runs the kept release from here on, `done` or not. A front whose
    // re-admit or port wait fails before `done` asks again and is answered "already runs".
    if !release.is_empty() {
        match state.estates.pen_for_a_call(cfg, company) {
            Ok(_pen) => {
                if let Some(mut r) = state.estates.get(company) {
                    r.release_of.insert(role.to_string(), release.clone());
                    if let Err(e) = super::save(state, &r) {
                        eprintln!("monetize-server/sold-estate: ALERT sold-estate.keep-boot-unsaved {host}'s {role} was keep-booted to release {} but the run was NOT saved: {e}", short(&release));
                    }
                }
            }
            Err(_) => eprintln!("monetize-server/sold-estate: ALERT sold-estate.keep-boot-unsaved {host}'s {role} was keep-booted to release {} but the run is being worked on: recorded on `done`", short(&release)),
        }
    }
    Ok(UpgradeAnswer {
        upgraded: true,
        machine: now_m,
        words,
    })
}

/// **`role` of `company` booted once from the release's keep medium** (`keep_medium`, of `cfg` —
/// the release an open update was opened with), its system rewritten, its data kept, started
/// again from its disk: the shop's keep boot, for the front's `Upgrade` and for the ONE box's own
/// step of an update (F9). A box gone at the provider is refused (it is recharged, never
/// upgraded); a failure is raised CODE RED with how the box is left.
pub(crate) fn keep_boot_box(
    state: &AppState,
    cfg: &EstateOrderConfig,
    company: &str,
    role: &str,
    laid: &monetize_cloud::lay::LaidEstate,
    keep_medium: &str,
    now: u64,
) -> Result<(monetize_cloud::lay::LaidMachine, String), SoldRefusal> {
    let host = cfg.host_of(company);
    let was = laid
        .machine(role)
        .cloned()
        .ok_or_else(|| SoldRefusal::Refused(format!("{host} has no {role} laid")))?;
    let objects = super::presigned_objects(
        cfg,
        state.estates.custody.as_ref(),
        state.estates.media_key_fed.as_deref(),
        now / 1_000,
    )
    .map_err(SoldRefusal::Unavailable)?;
    let medium = cfg
        .media
        .get(keep_medium)
        .map(|u| u.trim().to_string())
        .unwrap_or_default();
    let medium_object = if medium.is_empty() {
        objects
            .get(keep_medium)
            .filter(|o| !o.url.trim().is_empty())
            .cloned()
    } else {
        None
    };
    if medium.is_empty() && medium_object.is_none() {
        return Err(SoldRefusal::Refused(format!("this shop's release names no `{keep_medium}` medium: a sold box is upgraded only from the release's keep medium")));
    }
    let cloud = state.registry.find_cloud(&cfg.cloud).ok_or_else(|| {
        SoldRefusal::Unavailable(format!("the shop's cloud {:?} is not linked", cfg.cloud))
    })?;
    let id = monetize_cloud::ResourceId {
        provider: cloud.name().into(),
        id: was.server.clone(),
    };
    match monetize_cloud::ask::status(&cloud, &id) {
        Ok(monetize_cloud::ResourceStatus::Gone) | Err(CloudError::UnknownResource(_)) => {
            return Err(SoldRefusal::Refused(format!("{host}'s {role} does not stand at the provider: a lost box is laid again (Recharge), never upgraded")));
        }
        Ok(_) => {}
        Err(e) => {
            return Err(SoldRefusal::Unavailable(format!(
                "the provider could not say whether {host}'s {role} stands: {e}"
            )))
        }
    }
    let journal = state
        .estates
        .journal(company)
        .map_err(|e| SoldRefusal::Unavailable(format!("the lay journal: {e}")))?;
    {
        let mut g = state
            .estates
            .upgrading
            .lock()
            .unwrap_or_else(|p| p.into_inner());
        if !g.insert(company.to_string()) {
            return Err(SoldRefusal::Unavailable(format!(
                "an upgrade of {host} {}",
                monetize_embed::fleet::UPGRADE_RUNNING
            )));
        }
    }
    let _upgrading = Upgrading(&state.estates.upgrading, company.to_string());
    let keep = monetize_cloud::lay::KeepBoot {
        reference: laid.reference.clone(),
        zone: laid.zone.clone(),
        machine: was,
        medium,
        medium_object,
    };
    let now_m = match monetize_cloud::ask::keep_boot(&cloud, &keep, &journal) {
        Ok(m) => {
            super::code_red::clear(state, &format!("upgrade:{company}:{role}"));
            m
        }
        Err(e) => {
            let refusal = match e {
                CloudError::Refused(w) => SoldRefusal::Refused(format!(
                    "the provider refused to upgrade {host}'s {role}: {w}"
                )),
                other => SoldRefusal::Unavailable(format!("the provider: {other}")),
            };
            let words = match &refusal {
                SoldRefusal::Refused(w) | SoldRefusal::Unavailable(w) => w.clone(),
                SoldRefusal::NotSigned => String::new(),
            };
            // How the box is left, read from the provider's words (CODE RED audit 2, 2026-10-18).
            let (what, next) = if words.contains("the medium left in") {
                (format!("the {role}'s keep medium did not finish in time: stopped hard with the medium in, its disk NOT booted"), format!("look at {host}'s {role} console at the provider: the medium may have half-written its system; boot its disk only after a human looked"))
            } else if words.contains("put back: the medium out") {
                (format!("the {role}'s keep upgrade failed; the box was put back on its disk and runs its old release"), "ask the update again".to_string())
            } else {
                (format!("the {role}'s keep upgrade failed: the box may be stopped or half-done"), format!("look at {host}'s {role} at the provider: start it from its disk if it is stopped, then ask the update again"))
            };
            super::code_red::raise(
                state,
                &format!("upgrade:{company}:{role}"),
                &host,
                role,
                &what,
                &words,
                &next,
            );
            return Err(refusal);
        }
    };
    let words = format!("{host}'s {role} was booted from the release's keep medium: its system upgraded, its data kept, started again at {} / {}", now_m.public_ipv4, now_m.utility_ipv4);
    note(state, cfg, company, &words, now);
    Ok((now_m, words))
}

/// Who asks a lost front back ([`restore_front`]). **Never the front itself**: a dead front
/// signs nothing, so the trigger is its buyer (signed in with the passkey, the account's
/// `estate` ticket) or the operator (a guardian Press).
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RestoreBy {
    /// The account the estate is a row on.
    Buyer(String),
    /// The operator's principal.
    Operator(String),
}

impl RestoreBy {
    fn words(&self) -> String {
        match self {
            RestoreBy::Buyer(a) => format!("its buyer ({a})"),
            RestoreBy::Operator(p) => format!("the operator ({p})"),
        }
    }
}

/// [`restore_front`]'s answer.
#[derive(Clone, Debug)]
pub struct RestoreAnswer {
    /// The front as it stands now.
    pub machine: monetize_cloud::lay::LaidMachine,
    /// `true`: a new server (new addresses; DNS written again, main and twin follow it).
    pub moved: bool,
    /// The backup it was restored from.
    pub backup: String,
    /// The boxes changed AFTER the backup was taken (a main or twin laid again, or upgraded):
    /// the restored front does not know them as they are now and re-admits them.
    pub stale: Vec<String>,
    pub words: String,
}

/// **What is left when no backup of the front stands** — the named fallback (OM-6): the
/// operator lays the front again from the release medium with a ONE-TIME token, the estate
/// re-admits it with its installer material (`admit_front`, `TakeMaterial`).
pub const RESTORE_FALLBACK: &str =
    "re-lay the front from the release medium with a one-time token (OM-6, the operator's)";

/// ★ ACCT-6 (2026-10-29): **a front silent this long needs repair.** A front that carries the
/// update taker asks every 2 minutes, and its ask is written down at most hourly
/// ([`super::update::TAKEN_KEPT_EVERY_MS`]): three hours unwritten is a front that stopped.
pub const FRONT_SILENT_MS: u64 = 3 * super::update::TAKEN_KEPT_EVERY_MS;

/// Pure: ★ ACCT-6 — **why this estate's front needs a repair** ([`restore_front`]), in the
/// words a purchase row shows; empty while it stands. Only a RUNNING estate (`captured` or
/// `grace`), laid here (never adopted), with a front, whose front once asked for its update
/// and has been silent past [`FRONT_SILENT_MS`]. A front that never asked (a release with no
/// taker) is unknown, not lost: no repair on a guess.
pub fn repair_words(run: &EstateRun, host: &str, now_ms: u64) -> String {
    let running = matches!(run.phase.as_str(), phase::CAPTURED | phase::GRACE);
    let has_front = run
        .laid
        .as_ref()
        .is_some_and(|l| l.machine("front").is_some());
    if !running || !has_front || super::adopt::is_adopted(run) || run.update_taken_at_ms == 0 {
        return String::new();
    }
    let silent = now_ms.saturating_sub(run.update_taken_at_ms);
    if silent <= FRONT_SILENT_MS {
        return String::new();
    }
    format!("{host}'s front has not answered for {} hours. Restore it from its daily backup, with its keys.", silent / 3_600_000)
}

static RESTORING: Mutex<BTreeSet<String>> = Mutex::new(BTreeSet::new());

struct Restoring(String);

impl Drop for Restoring {
    fn drop(&mut self) {
        RESTORING
            .lock()
            .unwrap_or_else(|p| p.into_inner())
            .remove(&self.0);
    }
}

/// **S8: a sold estate's lost FRONT restored from its daily backup** (BACKUP-AUDIT §3,
/// 2026-10-11). The front holds the estate's own keys (its CA, its link keys, the pins of
/// main and twin); S6 lays it with the provider's daily backup of its one disk, and a front
/// restored from that backup keeps every key — nothing is re-trusted, nothing re-paired, no
/// installer material taken again. The trigger is `by` — the buyer or the operator; the dead
/// front cannot sign its own request.
///
/// In place when its server stands (stopped, the backup written over its disk, started); made
/// again when it is gone (its disk from the backup, a new server, the estate's firewall written
/// for the new address, the estate's DNS written again here). Main and twin follow a moved
/// front by their own re-feed (gunnar's installer listener re-points its link).
///
/// Refused by name: an estate not running (`captured` or `grace`), no front laid, and an estate
/// whose main and twin have not been heard within the guardian's silence window — a front
/// alone is not restored into an estate that is down: the front does not report on Fleet, so
/// the boxes that do are the proof the rest stands (code, not the audit: the audit's "front
/// silent ≥ N min" cannot be read). No backup: refused naming [`RESTORE_FALLBACK`], nothing
/// changed. Boxes laid again or upgraded after the backup are named in [`RestoreAnswer::stale`].
pub fn restore_front(
    state: &AppState,
    company: &str,
    by: RestoreBy,
) -> Result<RestoreAnswer, SoldRefusal> {
    let cfg = state
        .estates
        .cfg
        .as_ref()
        .ok_or_else(|| SoldRefusal::Refused("this monetize sells no estates".into()))?;
    let now = state.now();
    let run = state
        .estates
        .get(company)
        .ok_or_else(|| SoldRefusal::Refused(format!("{company} is no sold estate here")))?;
    // ★ ST-5: named on the site the estate was bought on.
    let site_terms = super::terms_of(state, cfg, &run).unwrap_or_else(|_| cfg.clone());
    let cfg = &site_terms;
    let host = cfg.host_of(company);
    if !matches!(run.phase.as_str(), phase::CAPTURED | phase::GRACE) {
        return Err(SoldRefusal::Refused(format!(
            "{host} is not running ({}): its front is not restored",
            run.phase
        )));
    }
    if super::adopt::is_adopted(&run) {
        return Err(SoldRefusal::Refused(super::adopt::not_laid_here(
            &run,
            "restoring its front",
        )));
    }
    let laid = run
        .laid
        .clone()
        .ok_or_else(|| SoldRefusal::Refused(format!("{host} has nothing laid")))?;
    let update_plan = super::lifecycle::of(cfg)
        .map_err(SoldRefusal::Refused)?
        .update_plan();
    let front = update_plan.front_role.as_str();
    let was = laid
        .machine(front)
        .cloned()
        .ok_or_else(|| SoldRefusal::Refused(format!("{host} has no {front} laid")))?;
    let silent_after = state
        .fleet
        .guardian()
        .map(|g| g.cfg.silent_after_ms)
        .ok_or_else(|| {
            SoldRefusal::Unavailable(
                "the fleet store is not open: monetize cannot hear the estate".into(),
            )
        })?;
    let others: Vec<String> = laid
        .machines
        .iter()
        .filter(|m| m.role != front)
        .map(|m| m.role.clone())
        .collect();
    let heard = crate::fleet::heard_since(state, company, &others, now.saturating_sub(silent_after)).map_err(|e| {
        SoldRefusal::Refused(format!("{host}'s {} have not been heard in the last {} s ({e}): a {front} is restored only into an estate whose boxes stand", others.join(" and "), silent_after / 1_000))
    })?;
    let plan = super::lifecycle::lay_plan_of(cfg, company, &run.quote.sizes, &run.quote.twin_plan)
        .map_err(SoldRefusal::Refused)?;
    let (narrate_from, shape) = (plan.narrate_from.clone(), plan.shape.clone());
    let front_plan = plan
        .machines
        .into_iter()
        .find(|m| m.role == front)
        .ok_or_else(|| SoldRefusal::Unavailable(format!("{host}'s plan names no {front}")))?;
    let cloud = state.registry.find_cloud(&cfg.cloud).ok_or_else(|| {
        SoldRefusal::Unavailable(format!("the shop's cloud {:?} is not linked", cfg.cloud))
    })?;
    let journal = state
        .estates
        .journal(company)
        .map_err(|e| SoldRefusal::Unavailable(format!("the lay journal: {e}")))?;
    {
        let mut g = RESTORING.lock().unwrap_or_else(|p| p.into_inner());
        if !g.insert(company.to_string()) {
            return Err(SoldRefusal::Unavailable(format!(
                "a restore of {host}'s front is already running here"
            )));
        }
    }
    let _restoring = Restoring(company.to_string());
    let ask = monetize_cloud::lay::RestoreFromBackup {
        reference: laid.reference.clone(),
        zone: laid.zone.clone(),
        machine: was.clone(),
        plan: front_plan,
        narrate_from,
        shape,
    };
    let restored =
        monetize_cloud::ask::restore_from_backup(&cloud, &ask, &journal).map_err(|e| match e {
            CloudError::Refused(w) => SoldRefusal::Refused(format!(
                "the provider refused to restore {host}'s front: {w}"
            )),
            other => SoldRefusal::Unavailable(format!("the provider: {other}")),
        })?;
    let Some(restored) = restored else {
        return Err(SoldRefusal::Refused(format!("no backup of {host}'s front stands at the provider: nothing was changed; {RESTORE_FALLBACK}")));
    };
    let stale: Vec<String> = update_plan
        .upgraded_by_shop
        .iter()
        .map(String::as_str)
        .filter(|role| {
            run.history.iter().any(|t| {
                t.at_ms >= restored.backup_created_ms
                    && t.note.starts_with(&format!("{host}'s {role} "))
                    && (t.note.contains("was laid again")
                        || t.note.contains("booted from the release's keep medium"))
            })
        })
        .map(String::from)
        .collect();
    let now_m = restored.machine.clone();
    let dns = if restored.moved {
        let records = super::records_for(company, &cfg.apex, &now_m.public_ipv4)
            .map_err(SoldRefusal::Refused)?;
        match state.estates.dns_on(&run.estate).write(&records) {
            Ok(line) => Some((records, line)),
            Err(e) => {
                let words = format!("{host}'s front was restored from backup {} at a NEW server {} ({}), but its DNS was not written: {e}", restored.backup, now_m.server, now_m.public_ipv4);
                save_front(
                    state,
                    cfg,
                    company,
                    front,
                    &now_m,
                    None,
                    Transition {
                        phase: String::new(),
                        at_ms: now,
                        note: words.clone(),
                    },
                )?;
                return Err(SoldRefusal::Unavailable(words));
            }
        }
    } else {
        None
    };
    let mut words = format!(
        "{host}'s front was restored from its backup {} (taken {}), asked by {}; {}: its own keys kept, nothing re-trusted",
        restored.backup,
        if restored.backup_created_ms > 0 { iso_date(restored.backup_created_ms) } else { "at an unread time".into() },
        by.words(),
        if restored.moved { format!("made again at {} / {} (main and twin follow it)", now_m.public_ipv4, now_m.utility_ipv4) } else { format!("in place on {}", now_m.server) },
    );
    if let Some((_, line)) = &dns {
        words.push_str(&format!("; {line}"));
    }
    if !stale.is_empty() {
        words.push_str(&format!(
            "; changed after the backup, re-admit: {}",
            stale.join(", ")
        ));
    }
    words.push_str(&format!(" (heard: {})", heard.join(", ")));
    save_front(
        state,
        cfg,
        company,
        front,
        &now_m,
        dns.map(|(r, _)| r),
        Transition {
            phase: String::new(),
            at_ms: now,
            note: words.clone(),
        },
    )?;
    Ok(RestoreAnswer {
        machine: now_m,
        moved: restored.moved,
        backup: restored.backup,
        stale,
        words,
    })
}

/// The run names the front as it stands (and its DNS, when written again), with one line
/// (`line`, its history entry).
fn save_front(
    state: &AppState,
    cfg: &EstateOrderConfig,
    company: &str,
    role: &str,
    front: &monetize_cloud::lay::LaidMachine,
    dns: Option<Vec<super::DnsRecord>>,
    line: Transition,
) -> Result<(), SoldRefusal> {
    let words = line.note.clone();
    let host = cfg.host_of(company);
    let Ok(_pen) = state.estates.pen_for_a_call(cfg, company) else {
        return Err(SoldRefusal::Unavailable(format!(
            "{host} is being worked on; its restored front is not written down yet: {words}"
        )));
    };
    if let Some(mut r) = state.estates.get(company) {
        if let Some(m) = r
            .laid
            .as_mut()
            .and_then(|l| l.machines.iter_mut().find(|m| m.role == role))
        {
            *m = front.clone();
        }
        if let Some(d) = dns {
            r.dns = d;
            // DNS-WRITER: written again by the site's writer of now (`dns_on`, the restore's).
            r.dns_writer = state.estates.dns_name_on(&r.estate);
        }
        r.history.push(line);
        super::save(state, &r)
            .map_err(|e| SoldRefusal::Unavailable(format!("the run was not saved: {e}")))?;
    }
    eprintln!("monetize-server/sold-estate: {words}");
    Ok(())
}

/// [`take_material`]'s answer: the bundle (empty with `done`) and one sentence.
#[derive(Clone, Debug)]
pub struct MaterialAnswer {
    pub bundle: Vec<u8>,
    pub words: String,
}

/// Whether the hand-off's forget waits for the estate to take its installer material: the
/// pairing handed one back, the estate has not taken it, and the buyer was told less than
/// [`MATERIAL_TAKE_WITHIN_MS`] ago.
pub fn material_waits(custody: &crate::custody::Custody, run: &EstateRun, now: u64) -> bool {
    run.material_taken_at_ms == 0
        && now < run.told_tried_at_ms.saturating_add(MATERIAL_TAKE_WITHIN_MS)
        && custody
            .installer_material(&run.company)
            .ok()
            .flatten()
            .is_some()
}

/// **`SoldEstate.TakeMaterial`: the estate takes its own installer material** (F4, 2026-10-10).
/// The shop's pairing hands the bundle (the estate's CA and its key, the installer's
/// certificate, the link keys, the seeds, the ledger and the plan) back into the custody; the
/// sold estate's FRONT pulls it here, keeps it in its primary's sealed slot, and calls `done` —
/// only then does the hand-off forget it with the rest ([`material_waits`]). Before, the shop
/// PUT it into the front's door (`/slot/installer-material`): a call INTO an estate, gone.
///
/// Refused by name: an estate not paired nor delivered ([`material_admits`]), a shop with no custody, a bundle never handed
/// back or already forgotten. Signed by the estate's client key.
pub fn take_material(
    state: &AppState,
    company: &str,
    done: bool,
    at_ms: i64,
    signature: &[u8],
) -> Result<MaterialAnswer, SoldRefusal> {
    take_material_as(state, company, done, Caller::Signed { at_ms, signature })
}

/// [`take_material`], asked by `by` (the old door's signed call, or `Fleet.Ask{material}`).
pub fn take_material_as(
    state: &AppState,
    company: &str,
    done: bool,
    by: Caller<'_>,
) -> Result<MaterialAnswer, SoldRefusal> {
    let cfg = state.estates.cfg.as_ref().ok_or(SoldRefusal::NotSigned)?;
    let now = state.now();
    let call = EstateCall {
        v: 1,
        call: CALL_TAKE_MATERIAL.into(),
        estate: company.to_string(),
        members: Vec::new(),
        gib: u64::from(done),
        at_unix_ms: 0,
        carries: String::new(),
    };
    let run = by.run(state.estates.get(company).as_ref(), &call, now)?;
    // ★ ST-5: named on the site the estate was bought on.
    let site_terms = super::terms_of(state, cfg, &run).unwrap_or_else(|_| cfg.clone());
    let cfg = &site_terms;
    let host = cfg.host_of(company);
    material_admits(&run, &host).map_err(SoldRefusal::Refused)?;
    let custody = state.estates.custody.as_ref().ok_or_else(|| {
        SoldRefusal::Refused("this shop keeps no custody: it holds no installer material".into())
    })?;
    if done {
        let words =
            format!("{host} took its installer material: the shop forgets it at the hand-off");
        let Ok(_pen) = state.estates.pen_for_a_call(cfg, company) else {
            return Err(SoldRefusal::Unavailable(format!(
                "{host} is being worked on; ask again"
            )));
        };
        if let Some(mut r) = state.estates.get(company) {
            if r.material_taken_at_ms == 0 {
                r.material_taken_at_ms = now.max(1);
                r.history.push(Transition {
                    phase: String::new(),
                    at_ms: now,
                    note: words.clone(),
                });
                super::save(state, &r).map_err(|e| {
                    SoldRefusal::Unavailable(format!("the run was not saved: {e}; ask done again"))
                })?;
            }
        }
        eprintln!("monetize-server/sold-estate: {words}");
        return Ok(MaterialAnswer {
            bundle: Vec::new(),
            words,
        });
    }
    if run.secrets_forgotten_at_ms > 0 || !custody.holds(company) {
        return Err(SoldRefusal::Refused(format!("the shop forgot {host}'s secrets at the hand-off: its installer material is the estate's own (its primary's slot)")));
    }
    match custody.installer_material(company) {
        Ok(Some(b)) => Ok(MaterialAnswer { bundle: b.into_bytes(), words: format!("{host}'s installer material, as its pairing left it") }),
        Ok(None) => Err(SoldRefusal::Refused(format!("{host}'s pairing handed no installer material back (an estate paired before F4, or by the kit)"))),
        Err(e) => Err(SoldRefusal::Unavailable(format!("the custody: {e}"))),
    }
}

/// Pure: **may `run`'s front take its installer material in its phase?** (F8, 2026-10-21) A
/// delivered estate (`captured`, `grace`, `suspended`, `deleting`) does; so does a `paired` one —
/// every box PAIRED (its installer's PASS, or adopted on a re-check): the material is the
/// estate's own and its payment is held. Refused before, a paired estate could never take it:
/// its primary keeps none, so its update fails on the twin ("no installer material is kept in
/// … monetize-backup yet"), and its main reports — the capture — only after that update
/// (test3-holger-rs). The hand-off still forgets the custody's copy only once the estate is
/// delivered ([`material_waits`]). An install still running and every other phase (a terminated
/// estate among them) are refused by name. Gunnar's and Holger's alike: one lifecycle.
pub fn material_admits(run: &EstateRun, host: &str) -> Result<(), String> {
    if phase::is_term(&run.phase) || run.phase == phase::PAIRED {
        return Ok(());
    }
    if matches!(run.phase.as_str(), phase::LAYING | phase::INSTALLING) {
        return Err(format!("{host} is not delivered ({}): its install is still running, and no installer material is handed over before every box is PAIRED", run.phase));
    }
    Err(format!(
        "{host} is not delivered ({}): its installer material is taken once every box is PAIRED",
        run.phase
    ))
}

/// A release identity, short, for a sentence.
fn short(release: &str) -> &str {
    if release.is_empty() {
        "(unnamed)"
    } else {
        &release[..release.len().min(12)]
    }
}

/// One line in the run's history, under its pen.
fn note(state: &AppState, cfg: &EstateOrderConfig, company: &str, words: &str, now: u64) {
    let Ok(_pen) = state.estates.pen_for_a_call(cfg, company) else {
        return;
    };
    if let Some(mut r) = state.estates.get(company) {
        r.history.push(Transition {
            phase: String::new(),
            at_ms: now,
            note: words.to_string(),
        });
        if let Err(e) = super::save(state, &r) {
            eprintln!("monetize-server: ALERT estate-orders.unwritten {}: a history line could not be written ({e}): {words}", r.reference);
        }
    }
    eprintln!("monetize-server/sold-estate: {words}");
}

/// **`Fleet.Ask{grow_set}`** (G16-d): the calling box — already authenticated by its fleet
/// key as `role` of `company` — sizes ITS OWN laid data disks: `members` (none = all of
/// them) to `gib` a disk (0 = what its role is paid to): no more than is paid, never smaller, at
/// this shop's provider, and the sizes read back into the run.
pub fn grow_own(
    state: &AppState,
    company: &str,
    role: &str,
    members: &[String],
    gib: u64,
) -> Result<GrowSetAnswer, SoldRefusal> {
    let cfg = state
        .estates
        .cfg
        .as_ref()
        .ok_or_else(|| SoldRefusal::Unavailable("this monetize sells no estates".into()))?;
    let now = state.now();
    let run = state
        .estates
        .get(company)
        .filter(|r| !phase::is_gone(&r.phase) && r.laid.is_some())
        .ok_or_else(|| SoldRefusal::Refused(format!("{company} is no laid sold estate here")))?;
    // ★ ST-5: named on the site the estate was bought on.
    let site_terms = super::terms_of(state, cfg, &run).unwrap_or_else(|_| cfg.clone());
    let cfg = &site_terms;
    let own: Vec<String> = recorded(cfg, &run, now)
        .into_iter()
        .filter(|l| l.role == role)
        .map(|l| l.member)
        .collect();
    if own.is_empty() {
        return Err(SoldRefusal::Refused(format!(
            "the {role} of {company} has no laid data disk"
        )));
    }
    if let Some(m) = members.iter().find(|m| !own.contains(m)) {
        return Err(SoldRefusal::Refused(format!(
            "the {role} sizes its own data disks: {m} is not one of them"
        )));
    }
    let members = if members.is_empty() {
        own
    } else {
        members.to_vec()
    };
    let gib = if gib == 0 {
        paid_gib_for(cfg, &run, role, now)
    } else {
        gib
    };
    grow_verified(state, cfg, &run, company, &members, gib, now)
}

/// The caller is who it says: its named disks to `gib`, at the provider, read back.
fn grow_verified(
    state: &AppState,
    cfg: &EstateOrderConfig,
    run: &EstateRun,
    company: &str,
    members: &[String],
    gib: u64,
    now: u64,
) -> Result<GrowSetAnswer, SoldRefusal> {
    let lines = recorded(cfg, run, now);
    let (role, server) = one_machine(company, &lines, members)?;
    let host = cfg.host_of(company);
    let named: Vec<&DiskLine> = lines
        .iter()
        .filter(|l| members.contains(&l.member))
        .collect();
    let paid = paid_gib_for(cfg, run, &role, now);
    if gib > paid {
        return Err(SoldRefusal::Refused(format!(
            "{host}'s {role} data is paid to {paid} GB a disk; {gib} GB is bought at {} first",
            cfg.apex
        )));
    }
    if let Some(bigger) = named.iter().find(|l| l.gib > gib) {
        return Err(SoldRefusal::Refused(format!(
            "a disk never shrinks: {} is {} GB, and {gib} GB was asked",
            bigger.member, bigger.gib
        )));
    }
    let from = named.iter().map(|l| l.gib).min().unwrap_or(0);
    {
        let mut g = GROWING.lock().unwrap_or_else(|p| p.into_inner());
        if !g.insert(company.to_string()) {
            return Err(SoldRefusal::Unavailable(format!(
                "a growth of {host}'s disks is already running here"
            )));
        }
    }
    let _growing = Growing(company.to_string());
    let cloud = state.registry.find_cloud(&cfg.cloud).ok_or_else(|| {
        SoldRefusal::Unavailable(format!("the shop's cloud {:?} is not linked", cfg.cloud))
    })?;
    let dir = state
        .estates
        .run_dir(company)
        .ok_or_else(|| SoldRefusal::Unavailable("no estate-orders directory".into()))?;
    let journal = monetize_cloud::grow::Journal::open(dir.join(format!("grow-{role}.journal")))
        .map_err(|e| SoldRefusal::Unavailable(format!("the growth journal: {e}")))?;
    let suffix = data_roles(cfg)
        .into_iter()
        .find(|d| d.role == role)
        .map(|d| d.set_suffix)
        .unwrap_or_default();
    let set = set_of_as(&cfg.product, &suffix, &server, members, gib);
    // On the provider's estate lane: a sold estate's resize never holds the
    // shop's own purchases back (2026-10-08).
    let outcome = monetize_cloud::ask::grow(&cloud, &set, true, &journal).map_err(|e| match e {
        // **The shop's cap holds a PAID step back** (A54, the owner
        // 2026-10-08): the estate is told to ask again — UNAVAILABLE, in words
        // that name no cap — and the operator is told to raise it.
        CloudError::OverCap(w) => {
            super::cap_alert(
                &run.reference,
                &format!("{}: {w}", super::ORDERS_WAIT),
                false,
                state.now(),
            );
            SoldRefusal::Unavailable(GROWTH_WAITS.to_string())
        }
        CloudError::Refused(w) => SoldRefusal::Refused(format!("the provider refused: {w}")),
        other => SoldRefusal::Unavailable(format!("the provider: {other}")),
    })?;
    // What is laid now, as the provider answers it: read back into the run.
    let survey = monetize_cloud::ask::survey(
        &cloud,
        &DataSet {
            target_gib: 0,
            ..set.clone()
        },
    )
    .ok();
    let reference = run
        .growth
        .as_ref()
        .map(|g| g.reference.clone())
        .unwrap_or_else(|| run.reference.clone());
    let to = survey
        .as_ref()
        .map(|s| s.current_gib)
        .filter(|g| *g > 0)
        .unwrap_or(match &outcome {
            GrowOutcome::Done { to_gib, .. } => *to_gib,
            _ => from,
        });
    let words = match &outcome {
        GrowOutcome::Done { .. } if to > from => format!("{company} grew {role} data {from} → {to} GiB per disk, paid order {reference}"),
        GrowOutcome::Done { .. } => format!("{company}'s {role} data is {to} GiB per disk already (paid order {reference}): nothing to grow"),
        GrowOutcome::Partial { why, .. } => format!("{company}'s {role} data grew in part toward {gib} GiB per disk (paid order {reference}): {why}"),
        GrowOutcome::Untouched { why } => format!("{company}'s {role} data was not grown (paid order {reference}): {why}"),
    };
    eprintln!("monetize-server/sold-estate: {words}");
    skidbladnir::functional_status(
        "monetize-server/sold-estate",
        outcome.word(),
        !matches!(outcome, GrowOutcome::Untouched { .. }),
        &words,
    );
    if let Some(s) = survey.as_ref() {
        read_back(state, cfg, company, s, &words, now);
    }
    let disks = survey
        .as_ref()
        .map(|s| surveyed(&lines, s))
        .unwrap_or_else(|| named.into_iter().cloned().collect());
    Ok(GrowSetAnswer {
        disks,
        outcome,
        words,
    })
}

/// The provider's sizes into the run's laid disks (only ever up), and the
/// quoted data size with main's — under the run's pen.
fn read_back(
    state: &AppState,
    cfg: &EstateOrderConfig,
    company: &str,
    survey: &SetSurvey,
    words: &str,
    now: u64,
) {
    let Ok(_pen) = state.estates.pen_for_a_call(cfg, company) else {
        return;
    };
    let Some(mut run) = state.estates.get(company) else {
        return;
    };
    let Some(laid) = run.laid.as_mut() else {
        return;
    };
    let mut moved = false;
    for m in laid.machines.iter_mut() {
        for d in m.disks.iter_mut().skip(1) {
            if let Some(v) = survey.volumes.iter().find(|v| v.id.0 == d.id) {
                if v.gib > d.gib {
                    d.gib = v.gib;
                    moved = true;
                }
            }
        }
    }
    let primary = data_roles(cfg)
        .into_iter()
        .next()
        .map(|d| d.role)
        .unwrap_or_default();
    if let Some(main) = run.laid.as_ref().and_then(|l| l.machine(&primary)) {
        let smallest = main.disks.iter().skip(1).map(|d| d.gib).min().unwrap_or(0);
        if smallest > run.quote.sizes.main_data_gib {
            run.quote.sizes.main_data_gib = smallest;
        }
    }
    if moved {
        run.history.push(Transition {
            phase: String::new(),
            at_ms: now,
            note: words.to_string(),
        });
        if let Err(e) = super::save(state, &run) {
            eprintln!("monetize-server: ALERT estate-orders.unwritten {}: the survey's sizes could not be written ({e}): {words}", run.reference);
        }
    }
}

#[cfg(test)]
mod tests {
    /// ★ **OM-13: a grown set is booked under the product the box sells** —
    /// `grow/<product>/<server>`, the twin's `<product>-twin`.
    #[test]
    fn a_grown_set_is_booked_under_the_configured_product() {
        let set = super::set_of_as("gunnar-test2", "", "srv-1", &["v1".into()], 20);
        assert_eq!(
            (set.product.as_str(), set.resource_key()),
            ("gunnar-test2", "grow/gunnar-test2/srv-1".to_string())
        );
        assert_eq!(
            super::set_of_as("gunnar-test2", "-twin", "srv-2", &[], 0).product,
            "gunnar-test2-twin"
        );
    }
}