mind-body: the reader takes the instance only; the control root is a constant a caller cannot supply

read_effective(instance) reads CONTROL_ROOT/<instance>/control.cc. The root override is a thread-local under cfg(test) inside the crate; the reader tests and the Grant launch tests move in-crate to use it. The operator CLI's show derives its display line from the store it already read. An external forge probe and compile_fail examples pin the rule; the instance gate is pinned with same-length, prefix and extension forgeries, and the Persona refusal with a claim of every kind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-10 09:05:22 +02:00
commit 3fac90076d
7 changed files with 576 additions and 407 deletions

View file

@ -18,7 +18,7 @@ use chrono::{DateTime, Utc};
use eureka_pipeline::Slug;
use rust_decimal::Decimal;
use crate::control::{BurnRate, ControlWriter, FileSource, control_path, load_state, read_effective};
use crate::control::{BurnRate, ControlWriter, FileSource, control_path, derive, load_state};
const USAGE: &str =
"usage: mind-control [--root <dir>] --instance <slug> show | brake hold | brake release | dial set --heat H --base-cooldown-s S --base-run-usd U";
@ -120,6 +120,6 @@ fn show(root: &Path, instance: &Slug, out: &mut impl Write) -> Result<()> {
}
Err(error) => writeln!(out, "store: undecodable ({error:#})")?,
}
writeln!(out, "effective: {:?}", read_effective(root, instance))?;
writeln!(out, "effective: {:?}", derive(&source, instance))?;
Ok(())
}

View file

