#[path = "../e2e/harness.rs"]
mod harness;
use std::path::Path;
use std::time::{Duration, Instant};
use oneagentgraph::event::{Origin, TurnMessage, TurnStarted};
use onepipeline::channel::Command;
use onepipeline::channel::Deliver;
use onepipeline::note::{deliver, deliver_with, Addressee, Delivered, Note, Reached};
use onepipeline::views::RunPaths;
use serde_json::{json, Value};
use harness::{agent, lifecycle, plan_of, World, CANCEL_GRACE_ENV, REFUSED};
const NOTE: &str = "the reviewer asked for a smaller diff; stop editing src/old.rs";
const CRITERION: &str = "`version.txt` holds `v: 2`";
const PLANNER_CONTEXT: &str = "the fixture moved to fixtures/v2 before this node was launched";
const SUPERVISOR_OPENING: &str = "You are the simulated USER and completion supervisor";
fn envelope(command: Value) -> String {
json!({"version": 2, "commands": [command]}).to_string()
}
fn note_op(node: &str, addressee: &str, text: &str, criterion: Option<&str>) -> Value {
let mut op = json!({"op": "note", "id": node, "addressee": addressee, "text": text});
if let Some(criterion) = criterion {
op["criterion"] = json!(criterion);
}
op
}
fn note_op_with(node: &str, text: &str, deliver: &str, persist: bool) -> Value {
let mut op = note_op(node, "worker", text, None);
op["deliver"] = json!(deliver);
op["persist"] = json!(persist);
op
}
fn dispatches_of(world: &World, run: &str, node: &str) -> Vec<Vec<String>> {
let mut dispatched: Vec<Vec<String>> = Vec::new();
for event in world.journal(run) {
if event["labels"]["node"] != node {
continue;
}
match event["kind"].as_str() {
Some("node-dispatched") => dispatched.push(Vec::new()),
Some("turn-started") => {
if let (Some(turns), Some(instruction)) = (
dispatched.last_mut(),
event["payload"]["instruction"].as_str(),
) {
turns.push(instruction.to_string());
}
}
_ => {}
}
}
dispatched
}
fn openings_of(world: &World, run: &str, node: &str) -> Vec<TurnStarted> {
world
.journal(run)
.iter()
.filter(|event| event["labels"]["node"] == node && event["kind"] == "turn-started")
.map(|event| {
serde_json::from_value(event["payload"].clone()).unwrap_or_else(|error| {
panic!("a relayed turn-started is not the payload the linked oneagentgraph declares: {error}: {event}")
})
})
.collect()
}
fn words_of(world: &World, run: &str, node: &str) -> Vec<TurnMessage> {
world
.journal(run)
.iter()
.filter(|event| event["labels"]["node"] == node && event["kind"] == "turn-message")
.map(|event| {
serde_json::from_value(event["payload"].clone()).unwrap_or_else(|error| {
panic!("a relayed turn-message is not the payload the linked oneagentgraph declares: {error}: {event}")
})
})
.collect()
}
fn presentations_of(world: &World, run: &str, node: &str) -> Vec<Value> {
world
.events_of(run, "note-shown")
.into_iter()
.filter(|event| event["labels"]["node"] == node)
.collect()
}
fn dispatch_records_of(world: &World, run: &str, node: &str) -> Vec<Value> {
world
.events_of(run, "node-dispatched")
.into_iter()
.filter(|event| event["labels"]["node"] == node)
.collect()
}
fn supervised_run(world: &World, run: &str, nodes: Vec<Value>) {
world.write_graphs();
world.write_supervised_node_graph();
let path = world.plan(run, &plan_of(run, nodes));
world
.run_on_agentgraph(&["start", &path, "--detach"])
.exited(0);
}
fn held_conversation(world: &World, run: &str, nodes: Vec<Value>) {
world.script(
"judge.asks-again",
"Run the check again and report what it said.",
);
world.script("turn.hold", "hold");
supervised_run(world, run, nodes);
world.until("the worker's turn to open", |world| {
!world.events_of(run, "turn-started").is_empty()
});
}
fn held_judge(world: &World, run: &str, nodes: Vec<Value>) {
world.script("judge.hold", "hold");
supervised_run(world, run, nodes);
world.until("the judge's turn to open", |world| {
world.fakes.join("judge.holding").exists()
});
}
fn release_when_the_note_is_queued(
world: &World,
run: &str,
gates: &[&str],
) -> std::thread::JoinHandle<()> {
let queue = world.run_file(run, "channel/commands.jsonl");
let fakes = world.fakes.clone();
let gates: Vec<String> = gates.iter().map(|gate| (*gate).to_string()).collect();
std::thread::spawn(move || {
let deadline = Instant::now() + Duration::from_secs(120);
while Instant::now() < deadline && !a_note_is_queued(&queue) {
std::thread::sleep(Duration::from_millis(20));
}
std::thread::sleep(Duration::from_secs(2));
for gate in &gates {
release(&fakes, gate);
}
})
}
fn a_note_is_queued(queue: &Path) -> bool {
let text = match std::fs::read_to_string(queue) {
Ok(text) => text,
Err(error) if error.kind() == std::io::ErrorKind::NotFound => return false,
Err(error) => panic!(
"the run's command queue at {} could not be read: {error}",
queue.display()
),
};
let mut lines = text.lines().peekable();
let mut queued = false;
while let Some(line) = lines.next() {
let envelope: Value = match serde_json::from_str(line) {
Ok(envelope) => envelope,
Err(_) if lines.peek().is_none() => break,
Err(error) => panic!("the command queue holds an unreadable record: {error}: {line}"),
};
let commands: Vec<Command> = serde_json::from_value(envelope["commands"].clone())
.unwrap_or_else(|error| {
panic!("the command queue holds commands this build cannot read: {error}: {line}")
});
queued |= commands
.iter()
.any(|command| matches!(command, Command::Note { .. }));
}
queued
}
fn release(fakes: &Path, name: &str) {
std::fs::write(fakes.join(name), "go").expect("the rendezvous is released");
}
fn prompts(world: &World) -> Vec<String> {
world
.invocations()
.into_iter()
.filter(|call| call["tool"] == "oneharness-config")
.filter_map(|call| call["args"][0].as_str().map(str::to_string))
.collect()
}
fn judged(world: &World) -> Vec<String> {
prompts(world)
.into_iter()
.filter(|prompt| prompt.contains(SUPERVISOR_OPENING))
.collect()
}
fn worked(world: &World) -> Vec<String> {
prompts(world)
.into_iter()
.filter(|prompt| !prompt.contains(SUPERVISOR_OPENING))
.collect()
}
fn recorded(world: &World, run: &str) -> Value {
let committed: Vec<Value> = world
.events_of(run, "edit-committed")
.into_iter()
.filter(|event| event["payload"]["command"]["op"] == "note")
.collect();
let [one] = &committed[..] else {
panic!(
"the run recorded {} committed notes, not one",
committed.len()
);
};
one["payload"]["operations"][0].clone()
}
#[test]
fn a_note_into_a_live_dispatch_reaches_both_parties_before_the_judges_verdict() {
let world = World::new("note-live");
let run = "live";
held_conversation(&world, run, vec![agent("build", &[])]);
let releasing = release_when_the_note_is_queued(&world, run, &["turn.go", "turn.settle"]);
let replied = world.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(note_op("build", "worker", NOTE, None)),
);
releasing.join().expect("the releasing thread finishes");
replied.exited(0).out_has("\"state\":\"applied\"");
world.until("the run to settle", |world| {
!world.events_of(run, "node-settled").is_empty()
});
let worker = worked(&world);
assert!(
worker.iter().any(|prompt| prompt.contains(NOTE)),
"no worker turn was handed the note:\n{worker:#?}"
);
let judge = judged(&world);
assert!(
judge.len() >= 2,
"the judge took {} decisions, so nothing here is 'before the verdict':\n{judge:#?}",
judge.len()
);
assert!(
judge[0].contains(NOTE),
"the judge's first decision was taken without the note:\n{}",
judge[0]
);
let operation = recorded(&world, run);
assert_eq!(operation["node"], json!("build"), "{operation}");
assert_eq!(operation["addressee"], json!("worker"), "{operation}");
assert_eq!(operation["text"], json!(NOTE), "{operation}");
assert_eq!(
operation["reached"],
json!("worker"),
"the note reached a party the note was not delivered to first: {operation}"
);
assert!(
operation.get("shown_to").is_none(),
"the delivery record claims a presentation the conversation had not made: {operation}"
);
assert_eq!(
operation["routed_to"],
json!(["worker", "supervisor"]),
"{operation}"
);
let shown = presentations_of(&world, run, "build");
assert_eq!(
shown
.iter()
.map(|event| event["payload"]["party"].clone())
.collect::<Vec<_>>(),
vec![json!("worker"), json!("supervisor")],
"the presentations the run recorded are not the worker's and then the judge's:\n{shown:#?}"
);
assert!(
shown
.iter()
.all(|event| event["payload"]["text"] == json!(NOTE)
&& event["payload"]["reached"] == json!("worker")),
"{shown:#?}"
);
assert_eq!(
shown[0]["payload"]["evidence"],
json!("delivered-origin"),
"{shown:#?}"
);
assert_eq!(
shown[1]["payload"]["evidence"],
json!("answering-turn"),
"{shown:#?}"
);
let worker_turn = shown[0]["payload"]["turn"].as_u64().expect("a turn");
let judge_turn = shown[1]["payload"]["turn"].as_u64().expect("a turn");
assert!(judge_turn >= worker_turn, "{shown:#?}");
let openings = openings_of(&world, run, "build");
let by_origin = |origin: Origin| -> Vec<&TurnStarted> {
openings
.iter()
.filter(|opening| opening.origin == Some(origin))
.collect()
};
let delivered = by_origin(Origin::Delivered);
assert!(
delivered.len() == 1 && delivered[0].instruction.contains(NOTE),
"the turn that carried the manager's note is not stamped as a delivery:\n{openings:#?}"
);
assert_eq!(
delivered[0].turn, worker_turn,
"the worker's recorded presentation is not the turn the producer stamped as the \
delivery"
);
let task = by_origin(Origin::Task);
assert!(
task.len() == 1 && task[0].turn == 1,
"the opening turn is not stamped as the composed task:\n{openings:#?}"
);
let supervised = by_origin(Origin::Supervisor);
assert!(
!supervised.is_empty()
&& supervised
.iter()
.all(|opening| opening.instruction.contains("Run the check again")),
"the turn the supervisor sent the worker back on is not stamped as the \
supervisor's own:\n{openings:#?}"
);
let words = words_of(&world, run, "build");
assert!(
words
.iter()
.filter(|word| word.role == "user")
.all(|word| word.origin == Some(Origin::Supervisor))
&& words.iter().any(|word| word.role == "user"),
"the supervisor's own words are not stamped as its own:\n{words:#?}"
);
assert!(
words
.iter()
.filter(|word| word.role == "assistant")
.all(|word| word.origin.is_none()),
"the worker's words were attributed to a party that did not author them:\n{words:#?}"
);
}
#[test]
fn a_note_in_an_envelope_the_run_refuses_is_never_offered_to_the_conversation() {
let world = World::new("note-envelope-unoffered");
let run = "unoffered";
held_conversation(&world, run, vec![agent("build", &[])]);
let releasing = release_when_the_note_is_queued(&world, run, &["turn.go", "turn.settle"]);
let replied = world.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&json!({"version": 2, "commands": [
note_op("build", "worker", NOTE, None),
{"op": "settle", "id": "build", "outcome": "done",
"evidence": "the change merged while nobody was looking"},
]})
.to_string(),
);
releasing.join().expect("the releasing thread finishes");
replied
.exited(REFUSED)
.err_has("still has a dispatch in flight");
world.until("the run to settle", |world| {
!world.events_of(run, "node-settled").is_empty()
});
assert!(
world.events_of(run, "edit-committed").is_empty()
&& world.events_of(run, "command-accepted").is_empty(),
"a command of a refused envelope reached the record: {:?}",
world.kinds(run)
);
let handed = prompts(&world);
assert!(
!handed.iter().any(|prompt| prompt.contains(NOTE)),
"validation offered the note to the conversation on behalf of an envelope the run \
then refused:\n{handed:#?}"
);
let answered = world
.command_outcomes(run)
.last()
.cloned()
.expect("the envelope was answered");
assert_eq!(answered["results"][0]["op"], json!("note"), "{answered}");
assert_eq!(
answered["results"][0]["outcome"],
json!("validated"),
"{answered}"
);
assert_eq!(
answered["results"][1]["outcome"],
json!("refused"),
"{answered}"
);
}
#[test]
fn a_note_to_a_node_with_no_conversation_refuses_before_any_note_of_it_is_offered() {
let world = World::new("note-envelope-refused");
let run = "envelope";
held_conversation(
&world,
run,
vec![agent("build", &[]), agent("later", &["build"])],
);
let releasing = release_when_the_note_is_queued(&world, run, &["turn.go", "turn.settle"]);
let replied = world.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&json!({"version": 2, "commands": [
note_op("build", "worker", NOTE, None),
note_op_with("later", "start from the fixture", "live", false),
]})
.to_string(),
);
releasing.join().expect("the releasing thread finishes");
replied
.exited(REFUSED)
.err_has("composes it into no dispatch");
world.until("the run to settle", |world| {
!world.events_of(run, "node-settled").is_empty()
});
let worker = worked(&world);
assert!(
!worker.iter().any(|prompt| prompt.contains(NOTE)),
"a note of an envelope the run refused was offered to the live turn anyway:\n\
{worker:#?}"
);
assert!(
world.events_of(run, "edit-committed").is_empty()
&& world.events_of(run, "command-accepted").is_empty(),
"a command of a refused envelope reached the record: {:?}",
world.kinds(run)
);
let answered = world
.command_outcomes(run)
.last()
.cloned()
.expect("the envelope was answered");
assert_eq!(answered["applied"], json!(false), "{answered}");
assert_eq!(answered["results"][0]["op"], json!("note"), "{answered}");
assert_eq!(
answered["results"][0]["outcome"],
json!("validated"),
"the note nobody was offered was reported as delivered or as its own refusal: \
{answered}"
);
assert_eq!(
answered["results"][1]["outcome"],
json!("refused"),
"{answered}"
);
}
#[test]
fn a_binding_note_enters_the_bar_its_judge_decides_against_as_the_workers_own() {
let world = World::new("note-binding");
let run = "binding";
held_conversation(&world, run, vec![agent("build", &[])]);
let releasing = release_when_the_note_is_queued(&world, run, &["turn.go", "turn.settle"]);
let replied = world.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(note_op("build", "worker", NOTE, Some(CRITERION))),
);
releasing.join().expect("the releasing thread finishes");
replied.exited(0).out_has("\"state\":\"applied\"");
world.until("the run to settle", |world| {
!world.events_of(run, "node-settled").is_empty()
});
let judge = judged(&world);
let first = judge.first().expect("the judge decided at least once");
let bar = first
.split_once("Completion criterion:")
.map(|(_, rest)| {
rest.split("Conversation transcript")
.next()
.unwrap_or(rest)
.to_string()
})
.unwrap_or_else(|| panic!("the judge was given no completion criterion:\n{first}"));
assert!(
bar.contains(CRITERION),
"the criterion the note bound is not in the bar the judge decides against:\n{bar}"
);
assert!(
first.contains("delivered to the WORKER"),
"the judge was not told whose task the note updates:\n{first}"
);
assert!(
first.contains(CRITERION) && first.contains(NOTE),
"the judge was not shown the note beside the criterion it added:\n{first}"
);
let operation = recorded(&world, run);
assert_eq!(operation["criterion"], json!(CRITERION), "{operation}");
}
#[test]
fn a_note_arriving_after_the_dispatch_has_completed_is_refused_and_recorded() {
let world = World::new("note-late");
let run = "late";
held_conversation(&world, run, vec![agent("build", &[])]);
release(&world.fakes, "turn.go");
release(&world.fakes, "turn.settle");
world.until("the run's driver to release it", |world| {
!world.run_file(run, "owner.lock").exists()
});
let refused = world.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(note_op("build", "worker", NOTE, None)),
);
refused
.exited(2)
.err_has("was not delivered")
.err_has("build")
.err_has("no dispatch of it will take the note either");
world
.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(note_op_with("build", NOTE, "next", true)),
)
.exited(REFUSED)
.err_has("it has settled done")
.err_has("`deliver: next` asks for no live delivery");
let committed: Vec<Value> = world
.events_of(run, "edit-committed")
.into_iter()
.filter(|event| event["payload"]["command"]["op"] == "note")
.collect();
assert!(
committed.is_empty(),
"an undelivered note was committed as though it had landed: {committed:#?}"
);
let rejected: Vec<Value> = world
.events_of(run, "edit-rejected")
.into_iter()
.filter(|event| event["payload"]["command"]["op"] == "note")
.collect();
let [recorded] = &rejected[..] else {
panic!(
"the run recorded {} rejected notes, not one",
rejected.len()
);
};
let reason = recorded["payload"]["reason"]
.as_str()
.expect("the record says why");
assert!(
reason.contains("was not delivered"),
"the record does not say the note was undelivered: {reason}"
);
}
#[test]
fn the_note_seam_answers_a_delivery_and_a_non_delivery_through_this_crates_own_api() {
let world = World::new("note-api");
let run = "api";
held_conversation(
&world,
run,
vec![agent("build", &[]), agent("later", &["build"])],
);
let paths = RunPaths::under(&world.runs, run);
let absent = deliver(&paths, "nowhere", &Note::to(Addressee::Worker, NOTE))
.expect_err("a node the graph does not hold takes no note");
let said = absent.to_string();
assert!(
said.contains("no node") && said.contains("nowhere"),
"the refusal does not name the node the graph does not hold: {said}"
);
let refused = deliver_with(
&paths,
"later",
&Note::to(Addressee::Worker, NOTE),
Deliver::Live,
false,
)
.expect_err("a note with no turn to take it and no dispatch to carry it to reaches nobody");
let said = refused.to_string();
assert!(
said.contains("later") && said.contains("no conversation"),
"the refusal does not name the node or say what was missing: {said}"
);
assert!(
said.contains("`persist: false` composes it into no dispatch"),
"the refusal does not say what left the note nowhere to go: {said}"
);
let releasing = release_when_the_note_is_queued(&world, run, &["turn.go", "turn.settle"]);
let delivered = deliver(
&paths,
"build",
&Note::to(Addressee::Worker, NOTE)
.binding(CRITERION)
.expect("the seam accepts this criterion"),
);
releasing.join().expect("the releasing thread finishes");
assert_eq!(
delivered.expect("the live conversation took the note"),
Delivered::To(Reached::Worker)
);
world.until("the run's driver to release it", |world| {
!world.run_file(run, "owner.lock").exists()
});
}
#[test]
fn a_note_no_turn_took_is_carried_to_the_nodes_next_dispatch_and_named_as_carried() {
let world = World::new("note-carried");
let run = "carried";
held_conversation(
&world,
run,
vec![agent("build", &[]), agent("later", &["build"])],
);
let refused = world.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(note_op_with("later", NOTE, "live", false)),
);
refused
.exited(REFUSED)
.err_has("later")
.err_has("`persist: false` composes it into no dispatch");
let releasing = release_when_the_note_is_queued(&world, run, &["turn.go", "turn.settle"]);
world
.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(note_op("later", "worker", NOTE, None)),
)
.exited(0)
.out_has("\"state\":\"applied\"");
releasing.join().expect("the releasing thread finishes");
let operation = recorded(&world, run);
assert_eq!(operation["node"], json!("later"), "{operation}");
assert_eq!(
operation["reached"],
json!("carried"),
"a note no turn took was not named as carried: {operation}"
);
assert!(
operation.get("shown_to").is_none() && operation.get("routed_to").is_none(),
"a note nobody has read yet is recorded as shown or routed to somebody: {operation}"
);
world.until("the run to settle", |world| {
world.events_of(run, "node-settled").len() >= 2
});
let dispatched = dispatches_of(&world, run, "later");
let [first] = &dispatched[..] else {
panic!(
"`later` was dispatched {} times, not once",
dispatched.len()
);
};
assert!(
first.iter().any(|instruction| instruction.contains(NOTE)),
"the carried note did not reach the dispatch it was carried to:\n{first:#?}"
);
let records = dispatch_records_of(&world, run, "later");
assert_eq!(records.len(), 1, "{records:#?}");
assert!(
records[0]["payload"].get("notes_spent").is_none(),
"the dispatch a note was carried to reported it spent: {}",
records[0]
);
let store = std::fs::read_to_string(world.run_file(run, "notes/later.carried.jsonl"))
.expect("the note was carried through a carry store");
let lines: Vec<&str> = store.lines().collect();
assert!(
lines.len() == 1 && lines[0].contains("onemessagebus-carry-store"),
"the dispatch a note was carried to did not drain its carry store:\n{store}"
);
let shown = presentations_of(&world, run, "later");
assert_eq!(
shown
.iter()
.map(|event| (
event["payload"]["party"].clone(),
event["payload"]["evidence"].clone()
))
.collect::<Vec<_>>(),
vec![
(json!("worker"), json!("opening-task")),
(json!("supervisor"), json!("answering-turn")),
],
"the dispatch a note was carried to did not record showing it:\n{shown:#?}"
);
assert!(
shown
.iter()
.all(|event| event["payload"]["text"] == json!(NOTE)
&& event["payload"]["reached"] == json!("carried")),
"{shown:#?}"
);
}
#[test]
fn a_note_recorded_carried_whose_text_a_turn_then_opens_on_is_recorded_as_shown() {
let world = World::new("note-carried-read");
let run = "carriedread";
world.script("judge.asks-again", NOTE);
world.script("turn.hold", "hold");
supervised_run(&world, run, vec![agent("build", &[])]);
world.until("the worker's turn to open", |world| {
!world.events_of(run, "turn-started").is_empty()
});
let releasing = release_when_the_note_is_queued(&world, run, &["turn.go", "turn.settle"]);
world
.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(note_op_with("build", NOTE, "next", true)),
)
.exited(0)
.out_has("\"state\":\"applied\"");
releasing.join().expect("the releasing thread finishes");
let delivery = recorded(&world, run);
assert_eq!(delivery["reached"], json!("carried"), "{delivery}");
assert!(
delivery.get("shown_to").is_none() && delivery.get("routed_to").is_none(),
"the seam took nothing, and the record says it routed something: {delivery}"
);
world.until("the run to settle", |world| {
!world.events_of(run, "node-settled").is_empty()
});
let openings = openings_of(&world, run, "build");
let read_in = openings
.iter()
.find(|opening| opening.instruction.contains(NOTE))
.unwrap_or_else(|| panic!("no worker turn opened on the note's text:\n{openings:#?}"));
assert_eq!(read_in.origin, Some(Origin::Supervisor), "{read_in:?}");
let shown = presentations_of(&world, run, "build");
assert_eq!(
shown
.iter()
.map(|event| {
(
event["payload"]["party"].clone(),
event["payload"]["evidence"].clone(),
event["payload"]["turn"].clone(),
)
})
.collect::<Vec<_>>(),
vec![
(
json!("worker"),
json!("instruction-text"),
json!(read_in.turn)
),
(
json!("supervisor"),
json!("answering-turn"),
json!(read_in.turn)
),
],
"a note recorded carried that a turn then opened on was not recorded as shown:\n\
{shown:#?}"
);
assert!(
shown
.iter()
.all(|event| event["payload"]["text"] == json!(NOTE)
&& event["payload"]["reached"] == json!("carried")),
"{shown:#?}"
);
}
#[test]
fn two_notes_in_one_envelope_are_each_recorded_on_the_turn_that_opened_on_them() {
let world = World::new("note-two-turns");
let run = "twoturns";
let first = "the reviewer asked for a smaller diff; stop editing src/old.rs";
let second = "leave the changelog alone; release-plz writes it";
world.script("turn.hold-each", "");
world.script("turn.hold", "hold");
world.write_graphs();
world.write_supervised_node_graph();
let path = world.plan(run, &plan_of(run, vec![agent("build", &[])]));
let mut launch = world.agentgraph_cmd(&["start", &path, "--detach"]);
launch.env(CANCEL_GRACE_ENV, "1");
world.run_on(launch, "start --detach").exited(0);
world.until("the worker's turn to open", |world| {
!world.events_of(run, "turn-started").is_empty()
});
let releasing = release_when_the_note_is_queued(&world, run, &["turn.go", "turn.settle"]);
let mut reply = world.agentgraph_cmd(&["reply", run]);
let body = json!({"version": 2, "commands": [
note_op("build", "worker", first, None),
note_op("build", "worker", second, None),
]})
.to_string();
let replied = std::thread::spawn(move || {
use std::io::Write;
let mut child = reply
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.expect("the binary starts");
child
.stdin
.as_mut()
.expect("stdin is piped")
.write_all(body.as_bytes())
.expect("the envelope is written");
child.wait_with_output().expect("the binary runs")
});
releasing.join().expect("the releasing thread finishes");
world.until("the turn carrying the first note to open", |world| {
worked(world).len() >= 2
});
std::thread::sleep(Duration::from_secs(2));
release(&world.fakes, "turn.go");
release(&world.fakes, "turn.settle");
let output = replied.join().expect("the reply thread finishes");
assert!(
output.status.success(),
"the envelope was not applied: {}",
String::from_utf8_lossy(&output.stderr)
);
world.until("the turn carrying the second note to open", |world| {
worked(world).len() >= 3
});
let committed: Vec<Value> = world
.events_of(run, "edit-committed")
.into_iter()
.filter(|event| event["payload"]["command"]["op"] == "note")
.map(|event| event["payload"]["operations"][0].clone())
.collect();
assert_eq!(committed.len(), 2, "{committed:#?}");
assert!(
committed
.iter()
.all(|operation| operation["reached"] == json!("worker")),
"a note did not reach the worker's turn: {committed:#?}"
);
world
.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(json!({"op": "cancel", "id": "build", "reason": "stop here"})),
)
.exited(0);
world.until("the held dispatch to be reaped at its deadline", |world| {
world
.events_of(run, "node-settled")
.iter()
.any(|event| event["labels"]["node"] == "build")
});
let openings = openings_of(&world, run, "build");
let turn_carrying = |text: &str| -> u64 {
let carrying: Vec<&TurnStarted> = openings
.iter()
.filter(|opening| opening.instruction.contains(text))
.collect();
assert_eq!(
carrying.len(),
1,
"{text:?} opened {} turns, not one:\n{openings:#?}",
carrying.len()
);
assert_eq!(
carrying[0].origin,
Some(Origin::Delivered),
"{:?}",
carrying[0]
);
carrying[0].turn
};
let first_turn = turn_carrying(first);
let second_turn = turn_carrying(second);
assert!(second_turn > first_turn, "{openings:#?}");
let shown = presentations_of(&world, run, "build");
let mut recorded: Vec<(String, String, u64)> = shown
.iter()
.map(|event| {
(
event["payload"]["text"]
.as_str()
.expect("a note")
.to_string(),
event["payload"]["party"]
.as_str()
.expect("a party")
.to_string(),
event["payload"]["turn"].as_u64().expect("a turn"),
)
})
.collect();
recorded.sort();
let mut expected = vec![
(first.to_string(), "worker".to_string(), first_turn),
(second.to_string(), "worker".to_string(), second_turn),
];
expected.sort();
assert_eq!(
recorded, expected,
"the presentations recorded are not one per note on the turn that opened on \
it:\n{shown:#?}"
);
for gate in ["turn.go", "turn.settle"] {
release(&world.fakes, gate);
}
}
#[test]
fn a_retry_replacement_spends_the_notes_the_node_it_supersedes_read_and_says_so() {
let world = World::new("note-retry-spent");
let run = "retryspent";
world.script("turn.hold-each", "Do build.");
world.script(
"judge.asks-again",
"Run the check again and report what it said.",
);
world.script("turn.hold", "hold");
world.script("judge.hold", "hold");
world.write_graphs();
world.write_supervised_node_graph();
let path = world.plan(
run,
&plan_of(run, vec![agent("build", &[]), agent("keep", &[])]),
);
let mut launch = world.agentgraph_cmd(&["start", &path, "--detach"]);
launch.env(CANCEL_GRACE_ENV, "1");
world.run_on(launch, "start --detach").exited(0);
world.until("the worker's turn to open", |world| {
!world.events_of(run, "turn-started").is_empty()
});
let releasing = release_when_the_note_is_queued(&world, run, &["turn.go", "turn.settle"]);
world
.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(note_op("build", "worker", NOTE, None)),
)
.exited(0)
.out_has("\"state\":\"applied\"");
releasing.join().expect("the releasing thread finishes");
assert_eq!(recorded(&world, run)["reached"], json!("worker"));
world
.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(json!({
"op": "retry",
"id": "build",
"node": {
"id": "build-again",
"persona": "engineer",
"task": "## What\nDo build again.",
},
})),
)
.exited(0)
.out_has("\"state\":\"applied\"");
world.until("the replacement to be dispatched", |world| {
!dispatch_records_of(world, run, "build-again").is_empty()
});
let records = dispatch_records_of(&world, run, "build-again");
assert_eq!(records.len(), 1, "{records:#?}");
let spent = records[0]["payload"]["notes_spent"]
.as_array()
.unwrap_or_else(|| {
panic!(
"the replacement does not say what its superseded node read: {}",
records[0]
)
});
assert_eq!(spent.len(), 1, "{spent:#?}");
assert_eq!(spent[0]["text"], json!(NOTE), "{spent:#?}");
assert_eq!(spent[0]["reached"], json!("worker"), "{spent:#?}");
assert!(
records[0]["payload"].get("notes_carried").is_none(),
"a replacement composed from the manager's own task carried a note: {}",
records[0]
);
for gate in ["turn.go", "turn.settle", "judge.go"] {
release(&world.fakes, gate);
}
}
#[test]
fn a_note_a_running_turn_took_is_not_carried_to_that_nodes_next_dispatch() {
let world = World::new("note-not-carried");
let run = "notcarried";
world.script("turn.hold-each", "Do build.");
world.script(
"judge.asks-again",
"Run the check again and report what it said.",
);
world.script("turn.hold", "hold");
world.script("judge.hold", "hold");
world.write_graphs();
world.write_supervised_node_graph();
let path = world.plan(
run,
&plan_of(run, vec![agent("build", &[]), agent("keep", &[])]),
);
let mut launch = world.agentgraph_cmd(&["start", &path, "--detach"]);
launch.env(CANCEL_GRACE_ENV, "1");
world.run_on(launch, "start --detach").exited(0);
world.until("the worker's turn to open", |world| {
!world.events_of(run, "turn-started").is_empty()
});
let releasing = release_when_the_note_is_queued(&world, run, &["turn.go", "turn.settle"]);
world
.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(note_op("build", "worker", NOTE, None)),
)
.exited(0)
.out_has("\"state\":\"applied\"");
releasing.join().expect("the releasing thread finishes");
let operation = recorded(&world, run);
assert_eq!(
operation["reached"],
json!("worker"),
"the note this journey is about did not reach a running turn: {operation}"
);
world
.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(json!({"op": "cancel", "id": "build", "reason": "re-dispatch it"})),
)
.exited(0);
world.until("the held dispatch to be reaped at its deadline", |world| {
world
.events_of(run, "node-settled")
.iter()
.any(|event| event["labels"]["node"] == "build")
});
world
.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(json!({"op": "requeue", "id": "build"})),
)
.exited(0)
.out_has("\"state\":\"applied\"");
world.until("the requeued node to be dispatched again", |world| {
dispatches_of(world, run, "build")
.get(1)
.is_some_and(|turns| !turns.is_empty())
});
let dispatched = dispatches_of(&world, run, "build");
assert!(
dispatched[0].iter().any(|turn| turn.contains(NOTE)),
"the note never reached a turn of the dispatch it was delivered into:\n{:#?}",
dispatched[0]
);
assert!(
dispatched[1].iter().all(|turn| !turn.contains(NOTE)),
"a note a running turn had already read was carried into the dispatch after \
it:\n{:#?}",
dispatched[1]
);
let records = dispatch_records_of(&world, run, "build");
assert_eq!(records.len(), 2, "{records:#?}");
assert!(
records[0]["payload"].get("notes_spent").is_none(),
"the first dispatch spent a note nothing had delivered yet: {}",
records[0]
);
let spent = records[1]["payload"]["notes_spent"]
.as_array()
.unwrap_or_else(|| {
panic!(
"the requeued dispatch does not say what it spent: {}",
records[1]
)
});
assert_eq!(spent.len(), 1, "{spent:#?}");
assert_eq!(spent[0]["text"], json!(NOTE), "{spent:#?}");
assert_eq!(spent[0]["reached"], json!("worker"), "{spent:#?}");
assert_eq!(spent[0]["addressee"], json!("worker"), "{spent:#?}");
let delivery = recorded(&world, run);
assert!(
delivery.get("shown_to").is_none(),
"the delivery record asserted a presentation the cancelled conversation never \
made: {delivery}"
);
assert_eq!(delivery["routed_to"], json!(["worker", "supervisor"]));
let shown = presentations_of(&world, run, "build");
assert_eq!(
shown
.iter()
.map(|event| event["payload"]["party"].clone())
.collect::<Vec<_>>(),
vec![json!("worker")],
"a conversation reaped before its judge was consulted recorded a presentation to \
the judge, or none to the worker whose turn opened on the note:\n{shown:#?}"
);
for gate in ["turn.go", "turn.settle", "judge.go"] {
release(&world.fakes, gate);
}
}
#[test]
fn a_note_a_dispatch_read_survives_the_engines_own_redispatch_of_the_node() {
let world = World::new("note-redispatch").with_env("ONEPIPELINE_PUBLICATION_ATTEMPTS", "2");
let run = "redispatch";
world.repository("change-auto", &[]);
world.script("harness.work", "the worker wrote this\n");
world.script("gh.checks", "llmlint completed failure required");
let mut service = lifecycle("service", &[]);
service["context"] = json!(PLANNER_CONTEXT);
held_conversation(&world, run, vec![service]);
let releasing = release_when_the_note_is_queued(&world, run, &["turn.go", "turn.settle"]);
let replied = world.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(note_op("service", "both", NOTE, Some(CRITERION))),
);
releasing.join().expect("the releasing thread finishes");
replied.exited(0).out_has("\"state\":\"applied\"");
let operation = recorded(&world, run);
assert_eq!(operation["reached"], json!("worker"), "{operation}");
world.until("the run to settle", |world| {
world.run_file(run, "result.json").is_file()
});
let records = dispatch_records_of(&world, run, "service");
assert_eq!(
records.len(),
2,
"the node was not dispatched exactly twice:\n{records:#?}"
);
let again = &records[1];
assert_eq!(again["payload"]["attempt"], json!(2), "{again}");
assert!(
again["payload"]["reason"]
.as_str()
.is_some_and(|reason| reason.starts_with("checks-failed:")),
"the re-dispatch is not the engine's own continuation: {again}"
);
let carried = again["payload"]["notes_carried"]
.as_array()
.unwrap_or_else(|| panic!("the re-dispatch does not name the notes it carries: {again}"));
assert_eq!(carried.len(), 1, "{carried:#?}");
assert_eq!(carried[0]["text"], json!(NOTE), "{carried:#?}");
assert_eq!(carried[0]["criterion"], json!(CRITERION), "{carried:#?}");
assert_eq!(carried[0]["addressee"], json!("both"), "{carried:#?}");
assert_eq!(carried[0]["reached"], json!("worker"), "{carried:#?}");
assert!(
again["payload"].get("notes_spent").is_none(),
"a dispatch composed with the note reported it spent: {again}"
);
let journal = world.journal(run);
let redispatched_at = journal
.iter()
.position(|event| {
event["kind"] == "node-dispatched"
&& event["labels"]["node"] == "service"
&& event["payload"]["attempt"] == json!(2)
})
.expect("the re-dispatch is in the store");
let after: Vec<Value> = journal[redispatched_at..]
.iter()
.filter(|event| event["kind"] == "note-shown" && event["labels"]["node"] == "service")
.map(|event| event["payload"]["party"].clone())
.collect();
assert_eq!(
after,
vec![json!("worker"), json!("supervisor")],
"the second conversation's presentations are not the worker's and then the \
judge's:\n{:#?}",
presentations_of(&world, run, "service")
);
assert_eq!(
presentations_of(&world, run, "service").len(),
4,
"each conversation shows the note to each party once:\n{:#?}",
presentations_of(&world, run, "service")
);
let dispatched = dispatches_of(&world, run, "service");
assert_eq!(dispatched.len(), 2, "{dispatched:#?}");
let opening = dispatched[1]
.first()
.unwrap_or_else(|| panic!("the second dispatch opened no turn:\n{dispatched:#?}"));
for said in [
"## Manager notes\nWhere this section and the operational notes below disagree, this \
section wins.\n\nThe manager delivered these notes to this node during an earlier \
dispatch of it, and this dispatch continues that node's work: each stands here exactly \
as it stood there, for the worker and for the supervisor alike. A note that states a \
criterion is part of the bar this node is judged against.\n\n1. Addressed to both parties",
NOTE,
CRITERION,
"## Planner context",
PLANNER_CONTEXT,
"checks-failed",
] {
assert!(
opening.contains(said),
"the re-dispatch's task lacks {said:?}:\n{opening}"
);
}
assert!(
!dispatched[0][0].contains("## Manager notes"),
"the first dispatch was composed with a note that had not been delivered yet:\n{}",
dispatched[0][0]
);
assert!(
dispatched[0][0].contains(PLANNER_CONTEXT) && !dispatched[0][0].contains("checks-failed"),
"the first dispatch was not composed with the planner's note alone:\n{}",
dispatched[0][0]
);
let planner_note_at = opening
.find(PLANNER_CONTEXT)
.expect("the planner's note is in the continuation");
let diagnosis_at = opening
.find("The previous attempt's publication failed")
.expect("the diagnosis is in the continuation");
assert!(
planner_note_at < diagnosis_at,
"the planner's note does not lead the continuation's context:\n{opening}"
);
let openings = openings_of(&world, run, "service");
let second_opening = openings
.iter()
.find(|turn| turn.instruction.contains("## Manager notes"))
.expect("the second dispatch's opening turn is in the store");
assert_eq!(second_opening.turn, 1, "{second_opening:?}");
assert_eq!(
second_opening.origin,
Some(Origin::Task),
"{second_opening:?}"
);
let judge = judged(&world);
assert!(
judge
.iter()
.any(|prompt| prompt.contains("## Manager notes") && prompt.contains(NOTE)),
"no judge decision of the second dispatch was handed the note the first \
dispatch obeyed:\n{judge:#?}"
);
}
#[test]
fn a_note_a_failed_delivery_attempt_is_carried_rather_than_refused_with_it() {
let world = World::new("note-attempted");
let run = "attempted";
world.script("harness.fail", "");
supervised_run(&world, run, vec![agent("build", &[])]);
world.until("the run's driver to release it", |world| {
!world.run_file(run, "owner.lock").exists()
});
world
.run_with_stdin_on(
world.cmd(&["reply", run]),
&envelope(note_op("build", "worker", NOTE, None)),
)
.exited(0)
.out_has("\"state\":\"applied\"");
let operation = recorded(&world, run);
assert_eq!(
operation["reached"],
json!("carried"),
"a note whose delivery was attempted and failed was not carried: {operation}"
);
}
#[test]
fn a_note_reaching_the_live_judge_re_takes_its_decision_and_rides_it_to_the_worker() {
let world = World::new("note-judge");
let run = "judge";
world.script(
"judge.asks-again",
"Run the check again and report what it said.",
);
world.script("judge.asks-again-times", "2");
held_judge(&world, run, vec![agent("build", &[])]);
let releasing = release_when_the_note_is_queued(&world, run, &["judge.go"]);
let replied = world.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(note_op("build", "supervisor", NOTE, None)),
);
releasing.join().expect("the releasing thread finishes");
replied.exited(0).out_has("\"state\":\"applied\"");
world.until("the run to settle", |world| {
!world.events_of(run, "node-settled").is_empty()
});
let operation = recorded(&world, run);
assert_eq!(operation["addressee"], json!("supervisor"), "{operation}");
assert_eq!(
operation["reached"],
json!("supervisor"),
"the note did not reach the party whose turn was live: {operation}"
);
assert_eq!(operation["shown_to"], json!(["supervisor"]), "{operation}");
assert_eq!(operation["routed_to"], json!(["worker"]), "{operation}");
let shown = presentations_of(&world, run, "build");
assert_eq!(
shown
.iter()
.map(|event| event["payload"]["party"].clone())
.collect::<Vec<_>>(),
vec![json!("worker")],
"the worker's presentation of a note that rode the judge's decision was not \
recorded once and alone:\n{shown:#?}"
);
let judge = judged(&world);
assert!(
judge
.iter()
.any(|prompt| prompt.contains("delivered to YOU, the supervisor")
&& prompt.contains(NOTE)),
"no judge decision was handed the note as its own:\n{judge:#?}"
);
let worker = worked(&world);
assert!(
worker.iter().any(|prompt| prompt
.contains("delivered to the SUPERVISOR, addressed to it and not to you")
&& prompt.contains(NOTE)),
"the note never rode the judge's response to the worker:\n{worker:#?}"
);
}
#[test]
fn a_note_the_judge_passed_the_work_with_is_recorded_as_judged_with() {
let world = World::new("note-passed");
let run = "passed";
held_judge(&world, run, vec![agent("build", &[])]);
let releasing = release_when_the_note_is_queued(&world, run, &["judge.go"]);
let replied = world.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(note_op("build", "both", NOTE, None)),
);
releasing.join().expect("the releasing thread finishes");
replied.exited(0).out_has("\"state\":\"applied\"");
world.until("the run to settle", |world| {
!world.events_of(run, "node-settled").is_empty()
});
let operation = recorded(&world, run);
assert_eq!(operation["addressee"], json!("both"), "{operation}");
assert_eq!(
operation["reached"],
json!("judged-with"),
"the run does not say the work was passed with the note in hand: {operation}"
);
assert!(
operation["completion_reason"].is_string(),
"the record does not carry the reason the work was passed: {operation}"
);
assert_eq!(
operation["shown_to"],
json!(["supervisor"]),
"a note only the judge read is recorded as shown to the worker too: {operation}"
);
assert!(
operation.get("routed_to").is_none(),
"a note the judge completed with was routed onward: {operation}"
);
assert!(
presentations_of(&world, run, "build").is_empty(),
"a presentation was recorded for a note that reached no turn after the decision"
);
let judge = judged(&world);
assert!(
judge
.iter()
.any(|prompt| prompt.contains("(addressed to both)") && prompt.contains(NOTE)),
"no judge decision was handed the note addressed to both parties:\n{judge:#?}"
);
}
#[test]
fn a_note_is_refused_when_this_run_composes_the_sibling_as_an_executable() {
let world = World::new("note-pinned");
let run = "pinned";
held_conversation(&world, run, vec![agent("build", &[])]);
release(&world.fakes, "turn.go");
release(&world.fakes, "turn.settle");
world.until("the run's driver to release it", |world| {
!world.run_file(run, "owner.lock").exists()
});
let refused = world.run_with_stdin_on(
world.cmd(&["reply", run]),
&envelope(note_op("build", "worker", NOTE, None)),
);
refused
.exited(2)
.err_has("was not delivered")
.err_has("ONEPIPELINE_ONEAGENTGRAPH_BIN")
.err_has("no verb");
}
#[test]
fn an_undeclared_monitor_is_refused_before_its_note_is_queued() {
let world = World::new("note-monitor");
let run = "notemonitor";
held_conversation(&world, run, vec![agent("build", &[])]);
let refused = world.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&json!({
"version": 2,
"author": "monitor",
"commands": [note_op("build", "worker", NOTE, Some(CRITERION))],
})
.to_string(),
);
refused
.exited(REFUSED)
.err_has("the envelope's author `monitor` is not declared")
.err_has("the declared authors are: planner");
let queue = world.run_file(run, "channel/commands.jsonl");
assert!(
!a_note_is_queued(&queue),
"a note the monitor was refused was queued anyway: {}",
std::fs::read_to_string(&queue).unwrap_or_default()
);
for kind in ["edit-committed", "edit-rejected"] {
assert!(
world.events_of(run, kind).is_empty(),
"the run recorded a `{kind}` for an envelope it refused at the boundary"
);
}
let releasing = release_when_the_note_is_queued(&world, run, &["turn.go", "turn.settle"]);
let replied = world.run_with_stdin_on(
world.agentgraph_cmd(&["reply", run]),
&envelope(note_op("build", "worker", NOTE, Some(CRITERION))),
);
releasing.join().expect("the releasing thread finishes");
replied.exited(0);
world.until("the run to settle", |world| {
!world.events_of(run, "node-settled").is_empty()
});
assert_eq!(recorded(&world, run)["reached"], json!("worker"));
}
#[test]
fn a_note_the_envelope_cannot_carry_is_refused_at_the_wire_and_nothing_is_queued() {
let world = World::new("note-boundary");
let run = "noteboundary";
held_conversation(&world, run, vec![agent("build", &[])]);
let refused = [
(
json!({"op": "context", "id": "build", "note": NOTE}),
"unknown variant `context`",
),
(
json!({"op": "note", "id": "build", "addressee": "worker", "text": NOTE,
"deliver": "auto"}),
"unknown variant `auto`",
),
(
note_op_with("build", NOTE, "next", false),
"reaches nobody whatever the run does",
),
(
json!({"op": "note", "id": "build", "addressee": "worker", "text": " \n"}),
"this one was blank",
),
(
json!({"op": "note", "id": "build", "addressee": "sponsor", "text": NOTE}),
"unknown variant `sponsor`",
),
(
json!({"op": "note", "id": "build", "text": NOTE}),
"missing field `addressee`",
),
(
note_op(
"build",
"worker",
NOTE,
Some("the tree pins oneagentgraph 0.3.15"),
),
"names a version literal",
),
];
for (op, named) in refused {
world
.run_with_stdin_on(world.agentgraph_cmd(&["reply", run]), &envelope(op))
.exited(REFUSED)
.err_has(named);
}
let queue = world.run_file(run, "channel/commands.jsonl");
assert!(
!a_note_is_queued(&queue),
"a note the envelope refused was queued anyway: {}",
std::fs::read_to_string(&queue).unwrap_or_default()
);
for kind in ["edit-committed", "edit-rejected"] {
assert!(
world.events_of(run, kind).is_empty(),
"the run recorded a `{kind}` for an envelope it refused at the wire"
);
}
release(&world.fakes, "turn.go");
release(&world.fakes, "turn.settle");
world.until("the run to settle", |world| {
!world.events_of(run, "node-settled").is_empty()
});
assert!(
worked(&world).iter().all(|prompt| !prompt.contains(NOTE)),
"a note the wire refused was handed to the worker anyway"
);
}