use crate::control::classify::Effect;
use crate::control::judge::answers::Standing;
use crate::control::judge::{Answers, Ruling, Scope};
use crate::control::policy::Policy;
use crate::control::wire::Request;
use crate::opslog::{OpEntry, Origin, YOG_CONTROL};
fn row(words: &[&str]) -> OpEntry {
OpEntry {
ts: "TS".to_owned(),
argv: words.iter().map(|s| (*s).to_owned()).collect(),
cwd: String::new(),
exit: 0,
stdout: String::new(),
stderr: String::new(),
origin: Origin::World,
client: crate::registry::Client::default(),
}
}
fn call(id: &str, name: &str, agent: &str) -> Request {
Request {
id: id.to_owned(),
name: name.to_owned(),
input: serde_json::json!({}),
role: "worker".to_owned(),
agent_id: agent.to_owned(),
}
}
fn ruling(answers: &Answers, request: &Request, ws: &str, effect: Effect) -> Standing {
answers.ruling(request, ws, effect, &Policy::default())
}
#[test]
fn a_floor_holds_every_class_above_read_across_the_whole_subtree() {
let answers = Answers::fold(&[row(&[YOG_CONTROL, "floor", "amber", "raise"])]);
assert!(answers.floored("amber"));
assert!(
answers.floored("amber-1-2"),
"the descent prefix carries it"
);
assert!(
!answers.floored("amberine"),
"a longer name is another agent"
);
assert!(!answers.floored("other"));
assert_eq!(
ruling(&answers, &call("t", "bash", "amber"), "w", Effect::Read).ruling,
Ruling::Pass
);
assert_eq!(
ruling(
&answers,
&call("t", "bash", "amber"),
"w",
Effect::TargetWrite
),
Standing {
ruling: Ruling::Hold,
scope: Scope::Conversation
}
);
assert_eq!(
ruling(
&answers,
&call("t", "bash", "amber-1"),
"w",
Effect::Process
)
.ruling,
Ruling::Hold
);
assert_eq!(
ruling(&answers, &call("t", "bash", "amber"), "w", Effect::Secret).ruling,
Ruling::Refuse
);
let answers = Answers::fold(&[
row(&[YOG_CONTROL, "floor", "amber", "raise"]),
row(&[YOG_CONTROL, "answer", "toolu_1", "pass", "call"]),
]);
assert_eq!(
ruling(
&answers,
&call("toolu_1", "bash", "amber"),
"w",
Effect::TargetWrite
)
.ruling,
Ruling::Pass
);
}
#[test]
fn a_floor_does_not_reach_the_compactor_s_checkpoint_pair() {
let answers = Answers::fold(&[row(&[YOG_CONTROL, "floor", "amber", "raise"])]);
for pair in ["write_summary", "mark_for_deletion"] {
assert_eq!(
ruling(
&answers,
&call("t", pair, "amber"),
"w",
Effect::TargetWrite
)
.ruling,
Ruling::Pass,
"{pair} is the compaction procedure's own act, not the agent's"
);
assert_eq!(
ruling(
&answers,
&call("t", pair, "amber-1"),
"w",
Effect::TargetWrite
)
.ruling,
Ruling::Pass,
"and the compactor of a floored conversation is a descendant"
);
}
assert_eq!(
ruling(
&answers,
&call("t", "load_skill", "amber"),
"w",
Effect::TargetWrite
)
.ruling,
Ruling::Hold
);
assert_eq!(
answers
.ruling(
&call("t", "write_summary", "amber"),
"w",
Effect::TargetWrite,
&Policy::parse("table:\n target-write: hold\n")
)
.ruling,
Ruling::Hold
);
}
#[test]
fn the_url_reading_is_a_class_the_floor_still_bites_on() {
let fetch = Request {
input: serde_json::json!({"url": "https://example.invalid/x"}),
..call("toolu_f", "box2_fetch", "amber")
};
let root = crate::control::root::Root {
writable: vec![std::path::PathBuf::from("/w/agent")],
cwd: std::path::PathBuf::from("/w/agent"),
home: std::path::PathBuf::from("/home/op"),
};
let effect = crate::control::classify::classify(&fetch, &root, &Policy::default()).effect;
assert_eq!(effect, Effect::OpenWorld);
let open = Answers::fold(&[]);
assert_eq!(ruling(&open, &fetch, "w", effect).ruling, Ruling::Pass);
let floored = Answers::fold(&[row(&[YOG_CONTROL, "floor", "amber", "raise"])]);
assert_eq!(
ruling(&floored, &fetch, "w", effect),
Standing {
ruling: Ruling::Hold,
scope: Scope::Conversation
}
);
}