@ -3,9 +3,11 @@
//! `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. The Grant names the
//! instance whose store was read, and that store's path is derived from the
//! instance here, by the one reader: no caller supplies a path or a source, so
//! a Grant is the proof that this instance's own root-owned store released.
//! instance whose store was read. The store is at a fixed place, `CONTROL_ROOT`,
//! and the one reader takes the instance only: no function, argument, variable
//! or flag lets a caller choose a root, a path or a source, so a Grant is the
//! proof that this instance's own root-owned store released. Only a
//! `#[cfg(test)]` override inside this crate moves the root.
//!
//! State is a CultCache single-file store at
//! `/etc/gamecult/minds/<instance>/control.cc`, root-owned and world-readable.
@ -35,8 +37,8 @@ use eureka_pipeline::Slug;
use rust_decimal::Decimal;
use rust_decimal::prelude::ToPrimitive;
/// Where every instance's control directory lives. Tests and the library never
/// touch it: the root is a parameter.
/// Where every instance's control directory lives. The reader reads only here;
/// the operator's CLI takes its own `--root` for writing and display.
pub const CONTROL_ROOT: &str = "/etc/gamecult/minds";
/// The one key each control document has in the store.
@ -170,7 +172,7 @@ pub struct ControlState {
impl ControlState {
/// The one derivation. Order: brake first, then dial; each failing rung is
/// its own reason.
fn effective(&self, instance: &Slug) -> Effective {
pub(crate) fn effective(&self, instance: &Slug) -> Effective {
let held = |reason| Effective::Held { reason };
let Some(brake) = &self.brake else {
return held(HeldReason::BrakeAbsent);
@ -233,45 +235,85 @@ pub fn load_state(source: &impl ControlSource) -> Result<ControlState> {
}
/// The only reader every organ uses (the waker now; the permit issuer and the
/// Persona organ later). The store is `instance`'s own, at the path
/// `control_path` derives under `root`; the caller supplies neither a path nor
/// a source. An instance that is not a slug reads as held.
pub fn read_effective(root: &Path, instance: &Slug) -> Effective {
match control_path(root, instance) {
/// Persona organ later). The store is `instance`'s own at
/// `CONTROL_ROOT/<instance>/control.cc`; the caller supplies neither a root, a
/// path nor a source. An instance that is not a slug reads as held.
///
/// Nothing outside this crate can name another place:
///
/// ```compile_fail
/// use eureka_pipeline::Slug;
/// // a root is not an argument
/// let _ = mind_body::control::read_effective(std::path::Path::new("/tmp"), &Slug("eureka".into()));
/// ```
///
/// ```compile_fail
/// // there is no reader over a source of the caller's
/// let _ = mind_body::control::read_effective_from;
/// ```
///
/// ```compile_fail
/// use mind_body::control::Grant;
/// // a Grant cannot be written out
/// let _ = Grant { instance: eureka_pipeline::Slug("eureka".into()), cadence: std::time::Duration::ZERO, run_cap_usd: rust_decimal::Decimal::ONE };
/// ```
///
/// ```compile_fail
/// // and the test constructor is not in the library build
/// let _ = mind_body::control::Grant::for_test;
/// ```
///
/// The same preamble with the real call compiles:
///
/// ```
/// use eureka_pipeline::Slug;
/// let _ = mind_body::control::read_effective(&Slug("eureka".into()));
/// ```
pub fn read_effective(instance: &Slug) -> Effective {
match control_path(&control_root(), instance) {
Ok(path) => derive(&FileSource::new(path), instance),
Err(_) => Effective::Held { reason: HeldReason::Undecodable },
}
}
fn derive(source: &impl ControlSource, instance: &Slug) -> Effective {
#[cfg(not(test))]
fn control_root() -> PathBuf {
PathBuf::from(CONTROL_ROOT)
}
/// The test seam: this crate's own tests move the root for their thread. It
/// does not exist in a library build, and it is not a cargo feature.
#[cfg(test)]
thread_local! {
static TEST_ROOT: std::cell::RefCell<Option<PathBuf>> = const { std::cell::RefCell::new(None) };
}
#[cfg(test)]
fn control_root() -> PathBuf {
TEST_ROOT.with(|root| root.borrow().clone()).unwrap_or_else(|| PathBuf::from(CONTROL_ROOT))
}
/// Runs `body` with the reader pointed at `root` on this thread.
#[cfg(test)]
pub(crate) fn with_root<T>(root: &Path, body: impl FnOnce() -> T) -> T {
let before = TEST_ROOT.with(|cell| cell.replace(Some(root.to_path_buf())));
let result = body();
TEST_ROOT.with(|cell| cell.replace(before));
result
}
/// The derivation over any source. The reader and the CLI's `show` (display
/// only: its output is text) are its callers; nothing public returns its result
/// for a source of the caller's.
pub(crate) fn derive(source: &impl ControlSource, instance: &Slug) -> Effective {
match load_state(source) {
Ok(state) => state.effective(instance),
Err(_) => Effective::Held { reason: HeldReason::Undecodable },
}
}
/// The same derivation over a fake store, for tests of the reader; the Grant it
/// makes names the instance given, and the launch judges that like any other.
#[cfg(test)]
pub(crate) fn read_effective_from(source: &impl ControlSource, instance: &Slug) -> Effective {
derive(source, instance)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_source_that_fails_reads_as_held() {
struct Failing;
impl ControlSource for Failing {
fn snapshot(&self) -> Result<Vec<CultCacheEnvelope>> {
Err(anyhow::anyhow!("disk gone"))
}
}
assert_eq!(read_effective_from(&Failing, &Slug("eureka".into())), Effective::Held { reason: HeldReason::Undecodable });
}
}
mod tests;
/// The operator's writer over one control file. Each setter replaces its
/// document whole; the other document is untouched. The file is created on the

View file

@ -0,0 +1,414 @@
//! The reader's tests, in the crate because they move the reader's root with
//! the `#[cfg(test)]` seam: no caller outside the crate can. Every test works in
//! a temporary directory through the same file door the units use; nothing
//! touches `/etc`. They run as root in the verify container like the writer's.
use std::path::{Path, PathBuf};
use std::time::Duration;
use chrono::{DateTime, TimeZone, Utc};
use cultcache_rs::{CultCache, DatabaseEntry, SingleFileMessagePackBackingStore};
use eureka_pipeline::Slug;
use rust_decimal::Decimal;
use std::str::FromStr;
use super::*;
fn dec(text: &str) -> Decimal {
Decimal::from_str(text).unwrap()
}
fn at(seconds: i64) -> DateTime<Utc> {
Utc.timestamp_opt(1_800_000_000 + seconds, 0).unwrap()
}
fn dial(heat: &str, cooldown: u32, run_usd: &str) -> BurnRate {
BurnRate { heat: dec(heat), base_cooldown_s: cooldown, base_run_usd: dec(run_usd), set_at: at(0), set_by: "op".into() }
}
/// The store of the instance `eureka` under the root `dir`.
fn store_path(dir: &Path) -> PathBuf {
dir.join("eureka").join("control.cc")
}
fn held(reason: HeldReason) -> Effective {
Effective::Held { reason }
}
/// A written store: brake released and the given dial, through the real writer.
fn released_store(dir: &Path, dial: BurnRate) -> PathBuf {
let path = store_path(dir);
let mut writer = ControlWriter::open(&path).unwrap();
writer.set_brake(true, at(0), "op").unwrap();
writer.set_dial(dial).unwrap();
path
}
/// The real reader's answer for the store at `<root>/<instance>/control.cc`,
/// with the reader's root moved to `<root>` on this thread.
fn effective(path: &Path) -> Effective {
let directory = path.parent().unwrap();
let instance = Slug(directory.file_name().unwrap().to_str().unwrap().into());
with_root(directory.parent().unwrap(), || read_effective(&instance))
}
/// A dial written around the writer's bounds check, so the reader's own check
/// is what is under test.
fn write_unchecked_dial(path: &Path, dial: &BurnRate) {
let mut cache = CultCache::new();
cache.register_entry_type::<BurnRate>().unwrap();
cache.register_entry_type::<Brake>().unwrap();
cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(path)).unwrap();
cache.pull_all_backing_stores().unwrap();
cache.put(DIAL_KEY, dial).unwrap();
}
#[test]
fn a_source_that_fails_reads_as_held() {
struct Failing;
impl ControlSource for Failing {
fn snapshot(&self) -> Result<Vec<CultCacheEnvelope>> {
Err(anyhow::anyhow!("disk gone"))
}
}
assert_eq!(derive(&Failing, &Slug("eureka".into())), Effective::Held { reason: HeldReason::Undecodable });
}
#[test]
fn an_absent_store_reads_as_held() {
let dir = tempfile::tempdir().unwrap();
assert_eq!(effective(&store_path(dir.path())), held(HeldReason::BrakeAbsent));
assert!(!store_path(dir.path()).exists(), "reading must not create the store");
}
#[test]
fn an_absent_brake_reads_as_held_even_with_a_dial() {
let dir = tempfile::tempdir().unwrap();
let path = store_path(dir.path());
ControlWriter::open(&path).unwrap().set_dial(dial("1", 3600, "1")).unwrap();
assert_eq!(effective(&path), held(HeldReason::BrakeAbsent));
}
#[test]
fn an_undecodable_store_reads_as_held() {
let dir = tempfile::tempdir().unwrap();
let path = released_store(dir.path(), dial("1", 3600, "1"));
let good = std::fs::read(&path).unwrap();
// Garbage in place of the store.
std::fs::write(&path, b"this is not a cultcache store").unwrap();
assert_eq!(effective(&path), held(HeldReason::Undecodable));
// A store cut off mid-document.
std::fs::write(&path, &good[..good.len() / 2]).unwrap();
assert_eq!(effective(&path), held(HeldReason::Undecodable));
// 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(_)));
}
#[test]
fn a_path_that_cannot_be_read_as_a_file_reads_as_held() {
let dir = tempfile::tempdir().unwrap();
// A directory sits where the store should be: it exists and cannot be read as a file.
let path = store_path(dir.path());
std::fs::create_dir_all(&path).unwrap();
assert_eq!(effective(&path), held(HeldReason::Undecodable));
}
#[test]
fn an_unknown_document_type_makes_the_store_undecodable() {
#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
#[cultcache(type = "eureka.control.something_else.v1", schema = "Other")]
struct Other {
#[cultcache(key = 0)]
value: u32,
}
let dir = tempfile::tempdir().unwrap();
let path = released_store(dir.path(), dial("1", 3600, "1"));
let mut cache = CultCache::new();
cache.register_entry_type::<Other>().unwrap();
cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&path)).unwrap();
cache.put("x", &Other { value: 1 }).unwrap();
// The store now holds a released brake, a good dial and a foreign document.
assert_eq!(effective(&path), held(HeldReason::Undecodable));
}
#[test]
fn a_brake_payload_that_does_not_decode_makes_the_store_undecodable() {
// Same type id as the brake, a different shape: the payload cannot decode as a Brake.
#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
#[cultcache(type = "eureka.control.brake.v1", schema = "ControlBrake")]
struct WrongBrake {
#[cultcache(key = 0)]
released: String,
}
let dir = tempfile::tempdir().unwrap();
let path = store_path(dir.path());
let mut cache = CultCache::new();
cache.register_entry_type::<WrongBrake>().unwrap();
cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&path)).unwrap();
cache.put(BRAKE_KEY, &WrongBrake { released: "yes".into() }).unwrap();
assert_eq!(effective(&path), held(HeldReason::Undecodable));
}
#[test]
fn a_decode_failure_outranks_a_held_brake() {
let dir = tempfile::tempdir().unwrap();
let path = released_store(dir.path(), dial("1", 3600, "1"));
ControlWriter::open(&path).unwrap().set_brake(false, at(5), "op").unwrap();
assert_eq!(effective(&path), held(HeldReason::BrakeHeld));
std::fs::write(&path, b"junk").unwrap();
assert_eq!(effective(&path), held(HeldReason::Undecodable));
}
#[test]
fn a_released_brake_with_no_dial_reads_held_dial_absent() {
let dir = tempfile::tempdir().unwrap();
let path = store_path(dir.path());
ControlWriter::open(&path).unwrap().set_brake(true, at(0), "op").unwrap();
assert_eq!(effective(&path), held(HeldReason::DialAbsent));
}
#[test]
fn dial_bounds_are_inclusive_at_both_ends() {
for (heat, expected_in) in [("0.05", true), ("2.0", true), ("0.0499", false), ("2.0001", false), ("0", false), ("-1", false), ("3", false)] {
let dir = tempfile::tempdir().unwrap();
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:?}");
} else {
assert_eq!(got, held(HeldReason::DialOutOfBounds), "heat {heat}");
}
}
}
#[test]
fn a_zero_base_cooldown_or_a_non_positive_run_cost_is_out_of_bounds() {
for bad in [dial("1", 0, "1"), dial("1", 3600, "0"), dial("1", 3600, "-0.5")] {
let dir = tempfile::tempdir().unwrap();
let path = released_store_unchecked(dir.path(), bad.clone());
assert_eq!(effective(&path), held(HeldReason::DialOutOfBounds), "{bad:?}");
}
let dir = tempfile::tempdir().unwrap();
let smallest = released_store_unchecked(dir.path(), dial("1", 1, "0.000001"));
assert!(matches!(effective(&smallest), Effective::Released(_)));
}
fn released_store_unchecked(dir: &Path, bad: BurnRate) -> PathBuf {
let path = store_path(dir);
ControlWriter::open(&path).unwrap().set_brake(true, at(0), "op").unwrap();
write_unchecked_dial(&path, &bad);
path
}
#[test]
fn cadence_and_run_cap_are_the_dial_divided_and_multiplied_by_heat() {
for (heat, cooldown, run_usd, cadence, cap) in [
("0.5", 3600u32, "5", Duration::from_secs(7200), dec("2.5")),
("2.0", 3600, "5", Duration::from_secs(1800), dec("10.0")),
("1", 600, "3", Duration::from_secs(600), dec("3")),
("0.05", 90, "4", Duration::from_secs(1800), dec("0.20")),
("1.5", 10, "2", Duration::new(6, 666_666_667), dec("3.0")),
("2.0", 1, "0.25", Duration::from_millis(500), dec("0.500")),
] {
let dir = tempfile::tempdir().unwrap();
let path = released_store(dir.path(), dial(heat, cooldown, 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}");
}
}
#[test]
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(_)));
ControlWriter::open(&path).unwrap().set_brake(false, at(60), "alice").unwrap();
assert_eq!(effective(&path), held(HeldReason::BrakeHeld));
let state = load_state(&FileSource::new(&path)).unwrap();
let brake = state.brake.unwrap();
assert_eq!((brake.released, brake.set_at, brake.set_by.as_str()), (false, at(60), "alice"));
// The dial survives the brake write untouched.
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(_)));
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"));
}
#[test]
fn reading_writes_nothing_and_takes_no_lock_file() {
let dir = tempfile::tempdir().unwrap();
let path = released_store(dir.path(), dial("1", 3600, "1"));
let store_dir = path.parent().unwrap();
let listing = |dir: &Path| {
let mut names: Vec<_> = std::fs::read_dir(dir).unwrap().map(|e| e.unwrap().file_name()).collect();
names.sort();
names
};
// The writer left its sibling lock file; remove it, so a reader that wants one has to create it.
for entry in std::fs::read_dir(store_dir).unwrap() {
let entry = entry.unwrap().path();
if entry != path {
std::fs::remove_file(entry).unwrap();
}
}
let before = (listing(store_dir), std::fs::read(&path).unwrap());
assert!(matches!(effective(&path), Effective::Released(_)));
assert_eq!((listing(store_dir), std::fs::read(&path).unwrap()), before);
}
/// A dial document under the dial's type id whose payload is not a dial.
#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
#[cultcache(type = "eureka.control.burn_rate.v1", schema = "ControlBurnRate")]
struct WrongDial {
#[cultcache(key = 0)]
heat: String,
}
fn write_wrong_dial(path: &Path, heat: &str) {
let mut cache = CultCache::new();
cache.register_entry_type::<WrongDial>().unwrap();
cache.register_entry_type::<mind_body::control::Brake>().unwrap();
cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(path)).unwrap();
cache.pull_all_backing_stores().unwrap();
cache.put(mind_body::control::DIAL_KEY, &WrongDial { heat: heat.into() }).unwrap();
}
#[test]
fn a_dial_that_does_not_decode_reads_held_whatever_the_brake_says() {
for brake_released in [true, false] {
for heat in ["not a number", "NaN", ""] {
let dir = tempfile::tempdir().unwrap();
let path = store_path(dir.path());
ControlWriter::open(&path).unwrap().set_brake(brake_released, at(0), "op").unwrap();
write_wrong_dial(&path, heat);
assert_eq!(
effective(&path),
held(HeldReason::Undecodable),
"brake released={brake_released}, dial heat {heat:?}: a dial that cannot be read is never replaced by a default"
);
}
}
}
mod grant {
//! A Grant is the proof that this instance's own control store released: the
//! reader derives the path from the instance, and a launch refuses a Grant
//! read for another instance before it asks the mind anything.
use anyhow::{Result, anyhow};
use cultnet_rs::Selection;
use eureka_pipeline::{PipelineDocument, RunTurn};
use huginn_mind::{PipelineAdmissionOutcome, PipelineSelectionPage};
use super::*;
use crate::launch::{Clock, Declined, LaunchOutcome, LaunchRequest, Launcher, Ports, open_and_launch};
use crate::queue::MindPort;
fn slug(name: &str) -> Slug {
Slug(name.into())
}
fn release(root: &Path, instance: &str) {
let mut writer = ControlWriter::open(control_path(root, &slug(instance)).unwrap()).unwrap();
writer.set_brake(true, at(0), "op").unwrap();
writer.set_dial(dial("1", 3600, "5")).unwrap();
}
fn read(root: &Path, instance: &str) -> Effective {
with_root(root, || read_effective(&slug(instance)))
}
/// A mind that answers nothing: a launch that reaches it has gone past the
/// instance check.
struct SilentMind(Slug);
impl MindPort for SilentMind {
fn instance(&self) -> &Slug {
&self.0
}
fn query(&self, _selection: &Selection) -> Result<PipelineSelectionPage> {
Err(anyhow!("the launch asked the mind"))
}
fn admit(&self, _agent: &str, _session: &str, _documents: Vec<PipelineDocument>) -> Result<PipelineAdmissionOutcome> {
Err(anyhow!("the launch admitted"))
}
}
struct NoUnits;
impl Launcher for NoUnits {
fn start(&self, _instance: &Slug, _turn: RunTurn) -> Result<()> {
Err(anyhow!("the launch started a unit"))
}
fn alive(&self, _instance: &Slug, _turn: RunTurn) -> bool {
false
}
}
struct Now;
impl Clock for Now {
fn now(&self) -> DateTime<Utc> {
at(100)
}
}
fn launch_as(mind_instance: &str, grant: Grant, turn: RunTurn) -> Result<LaunchOutcome> {
let mind = SilentMind(slug(mind_instance));
let ports = Ports { mind: &mind, launcher: &NoUnits, clock: &Now, host: "host" };
open_and_launch(&ports, LaunchRequest { turn, claims: vec![], agent: "agent".into(), grant })
}
#[test]
fn the_reader_makes_a_grant_for_the_instance_whose_store_it_read() {
let root = tempfile::tempdir().unwrap();
release(root.path(), "void");
let Effective::Released(grant) = read(root.path(), "void") else { panic!("void's store is released") };
assert_eq!(grant.instance(), &slug("void"));
assert_eq!(grant.run_cap_usd(), dec("5"));
}
#[test]
fn another_instances_released_store_yields_no_grant_for_this_one() {
let root = tempfile::tempdir().unwrap();
release(root.path(), "void");
assert_eq!(read(root.path(), "eureka"), held(HeldReason::BrakeAbsent));
for walk in ["../void", "void/..", "eureka/../void", "/void"] {
assert_eq!(read(root.path(), walk), held(HeldReason::Undecodable), "{walk}");
}
}
#[test]
fn a_grant_read_for_one_instance_cannot_launch_another() {
let root = tempfile::tempdir().unwrap();
release(root.path(), "void");
for turn in [RunTurn::SelfRun, RunTurn::PersonaTurn] {
let Effective::Released(grant) = read(root.path(), "void") else { panic!("void's store is released") };
// The mind is eureka's; the silent mind and the unit-less launcher fail loudly if the launch goes on.
let outcome = launch_as("eureka", grant, turn).unwrap();
assert_eq!(outcome, LaunchOutcome::Refused(Declined::GrantForOtherInstance), "{turn:?}");
}
}
#[test]
fn the_matching_grant_is_not_stopped_by_the_instance_check() {
let root = tempfile::tempdir().unwrap();
release(root.path(), "void");
let Effective::Released(grant) = read(root.path(), "void") else { panic!("void's store is released") };
let error = launch_as("void", grant, RunTurn::SelfRun).unwrap_err();
assert!(format!("{error:#}").contains("asked the mind"), "{error:#}");
}
}

