From 89f1042b85ef43ed4f9fb3c6648797ead8e6fd0e Mon Sep 17 00:00:00 2001 From: ssmithx Date: Wed, 9 Sep 2026 13:58:19 +0000 Subject: [PATCH] fix(cuprate): gate package.restart and package.update too (review) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restart and update are stop + recreate — a fresh start by another name — but only start carried the disk gate, so on a disk that shrank below the floor after install, either action silently resumed the unprunable Monero sync: the exact failure the gate exists to close. Both now call check_cuprate_disk_compatibility after validate_app_id and BEFORE any state mutation (user-stopped clear / Restarting / Updating flip), matching handle_package_start's fail-clean contract. --- core/archipelago/src/api/rpc/package/async_lifecycle.rs | 6 ++++++ core/archipelago/src/api/rpc/package/runtime.rs | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/core/archipelago/src/api/rpc/package/async_lifecycle.rs b/core/archipelago/src/api/rpc/package/async_lifecycle.rs index 3c99a163..ada96e83 100644 --- a/core/archipelago/src/api/rpc/package/async_lifecycle.rs +++ b/core/archipelago/src/api/rpc/package/async_lifecycle.rs @@ -295,6 +295,12 @@ impl RpcHandler { .ok_or_else(|| anyhow::anyhow!("Missing package id"))? .to_string(); super::validation::validate_app_id(&package_id)?; + // Update is stop → pull → remove → recreate, i.e. a fresh start by + // another name: on a disk that shrank since install it would resume + // cuprate's unprunable sync unchecked. Same gate as install and + // start, run BEFORE the Updating flip so a refusal leaves the app + // cleanly in its previous state. + super::dependencies::check_cuprate_disk_compatibility(&package_id).await?; // Reject if already in a transitional lifecycle. { diff --git a/core/archipelago/src/api/rpc/package/runtime.rs b/core/archipelago/src/api/rpc/package/runtime.rs index 8e0c02a1..de627004 100644 --- a/core/archipelago/src/api/rpc/package/runtime.rs +++ b/core/archipelago/src/api/rpc/package/runtime.rs @@ -257,6 +257,11 @@ impl RpcHandler { .and_then(|v| v.as_str()) .ok_or_else(|| anyhow::anyhow!("Missing package id"))?; validate_app_id(package_id)?; + // Restart is stop + recreate, so on a disk that shrank below the cuprate + // minimum after install it resumes the doomed unprunable sync just like + // start would — same gate, same "fail before clearing user-stopped / + // flipping state" contract (see handle_package_start). + super::dependencies::check_cuprate_disk_compatibility(package_id).await?; let single_orchestrator_app = self.orchestrator.is_some() && uses_single_orchestrator_app(package_id);