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 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-10 05:32:19 +02:00
commit ed5fc195d2
2 changed files with 61 additions and 28 deletions

View file

@ -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/<instance>/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";
/// `<root>/<instance>/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<PathBuf> {
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)?;

View file

@ -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}"),
}