View file

@ -850,19 +850,25 @@ mod tests {
fn a_grant_read_for_another_instance_opens_nothing_and_starts_nothing() {
let rig = Rig::new();
rig.mind.committed(vec![spec("x")]);
for turn in [RunTurn::SelfRun, RunTurn::PersonaTurn] {
let claims = if turn == RunTurn::SelfRun { vec![spec_ref("x")] } else { vec![] };
let ports = Ports { mind: &rig.mind, launcher: &rig.launcher, clock: &rig.clock, host: "yggdrasil-host" };
let grant = Grant::for_test(Slug("another-instance".into()), StdDuration::from_secs(60), five());
let outcome = open_and_launch(&ports, LaunchRequest { turn, claims, agent: "agent-x".into(), grant }).unwrap();
assert_eq!(outcome, LaunchOutcome::Refused(Declined::GrantForOtherInstance), "{turn:?}");
// Forgeries shaped like the real name: the same length and prefix, differing only at the end;
// a prefix of it; and a name it is a prefix of. Each is checked whole.
let forged = [format!("{}k", &INSTANCE[..INSTANCE.len() - 1]), INSTANCE[..INSTANCE.len() - 1].to_string(), format!("{INSTANCE}-test"), "another-instance".to_string()];
assert_eq!(forged[0].len(), INSTANCE.len());
for name in forged {
for turn in [RunTurn::SelfRun, RunTurn::PersonaTurn] {
let claims = if turn == RunTurn::SelfRun { vec![spec_ref("x")] } else { vec![] };
let ports = Ports { mind: &rig.mind, launcher: &rig.launcher, clock: &rig.clock, host: "yggdrasil-host" };
let grant = Grant::for_test(Slug(name.clone()), StdDuration::from_secs(60), five());
let outcome = open_and_launch(&ports, LaunchRequest { turn, claims, agent: "agent-x".into(), grant }).unwrap();
assert_eq!(outcome, LaunchOutcome::Refused(Declined::GrantForOtherInstance), "{name} {turn:?}");
}
}
assert_eq!((rig.runs(), rig.started()), (0, 0));
assert!(matches!(rig.launch(RunTurn::SelfRun, &[spec_ref("x")], five()), LaunchOutcome::Launched { .. }), "the mind's own Grant launches");
}
#[test]
fn a_persona_turn_with_claims_is_refused_and_opens_nothing() {
fn a_persona_turn_with_a_claim_of_any_kind_is_refused_and_opens_nothing() {
let rig = Rig::new();
rig.mind.committed(vec![spec("x"), spec("blocked")]);
rig.mind.committed(vec![question_in("fork", &spec_ref("blocked"))]);
@ -871,6 +877,11 @@ mod tests {
let outcome = rig.launch(RunTurn::PersonaTurn, &[spec_ref(item)], five());
assert_eq!(outcome, LaunchOutcome::Refused(Declined::PersonaRunTakesNoClaims), "{item}");
}
// And a claim of every kind the leaf has, whether or not the document exists.
for kind in PipelineKind::ALL {
let outcome = rig.launch(RunTurn::PersonaTurn, &[reference(*kind, "no-such-document")], five());
assert_eq!(outcome, LaunchOutcome::Refused(Declined::PersonaRunTakesNoClaims), "{kind:?}");
}
assert_eq!((rig.runs(), rig.started()), (0, 0));
assert!(matches!(rig.launch(RunTurn::PersonaTurn, &[], five()), LaunchOutcome::Launched { .. }));
}

View file

@ -14,9 +14,7 @@ use std::time::Duration;
use chrono::{DateTime, TimeZone, Utc};
use cultcache_rs::{CultCache, DatabaseEntry, SingleFileMessagePackBackingStore};
use mind_body::control::{
BRAKE_KEY, BurnRate, ControlWriter, Effective, FileSource, HeldReason, control_path, load_state, read_effective,
};
use mind_body::control::{BurnRate, ControlWriter, FileSource, control_path, load_state};
use eureka_pipeline::Slug;
use rust_decimal::Decimal;
use std::str::FromStr;
@ -38,10 +36,6 @@ fn store_path(dir: &Path) -> PathBuf {
dir.join("eureka").join("control.cc")
}
fn held(reason: HeldReason) -> Effective {
Effective::Held { reason }
}
/// A written store: brake released and the given dial, through the real writer.
fn released_store(dir: &Path, dial: BurnRate) -> PathBuf {
let path = store_path(dir);
@ -51,193 +45,6 @@ fn released_store(dir: &Path, dial: BurnRate) -> PathBuf {
path
}
/// The reader's answer for the store at `<root>/<instance>/control.cc`: the
/// reader derives that path itself from the root and the instance.
fn effective(path: &Path) -> Effective {
let directory = path.parent().unwrap();
let instance = Slug(directory.file_name().unwrap().to_str().unwrap().into());
read_effective(directory.parent().unwrap(), &instance)
}
/// A dial written around the writer's bounds check, so the reader's own check
/// is what is under test.
fn write_unchecked_dial(path: &Path, dial: &BurnRate) {
let mut cache = CultCache::new();
cache.register_entry_type::<BurnRate>().unwrap();
cache.register_entry_type::<mind_body::control::Brake>().unwrap();
cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(path)).unwrap();
cache.pull_all_backing_stores().unwrap();
cache.put(mind_body::control::DIAL_KEY, dial).unwrap();
}
#[test]
fn an_absent_store_reads_as_held() {
let dir = tempfile::tempdir().unwrap();
assert_eq!(effective(&store_path(dir.path())), held(HeldReason::BrakeAbsent));
assert!(!store_path(dir.path()).exists(), "reading must not create the store");
}
#[test]
fn an_absent_brake_reads_as_held_even_with_a_dial() {
let dir = tempfile::tempdir().unwrap();
let path = store_path(dir.path());
ControlWriter::open(&path).unwrap().set_dial(dial("1", 3600, "1")).unwrap();
assert_eq!(effective(&path), held(HeldReason::BrakeAbsent));
}
#[test]
fn an_undecodable_store_reads_as_held() {
let dir = tempfile::tempdir().unwrap();
let path = released_store(dir.path(), dial("1", 3600, "1"));
let good = std::fs::read(&path).unwrap();
// Garbage in place of the store.
std::fs::write(&path, b"this is not a cultcache store").unwrap();
assert_eq!(effective(&path), held(HeldReason::Undecodable));
// A store cut off mid-document.
std::fs::write(&path, &good[..good.len() / 2]).unwrap();
assert_eq!(effective(&path), held(HeldReason::Undecodable));
// 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(_)));
}
#[test]
fn a_path_that_cannot_be_read_as_a_file_reads_as_held() {
let dir = tempfile::tempdir().unwrap();
// A directory sits where the store should be: it exists and cannot be read as a file.
let path = store_path(dir.path());
std::fs::create_dir_all(&path).unwrap();
assert_eq!(effective(&path), held(HeldReason::Undecodable));
}
#[test]
fn an_unknown_document_type_makes_the_store_undecodable() {
#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
#[cultcache(type = "eureka.control.something_else.v1", schema = "Other")]
struct Other {
#[cultcache(key = 0)]
value: u32,
}
let dir = tempfile::tempdir().unwrap();
let path = released_store(dir.path(), dial("1", 3600, "1"));
let mut cache = CultCache::new();
cache.register_entry_type::<Other>().unwrap();
cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&path)).unwrap();
cache.put("x", &Other { value: 1 }).unwrap();
// The store now holds a released brake, a good dial and a foreign document.
assert_eq!(effective(&path), held(HeldReason::Undecodable));
}
#[test]
fn a_brake_payload_that_does_not_decode_makes_the_store_undecodable() {
// Same type id as the brake, a different shape: the payload cannot decode as a Brake.
#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
#[cultcache(type = "eureka.control.brake.v1", schema = "ControlBrake")]
struct WrongBrake {
#[cultcache(key = 0)]
released: String,
}
let dir = tempfile::tempdir().unwrap();
let path = store_path(dir.path());
let mut cache = CultCache::new();
cache.register_entry_type::<WrongBrake>().unwrap();
cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(&path)).unwrap();
cache.put(BRAKE_KEY, &WrongBrake { released: "yes".into() }).unwrap();
assert_eq!(effective(&path), held(HeldReason::Undecodable));
}
#[test]
fn a_decode_failure_outranks_a_held_brake() {
let dir = tempfile::tempdir().unwrap();
let path = released_store(dir.path(), dial("1", 3600, "1"));
ControlWriter::open(&path).unwrap().set_brake(false, at(5), "op").unwrap();
assert_eq!(effective(&path), held(HeldReason::BrakeHeld));
std::fs::write(&path, b"junk").unwrap();
assert_eq!(effective(&path), held(HeldReason::Undecodable));
}
#[test]
fn a_released_brake_with_no_dial_reads_held_dial_absent() {
let dir = tempfile::tempdir().unwrap();
let path = store_path(dir.path());
ControlWriter::open(&path).unwrap().set_brake(true, at(0), "op").unwrap();
assert_eq!(effective(&path), held(HeldReason::DialAbsent));
}
#[test]
fn dial_bounds_are_inclusive_at_both_ends() {
for (heat, expected_in) in [("0.05", true), ("2.0", true), ("0.0499", false), ("2.0001", false), ("0", false), ("-1", false), ("3", false)] {
let dir = tempfile::tempdir().unwrap();
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:?}");
} else {
assert_eq!(got, held(HeldReason::DialOutOfBounds), "heat {heat}");
}
}
}
#[test]
fn a_zero_base_cooldown_or_a_non_positive_run_cost_is_out_of_bounds() {
for bad in [dial("1", 0, "1"), dial("1", 3600, "0"), dial("1", 3600, "-0.5")] {
let dir = tempfile::tempdir().unwrap();
let path = released_store_unchecked(dir.path(), bad.clone());
assert_eq!(effective(&path), held(HeldReason::DialOutOfBounds), "{bad:?}");
}
let dir = tempfile::tempdir().unwrap();
let smallest = released_store_unchecked(dir.path(), dial("1", 1, "0.000001"));
assert!(matches!(effective(&smallest), Effective::Released(_)));
}
fn released_store_unchecked(dir: &Path, bad: BurnRate) -> PathBuf {
let path = store_path(dir);
ControlWriter::open(&path).unwrap().set_brake(true, at(0), "op").unwrap();
write_unchecked_dial(&path, &bad);
path
}
#[test]
fn cadence_and_run_cap_are_the_dial_divided_and_multiplied_by_heat() {
for (heat, cooldown, run_usd, cadence, cap) in [
("0.5", 3600u32, "5", Duration::from_secs(7200), dec("2.5")),
("2.0", 3600, "5", Duration::from_secs(1800), dec("10.0")),
("1", 600, "3", Duration::from_secs(600), dec("3")),
("0.05", 90, "4", Duration::from_secs(1800), dec("0.20")),
("1.5", 10, "2", Duration::new(6, 666_666_667), dec("3.0")),
("2.0", 1, "0.25", Duration::from_millis(500), dec("0.500")),
] {
let dir = tempfile::tempdir().unwrap();
let path = released_store(dir.path(), dial(heat, cooldown, 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}");
}
}
#[test]
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(_)));
ControlWriter::open(&path).unwrap().set_brake(false, at(60), "alice").unwrap();
assert_eq!(effective(&path), held(HeldReason::BrakeHeld));
let state = load_state(&FileSource::new(&path)).unwrap();
let brake = state.brake.unwrap();
assert_eq!((brake.released, brake.set_at, brake.set_by.as_str()), (false, at(60), "alice"));
// The dial survives the brake write untouched.
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(_)));
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"));
}
#[test]
fn setting_the_dial_replaces_it_whole_and_keeps_the_brake() {
let dir = tempfile::tempdir().unwrap();
@ -262,28 +69,6 @@ fn the_writer_refuses_an_out_of_bounds_dial_and_leaves_the_store_unchanged() {
}
}
#[test]
fn reading_writes_nothing_and_takes_no_lock_file() {
let dir = tempfile::tempdir().unwrap();
let path = released_store(dir.path(), dial("1", 3600, "1"));
let store_dir = path.parent().unwrap();
let listing = |dir: &Path| {
let mut names: Vec<_> = std::fs::read_dir(dir).unwrap().map(|e| e.unwrap().file_name()).collect();
names.sort();
names
};
// The writer left its sibling lock file; remove it, so a reader that wants one has to create it.
for entry in std::fs::read_dir(store_dir).unwrap() {
let entry = entry.unwrap().path();
if entry != path {
std::fs::remove_file(entry).unwrap();
}
}
let before = (listing(store_dir), std::fs::read(&path).unwrap());
assert!(matches!(effective(&path), Effective::Released(_)));
assert_eq!((listing(store_dir), std::fs::read(&path).unwrap()), before);
}
#[test]
fn the_control_path_is_derived_from_a_valid_instance_only() {
let root = Path::new(mind_body::control::CONTROL_ROOT);
@ -292,41 +77,6 @@ fn the_control_path_is_derived_from_a_valid_instance_only() {
assert!(control_path(root, &Slug(bad.into())).is_err(), "{bad:?}");
}
}
/// A dial document under the dial's type id whose payload is not a dial.
#[derive(Clone, Debug, PartialEq, Eq, DatabaseEntry)]
#[cultcache(type = "eureka.control.burn_rate.v1", schema = "ControlBurnRate")]
struct WrongDial {
#[cultcache(key = 0)]
heat: String,
}
fn write_wrong_dial(path: &Path, heat: &str) {
let mut cache = CultCache::new();
cache.register_entry_type::<WrongDial>().unwrap();
cache.register_entry_type::<mind_body::control::Brake>().unwrap();
cache.add_generic_backing_store(SingleFileMessagePackBackingStore::new(path)).unwrap();
cache.pull_all_backing_stores().unwrap();
cache.put(mind_body::control::DIAL_KEY, &WrongDial { heat: heat.into() }).unwrap();
}
#[test]
fn a_dial_that_does_not_decode_reads_held_whatever_the_brake_says() {
for brake_released in [true, false] {
for heat in ["not a number", "NaN", ""] {
let dir = tempfile::tempdir().unwrap();
let path = store_path(dir.path());
ControlWriter::open(&path).unwrap().set_brake(brake_released, at(0), "op").unwrap();
write_wrong_dial(&path, heat);
assert_eq!(
effective(&path),
held(HeldReason::Undecodable),
"brake released={brake_released}, dial heat {heat:?}: a dial that cannot be read is never replaced by a default"
);
}
}
}
#[cfg(unix)]
mod modes {
use super::*;
@ -391,7 +141,7 @@ mod modes {
);
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!(load_state(&FileSource::new(&path)).unwrap().brake.unwrap().released, "a non-root user can still read the store");
}
other => panic!("unknown role {other}"),
}

