From ed5fc195d2a81f0ca68dd5f415b8b25c7468743f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 10 Oct 2026 05:32:19 +0200 Subject: [PATCH] mind-body control: Released carries a Grant only read_effective makes The run cap and cadence leave the control reader only inside a Grant with private fields, so a cap cannot exist without a released brake and an in-bounds dial. effective() is private; its one caller is read_effective. Co-Authored-By: Claude Opus 5.5 --- crates/mind-body/src/control.rs | 59 ++++++++++++++++++++++--------- crates/mind-body/tests/control.rs | 30 +++++++++------- 2 files changed, 61 insertions(+), 28 deletions(-) diff --git a/crates/mind-body/src/control.rs b/crates/mind-body/src/control.rs index bf751e2..fa23015 100644 --- a/crates/mind-body/src/control.rs +++ b/crates/mind-body/src/control.rs @@ -1,5 +1,9 @@ //! The operator's brake and burn-rate dial, and the one reader of them. //! +//! `Released` carries a `Grant`, the only value that hands a run cap to the +//! launch: it cannot be built outside this module, so a cap exists only as the +//! reading of a released brake and an in-bounds dial. +//! //! State is a CultCache single-file store at //! `/etc/gamecult/minds//control.cc`, root-owned and world-readable. //! The operator's CLI replaces a document whole; every organ that acts calls @@ -39,9 +43,7 @@ pub const DIAL_KEY: &str = "dial"; /// `//control.cc`, after the leaf's slug grammar has passed, so /// an instance name cannot walk out of the root. pub fn control_path(root: &Path, instance: &Slug) -> Result { - instance - .validate_slug() - .map_err(|refusal| anyhow::anyhow!("instance {:?} is not a slug: {refusal:?}", instance.0))?; + instance.validate_slug().map_err(|refusal| anyhow::anyhow!("instance {:?} is not a slug: {refusal:?}", instance.0))?; Ok(root.join(&instance.0).join("control.cc")) } @@ -113,10 +115,36 @@ pub enum HeldReason { } /// What the operator's store allows right now. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] pub enum Effective { Held { reason: HeldReason }, - Released { cadence: Duration, run_cap_usd: Decimal }, + Released(Grant), +} + +/// The proof that the brake was released and the dial in bounds when read. Its +/// fields are private and only `read_effective` makes one; `open_and_launch` +/// takes it by value, so one reading opens at most one run. +#[derive(Debug, PartialEq, Eq)] +pub struct Grant { + cadence: Duration, + run_cap_usd: Decimal, +} + +impl Grant { + /// How often she may wake. + pub fn cadence(&self) -> Duration { + self.cadence + } + + /// The most one run may spend. + pub fn run_cap_usd(&self) -> Decimal { + self.run_cap_usd + } + + #[cfg(test)] + pub(crate) fn for_test(cadence: Duration, run_cap_usd: Decimal) -> Self { + Self { cadence, run_cap_usd } + } } /// The store's contents, decoded and not yet judged. @@ -129,18 +157,22 @@ pub struct ControlState { impl ControlState { /// The one derivation. Order: brake first, then dial; each failing rung is /// its own reason. - pub fn effective(&self) -> Effective { + fn effective(&self) -> Effective { let held = |reason| Effective::Held { reason }; - let Some(brake) = &self.brake else { return held(HeldReason::BrakeAbsent) }; + let Some(brake) = &self.brake else { + return held(HeldReason::BrakeAbsent); + }; if !brake.released { return held(HeldReason::BrakeHeld); } - let Some(dial) = &self.dial else { return held(HeldReason::DialAbsent) }; + let Some(dial) = &self.dial else { + return held(HeldReason::DialAbsent); + }; if !dial.in_bounds() { return held(HeldReason::DialOutOfBounds); } match (dial.cadence(), dial.run_cap_usd()) { - (Some(cadence), Some(run_cap_usd)) => Effective::Released { cadence, run_cap_usd }, + (Some(cadence), Some(run_cap_usd)) => Effective::Released(Grant { cadence, run_cap_usd }), _ => held(HeldReason::DialOutOfBounds), } } @@ -213,8 +245,7 @@ const FILE_MODE: u32 = 0o644; #[cfg(unix)] fn set_mode(path: &Path, mode: u32) -> Result<()> { use std::os::unix::fs::PermissionsExt; - std::fs::set_permissions(path, std::fs::Permissions::from_mode(mode)) - .with_context(|| format!("failed to set the mode of {}", path.display())) + std::fs::set_permissions(path, std::fs::Permissions::from_mode(mode)).with_context(|| format!("failed to set the mode of {}", path.display())) } /// A control path the writer will not write through: it is not root's, or @@ -326,11 +357,7 @@ impl ControlWriter { /// never holds one that the CLI put there. pub fn set_dial(&mut self, dial: BurnRate) -> Result<()> { if !dial.in_bounds() { - anyhow::bail!( - "dial refused: heat must be within {}..={}, base_cooldown_s above 0 and base_run_usd above 0", - heat_min(), - heat_max() - ); + anyhow::bail!("dial refused: heat must be within {}..={}, base_cooldown_s above 0 and base_run_usd above 0", heat_min(), heat_max()); } self.prepare()?; self.cache.put(DIAL_KEY, &dial)?; diff --git a/crates/mind-body/tests/control.rs b/crates/mind-body/tests/control.rs index 8ab013e..bfb66fd 100644 --- a/crates/mind-body/tests/control.rs +++ b/crates/mind-body/tests/control.rs @@ -96,7 +96,7 @@ fn an_undecodable_store_reads_as_held() { // The untouched store is still released, so the two reads above were the damage. std::fs::write(&path, &good).unwrap(); - assert!(matches!(effective(&path), Effective::Released { .. })); + assert!(matches!(effective(&path), Effective::Released(_))); } #[test] @@ -180,7 +180,7 @@ fn dial_bounds_are_inclusive_at_both_ends() { let path = released_store_unchecked(dir.path(), dial(heat, 3600, "1")); let got = effective(&path); if expected_in { - assert!(matches!(got, Effective::Released { .. }), "heat {heat}: {got:?}"); + assert!(matches!(got, Effective::Released(_)), "heat {heat}: {got:?}"); } else { assert_eq!(got, held(HeldReason::DialOutOfBounds), "heat {heat}"); } @@ -196,7 +196,7 @@ fn a_zero_base_cooldown_or_a_non_positive_run_cost_is_out_of_bounds() { } let dir = tempfile::tempdir().unwrap(); let smallest = released_store_unchecked(dir.path(), dial("1", 1, "0.000001")); - assert!(matches!(effective(&smallest), Effective::Released { .. })); + assert!(matches!(effective(&smallest), Effective::Released(_))); } fn released_store_unchecked(dir: &Path, bad: BurnRate) -> PathBuf { @@ -218,7 +218,9 @@ fn cadence_and_run_cap_are_the_dial_divided_and_multiplied_by_heat() { ] { let dir = tempfile::tempdir().unwrap(); let path = released_store(dir.path(), dial(heat, cooldown, run_usd)); - assert_eq!(effective(&path), Effective::Released { cadence, run_cap_usd: cap }, "heat {heat} cooldown {cooldown} run {run_usd}"); + let Effective::Released(grant) = effective(&path) else { panic!("heat {heat} cooldown {cooldown} run {run_usd}: not released") }; + assert_eq!(grant.cadence(), cadence, "heat {heat} cooldown {cooldown} run {run_usd}"); + assert_eq!(grant.run_cap_usd(), cap, "heat {heat} cooldown {cooldown} run {run_usd}"); } } @@ -226,7 +228,7 @@ fn cadence_and_run_cap_are_the_dial_divided_and_multiplied_by_heat() { fn the_operators_last_write_is_what_is_in_force_and_provenance_round_trips() { let dir = tempfile::tempdir().unwrap(); let path = released_store(dir.path(), dial("1", 3600, "1")); - assert!(matches!(effective(&path), Effective::Released { .. })); + assert!(matches!(effective(&path), Effective::Released(_))); ControlWriter::open(&path).unwrap().set_brake(false, at(60), "alice").unwrap(); assert_eq!(effective(&path), held(HeldReason::BrakeHeld)); @@ -237,7 +239,7 @@ fn the_operators_last_write_is_what_is_in_force_and_provenance_round_trips() { assert_eq!(state.dial.unwrap().set_by, "op"); ControlWriter::open(&path).unwrap().set_brake(true, at(120), "bob").unwrap(); - assert!(matches!(effective(&path), Effective::Released { .. })); + assert!(matches!(effective(&path), Effective::Released(_))); let brake = load_state(&FileSource::new(&path)).unwrap().brake.unwrap(); assert_eq!((brake.released, brake.set_at, brake.set_by.as_str()), (true, at(120), "bob")); } @@ -283,7 +285,7 @@ fn reading_writes_nothing_and_takes_no_lock_file() { } } let before = (listing(dir.path()), std::fs::read(&path).unwrap()); - assert!(matches!(effective(&path), Effective::Released { .. })); + assert!(matches!(effective(&path), Effective::Released(_))); assert_eq!((listing(dir.path()), std::fs::read(&path).unwrap()), before); } @@ -348,7 +350,9 @@ mod modes { /// nothing, so a plain run of the suite passes it vacuously. #[test] fn mode_child() { - let Ok(role) = std::env::var(CHILD) else { return }; + let Ok(role) = std::env::var(CHILD) else { + return; + }; let instance = std::env::var("MIND_BODY_INSTANCE").unwrap_or_else(|_| "eureka".into()); let path = Path::new(&std::env::var(ROOT).unwrap()).join(instance).join("control.cc"); match role.as_str() { @@ -386,12 +390,14 @@ mod modes { } "intruder" => { assert!(ControlWriter::open(&path).and_then(|mut writer| writer.set_brake(false, at(1), "intruder")).is_err()); - assert!(ControlWriter::open(Path::new(&std::env::var(ROOT).unwrap()).join("ghost").join("control.cc")) - .and_then(|mut writer| writer.set_brake(true, at(1), "intruder")) - .is_err()); + assert!( + ControlWriter::open(Path::new(&std::env::var(ROOT).unwrap()).join("ghost").join("control.cc")) + .and_then(|mut writer| writer.set_brake(true, at(1), "intruder")) + .is_err() + ); assert!(std::fs::OpenOptions::new().write(true).open(&path).is_err()); assert!(std::fs::OpenOptions::new().write(true).open(path.with_file_name("control.cc.lock")).is_err()); - assert!(matches!(effective(&path), Effective::Released { .. }), "a non-root user can still read the store"); + assert!(matches!(effective(&path), Effective::Released(_)), "a non-root user can still read the store"); } other => panic!("unknown role {other}"), }