View file

@ -0,0 +1,66 @@
//! The brake-grant rule seen from outside the crate: the only reader takes the
//! instance, so whatever a caller builds elsewhere (a store in a temporary
//! directory, a symlink to another instance's directory, a copy of another
//! instance's store, the relative root `.`) is never what a Grant is made from.
//! The signature half of the rule (no root argument, no source reader, no
//! struct literal, no test constructor) is the `compile_fail` examples on
//! `read_effective`; this is the behavioural half, committed because it is the
//! only defence of the rule against a forged store.
#![cfg(unix)]
use std::path::Path;
use chrono::{TimeZone, Utc};
use eureka_pipeline::Slug;
use mind_body::control::{BurnRate, ControlWriter, Effective, HeldReason, control_path, read_effective};
use rust_decimal::Decimal;
/// A name no real install has a store for under the real root.
const FORGED: &str = "forge-probe-instance";
const OTHER: &str = "forge-probe-other";
fn release(root: &Path, instance: &str) {
let mut writer = ControlWriter::open(control_path(root, &Slug(instance.into())).unwrap()).unwrap();
let at = Utc.timestamp_opt(1_800_000_000, 0).unwrap();
writer.set_brake(true, at, "forger").unwrap();
writer
.set_dial(BurnRate { heat: Decimal::ONE, base_cooldown_s: 3600, base_run_usd: Decimal::new(5, 0), set_at: at, set_by: "forger".into() })
.unwrap();
}
fn reads(instance: &str) -> Effective {
read_effective(&Slug(instance.into()))
}
#[test]
fn no_forged_store_yields_a_grant() {
assert_eq!(reads(FORGED), Effective::Held { reason: HeldReason::BrakeAbsent }, "the real root has no store for the probe's name");
// A released store for the name in a root of the forger's choosing.
let tmp = tempfile::tempdir().unwrap();
release(tmp.path(), FORGED);
assert!(matches!(reads(FORGED), Effective::Held { .. }), "store in a temporary root");
// A symlink from the name to another instance's released directory.
let linked = tempfile::tempdir().unwrap();
release(linked.path(), OTHER);
std::os::unix::fs::symlink(linked.path().join(OTHER), linked.path().join(FORGED)).unwrap();
assert!(matches!(reads(FORGED), Effective::Held { .. }), "symlink to another instance");
// A copy of another instance's store under the name.
let copied = tempfile::tempdir().unwrap();
release(copied.path(), OTHER);
std::fs::create_dir_all(copied.path().join(FORGED)).unwrap();
std::fs::copy(copied.path().join(OTHER).join("control.cc"), copied.path().join(FORGED).join("control.cc")).unwrap();
assert!(matches!(reads(FORGED), Effective::Held { .. }), "copy of another instance's store");
// The relative root '.': the working directory holds <name>/control.cc.
let here = tempfile::tempdir().unwrap();
release(here.path(), FORGED);
let before = std::env::current_dir().unwrap();
std::env::set_current_dir(here.path()).unwrap();
let relative = reads(FORGED);
std::env::set_current_dir(before).unwrap();
assert!(matches!(relative, Effective::Held { .. }), "relative root");
}

View file

@ -1,114 +0,0 @@
//! A Grant is the proof that this instance's own control store released. The
//! tests are an outside crate's view: the only reader takes a root and an
//! instance and derives the store path itself, and a launch refuses a Grant
//! read for another instance before it asks the mind anything.
use std::path::Path;
use anyhow::{Result, anyhow};
use chrono::{DateTime, TimeZone, Utc};
use cultnet_rs::Selection;
use eureka_pipeline::{PipelineDocument, RunTurn, Slug};
use huginn_mind::{PipelineAdmissionOutcome, PipelineSelectionPage};
use mind_body::control::{BurnRate, ControlWriter, Effective, HeldReason, control_path, read_effective};
use mind_body::launch::{Clock, Declined, LaunchOutcome, LaunchRequest, Launcher, Ports, open_and_launch};
use mind_body::queue::MindPort;
use rust_decimal::Decimal;
fn slug(name: &str) -> Slug {
Slug(name.into())
}
fn release(root: &Path, instance: &Slug) {
let mut writer = ControlWriter::open(control_path(root, instance).unwrap()).unwrap();
let at = Utc.timestamp_opt(1_800_000_000, 0).unwrap();
writer.set_brake(true, at, "op").unwrap();
writer.set_dial(BurnRate { heat: Decimal::ONE, base_cooldown_s: 3600, base_run_usd: Decimal::new(5, 0), set_at: at, set_by: "op".into() }).unwrap();
}
/// A mind that answers nothing: a launch that reaches it has gone past the
/// instance check.
struct SilentMind(Slug);
impl MindPort for SilentMind {
fn instance(&self) -> &Slug {
&self.0
}
fn query(&self, _selection: &Selection) -> Result<PipelineSelectionPage> {
Err(anyhow!("the launch asked the mind"))
}
fn admit(&self, _agent: &str, _session: &str, _documents: Vec<PipelineDocument>) -> Result<PipelineAdmissionOutcome> {
Err(anyhow!("the launch admitted"))
}
}
struct NoUnits;
impl Launcher for NoUnits {
fn start(&self, _instance: &Slug, _turn: RunTurn) -> Result<()> {
Err(anyhow!("the launch started a unit"))
}
fn alive(&self, _instance: &Slug, _turn: RunTurn) -> bool {
false
}
}
struct Now;
impl Clock for Now {
fn now(&self) -> DateTime<Utc> {
Utc.timestamp_opt(1_800_000_100, 0).unwrap()
}
}
fn launch_as(mind_instance: &str, grant: mind_body::control::Grant, turn: RunTurn) -> Result<LaunchOutcome> {
let mind = SilentMind(slug(mind_instance));
let ports = Ports { mind: &mind, launcher: &NoUnits, clock: &Now, host: "host" };
open_and_launch(&ports, LaunchRequest { turn, claims: vec![], agent: "agent".into(), grant })
}
#[test]
fn the_reader_makes_a_grant_for_the_instance_whose_store_it_read() {
let root = tempfile::tempdir().unwrap();
release(root.path(), &slug("void"));
let Effective::Released(grant) = read_effective(root.path(), &slug("void")) else { panic!("void's store is released") };
assert_eq!(grant.instance(), &slug("void"));
assert_eq!(grant.run_cap_usd(), Decimal::new(5, 0));
}
#[test]
fn another_instances_released_store_yields_no_grant_for_this_one() {
let root = tempfile::tempdir().unwrap();
release(root.path(), &slug("void"));
// The operator holds eureka's brake: eureka has no released store under this root.
assert_eq!(read_effective(root.path(), &slug("eureka")), Effective::Held { reason: HeldReason::BrakeAbsent });
// A path-shaped instance cannot reach void's store by walking.
for walk in ["../void", "void/..", "eureka/../void", "/void"] {
assert_eq!(read_effective(root.path(), &slug(walk)), Effective::Held { reason: HeldReason::Undecodable }, "{walk}");
}
}
#[test]
fn a_grant_read_for_one_instance_cannot_launch_another() {
let root = tempfile::tempdir().unwrap();
release(root.path(), &slug("void"));
for turn in [RunTurn::SelfRun, RunTurn::PersonaTurn] {
let Effective::Released(grant) = read_effective(root.path(), &slug("void")) else { panic!("void's store is released") };
// The mind is eureka's; the silent mind and the unit-less launcher fail loudly if the launch goes on.
let outcome = launch_as("eureka", grant, turn).unwrap();
assert_eq!(outcome, LaunchOutcome::Refused(Declined::GrantForOtherInstance), "{turn:?}");
}
}
#[test]
fn the_matching_grant_is_not_stopped_by_the_instance_check() {
let root = tempfile::tempdir().unwrap();
release(root.path(), &slug("void"));
let Effective::Released(grant) = read_effective(root.path(), &slug("void")) else { panic!("void's store is released") };
// Past the check the silent mind is asked, so the launch errors there.
let error = launch_as("void", grant, RunTurn::SelfRun).unwrap_err();
assert!(format!("{error:#}").contains("asked the mind"), "{error:#}");
}