use std::collections::BTreeSet;
use std::num::{NonZeroU32, NonZeroU64};
use std::path::{Path, PathBuf};
use clap::{CommandFactory, Parser};
use oneagentgraph::config::{ConfigRef, GraphConfig, JudgeSide, Member};
use oneagentgraph::persona::{merge, Persona};
use onepipeline::channel::{
allows, Author, Command as Edit, Dependents, Reply, Surface, SurfaceKind,
};
use onepipeline::cli::{
Cli, Command, DAG_GRAPH_OFF, DEFAULT_DISPATCH_ENV_HOOK_TIMEOUT_SECONDS,
DEFAULT_HEARTBEAT_INTERVAL_SECONDS, DEFAULT_HOOK_TIMEOUT_SECONDS,
DEFAULT_WRITEBACK_ITEM_BUDGET_SECONDS, WRITEBACK_CLASSIFIED_COMMANDS,
WRITEBACK_COMMAND_FLOOR_SECONDS, WRITEBACK_FAILURE_CLASS_MEMBER, WRITEBACK_FAILURE_EXIT,
WRITEBACK_ITEM_BUDGET_ENV, WRITEBACK_MEMBERS_FROM, WRITEBACK_MEMBER_READ,
WRITEBACK_PARTIAL_CLASS_MEMBER, WRITEBACK_PARTIAL_EXIT, WRITEBACK_PROJECTIONS_FILE,
WRITEBACK_REFUSED_CLASS, WRITEBACK_STORE_FILE,
};
use onepipeline::controls::NodeControls;
use onepipeline::error::{
EXIT_NODE_SETTLED, EXIT_NOTHING_DRIVING, EXIT_QUEUED, EXIT_REFUSED, EXIT_SUCCESS,
EXIT_SURFACE_WAITING, EXIT_WATCH_ELAPSED,
};
use onepipeline::event::{
ArtifactId, ArtifactRef, Envelope, EventKind, Labels, Phase, PipelineKind, Source,
ENVELOPE_VERSION, ENVELOPE_VERSIONS_READ, PIPELINE_KINDS,
};
use onepipeline::executor::{
CancelMode, CancellationToken, Capabilities, CapacityReport, DispatchRequest, Executor,
LocalExecutor, WorkspaceSpec,
};
use onepipeline::filter::{
EventFilter, Filters, LaunchConfig, Matcher, LAUNCH_CONFIG_SCHEMA_VERSION,
LAUNCH_CONFIG_SCHEMA_VERSIONS_READ,
};
use onepipeline::note::{Addressee, Delivered, Note, Party, Reached};
use onepipeline::plan::{
adoption_instructions, arrival_note, CrossRepoReference, Node, NodeKind, Plan, RepoType,
Resume, Step, Workflow, ADOPTION_INSTRUCTION_VARIABLES, AMENDMENT_HEADING,
AMENDMENT_PRECEDENCE, CROSS_REPO_REFERENCES_HEADING, DEFAULT_ADOPTION_INSTRUCTION,
OBSERVED_STATE, PLANNER_CONTEXT_HEADING, PLAN_SCHEMA_VERSION, PLAN_SCHEMA_VERSIONS_READ,
};
use onepipeline::report::{
retain, ACCEPTED_REPORT_FILE, MAX_REPORT_BYTES, MEMBER_SETTLED, REPORT_PATH,
};
use onepipeline::rules::{ExecutorKind, ExecutorRules, Predicate};
use onepipeline::verbs;
use onepipeline::views::{
FailureClass, Listing, NodeLanding, ProjectGroup, ProjectionActions, ProjectionEnded,
ProjectionFailure, ProjectionRecord, ProjectionScope, Projects, RunPaths, RunSummary,
RunTelemetry, WholeBecause, GROUP_HEADER, NO_PROJECT, SUMMARY_SCHEMA_VERSION,
};
use onevcs::{Adoption, MergePolicy, SessionRequest};
use serde_json::{json, Value};
const CONTRACT: &str = include_str!("../docs/contract.md");
fn repo_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
}
fn fenced_blocks(language: &str) -> Vec<String> {
let mut blocks = Vec::new();
let mut open: Option<String> = None;
let mut body = String::new();
for line in CONTRACT.lines() {
match &open {
Some(info) => {
if line.trim_end() == "```" {
if info == language {
blocks.push(std::mem::take(&mut body));
}
body.clear();
open = None;
} else {
body.push_str(line);
body.push('\n');
}
}
None => {
if let Some(info) = line.trim_end().strip_prefix("```") {
open = Some(info.trim().to_string());
body.clear();
}
}
}
}
assert!(open.is_none(), "unterminated ``` block in docs/contract.md");
blocks
}
fn fenced_block_naming(language: &str, needle: &str) -> String {
let mut matching: Vec<String> = fenced_blocks(language)
.into_iter()
.filter(|body| body.contains(needle))
.collect();
assert_eq!(
matching.len(),
1,
"expected exactly one ```{language} block naming {needle:?} in docs/contract.md, found {}",
matching.len()
);
matching.pop().expect("one block")
}
fn backticked() -> BTreeSet<String> {
let mut out = BTreeSet::new();
let mut rest = CONTRACT;
while let Some(open) = rest.find('`') {
rest = &rest[open + 1..];
let Some(close) = rest.find('`') else { break };
out.insert(rest[..close].to_string());
rest = &rest[close + 1..];
}
out
}
fn assert_contract_names(what: &str, names: &[&str]) {
for name in names {
assert!(
CONTRACT.contains(name),
"docs/contract.md no longer names the {what} `{name}`"
);
}
}
#[test]
fn the_contracts_rules_example_parses_and_round_trips() {
let yaml = fenced_block_naming("yaml", "executors:");
let rules: ExecutorRules = serde_norway::from_str(&yaml).expect("the rules example parses");
assert_eq!(
rules.executors.len(),
1,
"the example declares one executor"
);
let local = &rules.executors[0];
assert_eq!(local.name, "local");
assert_eq!(local.kind, ExecutorKind::Local);
assert_eq!(local.max_load1, Some(8.0));
assert_eq!(
local.min_free_mem.as_deref(),
Some("2GiB"),
"the size is carried as the contract writes it"
);
assert_eq!(
rules.rules.len(),
2,
"the example declares two ordered rules"
);
assert_eq!(
rules.rules[0].when,
Some(Predicate {
executor_has_capacity: Some("local".into()),
..Predicate::default()
}),
"the first rule tests capacity"
);
assert_eq!(rules.rules[0].use_executor, "local");
assert_eq!(
rules.rules[1].when, None,
"the last rule is the unconditional fallback"
);
assert_eq!(rules.rules[1].use_executor, "local");
let round_tripped: ExecutorRules =
serde_norway::from_str(&serde_norway::to_string(&rules).expect("serializes"))
.expect("re-parses");
assert_eq!(round_tripped, rules);
}
#[test]
fn the_contract_states_both_predicate_families_and_what_each_matches_on() {
let prose = CONTRACT.split_whitespace().collect::<Vec<_>>().join(" ");
assert!(
prose.contains("`executor_has_capacity: NAME` matches on **capacity**"),
"the contract no longer says what the capacity family matches on"
);
assert!(
prose.contains("`node_label: {KEY: VALUE, ...}` matches on the **node's labels**"),
"the contract no longer says what the label family matches on"
);
assert!(
prose.contains("Several conditions in one `when` conjoin"),
"the contract no longer says how two conditions in one `when` combine"
);
for key in onepipeline::rules::SELECTABLE_LABELS {
assert!(
prose.contains(&format!("`{key}`")),
"the contract does not name the selectable label `{key}`"
);
}
let rules: ExecutorRules = serde_norway::from_str(
"executors: [{name: local, type: local}]\n\
rules: [{when: {node_label: {step: implement}}, use: local}]\n",
)
.expect("it parses");
let err = rules
.validate()
.expect_err("`step` is not a key the contract lists");
assert!(err.to_string().contains("step"), "{err}");
}
#[test]
fn an_unknown_rules_key_is_refused_at_the_boundary() {
let bad = "executors:\n - {name: local, type: local, mx_load1: 8.0}\nrules:\n - use: local\n";
let err = serde_norway::from_str::<ExecutorRules>(bad)
.expect_err("a mistyped key is rejected, not silently dropped");
assert!(
err.to_string().contains("mx_load1"),
"the error names the offending key: {err}"
);
}
#[test]
fn the_shipped_rules_example_is_the_contracts_own() {
let shipped = std::fs::read_to_string(repo_root().join("examples/executors.yaml"))
.expect("examples/executors.yaml ships");
let shipped: ExecutorRules = serde_norway::from_str(&shipped).expect("it parses");
let documented: ExecutorRules =
serde_norway::from_str(&fenced_block_naming("yaml", "executors:"))
.expect("the contract's example parses");
assert_eq!(
shipped, documented,
"the shipped executor-rules example must be the contract's own"
);
}
#[test]
fn the_dispatch_request_carries_every_field_the_contract_declares() {
let request = DispatchRequest {
graph: ConfigRef("./graphs/node-scope.yaml".into()),
task: "## What\nDo the thing.".into(),
labels: Labels {
run_id: Some("run-1".into()),
round: Some(2),
node: Some("service".into()),
step: Some("implement".into()),
persona: Some("engineer".into()),
..Labels::default()
},
controls: NodeControls {
max_turns: NonZeroU32::new(24),
},
workspace: WorkspaceSpec::VcsSession(SessionRequest {
repo: "nickderobertis/some-service".into(),
branch: None,
base: None,
execution_checkout: None,
pool: None,
overflow: None,
labels: Default::default(),
}),
cancel: CancellationToken::new(),
attempt: NonZeroU32::new(2).expect("two is an attempt"),
};
assert_contract_names(
"DispatchRequest field",
&[
"graph",
"task",
"labels",
"controls",
"workspace",
"cancel",
"attempt",
],
);
assert_eq!(
request.attempt.get(),
2,
"the request carries which attempt of the node it is"
);
assert_eq!(
request.controls.max_turns,
NonZeroU32::new(24),
"the request carries the node's own controls, not only its labels"
);
assert_contract_names(
"reserved label",
&["run_id", "round", "node", "step", "persona"],
);
assert_contract_names(
"WorkspaceSpec variant",
&["Path(PathBuf)", "VcsSession(SessionRequest"],
);
match &request.workspace {
WorkspaceSpec::VcsSession(session) => {
assert_eq!(session.repo, "nickderobertis/some-service");
}
WorkspaceSpec::Path(path) => panic!("built a VcsSession, got a path: {}", path.display()),
}
let local = WorkspaceSpec::Path(Path::new("/tmp/work").to_path_buf());
assert_ne!(local, request.workspace);
}
#[test]
fn the_local_executor_is_the_one_v1_ships_and_takes_both_workspaces() {
let local = LocalExecutor;
assert_eq!(local.name(), "local");
assert_eq!(
local.capabilities(),
Capabilities { vcs_sessions: true },
"the contract says LocalExecutor supports both WorkspaceSpec variants"
);
assert!(CONTRACT.contains("v1 ships `LocalExecutor` only (supports both variants)"));
}
#[test]
fn the_local_executors_capacity_reports_the_three_numbers_the_contract_names() {
let report = LocalExecutor.capacity();
assert!(
report.load1.is_finite() && report.load1 >= 0.0,
"{report:?}"
);
assert!(report.mem_free_bytes > 0, "{report:?}");
assert_ne!(report, CapacityReport::default(), "nothing was probed");
assert_contract_names(
"CapacityReport field",
&["slots_free", "load1", "mem_free_bytes"],
);
}
static SEAM_ENV: std::sync::Mutex<()> = std::sync::Mutex::new(());
fn seam_env_lock() -> std::sync::MutexGuard<'static, ()> {
SEAM_ENV
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
}
#[test]
fn dispatching_goes_through_the_oneagentgraph_seam_and_says_so_when_it_cannot() {
let _seam = seam_env_lock();
std::env::set_var(
"ONEPIPELINE_ONEAGENTGRAPH_BIN",
"oneagentgraph-that-is-not-installed",
);
let Err(err) = LocalExecutor.dispatch(DispatchRequest {
graph: ConfigRef("./graphs/node-scope.yaml".into()),
task: "anything".into(),
labels: Labels::default(),
controls: NodeControls::default(),
workspace: WorkspaceSpec::Path(PathBuf::from(".")),
cancel: CancellationToken::new(),
attempt: NonZeroU32::MIN,
}) else {
panic!("no `oneagentgraph` is installed here, so the dispatch cannot start");
};
let message = err.to_string();
assert!(
message.contains("oneagentgraph"),
"the seam is unnamed: {message}"
);
std::env::remove_var("ONEPIPELINE_ONEAGENTGRAPH_BIN");
}
#[test]
fn the_contracts_launch_config_example_parses_and_round_trips() {
let yaml = fenced_block_naming("yaml", "schema_version: 2");
let config: LaunchConfig = serde_norway::from_str(&yaml).expect("the launch config parses");
assert!(
LAUNCH_CONFIG_SCHEMA_VERSIONS_READ.contains(&config.schema_version),
"the contract's example declares a version this build does not read: {}",
config.schema_version
);
assert_eq!(
config.pr_author_graph.as_deref(),
Some("./graphs/pr-author.yaml"),
"the contract's example declares the launch's other decision and this build \
does not read it"
);
let filters = config.filters;
let agentgraph = filters
.agentgraph
.as_ref()
.expect("it names a source filter");
assert_eq!(agentgraph.include, Vec::new(), "an absent include is empty");
assert_eq!(agentgraph.exclude.len(), 1);
assert_eq!(agentgraph.exclude[0].kind.as_deref(), Some("turn-activity"));
let vcs = filters.vcs.as_ref().expect("it names a vcs filter");
assert_eq!(vcs.include.len(), 2);
assert_eq!(vcs.include[0].kind.as_deref(), Some("gate-*"));
assert_eq!(
filters.profiles["planner"],
EventFilter {
include: vec![Matcher {
source: Some(Source::Pipeline),
..Matcher::default()
}],
exclude: Vec::new(),
}
);
assert_eq!(filters.profiles["detailed"], EventFilter::default());
let round_tripped: Filters =
serde_json::from_str(&serde_json::to_string(&filters).expect("serializes"))
.expect("re-parses");
assert_eq!(round_tripped, filters);
let golden: LaunchConfig = serde_json::from_str(
&std::fs::read_to_string(repo_root().join("tests/golden/launch-config-v2.json"))
.expect("the golden ships"),
)
.expect("the golden parses");
let mut recorded = golden.filters.clone();
let retired = recorded
.profiles
.remove("monitor")
.expect("the golden records an override under the name the profile shipped as then");
assert_eq!(retired, EventFilter::default());
let mut stated = filters.clone();
let detailed = stated
.profiles
.remove("detailed")
.expect("the contract's example overrides the shipped `detailed` profile");
assert_eq!(detailed, EventFilter::default());
assert_eq!(
(golden.schema_version, recorded, golden.pr_author_graph),
(config.schema_version, stated, config.pr_author_graph),
"tests/golden/launch-config-v2.json and the contract's own example are \
different documents beyond the recorded override's name"
);
let earlier: LaunchConfig = serde_json::from_str(
&std::fs::read_to_string(repo_root().join("tests/golden/launch-config-v1.json"))
.expect("the earlier golden ships"),
)
.expect("the earlier golden parses");
assert_eq!(earlier.schema_version, 1);
assert_eq!(
earlier.pr_author_graph, None,
"the earlier golden carries a key that version never had"
);
assert!(
CONTRACT.contains("a version-1 config is a complete document this build still reads"),
"the contract no longer says an earlier launch config still reads"
);
}
#[test]
fn the_contracts_launch_config_omits_an_empty_block_and_still_reads() {
for version in LAUNCH_CONFIG_SCHEMA_VERSIONS_READ {
let bare: LaunchConfig = serde_norway::from_str(&format!("schema_version: {version}\n"))
.expect("a config may declare only a version");
assert!(bare.filters.is_empty());
assert_eq!(bare.pr_author_graph, None);
assert_eq!(bare.node_validator, None);
}
assert_eq!(
serde_json::to_string(&LaunchConfig::default()).expect("serializes"),
format!(r#"{{"schema_version":{LAUNCH_CONFIG_SCHEMA_VERSION}}}"#),
"an empty filters block, an absent drafting graph, or an absent node \
validator was written out"
);
assert_contract_names(
"launch config surface",
&["--launch-config FILE", "schema_version: 2"],
);
}
#[test]
fn the_shipped_profiles_are_the_contracts_own_and_are_overridable() {
let empty = Filters::default();
assert_eq!(
empty.profile("planner").expect("planner ships"),
EventFilter {
include: vec![Matcher {
source: Some(Source::Pipeline),
..Matcher::default()
}],
exclude: Vec::new(),
}
);
assert_eq!(
empty.profile("detailed").expect("detailed ships"),
EventFilter::default(),
"the shipped detailed profile is unfiltered"
);
let retired = empty
.profile("monitor")
.expect_err("the retired profile name is not an alias")
.to_string();
assert!(
retired.contains("'monitor' is not a filter profile") && retired.contains("detailed"),
"{retired}"
);
let mine = EventFilter::parse(r#"{"include": [{"kind": "node-*"}]}"#).expect("a filter");
let overridden = Filters {
profiles: [
("planner".to_string(), mine.clone()),
("detailed".to_string(), mine.clone()),
]
.into_iter()
.collect(),
..Filters::default()
};
assert_eq!(overridden.profile("planner").expect("overridden"), mine);
assert_eq!(overridden.profile("detailed").expect("overridden"), mine);
let unknown = empty
.profile("planer")
.expect_err("a profile this run does not have is refused");
let said = unknown.to_string();
assert!(said.contains("planer"), "{said}");
assert!(
said.contains("planner") && said.contains("detailed"),
"{said}"
);
}
#[test]
fn a_filter_spec_is_refused_by_the_shared_grammars_own_rules() {
let unknown_field = EventFilter::parse(r#"{"include": [{"role": "agent"}]}"#)
.expect_err("a matcher field the grammar does not have is refused");
let said = unknown_field.to_string();
assert!(said.contains("role"), "the refusal names the field: {said}");
assert!(
said.contains("include") && said.contains('1'),
"the refusal says which list and where in it: {said}"
);
let stray = EventFilter::parse(r#"{"includes": []}"#)
.expect_err("a filter names include and exclude and nothing else");
assert!(stray.to_string().contains("includes"), "{stray}");
let deprecated = EventFilter::parse(r#"{"include": [{"round": "1"}]}"#)
.expect_err("`round` is not in the grammar");
assert!(deprecated.to_string().contains("round"), "{deprecated}");
let empty_matcher = EventFilter::parse(r#"{"exclude": [{}]}"#)
.expect_err("a matcher naming no field matches everything");
assert!(
empty_matcher.to_string().contains("exclude"),
"{empty_matcher}"
);
let empty_field = EventFilter::parse(r#"{"include": [{"kind": ""}]}"#)
.expect_err("nothing on the stream carries an empty kind");
assert!(empty_field.to_string().contains("kind"), "{empty_field}");
let record = serde_json::from_str::<Filters>(r#"{"vcs": {"exclude": [{}]}}"#)
.expect_err("a launch record carrying an unusable filter is refused");
assert!(record.to_string().contains("exclude"), "{record}");
}
fn property_names(node: &Value, root: &Value) -> BTreeSet<String> {
let mut names = BTreeSet::new();
if let Some(properties) = node.get("properties").and_then(Value::as_object) {
names.extend(properties.keys().cloned());
}
if let Some(target) = node
.get("$ref")
.and_then(Value::as_str)
.and_then(|reference| reference.strip_prefix('#'))
.and_then(|pointer| root.pointer(pointer))
{
names.extend(property_names(target, root));
}
if let Some(parts) = node.get("allOf").and_then(Value::as_array) {
for part in parts {
names.extend(property_names(part, root));
}
}
names
}
fn backticked_in(passage: &str) -> BTreeSet<String> {
passage
.split('`')
.skip(1)
.step_by(2)
.map(str::to_owned)
.collect()
}
#[test]
fn the_marked_copy_of_the_bus_contract_is_reconciled_against_the_released_bus() {
let decided = CONTRACT
.split_once("decided against `onemessagebus` ")
.and_then(|(_, rest)| {
rest.split(|c: char| !(c.is_ascii_digit() || c == '.'))
.next()
})
.map(|version| version.trim_end_matches('.'))
.filter(|version| !version.is_empty())
.expect("the contract names the bus release its marked copy was decided against");
let lock = std::fs::read_to_string(repo_root().join("Cargo.lock")).expect("the lock ships");
for bus in ["onemessagebus", "onemessagebus-agent"] {
let resolved: Vec<&str> = lock
.split("[[package]]")
.filter(|package| {
package
.lines()
.any(|line| line == format!("name = \"{bus}\""))
})
.filter_map(|package| {
package
.lines()
.find_map(|line| line.strip_prefix("version = \""))
.map(|version| version.trim_end_matches('"'))
})
.collect();
assert_eq!(
resolved,
vec![decided],
"docs/contract.md's copy was decided against `onemessagebus` {decided}, and the lock \
resolves {bus} at {resolved:?}: re-decide the copy against the linked release"
);
}
let grammar = CONTRACT
.lines()
.find(|line| line.starts_with("**Filtering is owned by the stream's source.**"))
.expect("the contract states the filter grammar");
let fields = grammar
.split_once("A matcher's fields are all optional")
.and_then(|(_, rest)| rest.split_once("An absent or empty"))
.map(|(clause, _)| clause)
.expect("the grammar paragraph lists the matcher's fields");
let named: BTreeSet<String> = backticked_in(fields)
.into_iter()
.filter(|token| token.chars().all(|c| c.is_ascii_lowercase() || c == '_'))
.filter(|token| token != "onevcs")
.collect();
let document = serde_json::to_value(schemars::schema_for!(Matcher))
.expect("the bus's matcher document serializes");
assert_eq!(
named,
property_names(&document, &document),
"the grammar paragraph's matcher fields are not the ones the linked bus declares"
);
let sources = CONTRACT
.split_once("interleaving the three sources ")
.and_then(|(_, rest)| rest.split_once('.'))
.map(|(list, _)| backticked_in(list))
.expect("the contract names the merged stream's sources");
assert_eq!(
sources,
Source::every()
.iter()
.map(|source| source.as_str().to_owned())
.collect::<BTreeSet<_>>(),
"the contract's sources are not the ones the linked bus declares"
);
}
#[test]
fn the_contract_names_the_producers_words_for_a_chain_that_stopped() {
use oneagentgraph::event::Cause;
let passage = CONTRACT
.split_once("**A chain that stopped raises a finding.**")
.and_then(|(_, rest)| rest.split_once("\n\n"))
.map(|(passage, _)| passage)
.expect("the contract states which death is a chain that stopped");
let named = backticked_in(passage);
for word in [
oneagentgraph::member::Rule::ProviderFailure.as_str(),
Cause::Unclassified.as_str(),
Cause::FallbackChainExhausted.as_str(),
"finding",
"proposal",
] {
assert!(
named.contains(word),
"the chain-stopping paragraph does not name `{word}`: {passage}"
);
}
}
#[test]
fn the_committed_planner_channel_document_is_the_compiled_in_layout() {
use onepipeline::channel::layout::{bundle_json, DOCUMENT_PATH};
let path = repo_root().join(DOCUMENT_PATH);
let generated = bundle_json();
if std::env::var_os("ONEPIPELINE_WRITE_LAYOUT_DOCUMENT").is_some() {
std::fs::write(&path, &generated).expect("the document is written");
}
let committed = std::fs::read_to_string(&path)
.unwrap_or_else(|error| panic!("{DOCUMENT_PATH} is committed: {error}"));
assert!(
committed == generated,
"{DOCUMENT_PATH} is not what the compiled-in layout generates. If the layout \
changed on purpose, raise `DOCUMENT_VERSION` and regenerate it with \
`ONEPIPELINE_WRITE_LAYOUT_DOCUMENT=1 cargo test --test contract \
the_committed_planner_channel_document_is_the_compiled_in_layout`; never edit it \
by hand.\n--- committed\n{committed}\n--- generated\n{generated}"
);
}
#[test]
fn the_contract_states_the_planner_channel_documents_path_version_and_source() {
use onepipeline::channel::layout::{document, DOCUMENT_PATH, DOCUMENT_VERSION};
let passage = CONTRACT
.split_once("**The planner-channel layout is published as a document.**")
.and_then(|(_, rest)| rest.split_once("\n\n"))
.map(|(passage, _)| passage)
.expect("the contract states the published layout document");
let named = backticked_in(passage);
for word in [
DOCUMENT_PATH,
DOCUMENT_VERSION,
"LayoutDocument",
"SchemaBundle",
] {
assert!(
named.contains(word),
"the layout-document paragraph does not name `{word}`: {passage}"
);
}
assert!(
passage.contains("compiled-in layout is its one source"),
"the paragraph does not say where the document comes from: {passage}"
);
let committed = std::fs::read_to_string(repo_root().join(DOCUMENT_PATH))
.expect("the document is committed");
let bundle =
onemessagebus::SchemaBundle::from_json(&committed).expect("the bus reads the document");
assert_eq!(bundle.version().to_string(), DOCUMENT_VERSION);
assert_eq!(bundle.layouts(), [document()]);
}
#[test]
fn the_grammar_matches_the_way_the_contract_says_it_does() {
let envelope = |source: Source, kind: &str, labels: Labels| Envelope {
v: ENVELOPE_VERSION,
ts: "2026-08-15T00:00:00.000Z".into(),
stream: "s".into(),
seq: 0,
source,
kind: EventKind(kind.into()),
dimensions: Default::default(),
labels,
payload: Default::default(),
artifacts: Vec::new(),
};
let plain = envelope(Source::Agentgraph, "turn-activity", Labels::default());
assert!(
EventFilter::default().matches(&plain),
"an absent include admits everything"
);
let excluded = EventFilter::parse(r#"{"exclude": [{"kind": "turn-*"}]}"#).expect("a filter");
assert!(!excluded.matches(&plain), "a glob matches the wire string");
let both = EventFilter::parse(
r#"{"include": [{"source": "agentgraph"}], "exclude": [{"kind": "turn-activity"}]}"#,
)
.expect("a filter");
assert!(!both.matches(&plain), "exclude wins over include");
let asks_node = EventFilter::parse(r#"{"include": [{"node": "build"}]}"#).expect("a filter");
assert!(
!asks_node.matches(&plain),
"an unstamped label never matches"
);
assert!(asks_node.matches(&envelope(
Source::Pipeline,
"node-settled",
Labels {
node: Some("build".into()),
..Labels::default()
}
)));
let asks_member =
EventFilter::parse(r#"{"include": [{"member": "worker"}]}"#).expect("a filter");
let mut relayed = plain.clone();
relayed
.labels
.extra
.insert("member".into(), json!("worker"));
assert!(asks_member.matches(&relayed));
assert!(!asks_member.matches(&plain));
}
#[test]
fn a_dispatch_is_cancelled_the_two_ways_the_contract_names() {
assert_ne!(CancelMode::Cooperative, CancelMode::Kill);
assert_contract_names("CancelMode variant", &["Cooperative | Kill"]);
}
#[test]
fn the_contract_declares_the_seams_traits_and_methods() {
let sketch = fenced_block_naming("rust", "pub trait Executor");
for item in [
"pub trait Executor",
"fn name(",
"fn capabilities(",
"fn capacity(",
"fn dispatch(",
"pub struct DispatchRequest",
"pub trait DispatchHandle",
"fn events(",
"fn wait(",
"fn cancel(",
] {
assert!(
sketch.contains(item),
"the contract's Rust block no longer declares `{item}`"
);
}
}
#[test]
fn the_contract_declares_the_host_shutdown_seam_this_crate_publishes() {
use onepipeline::verbs::{
BranchPreserved, DispatchEnding, DispatchStopped, Preserved, RunShutdown, Shutdown,
ShutdownRequest, ShutdownScope, StopTeardown,
};
let sketch = fenced_block_naming("rust", "pub enum ShutdownScope");
for item in [
"pub enum ShutdownScope { Run(String), Mine, Host }",
"pub struct ShutdownRequest",
"pub enum DispatchEnding { Graceful, Killed, StillRunning }",
"pub enum Preserved { Pushed, AlreadyOnOrigin, NoRemote, Refused }",
"pub struct DispatchStopped",
"pub struct BranchPreserved",
"pub struct RunShutdown",
"pub struct Shutdown",
"pub fn shutdown(root: &Path, request: ShutdownRequest) -> Result<Shutdown>;",
"pub fn render_shutdown(shutdown: &Shutdown) -> String;",
"impl Shutdown { pub fn exit_code(&self) -> i32; }",
"pub not_pushed: Vec<(String, String)>",
"pub not_pushed_unread: Option<String>",
] {
assert!(
sketch.contains(item),
"the contract's shutdown block no longer declares `{item}`"
);
}
for (name, fields) in [
(
"ShutdownRequest",
&[
("scope", "ShutdownScope"),
("session", "String"),
("grace", "Duration"),
("force", "bool"),
][..],
),
(
"DispatchStopped",
&[
("node", "String"),
("pid", "u32"),
("interrupt", "String"),
("detail", "String"),
("ended", "DispatchEnding"),
("waited", "Duration"),
][..],
),
(
"BranchPreserved",
&[
("identity", "String"),
("branch", "String"),
("outcome", "Preserved"),
("remote", "Option<String>"),
("commit", "Option<String>"),
("detail", "String"),
][..],
),
(
"RunShutdown",
&[
("run", "String"),
("owner", "String"),
("forced_over_owner", "bool"),
("dispatches", "Vec<DispatchStopped>"),
("teardown", "journal::StopTeardown"),
("branches", "Vec<BranchPreserved>"),
][..],
),
(
"Shutdown",
&[
("root", "PathBuf"),
("scope", "ShutdownScope"),
("grace", "Duration"),
("forced", "bool"),
("runs", "Vec<RunShutdown>"),
("not_pushed", "Vec<(String, String)>"),
("not_pushed_unread", "Option<String>"),
][..],
),
] {
let expected: Vec<(String, String)> = fields
.iter()
.map(|(field, ty)| ((*field).to_string(), (*ty).to_string()))
.collect();
assert_eq!(
sketch_struct_fields(&sketch, name),
expected,
"the contract's `{name}` fields have drifted from the type this crate publishes"
);
}
let stopped = DispatchStopped {
node: "build".into(),
pid: 4_242,
interrupt: "delivered".into(),
detail: "the running turn took the redirection".into(),
ended: DispatchEnding::Graceful,
waited: std::time::Duration::from_secs(3),
};
let preserved = BranchPreserved {
identity: "github.com/owner/service".into(),
branch: "feat/thing".into(),
outcome: Preserved::Pushed,
remote: Some("https://github.com/owner/service.git".into()),
commit: Some("abc1234".into()),
detail: String::new(),
};
let run = RunShutdown {
run: "run-1".into(),
owner: "[mine]".into(),
forced_over_owner: false,
dispatches: vec![stopped],
teardown: StopTeardown::Signalled,
branches: vec![preserved],
};
let shutdown = Shutdown {
root: PathBuf::from("/runs"),
scope: ShutdownScope::Host,
grace: std::time::Duration::from_secs(600),
forced: false,
runs: vec![run],
not_pushed: vec![("github.com/owner/other".into(), "feat/left".into())],
not_pushed_unread: None,
};
assert_eq!(shutdown.exit_code(), 0);
let report = onepipeline::verbs::render_shutdown(&shutdown);
assert!(report.contains("/runs"), "{report}");
assert!(
report.contains("github.com/owner/other@feat/left"),
"{report}"
);
assert!(report.contains("on its origin unproven"), "{report}");
let killed = Shutdown {
runs: vec![RunShutdown {
dispatches: vec![DispatchStopped {
ended: DispatchEnding::Killed,
..shutdown.runs[0].dispatches[0].clone()
}],
..shutdown.runs[0].clone()
}],
..shutdown
};
assert_eq!(killed.exit_code(), EXIT_REFUSED);
assert_ne!(ShutdownScope::Mine, ShutdownScope::Host);
let _: ShutdownRequest = ShutdownRequest {
scope: ShutdownScope::Run("run-1".into()),
session: "s".into(),
grace: std::time::Duration::from_secs(onepipeline::cli::DEFAULT_SHUTDOWN_GRACE_SECONDS),
force: false,
};
assert_eq!(onepipeline::cli::DEFAULT_SHUTDOWN_GRACE_SECONDS, 600);
assert_contract_names(
"shutdown paragraph's",
&[
"`onepipeline shutdown [RUN] [--mine] [--host] [--grace SECONDS] [--force]`",
"**default 600**",
"A shutdown journals no `run-stopped` and fires no run-end hook",
"on its origin *unproven*",
],
);
}
fn sketch_struct_fields(sketch: &str, name: &str) -> Vec<(String, String)> {
let code: String = sketch
.lines()
.filter(|line| !line.trim_start().starts_with("///"))
.collect::<Vec<_>>()
.join("\n");
let open = format!("pub struct {name} {{");
let start = code
.find(&open)
.unwrap_or_else(|| panic!("the contract's shutdown block declares no `{open}`"))
+ open.len();
let body = &code[start..start + code[start..].find('}').expect("the struct closes")];
let mut fields = Vec::new();
let mut depth = 0_i32;
let mut field = String::new();
for ch in body.chars().chain(std::iter::once(',')) {
match ch {
'<' | '(' => depth += 1,
'>' | ')' => depth -= 1,
_ => {}
}
if ch == ',' && depth == 0 {
let spelled = field.split_whitespace().collect::<Vec<_>>().join(" ");
if let Some(rest) = spelled.strip_prefix("pub ") {
let (field_name, ty) = rest.split_once(':').expect("a field has a type");
fields.push((field_name.trim().to_string(), ty.trim().to_string()));
}
field.clear();
} else {
field.push(ch);
}
}
fields
}
fn every_node_shape() -> Value {
json!({
"schema_version": PLAN_SCHEMA_VERSION,
"name": "every-shape",
"concurrency": 3,
"goal": {"text": "prove the schema"},
"tasks": [
{
"id": "direct",
"persona": "engineer",
"task": "## What\nx\n\n## Why\ny\n\n## Acceptance criteria\n- z",
"max_turns": 24,
"expects_no_diff": true,
"context": "the earlier round already landed the schema",
"executor": "local",
"agent_graph": "./graphs/node-scope.yaml",
"deps": ["run:other-run#upstream"]
},
{
"id": "approval",
"kind": "human",
"task": "Approve the design.",
"deps": ["direct"]
},
{
"id": "lifecycle",
"repo": "nickderobertis/some-service",
"repo_type": "team",
"workflow": "remote",
"merge_policy": "change-auto",
"base_branch": "main",
"branch": "feat/thing",
"title": "feat: thing",
"execution_checkout": "isolated",
"parked": true,
"resume": {
"branch": "feat/thing",
"checkpoint": "abc1234",
"completed_steps": ["implement"]
},
"deps": ["approval"],
"steps": [
{
"id": "implement",
"persona": "engineer",
"task": "## What\nx",
"max_turns": 32,
"expects_no_diff": false,
"executor": "local",
"agent_graph": "./graphs/node-scope.yaml"
},
{
"id": "sign-off",
"kind": "human",
"task": "Exercise staging and approve.",
"deps": ["implement"]
}
]
}
]
})
}
#[test]
fn the_plan_schema_carries_every_node_shape_the_contract_names() {
let plan: Plan = serde_json::from_value(every_node_shape()).expect("the plan parses");
assert_eq!(plan.schema_version, PLAN_SCHEMA_VERSION);
assert_eq!(plan.concurrency, 3);
assert_eq!(plan.goal.as_ref().expect("a goal").text, "prove the schema");
assert_eq!(plan.tasks.len(), 3);
let direct = &plan.tasks[0];
assert_eq!(direct.kind, NodeKind::Agent, "`agent` is the default kind");
assert!(direct.expects_no_diff);
assert_eq!(
direct.max_turns,
Some(24),
"a turn budget is a node-level control the schema keeps"
);
assert_eq!(direct.executor.as_deref(), Some("local"));
assert_eq!(
direct.agent_graph,
Some(ConfigRef("./graphs/node-scope.yaml".into())),
"`agent_graph` is an oneagentgraph config reference"
);
assert_eq!(
direct.context.as_deref(),
Some("the earlier round already landed the schema")
);
assert_eq!(
direct.deps,
vec!["run:other-run#upstream"],
"a cross-DAG reference is a dependency like any other"
);
assert_eq!(plan.tasks[1].kind, NodeKind::Human);
let lifecycle = &plan.tasks[2];
assert_eq!(
lifecycle.repo.as_deref(),
Some("nickderobertis/some-service")
);
assert_eq!(lifecycle.repo_type, Some(RepoType::Team));
assert_eq!(lifecycle.workflow, Some(Workflow::Remote));
assert_eq!(lifecycle.merge_policy, Some(MergePolicy::ChangeAuto));
assert!(lifecycle.parked);
assert_eq!(
lifecycle.resume,
Some(Resume {
branch: "feat/thing".into(),
checkpoint: Some("abc1234".into()),
completed_steps: vec!["implement".into()],
})
);
let steps = lifecycle
.steps
.as_ref()
.expect("nested steps on one branch");
assert_eq!(steps.len(), 2);
assert_eq!(steps[0].kind, NodeKind::Agent);
assert_eq!(steps[1].kind, NodeKind::Human);
assert_eq!(
steps[0].max_turns,
Some(32),
"a step carries its own turn budget"
);
assert_contract_names(
"node shape",
&[
"`agent` direct",
"lifecycle with `repo`",
"`kind: human`",
"nested `steps` on one branch",
"`expects_no_diff`",
"`context`",
"cross-DAG `run:<id>#<node>` refs",
"per-node `max_turns`",
"`executor: NAME`",
"`agent_graph: REF`",
],
);
}
#[test]
fn the_contracts_plan_schema_version_is_the_one_this_crate_writes() {
assert!(
CONTRACT.contains(&format!("Plan schema v{PLAN_SCHEMA_VERSION} =")),
"the contract states a different plan schema version than this crate writes \
({PLAN_SCHEMA_VERSION})"
);
assert!(
CONTRACT.contains("this build reads **3, 2, and 1**"),
"the contract no longer names the versions this build reads"
);
assert_eq!(
PLAN_SCHEMA_VERSIONS_READ,
[3, 2, 1],
"this crate reads a different set of versions than the contract states"
);
for version in PLAN_SCHEMA_VERSIONS_READ {
let plan: Plan = serde_json::from_value(json!({
"schema_version": version,
"tasks": [{"id": "a", "persona": "engineer", "task": "Do it."}],
}))
.unwrap_or_else(|why| panic!("a version {version} plan is a readable document: {why}"));
assert_eq!(plan.schema_version, version);
}
let earlier: Plan = serde_json::from_value(json!({
"schema_version": 1,
"tasks": [{"id": "a", "persona": "engineer", "task": "Do it."}],
}))
.expect("it still reads");
let current = Plan {
schema_version: PLAN_SCHEMA_VERSION,
..earlier
};
let written = serde_json::to_value(¤t).expect("it serialises");
assert_eq!(written["schema_version"], PLAN_SCHEMA_VERSION);
}
#[test]
fn every_reserved_metadata_key_the_contract_names_is_a_field_of_this_schema() {
let plan = serde_json::to_value(Plan {
schema_version: PLAN_SCHEMA_VERSION,
goal: Some(onepipeline::plan::Goal { text: "why".into() }),
name: Some("named".into()),
concurrency: 2,
tasks: Vec::new(),
})
.expect("a plan serialises");
let node = serde_json::to_value(Node {
id: "n".into(),
kind: NodeKind::Human,
task: Some("t".into()),
persona: Some("engineer".into()),
deps: vec!["other".into()],
max_turns: Some(1),
expects_no_diff: true,
context: Some("note".into()),
parked: true,
executor: Some("local".into()),
agent_graph: Some(ConfigRef("g".into())),
repo: Some("github.com/owner/name".into()),
repo_type: Some(RepoType::Team),
workflow: Some(Workflow::Remote),
merge_policy: Some(MergePolicy::ChangeAuto),
base_branch: Some("main".into()),
branch: Some("topic".into()),
title: Some("feat: x".into()),
body: Some("why".into()),
draft: true,
execution_checkout: Some("checkout".into()),
pool: Some(1),
overflow: Some(onevcs::Bound::Bounded(2)),
steps: Some(Vec::new()),
resume: Some(Resume {
branch: "topic".into(),
checkpoint: None,
completed_steps: Vec::new(),
}),
adoption: Some(Adoption::Published),
amendment: Some("changed requirements".into()),
consumes: std::collections::BTreeMap::new(),
delivers: vec!["tickets:t-1".into()],
})
.expect("a node serialises");
let fields: BTreeSet<String> = plan
.as_object()
.expect("a mapping")
.keys()
.chain(node.as_object().expect("a mapping").keys())
.cloned()
.collect();
let history: Value = serde_json::from_str(&fenced_block_naming("json", "oneharness_history"))
.expect("the run-history block is JSON");
let history = &history["oneharness_history"];
let stamped: BTreeSet<String> = history["labels"]
.as_object()
.expect("the block names its labels")
.values()
.filter_map(Value::as_str)
.map(ToOwned::to_owned)
.chain(history["label_prefix"].as_str().map(ToOwned::to_owned))
.collect();
let named: BTreeSet<String> = backticked()
.iter()
.filter(|token| !stamped.contains(*token))
.filter_map(|token| token.strip_prefix("onepipeline.").map(ToOwned::to_owned))
.filter(|field| field != "<field>")
.collect();
assert!(
!named.is_empty(),
"the contract names no reserved metadata key at all"
);
for field in &named {
assert!(
fields.contains(field),
"the contract reserves `onepipeline.{field}`, which is not a field of the plan schema"
);
}
assert!(
CONTRACT.contains(
"The plan-level fields — `schema_version`, `goal`, `name`, `concurrency` — are \
reserved metadata keys `onepipeline.<field>` on the **project**"
),
"the contract no longer states which fields the project carries"
);
for field in ["schema_version", "goal", "name", "concurrency"] {
assert!(
plan.as_object().expect("a mapping").contains_key(field),
"the contract reserves `{field}` on the project, which is not a plan field"
);
}
}
#[test]
fn a_plan_still_carrying_done_when_is_refused_by_name_and_told_where_the_bar_goes() {
assert!(
CONTRACT.contains("A plan still carrying `done_when` is refused **by name**"),
"the contract no longer states the refusal"
);
assert!(
CONTRACT.contains(
"A retired field is refused by its own name here exactly as it is in a \
plan document"
),
"the contract no longer carries the refusal into the store"
);
for version in PLAN_SCHEMA_VERSIONS_READ {
for field in ["done_when", "verify_via_ci"] {
let refused = serde_json::from_value::<Plan>(json!({
"schema_version": version,
"tasks": [{"id": "contract", "persona": "engineer", "task": "t", field: true}],
}))
.expect_err("a retired field is not a field of this schema");
assert!(
refused.to_string().contains(field),
"the schema's own refusal does not name the field: {refused}"
);
}
}
for field in ["done_when", "verify_via_ci"] {
serde_json::from_value::<Step>(json!({"id": "implement", field: true}))
.expect_err("a retired field is not a field of a step either");
}
let plan: Plan = serde_json::from_value(json!({
"schema_version": PLAN_SCHEMA_VERSION,
"tasks": [{"id": "contract", "persona": "engineer", "task": "t", "max_turns": 45}],
}))
.expect("a plan without the retired field reads");
assert_eq!(plan.tasks[0].max_turns, Some(45));
}
#[test]
fn a_dispatch_built_outside_a_run_still_carries_its_controls_into_the_launch() {
let _seam = seam_env_lock();
let root = scratch("seam");
std::env::set_var("ONEAGENTGRAPH_STATE_DIR", root.join("state"));
let graph = root.join("single-sided.yaml");
std::fs::write(
&graph,
"version: 1\nname: single-sided\nmembers:\n worker:\n kind: oneharness\n \
oneharness_config: ./nothing.toml\n",
)
.expect("the graph is written");
let request = |controls| DispatchRequest {
graph: ConfigRef(graph.display().to_string()),
task: "## What\nDo the thing.".into(),
labels: Labels::default(),
controls,
workspace: WorkspaceSpec::Path(root.clone()),
cancel: CancellationToken::new(),
attempt: NonZeroU32::MIN,
};
let Err(refused) = LocalExecutor.dispatch(request(NodeControls {
max_turns: NonZeroU32::new(45),
})) else {
panic!("a single-sided member has no `max_turns`, so the launch cannot start");
};
let refused = refused.to_string();
assert!(
refused.contains("max_turns"),
"the control never reached the launch: {refused}"
);
let Err(other) = LocalExecutor.dispatch(request(NodeControls::default())) else {
panic!("the graph names a config that does not exist");
};
assert!(
!other.to_string().contains("max_turns"),
"a control nobody declared was sent anyway: {other}"
);
std::env::remove_var("ONEAGENTGRAPH_STATE_DIR");
std::fs::remove_dir_all(&root).ok();
}
#[test]
fn a_declared_turn_budget_reaches_the_effective_configuration_of_the_worker() {
assert!(
CONTRACT.contains("`max_turns` is the worker member's own turn ceiling"),
"the contract no longer says where a turn budget lands"
);
let text = std::fs::read_to_string(repo_root().join("graphs/node-scope.yaml"))
.expect("the node-scope graph ships");
let effective = |controls: NodeControls| -> GraphConfig {
let overrides: Vec<_> = controls
.overrides()
.expect("a declared budget is appliable")
.iter()
.map(|set| oneagentgraph::run::parse_set(set).expect("the sibling parses the override"))
.collect();
let mut document: Value = serde_norway::from_str(&text).expect("the graph parses");
oneagentgraph::run::apply_overrides(&mut document, &overrides)
.expect("the sibling applies the override");
serde_norway::from_value(serde_norway::to_value(&document).expect("a value"))
.expect("the overridden graph is still a valid graph config")
};
let turns_of = |graph: &GraphConfig| match graph.members.get("worker") {
Some(Member::Onejudge(worker)) => worker.max_turns,
other => panic!("the node-scope worker is a two-party member: {other:?}"),
};
assert_eq!(
turns_of(&effective(NodeControls::default())),
None,
"the shipped graph must state no budget, or this proves nothing"
);
assert_eq!(
turns_of(&effective(NodeControls {
max_turns: NonZeroU32::new(45)
})),
Some(45),
"the node's turn budget did not reach the member that runs its work"
);
}
#[test]
fn resume_carries_what_the_contract_says_a_preserved_branch_needs() {
let prose = CONTRACT.split_whitespace().collect::<Vec<_>>().join(" ");
assert!(
prose.contains("`{branch, checkpoint?, completed_steps?}`"),
"the contract no longer states the `resume` shape"
);
assert!(
prose.contains("`completed_steps` names the steps that branch already carries"),
"the contract no longer says what `completed_steps` means"
);
assert!(
prose.contains("`checkpoint` must be a commit reachable on the remote"),
"the contract no longer says what a checkpoint is"
);
let full: Resume = serde_json::from_value(json!({
"branch": "feat/thing",
"checkpoint": "abc1234",
"completed_steps": ["implement", "review"]
}))
.expect("the stated shape parses");
assert_eq!(full.completed_steps, ["implement", "review"]);
let minimal: Resume =
serde_json::from_value(json!({"branch": "feat/thing"})).expect("branch alone is a resume");
assert!(
minimal.completed_steps.is_empty(),
"an absent list re-runs the whole workstream"
);
assert_eq!(
serde_json::to_value(&minimal).expect("serializes"),
json!({"branch": "feat/thing"})
);
}
#[test]
fn a_plan_round_trips_without_losing_a_field() {
let plan: Plan = serde_json::from_value(every_node_shape()).expect("parses");
let again: Plan = serde_json::from_value(serde_json::to_value(&plan).expect("serializes"))
.expect("re-parses");
assert_eq!(again, plan);
}
#[test]
fn a_mistyped_node_key_is_refused_at_the_boundary() {
let err = serde_json::from_value::<Plan>(json!({
"schema_version": PLAN_SCHEMA_VERSION,
"tasks": [{"id": "x", "persna": "engineer"}]
}))
.expect_err("a mistyped key is rejected, not silently dropped");
assert!(
err.to_string().contains("persna"),
"the error names it: {err}"
);
}
#[test]
fn a_node_and_a_step_default_to_the_shapes_the_contract_states() {
let node = Node {
id: "x".into(),
..Node::default()
};
assert_eq!(node.kind, NodeKind::Agent);
assert!(!node.expects_no_diff);
assert!(!node.parked);
assert!(node.deps.is_empty());
let step = Step {
id: "s".into(),
..Step::default()
};
assert_eq!(step.kind, NodeKind::Agent);
assert!(!step.expects_no_diff);
let rendered = serde_json::to_value(&node).expect("serializes");
assert_eq!(
rendered,
json!({"id": "x"}),
"the default kind is omitted, so an old consumer sees no field it did not have"
);
}
#[test]
fn the_shipped_example_store_holds_a_project_per_example_plan() {
let store = repo_root().join("examples").join("plan-store");
assert!(
store.join("onetaskgraph.yaml").is_file(),
"the example store configures no source, so nothing can read it"
);
for name in ["single-node", "tracked-release"] {
let project = store.join("projects").join(format!("{name}.md"));
let text = std::fs::read_to_string(&project)
.unwrap_or_else(|e| panic!("the {name} project ships: {e}"));
assert!(
text.contains(&format!(
"\"onepipeline.schema_version\": {PLAN_SCHEMA_VERSION}"
)),
"the {name} project does not declare the schema version this crate writes:\n{text}"
);
let tasks = store.join("tasks").join(name);
assert!(
std::fs::read_dir(&tasks)
.unwrap_or_else(|e| panic!("the {name} project has tasks: {e}"))
.count()
> 0,
"the {name} project holds no task, so its plan has no node"
);
}
}
fn op_of(command: &Edit) -> &'static str {
match command {
Edit::Add { .. } => "add",
Edit::Drop { .. } => "drop",
Edit::Reparent { .. } => "reparent",
Edit::Retry { .. } => "retry",
Edit::Cancel { .. } => "cancel",
Edit::Settle { .. } => "settle",
Edit::Requeue { .. } => "requeue",
Edit::Attest { .. } => "attest",
Edit::Complete { .. } => "complete",
Edit::Amend { .. } => "amend",
Edit::Note { .. } => "note",
Edit::Finding { .. } => "finding",
}
}
const OPS: &[&str] = &[
"add", "drop", "reparent", "retry", "cancel", "requeue", "attest", "complete", "context",
];
const REMOVED_OPS: &[&str] = &["context"];
fn contract_ops_this_build_accepts() -> Vec<&'static str> {
OPS.iter()
.copied()
.filter(|op| !REMOVED_OPS.contains(op))
.collect()
}
#[test]
fn the_contract_lists_exactly_the_ops_this_crate_accepts() {
let listed = "`add | drop | reparent | retry | cancel | requeue | attest | complete | context`";
assert!(
CONTRACT.contains(listed),
"the contract's op list moved; update OPS with it"
);
assert_eq!(OPS.len(), 9);
let removed: Vec<String> = serde_json::from_value(divergence_block("60.")["removed"].clone())
.expect("entry 60 names what it removes");
assert_eq!(
removed,
REMOVED_OPS
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>(),
"the record and this suite disagree about which of the contract's ops are gone"
);
for op in REMOVED_OPS {
let err = serde_json::from_value::<Edit>(json!({"op": op, "id": "x", "note": "hello"}))
.expect_err("an op the contract lists and this build removed is refused");
assert!(
err.to_string().contains(op),
"the refusal does not name `{op}`: {err}"
);
}
assert_eq!(
op_of(&Edit::Cancel {
id: "x".into(),
reason: None
}),
"cancel",
"the exhaustive match above is what proves the variant set, and it runs"
);
}
fn divergence_block(number: &str) -> Value {
let record = std::fs::read_to_string(repo_root().join("docs/contract-divergences.md"))
.expect("the divergence record reads");
let entry = record
.split("\n## ")
.find(|entry| entry.starts_with(number))
.unwrap_or_else(|| panic!("the divergence record still carries entry {number}"));
let block = entry
.split("```json")
.nth(1)
.and_then(|rest| rest.split("```").next())
.unwrap_or_else(|| panic!("entry {number} carries the json block this test drives"));
serde_json::from_str(block).unwrap_or_else(|e| panic!("entry {number}'s block is JSON: {e}"))
}
#[test]
fn the_release_adoption_surface_is_what_the_divergence_record_names() {
let block = divergence_block("40.");
let written = block["node"].clone();
let node: Node = serde_json::from_value(written.clone()).expect("entry 40's node parses");
assert_eq!(
serde_json::to_value(&node).expect("serializes"),
written,
"entry 40's node does not round-trip as written"
);
assert_eq!(
node.adoption,
Some(Adoption::Published),
"`adoption` is the node rung of the chain"
);
assert_eq!(
node.consumes
.get("engine")
.map(std::string::ToString::to_string),
Some("crate".to_string()),
"`consumes` is keyed by dependency node id"
);
let plain = json!({"id": "solo", "persona": "engineer", "task": "## What\nx"});
let bare: Node = serde_json::from_value(plain.clone()).expect("a node naming neither parses");
assert_eq!(bare.adoption, None);
assert!(bare.consumes.is_empty());
assert_eq!(
serde_json::to_value(&bare).expect("serializes"),
plain,
"a node naming neither field gained one on the way out"
);
let kinds: Vec<String> =
serde_json::from_value(block["event_kinds"].clone()).expect("entry 40 names its kinds");
assert!(!kinds.is_empty());
for kind in &kinds {
assert!(
PipelineKind::from_wire(&EventKind(kind.clone())).is_some(),
"`{kind}` is not a kind this crate emits"
);
}
assert_eq!(
block["heading"].as_str(),
Some(CROSS_REPO_REFERENCES_HEADING),
"entry 40 names a different heading than this crate publishes"
);
assert_ne!(CROSS_REPO_REFERENCES_HEADING, PLANNER_CONTEXT_HEADING);
let wait = &block["wait_surface"];
assert_eq!(wait["kind"].as_str(), Some("release-wait"));
assert!(kinds.contains(&"release-wait".to_string()));
assert_eq!(wait["epoch"].as_str(), Some("queued_at"));
let queued = serde_json::to_value(Surface {
id: 1,
kind: "release-wait".into(),
message: "held".into(),
source: "proposal".into(),
blocking: false,
queued_at: 7,
abandoned: false,
asker: None,
workstream: Some("consumer".into()),
correlation: None,
})
.expect("a surface serializes");
assert_eq!(
queued["queued_at"],
json!(7),
"the field the entry says fixes a wait's epoch is not one a surface carries"
);
let ending: Vec<String> = serde_json::from_value(wait["withheld_after"].clone())
.expect("entry 40 names the records that end a hold");
assert!(
!ending.is_empty(),
"entry 40 names no record that ends a hold"
);
for kind in &ending {
assert!(
PipelineKind::from_wire(&EventKind(kind.clone())).is_some(),
"`{kind}` is not a kind this crate emits"
);
}
let record = std::fs::read_to_string(repo_root().join("docs/contract-divergences.md"))
.expect("the divergence record ships");
let prose = record.split_whitespace().collect::<Vec<_>>().join(" ");
for said in [
"fixed by the instant it was queued",
"at or after that instant",
"is **withheld**, never handed out",
"recorded neither as `planner-surfaced`",
] {
assert!(
prose.contains(said),
"entry 40 no longer states the rule that withholds a stale wait: {said:?}"
);
}
}
#[test]
fn the_workspace_placement_surface_is_what_the_divergence_record_names() {
let block = divergence_block("82.");
let written = block["node"].clone();
let node: Node = serde_json::from_value(written.clone()).expect("entry 82's node parses");
assert_eq!(
serde_json::to_value(&node).expect("serializes"),
written,
"entry 82's node does not round-trip as written"
);
assert_eq!(node.pool, Some(1));
assert_eq!(node.overflow, Some(onevcs::Bound::Bounded(0)));
let unlimited: Node = serde_json::from_value(json!({
"id": "n", "persona": "engineer", "task": "## What\nx", "overflow": "unlimited"
}))
.expect("the sibling's word parses");
assert_eq!(unlimited.overflow, Some(onevcs::Bound::Unlimited));
assert_eq!(
serde_json::to_value(&unlimited).expect("serializes")["overflow"],
json!("unlimited")
);
let plain = json!({"id": "solo", "persona": "engineer", "task": "## What\nx"});
let bare: Node = serde_json::from_value(plain.clone()).expect("a node naming neither parses");
assert_eq!(bare.pool, None);
assert_eq!(bare.overflow, None);
assert_eq!(
serde_json::to_value(&bare).expect("serializes"),
plain,
"a node naming neither field gained one on the way out"
);
assert_eq!(
block["refused_below_schema"].as_u64(),
Some(u64::from(PLAN_SCHEMA_VERSION))
);
let kind = block["requeue"]["kind"].as_str().expect("a kind");
assert_eq!(
PipelineKind::from_wire(&EventKind(kind.to_owned())),
Some(PipelineKind::NodeRequeued)
);
assert_eq!(block["requeue"]["fields"], json!(["reason", "detail"]));
assert_eq!(
block["requeue"]["pinned_fields"],
json!(["branch", "attempt"])
);
for names in [
"`pool: u32` and `overflow: N|unlimited`",
"**held under `workspace`**",
"`workspace-wait` surface",
"`reason: workspace-exhausted`",
"neither settled nor `awaiting-planner`",
"on **any attempt of any node** — no pool-exhausted refusal writes a settlement or \
spends a boundary attempt",
"**keeps that pin through the queue**: its `node-requeued` also carries the `branch`",
"A `retry` is never what continues a node the host was merely too busy for",
] {
assert!(
CONTRACT.contains(names),
"the contract no longer states {names}"
);
}
}
#[test]
fn the_pool_maintenance_schedule_is_what_the_divergence_record_names() {
use onepipeline::maintenance::{
MaintenanceConfig, DEFAULT_PACE_SECONDS, FLAG, KEY, PACE_ENV, SCHEDULE_VERSION,
};
let block = divergence_block("83.");
assert_eq!(block["flag"].as_str(), Some(FLAG));
assert_eq!(block["config_key"].as_str(), Some(KEY));
assert!(
CONTRACT.contains("[--maintenance-config FILE]"),
"the driver invocation no longer names the maintenance flag"
);
let Command::Start(started) = Cli::try_parse_from([
"onepipeline",
"start",
"plans:demo",
FLAG,
"./maintenance.yml",
])
.expect("the flag the block names is one `start` takes")
.command
else {
panic!("that is not a start")
};
assert_eq!(
started.maintenance_config.as_deref(),
Some("./maintenance.yml")
);
let Command::Start(unset) = Cli::try_parse_from(["onepipeline", "start", "plans:demo"])
.expect("it parses")
.command
else {
panic!("that is not a start")
};
assert_eq!(unset.maintenance_config, None);
let refused = Cli::try_parse_from(["onepipeline", "adopt", "demo", FLAG, "x"])
.expect_err("adopt takes no maintenance flag");
assert!(refused.to_string().contains(FLAG), "{refused}");
let at = u32::try_from(
block["config_schema_version"]
.as_u64()
.expect("the block states the version the key arrived at"),
)
.expect("a version fits");
assert_eq!(at, LAUNCH_CONFIG_SCHEMA_VERSION);
let named: LaunchConfig = serde_json::from_value(json!({
"schema_version": at,
KEY: "./maintenance.yml",
}))
.expect("a config naming the schedule parses");
assert_eq!(
named.maintenance_config.as_deref(),
Some("./maintenance.yml")
);
let example = fenced_block_naming("yaml", "maintenance_config:");
let example: LaunchConfig =
serde_norway::from_str(&example).expect("the contract's launch example parses");
assert_eq!(example.schema_version, at);
assert_eq!(
example.maintenance_config.as_deref(),
Some("./maintenance.yml")
);
let dir = std::env::temp_dir().join(format!(
"onepipeline-contract-maintenance-{}",
std::process::id()
));
std::fs::create_dir_all(&dir).expect("a scratch directory");
for version in LAUNCH_CONFIG_SCHEMA_VERSIONS_READ
.into_iter()
.filter(|version| *version < at)
{
let path = dir.join(format!("{version}.yaml"));
std::fs::write(
&path,
format!("schema_version: {version}\n{KEY}: ./maintenance.yml\n"),
)
.expect("the config is written");
let refused = LaunchConfig::load(&path)
.expect_err("a version that never had the key refuses it")
.to_string();
assert!(
refused.contains(&format!("`{KEY}`")) && refused.contains(&format!("schema {at} key")),
"schema {version} did not refuse `{KEY}` by its name: {refused}"
);
}
let written = block["schedule"].clone();
let schedule: MaintenanceConfig =
serde_json::from_value(written.clone()).expect("entry 83's schedule parses");
assert_eq!(schedule.version, SCHEDULE_VERSION);
assert_eq!(
block["schedule_version"].as_u64(),
Some(u64::from(SCHEDULE_VERSION))
);
assert_eq!(schedule.default.every.to_string(), "7d");
assert_eq!(schedule.rules.len(), 1);
assert_eq!(schedule.rules[0].every.to_string(), "3d");
assert_eq!(schedule.rules[0].r#match.name.as_deref(), Some("onevcs"));
assert_eq!(
serde_json::to_value(&schedule).expect("serializes"),
written,
"entry 83's schedule does not round-trip as written"
);
let contract_schedule: MaintenanceConfig =
serde_norway::from_str(&fenced_block_naming("yaml", "every: 7d"))
.expect("the contract's schedule example parses");
assert_eq!(contract_schedule, schedule);
let schedule_path = dir.join("schedule.yml");
for (document, names) in [
(
"version: 1\ndefault:\n every: 7d\nat: \"03:00\"\n",
"unknown field `at`",
),
("version: 2\ndefault:\n every: 7d\n", "`version` is 2"),
(
"version: 1\ndefault:\n every: 7d\nrules:\n - match: {}\n every: 1d\n",
"`match` names no field",
),
("version: 1\ndefault:\n every: 7x\n", "`every`"),
] {
std::fs::write(&schedule_path, document).expect("the schedule is written");
let refused = MaintenanceConfig::load(FLAG, &schedule_path)
.expect_err("the document is refused")
.to_string();
assert!(
refused.contains(names),
"{document:?} was refused as: {refused}"
);
}
assert_eq!(
block["refused"].as_array().map(Vec::len),
Some(4),
"the block lists a different number of refusals than the test drives"
);
let _ = std::fs::remove_dir_all(&dir);
let kinds: Vec<String> =
serde_json::from_value(block["event_kinds"].clone()).expect("entry 83 names its kind");
assert_eq!(kinds, ["pool-maintenance"]);
assert_eq!(
PipelineKind::from_wire(&EventKind(kinds[0].clone())),
Some(PipelineKind::PoolMaintenance)
);
assert_eq!(block["pace_env"].as_str(), Some(PACE_ENV));
assert_eq!(
block["default_pace_seconds"].as_u64(),
Some(DEFAULT_PACE_SECONDS)
);
assert_eq!(
block["load_env"].as_str(),
Some(onepipeline::executor::LOAD1_ENV)
);
let tokens = backticked();
for token in [KEY, PACE_ENV, "pool-maintenance", "schema_version: 9"] {
assert!(
tokens.contains(token),
"the contract no longer names `{token}`"
);
}
assert!(
tokens.contains(&format!("{FLAG} FILE")),
"the contract no longer names `{FLAG} FILE`"
);
for names in [
"the flag beats the config, and a blank value, flag or key, is this launch saying it has none",
"`every` is the **only** key a rule or the default carries",
"a slot is due when `last_maintained < now − every`, and the sibling decides it",
"nothing is written when every identity answered `no-maintain-command`, `no-slots` or `not-due`",
"A launch naming no schedule runs no maintenance, spawns no thread, and behaves exactly as before",
] {
assert!(CONTRACT.contains(names), "the contract no longer states {names}");
}
}
fn summary_fields() -> BTreeSet<String> {
let document = RunSummary {
schema_version: SUMMARY_SCHEMA_VERSION,
run_id: "gated".into(),
last_write_at: Some(1_786_000_000_000),
last_event_kind: Some("node-settled".into()),
event_count: 11,
node_counts: [("done".to_string(), 1)].into_iter().collect(),
stop_recorded: true,
graph_complete: true,
decisions_pending: 1,
surfaces_queued: 1,
surfaces_read: 1,
awaiting_human_action: true,
project: "plans:gated".into(),
name: Some("Gated".into()),
launcher: "claude-code".into(),
session: "a-session".into(),
started_at: Some("2026-01-01T00:00:00.000Z".into()),
pid: NonZeroU32::new(4_242),
host: Some("a-host".into()),
started: Some("linux-proc-stat:1".into()),
let_go_by: serde_json::from_value(json!({"host": "a-host", "pid": 4242}))
.expect("a driver claim reads"),
timing: serde_json::from_str::<RunTelemetry>(include_str!("golden/telemetry-v2.json"))
.expect("the telemetry golden reads back into the types"),
parked: vec!["idle".into()],
judge_rejected: vec!["publish".into()],
landings: [(
"publish".to_string(),
NodeLanding {
landing: "unlanded".into(),
branch: Some("onepipeline/gated".into()),
repo: Some("nickderobertis/onepipeline".into()),
drafted: false,
},
)]
.into_iter()
.collect(),
oneharness_sessions: Some("/runs/gated/oneharness-sessions.jsonl".into()),
journal_len: 8_192,
journal_mtime_ms: 1_786_000_000_100,
};
serde_json::to_value(&document)
.expect("a summary is an object")
.as_object()
.expect("a summary is an object")
.keys()
.cloned()
.collect()
}
fn landing_fields() -> BTreeSet<String> {
let landing = NodeLanding {
landing: "unlanded".into(),
branch: Some("onepipeline/gated".into()),
repo: Some("nickderobertis/onepipeline".into()),
drafted: true,
};
serde_json::to_value(&landing)
.expect("a landing is an object")
.as_object()
.expect("a landing is an object")
.keys()
.cloned()
.collect()
}
#[test]
fn the_summary_document_is_what_the_divergence_record_names() {
let block = divergence_block("56.");
assert_eq!(
block["schema_version"].as_u64(),
Some(u64::from(SUMMARY_SCHEMA_VERSION)),
"entry 56 states a schema version this build does not write"
);
let named: BTreeSet<String> = serde_json::from_value(block["fields"].clone())
.expect("entry 56 names the document's fields");
assert_eq!(
named,
summary_fields(),
"entry 56's inventory is not the document this build writes"
);
let landings: BTreeSet<String> = serde_json::from_value(block["landing_fields"].clone())
.expect("entry 56 names the landing inputs' fields");
assert_eq!(
landings,
landing_fields(),
"entry 56's landing inventory is not what this build writes"
);
}
#[test]
fn the_amendment_and_validator_surface_is_what_the_divergence_record_names() {
let block = divergence_block("41.");
let fixtures: Vec<Value> =
serde_json::from_value(block["ops"].clone()).expect("entry 41 names the op it adds");
let monitor_may: BTreeSet<String> = serde_json::from_value(block["monitor_may_issue"].clone())
.expect("entry 41 says which of them the monitor may issue");
assert!(!fixtures.is_empty(), "{block}");
for fixture in &fixtures {
let op = fixture["op"].as_str().expect("the fixture names its op");
assert!(
!OPS.contains(&op),
"`{op}` is on the contract's own list, so it is no divergence"
);
let edit: Edit = serde_json::from_value(fixture.clone())
.unwrap_or_else(|e| panic!("`{op}` deserializes: {e}"));
assert_eq!(op_of(&edit), op, "`{op}` deserialized into another variant");
assert_eq!(
&serde_json::to_value(&edit).expect("serializes"),
fixture,
"`{op}` round-trips unchanged"
);
allows(Author::planner(), &edit)
.unwrap_or_else(|e| panic!("the planner was refused `{op}`: {e}"));
let verdict = allows(Author::from("monitor"), &edit);
if monitor_may.contains(op) {
verdict.unwrap_or_else(|e| panic!("the monitor was refused `{op}`: {e}"));
continue;
}
let refusal = verdict
.expect_err(&format!("the monitor was allowed `{op}`"))
.to_string();
assert!(
refusal.contains(op) && refusal.contains("Surface it to the planner"),
"the refusal does not name `{op}` and what to do instead: {refusal}"
);
}
let written = block["node"].clone();
let node: Node = serde_json::from_value(written.clone()).expect("entry 41's node parses");
assert_eq!(
serde_json::to_value(&node).expect("serializes"),
written,
"entry 41's node does not round-trip as written"
);
let text = node.amendment.clone().expect("the node carries one");
let plain = json!({"id": "solo", "persona": "engineer", "task": "## What\nx"});
let bare: Node = serde_json::from_value(plain.clone()).expect("a node naming none parses");
assert_eq!(bare.amendment, None);
assert_eq!(
serde_json::to_value(&bare).expect("serializes"),
plain,
"a node naming no amendment gained one on the way out"
);
assert_eq!(
block["heading"].as_str(),
Some(AMENDMENT_HEADING),
"entry 41 names a different heading than this crate publishes"
);
assert_eq!(
block["precedence"].as_str(),
Some(AMENDMENT_PRECEDENCE),
"entry 41 states a different precedence sentence than this crate publishes"
);
assert_ne!(AMENDMENT_HEADING, PLANNER_CONTEXT_HEADING);
let section = block["rendered_into"]
.as_str()
.expect("entry 41 names the section the amendment is rendered into");
assert!(
section.starts_with("## ") && AMENDMENT_HEADING.starts_with("### "),
"the amendment's heading is not a sub-heading of the section it is rendered into"
);
for task in [
"## What\nship it\n\n## Acceptance criteria\n\n- it ships\n\n## Additional info\n\nrun the gate.\n",
"## What\nship it\n\n## Additional info\n\nrun the gate.\n",
] {
let rendered = Node {
task: Some(task.into()),
..node.clone()
}
.rendered_task();
let at = |needle: &str| {
rendered
.find(needle)
.unwrap_or_else(|| panic!("{needle} is not rendered: {rendered}"))
};
assert!(
at(section) < at(AMENDMENT_HEADING) && at(AMENDMENT_HEADING) < at("## Additional info"),
"the amendment is not inside the criteria and above the notes: {rendered}"
);
assert_eq!(
rendered.matches(section).count(),
1,
"the amendment made a second acceptance section: {rendered}"
);
assert!(
!rendered.contains("\n## Amendment"),
"the amendment is a section of its own beside the criteria: {rendered}"
);
assert!(
rendered.contains(&format!("{AMENDMENT_HEADING}\n{AMENDMENT_PRECEDENCE}\n\n- {text}\n")),
"the amendment's clause is not a criterion under the sentence stating its \
precedence: {rendered}"
);
assert!(
AMENDMENT_PRECEDENCE.contains("takes precedence over the whole task"),
"the amendment does not state its precedence over the whole task"
);
}
let validator = &block["validator"];
assert_eq!(validator["config_key"].as_str(), Some("node_validator"));
let at = validator["config_schema_version"]
.as_u64()
.expect("entry 41 states the version the key arrived at");
let arrived = u32::try_from(at).expect("a version fits");
assert!(
LAUNCH_CONFIG_SCHEMA_VERSIONS_READ.contains(&arrived)
&& arrived <= LAUNCH_CONFIG_SCHEMA_VERSION,
"entry 41 states the validator key arrived at schema {arrived}, which is not a version this build reads"
);
let named: LaunchConfig = serde_json::from_value(json!({
"schema_version": at,
"node_validator": "./scripts/check-node.sh",
}))
.expect("a launch config naming a validator parses");
assert_eq!(
named.node_validator.as_deref(),
Some("./scripts/check-node.sh")
);
let flag = validator["flag"].as_str().expect("entry 41 names the flag");
let parsed = Cli::try_parse_from(["onepipeline", "start", "plan.json", flag, "check-node"])
.expect("the flag entry 41 names is one `start` takes");
let Command::Start(started) = parsed.command else {
panic!("that is not a start")
};
assert_eq!(started.node_validator.as_deref(), Some("check-node"));
let offered: BTreeSet<String> = serde_json::from_value(validator["ops_offered"].clone())
.expect("entry 41 names the ops a validator is offered");
assert_eq!(
offered,
["add", "amend", "requeue", "retry"]
.into_iter()
.map(str::to_string)
.collect::<BTreeSet<String>>()
);
let readme = std::fs::read_to_string(repo_root().join("README.md")).expect("the README ships");
let prose = readme.split_whitespace().collect::<Vec<_>>().join(" ");
let precedence: Vec<String> = serde_json::from_value(validator["precedence"].clone())
.expect("entry 41 states the order it proposes");
let mut at: Vec<usize> = Vec::new();
for named in &precedence {
let spelling = validator[named.as_str()]
.as_str()
.expect("entry 41 names it");
let found = prose.find(spelling).unwrap_or_else(|| {
panic!("the README does not name the validator's {named}, `{spelling}`")
});
at.push(found);
}
assert!(
at.windows(2).all(|pair| pair[0] < pair[1]),
"the README names the three spellings in an order entry 41 does not propose: \
{precedence:?} at {at:?}"
);
for op in offered.iter().chain(std::iter::once(&"note".to_string())) {
assert!(
prose.contains(&format!("`{op}`")),
"the README's live-edit guidance does not name `{op}`"
);
}
for heading in [AMENDMENT_HEADING, PLANNER_CONTEXT_HEADING] {
assert!(
prose.contains(heading),
"the README does not name `{heading}`, which is where this crate renders one of \
the two levers"
);
}
assert!(
prose.contains("adds no acceptance criteria")
&& prose.contains("the worker and the judge reviewing it read the same ruling"),
"the README no longer states which lever changes what a node is judged against \
and which one only steers its worker"
);
let record = std::fs::read_to_string(repo_root().join("docs/contract-divergences.md"))
.expect("the divergence record ships");
for (which, copy) in [
("the README", prose.clone()),
(
"divergence entry 41",
record.split_whitespace().collect::<Vec<_>>().join(" "),
),
] {
assert!(
copy.contains("on the dispatch that follows")
&& copy.contains("A turn already in flight is not reached"),
"{which} no longer says which dispatch an amendment binds; the journeys \
establish that a turn already running is not reached"
);
}
assert!(
prose.contains("exit `1` refuses it with the command's own stderr as the reason")
&& prose.contains("naming none is the default and runs no validator at all"),
"the README no longer states what a validator's answers mean"
);
}
#[test]
fn the_envelope_reviewer_surface_is_what_the_divergence_record_names() {
let block = divergence_block("45.");
let reviewer = &block["reviewer"];
assert_eq!(reviewer["config_key"].as_str(), Some("envelope_reviewer"));
let at = reviewer["config_schema_version"]
.as_u64()
.expect("entry 45 states the version the key arrived at");
let arrived = u32::try_from(at).expect("a version fits");
assert!(
LAUNCH_CONFIG_SCHEMA_VERSIONS_READ.contains(&arrived)
&& arrived <= LAUNCH_CONFIG_SCHEMA_VERSION,
"entry 45 states the reviewer key arrived at schema {arrived}, which is not a version this build reads"
);
let named: LaunchConfig = serde_json::from_value(json!({
"schema_version": at,
"envelope_reviewer": "./scripts/review-envelope.sh",
}))
.expect("a launch config naming a reviewer parses");
assert_eq!(
named.envelope_reviewer.as_deref(),
Some("./scripts/review-envelope.sh")
);
for version in LAUNCH_CONFIG_SCHEMA_VERSIONS_READ {
let earlier: LaunchConfig =
serde_json::from_value(json!({"schema_version": version})).expect("it parses");
assert_eq!(earlier.envelope_reviewer, None);
}
let flag = reviewer["flag"].as_str().expect("entry 45 names the flag");
let parsed = Cli::try_parse_from(["onepipeline", "start", "plan.json", flag, "review-edit"])
.expect("the flag entry 45 names is one `start` takes");
let Command::Start(started) = parsed.command else {
panic!("that is not a start")
};
assert_eq!(started.envelope_reviewer.as_deref(), Some("review-edit"));
let document = &reviewer["document"];
let listed: BTreeSet<String> =
serde_json::from_value(reviewer["ops_listed_as_changes"].clone())
.expect("entry 45 names the ops it lists as changes");
let known: BTreeSet<String> = OPS
.iter()
.map(|op| (*op).to_string())
.chain(std::iter::once("amend".to_string()))
.collect();
assert!(
listed.is_subset(&known),
"entry 45 lists an op this build has no such thing as: {listed:?}"
);
let changes = document["changes"]
.as_array()
.expect("the document carries a changes list");
assert!(!changes.is_empty(), "{document}");
for change in changes {
let op = change["op"].as_str().expect("each change names its op");
assert!(
listed.contains(op),
"entry 45's document carries a change under `{op}`, which it does not list"
);
let written = change["node"].clone();
let node: Node = serde_json::from_value(written.clone())
.unwrap_or_else(|e| panic!("a changed node is a plan node: {e}"));
assert_eq!(
serde_json::to_value(&node).expect("serializes"),
written,
"a changed node does not round-trip as the entry writes it"
);
}
let written = document["plan"].clone();
let plan: Plan =
serde_json::from_value(written.clone()).expect("the plan under review is a plan");
assert_eq!(plan.schema_version, PLAN_SCHEMA_VERSION);
assert_eq!(
serde_json::to_value(&plan).expect("serializes"),
written,
"the plan under review does not round-trip as the entry writes it"
);
assert_eq!(
document["goal"].as_str(),
plan.goal.as_ref().map(|goal| goal.text.as_str()),
"{document}"
);
assert_eq!(
reviewer["offers_per_accepted_envelope"].as_u64(),
Some(1),
"entry 45 no longer states how many times an accepted envelope is offered"
);
let readme = std::fs::read_to_string(repo_root().join("README.md")).expect("the README ships");
let prose = readme.split_whitespace().collect::<Vec<_>>().join(" ");
let precedence: Vec<String> = serde_json::from_value(reviewer["precedence"].clone())
.expect("entry 45 states the order it proposes");
let mut at: Vec<usize> = Vec::new();
for spelling in &precedence {
let named = reviewer[spelling.as_str()]
.as_str()
.expect("entry 45 names it");
at.push(prose.find(named).unwrap_or_else(|| {
panic!("the README does not name the reviewer's {spelling}, `{named}`")
}));
}
assert!(
at.windows(2).all(|pair| pair[0] < pair[1]),
"the README names the three spellings in an order entry 45 does not propose: \
{precedence:?} at {at:?}"
);
for promise in [
"refuses the whole envelope",
"once per envelope",
"reviewed by nothing",
"reported as having declared none",
"naming none is the default and runs no reviewer at all",
] {
assert!(
prose.contains(promise),
"the README no longer states that the envelope reviewer {promise}"
);
}
let prefix = reviewer["objection_prefix"]
.as_str()
.expect("entry 45 states the line a reviewer declares its objection on");
assert!(
prose.contains(prefix),
"the README does not state the `{prefix}` line a reviewer declares on"
);
}
#[test]
fn the_writeback_budget_surface_is_what_the_divergence_record_names() {
let block = divergence_block("71.");
let budget = &block["budget"];
assert_eq!(budget["config_key"].as_str(), Some("writeback_item_budget"));
let at = budget["config_schema_version"]
.as_u64()
.expect("entry 71 states the version the key arrived at");
let arrived = u32::try_from(at).expect("a version fits");
assert!(
LAUNCH_CONFIG_SCHEMA_VERSIONS_READ.contains(&arrived)
&& arrived <= LAUNCH_CONFIG_SCHEMA_VERSION,
"entry 71 states the budget key arrived at schema {arrived}, which is not a \
version this build reads"
);
let named: LaunchConfig = serde_json::from_value(json!({
"schema_version": at,
"writeback_item_budget": 12,
}))
.expect("a launch config naming a budget parses");
assert_eq!(named.writeback_item_budget, NonZeroU64::new(12));
for version in LAUNCH_CONFIG_SCHEMA_VERSIONS_READ {
let earlier: LaunchConfig =
serde_json::from_value(json!({"schema_version": version})).expect("it parses");
assert_eq!(earlier.writeback_item_budget, None);
if version < arrived {
let dir = std::env::temp_dir().join(format!(
"onepipeline-contract-budget-{}-{version}",
std::process::id()
));
std::fs::create_dir_all(&dir).expect("a scratch directory");
let path = dir.join("launch.yaml");
std::fs::write(
&path,
format!("schema_version: {version}\nwriteback_item_budget: 12\n"),
)
.expect("the config is written");
let refused = LaunchConfig::load(&path)
.expect_err("a version that never had the key refuses it")
.to_string();
assert!(
refused.contains("`writeback_item_budget`")
&& refused.contains(&format!("schema {arrived} key")),
"schema {version} did not refuse the key by its name: {refused}"
);
let _ = std::fs::remove_dir_all(&dir);
}
}
let flag = budget["flag"].as_str().expect("entry 71 names the flag");
let parsed = Cli::try_parse_from(["onepipeline", "start", "plan.json", flag, "12"])
.expect("the flag entry 71 names is one `start` takes");
let Command::Start(started) = parsed.command else {
panic!("that is not a start")
};
assert_eq!(started.writeback_item_budget, Some(12));
let parsed = Cli::try_parse_from(["onepipeline", "start", "plan.json"]).expect("it parses");
let Command::Start(unset) = parsed.command else {
panic!("that is not a start")
};
assert_eq!(unset.writeback_item_budget, None);
assert_eq!(
budget["environment"].as_str(),
Some(WRITEBACK_ITEM_BUDGET_ENV),
"entry 71 names a different variable than the engine reads"
);
let precedence: Vec<String> = serde_json::from_value(budget["precedence"].clone())
.expect("entry 71 states the order it proposes");
assert_eq!(precedence, ["flag", "environment", "config_key"]);
assert_eq!(
budget["default_seconds"].as_u64(),
Some(DEFAULT_WRITEBACK_ITEM_BUDGET_SECONDS.get()),
"entry 71 states a different shipped default than the code carries"
);
assert_eq!(
budget["floor_seconds"].as_u64(),
Some(WRITEBACK_COMMAND_FLOOR_SECONDS),
"entry 71 states a different floor than the code carries"
);
assert!(
budget["default_seconds"]
.as_u64()
.is_some_and(|seconds| seconds > 0),
"entry 71 states a shipped default of zero"
);
assert_eq!(
budget["deadline"].as_str(),
Some("max(floor_seconds, budget × items)"),
"entry 71 states a deadline other than the arithmetic its examples are held to"
);
let examples = budget["examples"]
.as_array()
.expect("entry 71 works an example");
assert!(!examples.is_empty(), "{budget}");
for example in examples {
let items = example["items"].as_u64().expect("an item count");
let per_item = example["budget_seconds"].as_u64().expect("a budget");
let deadline = example["deadline_seconds"].as_u64().expect("a deadline");
assert_eq!(
deadline,
(per_item * items).max(WRITEBACK_COMMAND_FLOOR_SECONDS),
"entry 71's example is not the arithmetic it states: {example}"
);
let refusal = example["refusal"].as_str().expect("the refusal");
assert!(
refusal.starts_with(&format!("project-copy exceeded {deadline} seconds ("))
&& refusal.contains(&format!("{items} items × {per_item} seconds per item")),
"entry 71's refusal does not name what it computed: {refusal}"
);
assert_eq!(
refusal.contains("floor"),
per_item * items < WRITEBACK_COMMAND_FLOOR_SECONDS,
"entry 71's refusal says the floor governed where it did not, or the reverse: \
{refusal}"
);
}
let readme = std::fs::read_to_string(repo_root().join("README.md")).expect("the README ships");
let prose = readme.split_whitespace().collect::<Vec<_>>().join(" ");
let mut found: Vec<usize> = Vec::new();
for spelling in &precedence {
let named = budget[spelling.as_str()]
.as_str()
.expect("entry 71 names it");
found.push(prose.find(named).unwrap_or_else(|| {
panic!("the README does not name the budget's {spelling}, `{named}`")
}));
}
assert!(
found.windows(2).all(|pair| pair[0] < pair[1]),
"the README names the three spellings in an order entry 71 does not propose: \
{precedence:?} at {found:?}"
);
for promise in [
"multiplied by the number of items",
"never below the sixty-second floor",
"zero is refused",
"naming none takes ten seconds per item",
] {
assert!(
prose.contains(promise),
"the README no longer states that the write-back budget is {promise}"
);
}
}
#[test]
fn the_run_end_hooks_surface_is_what_the_contract_names() {
let block: Value = serde_json::from_str(&fenced_block_naming("json", "run_end_hooks"))
.expect("the run-end hooks block is JSON");
let hooks = &block["run_end_hooks"];
let spelled = |group: &str, which: &str| -> String {
hooks[group][which]
.as_str()
.unwrap_or_else(|| panic!("the block names no {group}.{which}"))
.to_string()
};
assert!(
CONTRACT
.contains("[--success-hook COMMAND] [--failure-hook COMMAND] [--hook-timeout SECONDS]"),
"the driver invocation no longer names the run-end hook flags"
);
let parsed = Cli::try_parse_from([
"onepipeline".to_string(),
"start".to_string(),
"plans:demo".to_string(),
spelled("flags", "success"),
"./follow-up.sh".to_string(),
spelled("flags", "failure"),
"./report-failure.sh".to_string(),
spelled("flags", "timeout"),
"30".to_string(),
])
.expect("the flags the block names are ones `start` takes");
let Command::Start(started) = parsed.command else {
panic!("that is not a start")
};
assert_eq!(started.success_hook.as_deref(), Some("./follow-up.sh"));
assert_eq!(started.failure_hook.as_deref(), Some("./report-failure.sh"));
assert_eq!(started.hook_timeout, NonZeroU64::new(30));
let Command::Start(unset) = Cli::try_parse_from(["onepipeline", "start", "plans:demo"])
.expect("it parses")
.command
else {
panic!("that is not a start")
};
assert_eq!(
(unset.success_hook, unset.failure_hook, unset.hook_timeout),
(None, None, None),
"a launch naming no hook named one"
);
let at = hooks["config_schema_version"]
.as_u64()
.expect("the block states the version the keys arrived at");
let arrived = u32::try_from(at).expect("a version fits");
assert!(
LAUNCH_CONFIG_SCHEMA_VERSIONS_READ.contains(&arrived)
&& arrived <= LAUNCH_CONFIG_SCHEMA_VERSION,
"the block states the hook keys arrived at schema {arrived}, which this build does not read"
);
let keys = [
(spelled("config_keys", "success"), json!("./follow-up.sh")),
(
spelled("config_keys", "failure"),
json!("./report-failure.sh"),
),
(spelled("config_keys", "timeout"), json!(45)),
];
let mut document = serde_json::Map::new();
document.insert("schema_version".into(), json!(at));
for (key, value) in &keys {
document.insert(key.clone(), value.clone());
}
let named: LaunchConfig =
serde_json::from_value(Value::Object(document)).expect("a config naming both hooks parses");
assert_eq!(named.success_hook.as_deref(), Some("./follow-up.sh"));
assert_eq!(named.failure_hook.as_deref(), Some("./report-failure.sh"));
assert_eq!(named.hook_timeout, NonZeroU64::new(45));
let dir =
std::env::temp_dir().join(format!("onepipeline-contract-hooks-{}", std::process::id()));
std::fs::create_dir_all(&dir).expect("a scratch directory");
for version in LAUNCH_CONFIG_SCHEMA_VERSIONS_READ
.into_iter()
.filter(|version| *version < arrived)
{
for (key, value) in &keys {
let path = dir.join(format!("{version}-{key}.yaml"));
std::fs::write(
&path,
format!("schema_version: {version}\n{key}: {value}\n"),
)
.expect("the config is written");
let refused = LaunchConfig::load(&path)
.expect_err("a version that never had the key refuses it")
.to_string();
assert!(
refused.contains(&format!("`{key}`"))
&& refused.contains(&format!("schema {arrived} key")),
"schema {version} did not refuse `{key}` by its name: {refused}"
);
}
}
let _ = std::fs::remove_dir_all(&dir);
let mut zero = serde_json::Map::new();
zero.insert("schema_version".into(), json!(at));
zero.insert(spelled("config_keys", "timeout"), json!(0));
let refused = serde_json::from_value::<LaunchConfig>(Value::Object(zero))
.expect_err("a timeout of zero is refused")
.to_string();
assert!(refused.contains("zero"), "{refused}");
assert_eq!(
hooks["default_timeout_seconds"].as_u64(),
Some(DEFAULT_HOOK_TIMEOUT_SECONDS.get()),
"the block states a different shipped timeout than the code carries"
);
let payloads = hooks["payloads"]
.as_object()
.expect("the block names the payloads");
let tokens = backticked();
assert_eq!(payloads.len(), 3, "{payloads:?}");
for kind in payloads.keys() {
assert!(
PipelineKind::from_wire(&EventKind(kind.clone())).is_some(),
"`{kind}` is not a kind this build emits"
);
assert!(
tokens.contains(kind),
"the contract's kind list does not name `{kind}`"
);
}
let endings: Vec<String> =
serde_json::from_value(hooks["endings"].clone()).expect("the block names the endings");
let reason_kinds: Vec<String> = serde_json::from_value(hooks["reason_kinds"].clone())
.expect("the block names the reason kinds");
assert!(endings.contains(
&payloads["run-hook-finished"]["ending"]
.as_str()
.expect("an ending")
.to_string()
));
assert_eq!(hooks["stdin"]["success"]["reason"], Value::Null);
let failure = &hooks["stdin"]["failure"]["reason"];
assert!(reason_kinds.contains(&failure["kind"].as_str().expect("a kind").to_string()));
assert_eq!(failure, &payloads["run-hook-fired"]["reason"]);
for node in failure["nodes"].as_array().expect("the reason lists nodes") {
let fields: BTreeSet<&str> = node
.as_object()
.expect("a node is an object")
.keys()
.map(String::as_str)
.collect();
assert_eq!(fields, BTreeSet::from(["id", "status", "outcome"]));
}
let readme = std::fs::read_to_string(repo_root().join("README.md")).expect("the README ships");
let prose = readme.split_whitespace().collect::<Vec<_>>().join(" ");
for group in ["flags", "config_keys"] {
for which in ["success", "failure", "timeout"] {
let named = spelled(group, which);
assert!(
prose.contains(&named),
"the README does not name the run-end hooks' {group} `{named}`"
);
}
}
let environment: Vec<String> = serde_json::from_value(hooks["environment"].clone())
.expect("the block names a hook's environment");
for variable in &environment {
assert!(
prose.contains(variable.as_str()),
"the README does not name `{variable}`, which a hook is given"
);
}
let log = hooks["log"].as_str().expect("the block names the log");
assert!(
prose.contains(log),
"the README does not say a hook's output is kept in `{log}`"
);
assert_eq!(
DEFAULT_HOOK_TIMEOUT_SECONDS.get(),
600,
"the README's shipped timeout is written in words; move them with the constant"
);
for promise in [
"six hundred seconds when unnamed, zero refused",
"has not ended and fires neither",
"a hook never changes how the run settled",
] {
assert!(
prose.contains(promise),
"the README no longer states that {promise}"
);
}
let contract = CONTRACT.split_whitespace().collect::<Vec<_>>().join(" ");
for promise in [
"at most once per ending",
"judged by what the edit left behind, not by which operation it carried",
"a run recovered from a failure still fires the hook it then reaches",
"a settle that carries a failed ending to a complete one",
] {
assert!(
contract.contains(promise),
"the contract no longer states that {promise}"
);
assert!(
prose.contains(promise),
"the README states the epoch rule differently from the contract: {promise}"
);
}
}
#[test]
fn the_run_history_surface_is_what_the_contract_names() {
use onepipeline::agents;
let block: Value = serde_json::from_str(&fenced_block_naming("json", "oneharness_history"))
.expect("the run-history block is JSON");
let history = &block["oneharness_history"];
let spelled = |path: &[&str]| -> String {
path.iter()
.fold(history, |value, key| &value[*key])
.as_str()
.unwrap_or_else(|| panic!("the block names no {}", path.join(".")))
.to_string()
};
assert_eq!(spelled(&["environment", "history"]), agents::HISTORY_ENV);
assert_eq!(
spelled(&["environment", "pointer_file"]),
agents::POINTER_FILE_ENV
);
assert_eq!(spelled(&["environment", "labels"]), agents::LABELS_ENV);
assert_eq!(spelled(&["never_set"]), agents::HISTORY_DIR_ENV);
assert_eq!(spelled(&["pointer_file"]), agents::SESSIONS_FILE);
assert_eq!(
RunPaths::under(Path::new("/runs"), "demo")
.oneharness_sessions()
.file_name()
.and_then(|name| name.to_str()),
Some(agents::SESSIONS_FILE)
);
assert_eq!(spelled(&["label_prefix"]), agents::LABEL_PREFIX);
let keys = [
("run_id", agents::RUN_ID_LABEL),
("project", agents::PROJECT_LABEL),
("scope", agents::SCOPE_LABEL),
("node", agents::NODE_LABEL),
("step", agents::STEP_LABEL),
("attempt", agents::ATTEMPT_LABEL),
];
for (name, constant) in keys {
assert_eq!(spelled(&["labels", name]), constant, "labels.{name}");
assert!(
constant.starts_with(agents::LABEL_PREFIX),
"{constant} is not under the engine's prefix"
);
}
let named_keys: BTreeSet<String> = history["labels"]
.as_object()
.expect("labels is an object")
.keys()
.cloned()
.collect();
assert_eq!(
named_keys,
keys.iter().map(|(name, _)| (*name).to_string()).collect(),
"the block names a key the crate does not, or the crate one the block does not"
);
let scopes: std::collections::BTreeMap<String, String> =
serde_json::from_value(history["scopes"].clone()).expect("the scopes are words");
assert_eq!(
scopes.values().cloned().collect::<BTreeSet<_>>(),
agents::Scope::ALL
.iter()
.map(|scope| scope.as_str().to_string())
.collect(),
"the scope words are not the crate's"
);
let stamp = &history["stamp"];
let attempt =
u32::try_from(stamp["attempt"].as_u64().expect("an attempt")).expect("an attempt fits");
let attempt = NonZeroU32::new(attempt).expect("an attempt counts from one");
let node = stamp["node"].as_str().expect("the example names a node");
let launched = match spelled(&["stamp", "scope"]).as_str() {
"node" => agents::Launched::Node {
node,
step: stamp["step"].as_str(),
attempt,
},
"pr-author" => agents::Launched::PrAuthor { node, attempt },
"observer" => agents::Launched::Observer,
other => panic!("the example's scope `{other}` is not one of the words"),
};
assert_eq!(
launched.scope().as_str(),
spelled(&["stamp", "scope"]),
"the launch's scope word is not the example's"
);
let composed = agents::compose_labels(
Some(&spelled(&["inherited"])),
&agents::Stamp {
run: &spelled(&["stamp", "run_id"]),
project: stamp["project"].as_str(),
launched,
},
)
.expect("the block's example composes");
assert_eq!(composed, spelled(&["composed"]));
let at = history["summary_schema_version"]
.as_u64()
.expect("the block states the summary version the field arrived at");
assert_eq!(
u64::from(SUMMARY_SCHEMA_VERSION),
at,
"the summary schema moved past the version the block states"
);
assert!(
CONTRACT.contains(&spelled(&["opt_out"])),
"the paragraph no longer states the opt-out"
);
for args in [
vec!["onepipeline", "agents", "demo"],
vec!["onepipeline", "agents", "demo", "service"],
vec!["onepipeline", "agents", "--project", "plans:demo"],
] {
let parsed = Cli::try_parse_from(args.clone())
.unwrap_or_else(|error| panic!("{args:?} is not a spelling `agents` takes: {error}"));
assert!(
matches!(parsed.command, Command::Agents(_)),
"{args:?} parsed as something else"
);
}
for args in [
vec!["onepipeline", "agents"],
vec!["onepipeline", "agents", "demo", "--project", "plans:demo"],
] {
Cli::try_parse_from(args.clone())
.err()
.unwrap_or_else(|| panic!("{args:?} is a spelling `agents` refuses"));
}
assert_contract_names(
"agents verb",
&[
"onepipeline agents RUN [NODE]",
"onepipeline agents --project PROJECT",
"verbs::agents(&RunPaths, AgentScope::Run | AgentScope::Node(NODE)) -> Agents",
"verbs::project_agents(root, PROJECT) -> Agents",
"RunPaths::oneharness_sessions()",
"RunSummary.oneharness_sessions",
"DispatchRequest.attempt",
],
);
}
#[test]
fn the_dispatch_env_hook_surface_is_what_the_contract_names() {
let block: Value = serde_json::from_str(&fenced_block_naming("json", "dispatch_env_hook"))
.expect("the dispatch-env hook block is JSON");
let hook = &block["dispatch_env_hook"];
let spelled = |group: &str, which: &str| -> String {
hook[group][which]
.as_str()
.unwrap_or_else(|| panic!("the block names no {group}.{which}"))
.to_string()
};
assert!(
CONTRACT.contains("[--dispatch-env-hook COMMAND] [--dispatch-env-hook-timeout SECONDS]"),
"the driver invocation no longer names the dispatch-env hook flags"
);
let parsed = Cli::try_parse_from([
"onepipeline".to_string(),
"start".to_string(),
"plans:demo".to_string(),
spelled("flags", "command"),
"./dispatch-env.sh".to_string(),
spelled("flags", "timeout"),
"30".to_string(),
])
.expect("the flags the block names are ones `start` takes");
let Command::Start(started) = parsed.command else {
panic!("that is not a start")
};
assert_eq!(
started.dispatch_env_hook.as_deref(),
Some("./dispatch-env.sh")
);
assert_eq!(started.dispatch_env_hook_timeout, NonZeroU64::new(30));
let Command::Start(unset) = Cli::try_parse_from(["onepipeline", "start", "plans:demo"])
.expect("it parses")
.command
else {
panic!("that is not a start")
};
assert_eq!(
(unset.dispatch_env_hook, unset.dispatch_env_hook_timeout),
(None, None),
"a launch naming no hook named one"
);
for flag in ["command", "timeout"] {
let refused = Cli::try_parse_from([
"onepipeline".to_string(),
"adopt".to_string(),
"demo".to_string(),
spelled("flags", flag),
"x".to_string(),
])
.expect_err("adopt takes no dispatch-env hook flag");
assert!(
refused.to_string().contains(&spelled("flags", flag)),
"{refused}"
);
}
let at = hook["config_schema_version"]
.as_u64()
.expect("the block states the version the keys arrived at");
let arrived = u32::try_from(at).expect("a version fits");
assert!(
LAUNCH_CONFIG_SCHEMA_VERSIONS_READ.contains(&arrived)
&& arrived <= LAUNCH_CONFIG_SCHEMA_VERSION,
"the block states the hook keys arrived at schema {arrived}, which this build does not read"
);
let keys = [
(
spelled("config_keys", "command"),
json!("./dispatch-env.sh"),
),
(spelled("config_keys", "timeout"), json!(45)),
];
let mut document = serde_json::Map::new();
document.insert("schema_version".into(), json!(at));
for (key, value) in &keys {
document.insert(key.clone(), value.clone());
}
let named: LaunchConfig =
serde_json::from_value(Value::Object(document)).expect("a config naming the hook parses");
assert_eq!(
named.dispatch_env_hook.as_deref(),
Some("./dispatch-env.sh")
);
assert_eq!(named.dispatch_env_hook_timeout, NonZeroU64::new(45));
let dir = std::env::temp_dir().join(format!(
"onepipeline-contract-dispatch-env-{}",
std::process::id()
));
std::fs::create_dir_all(&dir).expect("a scratch directory");
for version in LAUNCH_CONFIG_SCHEMA_VERSIONS_READ
.into_iter()
.filter(|version| *version < arrived)
{
for (key, value) in &keys {
let path = dir.join(format!("{version}-{key}.yaml"));
std::fs::write(
&path,
format!("schema_version: {version}\n{key}: {value}\n"),
)
.expect("the config is written");
let refused = LaunchConfig::load(&path)
.expect_err("a version that never had the key refuses it")
.to_string();
assert!(
refused.contains(&format!("`{key}`"))
&& refused.contains(&format!("schema {arrived} key")),
"schema {version} did not refuse `{key}` by its name: {refused}"
);
}
}
let _ = std::fs::remove_dir_all(&dir);
let mut zero = serde_json::Map::new();
zero.insert("schema_version".into(), json!(at));
zero.insert(spelled("config_keys", "timeout"), json!(0));
let refused = serde_json::from_value::<LaunchConfig>(Value::Object(zero))
.expect_err("a timeout of zero is refused")
.to_string();
assert!(refused.contains("zero"), "{refused}");
assert_eq!(
hook["default_timeout_seconds"].as_u64(),
Some(DEFAULT_DISPATCH_ENV_HOOK_TIMEOUT_SECONDS.get()),
"the block states a different shipped timeout than the code carries"
);
let stdout = &hook["stdout"];
assert_eq!(stdout["version"], json!(1));
let fields: BTreeSet<&str> = stdout
.as_object()
.expect("the document is an object")
.keys()
.map(String::as_str)
.collect();
assert_eq!(fields, BTreeSet::from(["version", "env"]));
for (name, value) in stdout["env"].as_object().expect("`env` is an object") {
assert!(
value.is_string(),
"`env.{name}` is not a string in the block"
);
}
let name = hook["hook"].as_str().expect("the block names the hook");
assert_eq!(
hook["log"].as_str(),
Some(format!("hooks/{name}.log").as_str())
);
assert!(
CONTRACT.contains(&format!("`ONEPIPELINE_HOOK={name}`")),
"the prose does not say what ONEPIPELINE_HOOK says"
);
let environment: Vec<String> = serde_json::from_value(hook["environment"].clone())
.expect("the block names the hook's environment");
let tokens = backticked();
for variable in &environment {
assert!(
tokens.contains(variable),
"the contract's prose does not name `{variable}`, which the block says a hook is given"
);
}
let endings: Vec<String> =
serde_json::from_value(hook["endings"].clone()).expect("the block names the endings");
assert_eq!(endings, ["exit", "timeout", "could-not-start", "malformed"]);
let outcome = hook["refusal_outcome"]
.as_str()
.expect("the block names the outcome a refused launch settles under");
assert_eq!(outcome, "infrastructure-failure");
assert!(
tokens.contains(outcome),
"a refused launch settles under a word the contract does not already name"
);
let readme = std::fs::read_to_string(repo_root().join("README.md")).expect("the README ships");
let prose = readme.split_whitespace().collect::<Vec<_>>().join(" ");
for group in ["flags", "config_keys"] {
for which in ["command", "timeout"] {
let named = spelled(group, which);
assert!(
prose.contains(&named),
"the README does not name the dispatch-env hook's {group} `{named}`"
);
}
}
for variable in &environment {
assert!(
prose.contains(variable.as_str()),
"the README does not name `{variable}`, which the hook is given"
);
}
let log = hook["log"].as_str().expect("the block names the log");
assert!(
prose.contains(log),
"the README does not say the hook's stderr is kept in `{log}`"
);
assert_eq!(
DEFAULT_DISPATCH_ENV_HOOK_TIMEOUT_SECONDS.get(),
60,
"the README's shipped timeout is written in words; move them with the constant"
);
for promise in [
"sixty seconds when unnamed, zero refused",
"for that one child launch only",
"no value it prints is written anywhere the run keeps",
"Naming no hook dispatches exactly as before",
] {
assert!(
prose.contains(promise),
"the README no longer states that {promise}"
);
}
}
#[test]
fn the_writeback_refusal_rule_is_what_the_divergence_record_names() {
let block = divergence_block("72.");
let rule = &block["failure"];
assert_eq!(
rule["member"].as_str(),
Some(WRITEBACK_FAILURE_CLASS_MEMBER),
"entry 72 names a different member than the worker branches on"
);
assert_eq!(
rule["stops_the_timer"].as_str(),
Some(WRITEBACK_REFUSED_CLASS),
"entry 72 names a different class than the one that stops the retry timer"
);
assert_eq!(
rule["failure_document_exit"].as_i64(),
Some(i64::from(WRITEBACK_FAILURE_EXIT)),
"entry 72 reads the failure document under a different exit than the worker does"
);
assert_eq!(
rule["commands"],
json!(WRITEBACK_CLASSIFIED_COMMANDS),
"entry 72 names different commands than the worker reads a class off"
);
let partial = &rule["partial_answer"];
assert_eq!(
partial["exit"].as_i64(),
Some(i64::from(WRITEBACK_PARTIAL_EXIT)),
"entry 72 reads a partial answer under a different exit than the worker does"
);
assert_eq!(
partial["member"].as_str(),
Some(WRITEBACK_PARTIAL_CLASS_MEMBER),
"entry 72 names a different partial-answer member than the worker reads"
);
assert_eq!(
partial["refused_when"].as_str(),
Some("every"),
"entry 72 states a partial answer is refused on something other than every entry"
);
let contract =
std::fs::read_to_string(repo_root().join("docs/contract.md")).expect("the contract reads");
assert!(
contract.contains("Write-back is best effort and retried off the reconcile loop"),
"the sentence entry 72 proposes to narrow is no longer the contract's"
);
}
fn json_type(value: &Value) -> &'static str {
match value {
Value::Null => "null",
Value::Bool(_) => "boolean",
Value::Number(number) if number.is_u64() || number.is_i64() => "integer",
Value::Number(_) => "number",
Value::String(_) => "string",
Value::Array(_) => "array",
Value::Object(_) => "object",
}
}
#[test]
fn the_writeback_projection_record_is_what_the_divergence_record_names() {
let block = divergence_block("73.");
let projection = &block["projection"];
let detection = &block["detection"];
let member = &block["member_projection"];
assert_eq!(
projection["record"].as_str(),
Some(format!("<run dir>/{WRITEBACK_PROJECTIONS_FILE}").as_str()),
"entry 73 names a different record than the worker appends to"
);
assert_eq!(
detection["record"].as_str(),
Some(format!("<run dir>/{WRITEBACK_STORE_FILE}").as_str()),
"entry 73 keeps the store's answer somewhere other than the worker does"
);
assert_eq!(
detection["members_from"].as_str(),
Some(WRITEBACK_MEMBERS_FROM),
"entry 73 names a different first release offering a member copy"
);
assert_eq!(
detection["command"].as_str(),
Some("onetaskgraph --version")
);
assert_eq!(
member["reads"],
json!([WRITEBACK_CLASSIFIED_COMMANDS[0], WRITEBACK_MEMBER_READ]),
"entry 73 names other reads for a member projection than the worker runs"
);
assert_eq!(
member["never_reads"],
json!([WRITEBACK_CLASSIFIED_COMMANDS[1]]),
"entry 73 no longer says a member projection runs no page of tasks"
);
let example = &projection["example"];
let record: ProjectionRecord = serde_json::from_value(example.clone())
.unwrap_or_else(|error| panic!("entry 73's example is not a record: {error}"));
assert_eq!(
serde_json::to_value(&record).expect("a record serializes"),
*example,
"entry 73's example does not write back as itself"
);
let lines = [
record.clone(),
ProjectionRecord {
scope: ProjectionScope::Whole(WholeBecause::AfterFailure),
ended: ProjectionEnded::Failed {
classified: Some(ProjectionFailure {
class: FailureClass::Refused,
kind: "stale-origin".to_owned(),
}),
reason: "copy exited 1: the store's own words".to_owned(),
},
..record.clone()
},
ProjectionRecord {
scope: ProjectionScope::Whole(WholeBecause::First),
ended: ProjectionEnded::Projected {
actions: None,
spent: None,
},
..record.clone()
},
ProjectionRecord {
scope: ProjectionScope::Whole(WholeBecause::StoreLacksMembers),
ended: ProjectionEnded::Failed {
classified: None,
reason: "project-copy exceeded 60 seconds".to_owned(),
},
..record.clone()
},
ProjectionRecord {
scope: ProjectionScope::Whole(WholeBecause::First),
ended: ProjectionEnded::Failed {
classified: Some(ProjectionFailure {
class: FailureClass::Transient,
kind: "unavailable".to_owned(),
}),
reason: "the copy landed, but the store could not keep every delivered ticket \
in step"
.to_owned(),
},
delivered: vec![json!({
"ticket": "tickets:t/one", "deliverer": "plans:p/a", "outcome": "failed",
"from": "queued",
"failure": {"class": "transient", "kind": "unavailable", "source": "tickets",
"message": "cannot write", "retry_after_seconds": null}
})
.as_object()
.cloned()
.expect("a delivered entry is an object")],
..record.clone()
},
];
let fields = projection["fields"]
.as_object()
.expect("entry 73 names the record's fields");
let always: BTreeSet<&String> = fields
.iter()
.filter(|(_, field)| field["omitted_when"].is_null())
.map(|(name, _)| name)
.collect();
let mut written_keys: BTreeSet<String> = BTreeSet::new();
let mut written_words: std::collections::BTreeMap<String, BTreeSet<String>> =
std::collections::BTreeMap::new();
for line in &lines {
let written = serde_json::to_value(line).expect("a record serializes");
let written = written.as_object().expect("a record is one object");
let keys: BTreeSet<&String> = written.keys().collect();
assert!(
always.is_subset(&keys) && keys.iter().all(|key| fields.contains_key(*key)),
"the record writes other keys than entry 73 names: {keys:?}"
);
written_keys.extend(written.keys().cloned());
if line.delivered.is_empty() {
assert!(
!written.contains_key("delivered"),
"a line that reached no ticket wrote `delivered`: {written:?}"
);
}
for (name, field) in fields {
let Some(value) = written.get(name) else {
continue;
};
let types: Vec<&str> = match &field["type"] {
Value::String(one) => vec![one.as_str()],
Value::Array(several) => several.iter().filter_map(Value::as_str).collect(),
other => panic!("entry 73 types `{name}` as {other}"),
};
assert!(
types.contains(&json_type(value)),
"`{name}` is written as {} where entry 73 types it {types:?}: {value}",
json_type(value)
);
if let (Some(admitted), Some(word)) = (field["values"].as_array(), value.as_str()) {
assert!(
admitted.contains(&json!(word)),
"`{name}` is written as `{word}`, which entry 73 does not admit"
);
written_words
.entry(name.clone())
.or_default()
.insert(word.to_owned());
}
if let (Some(members), Some(object)) = (field["members"].as_array(), value.as_object())
{
assert_eq!(
object.keys().map(String::as_str).collect::<BTreeSet<_>>(),
members
.iter()
.filter_map(Value::as_str)
.collect::<BTreeSet<_>>(),
"`{name}` is written with other members than entry 73 names"
);
}
}
}
assert_eq!(
written_keys.iter().collect::<BTreeSet<_>>(),
fields.keys().collect::<BTreeSet<_>>(),
"a key entry 73 names is written on no shape of line"
);
for name in ["scope", "outcome"] {
let admitted: BTreeSet<String> = serde_json::from_value(fields[name]["values"].clone())
.expect("entry 73 lists the words");
assert_eq!(
written_words.get(name),
Some(&admitted),
"entry 73 admits other `{name}` words than the record writes"
);
}
let because: BTreeSet<String> = [
WholeBecause::First,
WholeBecause::AfterFailure,
WholeBecause::StoreLacksMembers,
]
.into_iter()
.map(|reason| {
serde_json::to_value(reason)
.ok()
.and_then(|word| word.as_str().map(str::to_owned))
.expect("a reason is a word")
})
.collect();
assert_eq!(
serde_json::from_value::<BTreeSet<String>>(fields["whole_because"]["values"].clone())
.expect("entry 73 lists the reasons"),
because
);
let classes: BTreeSet<String> = [FailureClass::Refused, FailureClass::Transient]
.into_iter()
.map(|class| {
serde_json::to_value(class)
.ok()
.and_then(|word| word.as_str().map(str::to_owned))
.expect("a class is a word")
})
.collect();
assert_eq!(
serde_json::from_value::<BTreeSet<String>>(fields["class"]["values"].clone())
.expect("entry 73 lists the classes"),
classes
);
assert_eq!(
fields["actions"]["members"],
json!(serde_json::to_value(ProjectionActions::default())
.expect("counts serialize")
.as_object()
.expect("an object")
.keys()
.collect::<Vec<_>>())
);
for (contradiction, patch) in [
(
"a member copy with a reason to be whole",
json!({"whole_because": "first"}),
),
("a whole copy with no reason", json!({"scope": "whole"})),
(
"a landed attempt with a failure's reason",
json!({"reason": "it failed"}),
),
(
"a failed attempt with a copy report",
json!({"outcome": "failed", "reason": "it failed"}),
),
(
"a failed attempt with no reason",
json!({"outcome": "failed", "actions": null, "spent": null}),
),
(
"a class without its kind",
json!({"outcome": "failed", "reason": "it failed", "actions": null, "spent": null,
"class": "refused"}),
),
("a key the entry does not name", json!({"cost": 94})),
("a start that is not a time", json!({"at": "yesterday"})),
(
"a start that is not UTC",
json!({"at": "2026-09-13T12:00:00+02:00"}),
),
(
"a project that is not a qualified id",
json!({"project": "writeback-quota-plan"}),
),
("an item with no node id", json!({"items": [""]})),
] {
let mut line = example.clone();
for (key, value) in patch.as_object().expect("a patch") {
line[key] = value.clone();
}
assert!(
serde_json::from_value::<ProjectionRecord>(line.clone()).is_err(),
"{contradiction} was read as a record: {line}"
);
}
let schema = &projection["schema"];
let current = onepipeline::cli::WRITEBACK_PROJECTIONS_SCHEMA_VERSION;
assert_eq!(
schema["current"].as_u64(),
Some(u64::from(current)),
"entry 73 names a different current schema version than the worker writes"
);
assert_eq!(schema["read"], json!([1, 2, current]));
assert_eq!(schema["absent_means"], json!(1));
assert_eq!(schema["added_at_2"], json!(["delivered"]));
assert_eq!(schema["added_at_3"], json!(["actions.reopened"]));
let delivered_example = &projection["example_delivered"];
for golden in [example, delivered_example] {
assert_eq!(
golden["schema_version"].as_u64(),
Some(u64::from(current)),
"a golden line of entry 73 is not at the current schema version: {golden}"
);
}
assert!(
delivered_example["delivered"][0].get("pruned").is_some(),
"the golden entry carries no member this build never names, so verbatim proves nothing"
);
let with_tickets: ProjectionRecord = serde_json::from_value(delivered_example.clone())
.unwrap_or_else(|error| panic!("entry 73's delivered example is not a record: {error}"));
assert_eq!(
json!(with_tickets.delivered),
delivered_example["delivered"],
"the delivered entries were not kept verbatim"
);
assert_eq!(
serde_json::to_value(&with_tickets).expect("a record serializes"),
*delivered_example,
"entry 73's delivered example does not write back as itself"
);
assert!(
record.delivered.is_empty() && example.get("delivered").is_none(),
"the plain golden line was meant to name no ticket"
);
assert!(
serde_json::to_value(&record)
.expect("a record serializes")
.get("delivered")
.is_none(),
"a line that reached no ticket wrote a `delivered` key"
);
assert_eq!(
delivered_example["actions"]["reopened"],
json!(1),
"entry 73's delivered example counts no reopen, so the key's round trip is untested"
);
assert_eq!(example["actions"]["reopened"], json!(0));
let mut older_actions = example["actions"].clone();
older_actions
.as_object_mut()
.expect("actions is an object")
.remove("reopened");
let mut unversioned = example.clone();
unversioned
.as_object_mut()
.expect("a line is an object")
.remove("schema_version");
unversioned["actions"] = older_actions.clone();
let older: ProjectionRecord = serde_json::from_value(unversioned)
.unwrap_or_else(|error| panic!("a version 1 line did not read: {error}"));
assert_eq!(
serde_json::to_value(&older).expect("a record serializes"),
*example,
"a version 1 line was not written back at the current version"
);
let mut second = delivered_example.clone();
second["schema_version"] = json!(2);
second["actions"] = older_actions.clone();
let second: ProjectionRecord = serde_json::from_value(second)
.unwrap_or_else(|error| panic!("a version 2 line did not read: {error}"));
let mut expected = delivered_example.clone();
expected["actions"]["reopened"] = json!(0);
assert_eq!(
serde_json::to_value(&second).expect("a record serializes"),
expected,
"a version 2 line was not written back at the current version with `reopened` zero"
);
for (refused, patch) in [
(
"a version 1 line naming `delivered`",
json!({"schema_version": 1, "actions": older_actions,
"delivered": delivered_example["delivered"]}),
),
(
"a version 1 line naming an empty `delivered`",
json!({"schema_version": 1, "actions": older_actions, "delivered": []}),
),
(
"a version 1 line naming `actions.reopened`",
json!({"schema_version": 1}),
),
(
"a version 2 line naming `actions.reopened`",
json!({"schema_version": 2}),
),
(
"a version 3 line naming `actions` without `reopened`",
json!({"actions": older_actions}),
),
(
"a version this build has never written",
json!({"schema_version": current + 1}),
),
("version 0", json!({"schema_version": 0})),
] {
let mut line = example.clone();
for (key, value) in patch.as_object().expect("a patch") {
line[key] = value.clone();
}
assert!(
serde_json::from_value::<ProjectionRecord>(line.clone()).is_err(),
"{refused} was read as a record: {line}"
);
}
}
#[test]
fn the_criterion_check_is_what_the_divergence_record_names() {
let block = divergence_block("47.");
let kinds: Vec<String> =
serde_json::from_value(block["event_kinds"].clone()).expect("entry 47 names its kinds");
assert!(!kinds.is_empty());
for kind in &kinds {
assert!(
PipelineKind::from_wire(&EventKind(kind.clone())).is_some(),
"`{kind}` is not a kind this crate emits"
);
assert!(
!CONTRACT.contains(&format!("`{kind}`")),
"the contract names `{kind}`, so it is no divergence"
);
}
let raised = block["surface_kind"]
.as_str()
.expect("entry 47 names the surface a mismatch is raised under");
let parsed: SurfaceKind = serde_json::from_value(json!(raised))
.unwrap_or_else(|e| panic!("`{raised}` is a kind this build parses: {e}"));
assert_eq!(parsed, SurfaceKind::finding());
let answers: BTreeSet<String> =
serde_json::from_value(block["answers"].clone()).expect("entry 47 names its answers");
assert_eq!(
answers,
["match", "mismatch", "unread"]
.into_iter()
.map(str::to_string)
.collect::<BTreeSet<String>>(),
"entry 47 no longer keeps a file it could not read apart from one that disagreed"
);
}
#[test]
fn every_op_deserializes_with_the_fields_the_protocol_requires() {
let envelopes: Vec<(&str, Value)> = vec![
("add", json!({"op": "add", "node": {"id": "new"}})),
(
"drop",
json!({"op": "drop", "id": "slow", "dependents": "detach"}),
),
(
"reparent",
json!({"op": "reparent", "id": "pending", "deps": ["slow"]}),
),
(
"retry",
json!({"op": "retry", "id": "failed", "node": {"id": "retry"}}),
),
("cancel", json!({"op": "cancel", "id": "sweep"})),
(
"requeue",
json!({"op": "requeue", "id": "sweep", "amend": {"max_turns": 32}}),
),
("attest", json!({"op": "attest", "ref": "approve"})),
(
"complete",
json!({"op": "complete", "reason": "closeout verified"}),
),
];
let seen: Vec<&str> = envelopes.iter().map(|(op, _)| *op).collect();
assert_eq!(
seen,
contract_ops_this_build_accepts(),
"every op the contract lists and this build still accepts is exercised, in order"
);
for (op, value) in &envelopes {
let edit: Edit = serde_json::from_value(value.clone())
.unwrap_or_else(|e| panic!("`{op}` deserializes: {e}"));
assert_eq!(
&op_of(&edit),
op,
"`{op}` deserialized into another variant"
);
let again = serde_json::to_value(&edit).expect("serializes");
assert_eq!(&again, value, "`{op}` round-trips unchanged");
}
}
#[test]
fn a_note_carries_two_axes_and_the_defaults_entry_60_declares() {
let prose = CONTRACT.split_whitespace().collect::<Vec<_>>().join(" ");
assert!(
prose.contains("`deliver: auto|live|next`, defaulting to `auto`"),
"the contract's `context` paragraph moved; entry 60 names the sentence it replaces"
);
let block = divergence_block("60.");
let deliver = &block["deliver"];
let values: Vec<String> =
serde_json::from_value(deliver["values"].clone()).expect("entry 60 names them");
let default = deliver["default"]
.as_str()
.expect("entry 60 names the default");
let gone = deliver["gone"]
.as_str()
.expect("entry 60 names what is gone");
let persists = block["persist"]["default"]
.as_bool()
.expect("entry 60 names `persist`'s default");
let note = |extra: Value| {
let mut value =
json!({"op": "note", "id": "slow", "addressee": "worker", "text": "the fix landed"});
for (key, field) in extra.as_object().expect("an object") {
value[key] = field.clone();
}
serde_json::from_value::<Edit>(value).expect("the note parses")
};
let spelled: Vec<Edit> = values
.iter()
.map(|value| note(json!({"deliver": value})))
.collect();
assert_eq!(spelled.len(), 2, "entry 60 names two delivery values");
assert_ne!(spelled[0], spelled[1]);
let bare = note(json!({}));
assert_eq!(
bare,
note(json!({"deliver": default, "persist": persists})),
"a note that says nothing about either axis is not the declared default"
);
assert_eq!(
serde_json::to_value(&bare).expect("serializes"),
json!({"op": "note", "id": "slow", "addressee": "worker", "text": "the fix landed"}),
"a note carrying the defaults writes them out"
);
let other = values
.iter()
.find(|value| value.as_str() != default)
.expect("entry 60 names a second value");
assert_eq!(
serde_json::to_value(note(json!({"deliver": other, "persist": !persists})))
.expect("serializes"),
json!({
"op": "note", "id": "slow", "addressee": "worker", "text": "the fix landed",
"deliver": other, "persist": !persists
})
);
let err = serde_json::from_value::<Edit>(
json!({"op": "note", "id": "slow", "addressee": "worker", "text": "n", "deliver": gone}),
)
.expect_err("the removed delivery value is refused");
assert!(err.to_string().contains(gone), "the error names it: {err}");
let was_auto = block["combinations"]
.as_array()
.expect("entry 60 names the four combinations")
.iter()
.find(|one| one["default"] == json!(true))
.expect("one of them is the default");
assert_eq!(
note(json!({"deliver": was_auto["deliver"], "persist": was_auto["persist"]})),
bare,
"the combination entry 60 calls the default is not what a bare note carries"
);
assert_eq!(block["combinations"].as_array().expect("an array").len(), 4);
}
#[test]
fn drop_must_state_the_dependents_fate() {
let err = serde_json::from_value::<Edit>(json!({"op": "drop", "id": "slow"}))
.expect_err("`dependents` is required");
assert!(
err.to_string().contains("dependents"),
"the error names it: {err}"
);
assert_ne!(Dependents::Drop, Dependents::Detach);
assert!(CONTRACT.contains("drop"));
}
#[test]
fn an_unknown_op_is_refused_rather_than_ignored() {
let err = serde_json::from_value::<Edit>(json!({"op": "rewrite", "id": "x"}))
.expect_err("an op outside the protocol is refused");
assert!(
err.to_string().contains("rewrite"),
"the error names it: {err}"
);
}
#[test]
fn a_command_only_envelope_and_a_verdict_envelope_are_both_replies() {
let commands_only: Reply = serde_json::from_value(json!({
"version": 1,
"commands": [{"op": "attest", "ref": "approve"}]
}))
.expect("a command-only envelope parses");
assert_eq!(commands_only.version, Some(1));
assert_eq!(commands_only.commands.len(), 1);
assert_eq!(commands_only.completion, None);
let both: Reply = serde_json::from_value(json!({
"completion": false,
"message": "apply the replacement and continue",
"reason": "the failed node is retryable",
"version": 1,
"commands": [{"op": "retry", "id": "failed", "node": {"id": "retry", "expects_no_diff": true}}]
}))
.expect("commands may accompany a legacy verdict");
assert_eq!(both.completion, Some(false));
assert_eq!(both.commands.len(), 1);
let legacy: Reply = serde_json::from_value(json!({"completion": true, "reason": "done"}))
.expect("a legacy verdict alone parses");
assert!(legacy.commands.is_empty());
assert!(CONTRACT.contains(r#"{"version": 1, "commands": [...]}"#));
}
#[test]
fn a_reply_declares_the_halves_the_contract_routes_it_by() {
let read = |value: Value| serde_json::from_value::<Reply>(value).expect("the envelope parses");
let commands_only = read(json!({
"version": 1,
"commands": [
{"op": "note", "id": "plan", "addressee": "worker", "text": "the scope changed"}
]
}));
assert_eq!(commands_only.completion, None);
assert_eq!(commands_only.message, None);
assert_eq!(commands_only.reason, None);
assert_eq!(commands_only.commands.len(), 1);
for (half, value) in [
("completion", json!({"completion": false})),
("message", json!({"message": "keep going"})),
("reason", json!({"reason": "keep going"})),
] {
let alone = read(value);
assert!(
alone.completion.is_some() || alone.message.is_some() || alone.reason.is_some(),
"`{half}` alone declares no verdict half"
);
assert!(
alone.commands.is_empty(),
"`{half}` alone declares a commands half"
);
}
let both = read(json!({
"completion": false,
"reason": "retry it",
"version": 1,
"commands": [{"op": "cancel", "id": "slow"}]
}));
assert_eq!(both.reason.as_deref(), Some("retry it"));
assert_eq!(both.commands.len(), 1);
assert!(
CONTRACT.contains(
"**A reply is routed by the halves it carries, never by which reader reaches the \
queue first.**"
),
"the contract no longer states that a reply is routed by its halves"
);
assert!(
CONTRACT.contains(
"It answers a pending surface only when it carries a **verdict half** — \
`completion`, `message`, or `reason`"
),
"the contract no longer says which half answers a pending surface"
);
assert!(
CONTRACT.contains(
"belongs to the command path alone: it leaves the pending surface, and any reader \
waiting there for a verdict, untouched"
),
"the contract no longer says where a commands-only envelope goes"
);
assert!(
CONTRACT.contains("One carrying both is delivered to both"),
"the contract no longer says what an envelope carrying both halves does"
);
assert!(
CONTRACT.contains("Neither reader advances the other's cursor"),
"the contract no longer promises the two cursors stay apart"
);
}
#[test]
fn the_contract_declares_an_open_surface_kind_vocabulary() {
let check_in: SurfaceKind = serde_json::from_value(json!("check-in")).expect("parses");
assert_eq!(check_in, SurfaceKind::check_in());
let host_kind: SurfaceKind = serde_json::from_value(json!("host-defined")).expect("parses");
assert_eq!(host_kind.as_str(), "host-defined");
assert!(CONTRACT.contains("--kind KIND"));
assert!(CONTRACT.contains("^[a-z][a-z0-9-]{0,63}$"));
assert!(
CONTRACT.contains(
"restarts the check-in clock of **every member the run's recorded observer graph \
declares `resettable` in its `schedule`**"
),
"consuming a surface restarts the resettable clocks"
);
assert!(
!CONTRACT.contains("reset-timer RUN check-in"),
"the contract names a member of one host's observer graph"
);
assert!(CONTRACT.contains("`edit-applied`, queued non-blocking"));
assert!(CONTRACT.contains("`<author> applied an edit: <command>`"));
}
#[test]
fn the_refusals_the_contract_lists_are_the_channels_own_words() {
let examples: Vec<Value> = serde_json::from_str(&fenced_block_naming("json", "\"refused\""))
.expect("the block is JSON");
assert!(examples.len() >= 8, "{examples:?}");
for example in &examples {
let author = Author::from(example["author"].as_str().expect("an author word"));
assert_ne!(author.as_str(), "planner", "{example}");
let refused = example["refused"].as_str().expect("a refusal");
let answered = if example.get("verdict").is_some() {
onepipeline::channel::allows_completion(author, Some(true))
} else {
let edit: Edit = serde_json::from_value(example["command"].clone())
.unwrap_or_else(|e| panic!("the example's command parses: {e}: {example}"));
allows(author, &edit)
}
.expect_err("an author granted nothing is refused")
.to_string();
assert_eq!(
answered,
format!("refused: {refused}"),
"the channel refuses in different words than the contract states"
);
}
}
#[test]
fn the_contracts_open_author_grammar_is_the_channels_complete_boundary() {
assert!(CONTRACT.contains("Channel authors are open words"));
assert!(CONTRACT.contains("^[a-z][a-z0-9-]{0,63}$"));
for word in ["planner", "monitor", "sentinel", "a", &"a".repeat(64)] {
let author: Author = serde_json::from_value(json!(word))
.unwrap_or_else(|error| panic!("the documented author `{word}` parses: {error}"));
assert_eq!(author.as_str(), word);
assert_eq!(
serde_json::to_value(author).expect("serializes"),
json!(word)
);
}
for word in ["", "Monitor", "two_words", "-leading", &"a".repeat(65)] {
let error = serde_json::from_value::<Author>(json!(word))
.expect_err(&format!("the undocumented author `{word}` was accepted"));
assert!(
error.to_string().contains("^[a-z][a-z0-9-]{0,63}$"),
"the refusal does not name the contract grammar: {error}"
);
}
}
#[test]
fn the_reply_exit_codes_are_the_ones_the_contract_assigns() {
assert!(CONTRACT.contains(
"reply exit 0 = applied, 1 = accepted-not-yet-reconciled, 2 = refused/malformed"
));
assert_eq!(EXIT_SUCCESS, 0);
assert_eq!(EXIT_QUEUED, 1);
assert_eq!(EXIT_REFUSED, 2);
assert!(CONTRACT.contains("exit 3 = nothing is driving the run"));
assert_eq!(EXIT_NOTHING_DRIVING, 3);
let spent = [
EXIT_SUCCESS,
EXIT_QUEUED,
EXIT_REFUSED,
EXIT_NOTHING_DRIVING,
];
let mut unique = spent.to_vec();
unique.sort_unstable();
unique.dedup();
assert_eq!(unique.len(), spent.len(), "two verdicts share an exit code");
}
#[test]
fn the_divergence_record_names_the_envelope_version_this_build_writes_and_reads() {
let block = divergence_block("65.");
assert_eq!(
block["journal_envelope_version"],
json!(ENVELOPE_VERSION),
"entry 65 names an envelope version this build does not write"
);
assert_eq!(
serde_json::from_value::<Vec<u32>>(block["journal_envelope_versions_read"].clone())
.expect("entry 65 names the versions this build reads"),
ENVELOPE_VERSIONS_READ,
"entry 65 names a different read set from the one this build honours"
);
assert!(
ENVELOPE_VERSIONS_READ.contains(&ENVELOPE_VERSION)
&& ENVELOPE_VERSIONS_READ.contains(&1)
&& ENVELOPE_VERSIONS_READ
.iter()
.all(|version| *version <= ENVELOPE_VERSION),
"the read set is not the versions up to the one this build writes: \
{ENVELOPE_VERSIONS_READ:?}"
);
assert!(
block.get("envelope_version").is_none(),
"entry 65 spells its version under the key entries 57 and 60 use for the reply \
envelope's, which a consumer reads as that one"
);
}
#[test]
fn the_delivered_surfaces_instant_is_what_the_divergence_record_names() {
let block = divergence_block("66.");
let kind = block["delivery_kind"]
.as_str()
.expect("entry 66 names the kind that delivers a surface");
assert!(
PIPELINE_KINDS
.iter()
.any(|carried| carried.as_str() == kind),
"entry 66 names `{kind}`, which is not a kind this build emits"
);
assert_eq!(
block["queued_at_units"], "epoch-milliseconds",
"entry 66 spells the instant in units this crate does not record in"
);
assert_eq!(
serde_json::from_value::<Vec<String>>(block["carried_beside"].clone())
.expect("entry 66 names the fields the instant joins"),
["kind", "message", "source", "blocking"]
);
let field = block["queued_at_field"]
.as_str()
.expect("entry 66 names the field");
let verbs = std::fs::read_to_string(repo_root().join("src/verbs.rs")).expect("the verbs ship");
assert!(
verbs.contains(&format!("(\"{field}\", json!(surface.{field}))")),
"entry 66 names a field the hand-out does not write: {field}"
);
let journeys = std::fs::read_to_string(repo_root().join("tests/e2e/channel.rs"))
.expect("the channel journeys ship");
assert!(
journeys.contains("fn a_delivered_surface_is_recorded_with_the_instant_it_was_queued("),
"entry 66 names a journey the channel suite does not run"
);
}
#[test]
fn the_replys_exit_statuses_are_what_the_divergence_record_names() {
let block = divergence_block("67.");
assert_eq!(
block["reply_applied_exit"],
json!(EXIT_SUCCESS),
"entry 67 names a status this build does not exit at for an applied edit"
);
assert_eq!(
block["reply_queued_exit"],
json!(EXIT_SUCCESS),
"entry 67 names a status this build does not exit at for a queued edit"
);
assert_eq!(
block["reply_refused_exit"],
json!(EXIT_REFUSED),
"entry 67 names a status this build does not exit at for a refused edit"
);
assert_eq!(
block["reply_queued_exit"], block["reply_applied_exit"],
"entry 67 has a queued envelope answering with a status of its own again"
);
assert_ne!(
block["reply_queued_exit"],
json!(EXIT_QUEUED),
"entry 67 has a queued reply answering with the unfinished-run status again"
);
let verbs = std::fs::read_to_string(repo_root().join("src/verbs.rs")).expect("the verbs ship");
assert!(
verbs.contains("durable command queue")
&& verbs.contains("has to drive the run for them to")
&& verbs.contains("They are not to be sent"),
"the reply no longer says what a queued envelope is waiting for"
);
}
#[test]
fn an_envelope_round_trips_through_the_merged_streams_shape() {
let wire = json!({
"v": ENVELOPE_VERSION,
"ts": "2026-08-07T12:00:00.000Z",
"stream": "onepipeline-7f3a",
"seq": 42,
"source": "pipeline",
"kind": "node-settled",
"labels": {"run_id": "run-1", "round": 2, "node": "service", "attempt": 1},
"payload": {"status": "done"},
"artifacts": [{"id": "gate-log", "kind": "log", "bytes": 8192}]
});
let envelope: Envelope = serde_json::from_value(wire.clone()).expect("the envelope parses");
assert_eq!(envelope.source, Source::Pipeline);
assert_eq!(envelope.kind, EventKind("node-settled".into()));
assert_eq!(envelope.labels.run_id.as_deref(), Some("run-1"));
assert_eq!(envelope.labels.round, Some(2));
assert_eq!(
envelope.labels.extra.get("attempt"),
Some(&json!(1)),
"a label outside the reserved keys rides in `extra`"
);
assert_eq!(
envelope.artifacts,
vec![ArtifactRef {
id: "gate-log".into(),
kind: "log".into(),
bytes: 8192
}]
);
assert_eq!(serde_json::to_value(&envelope).expect("serializes"), wire);
}
#[test]
fn the_wire_types_resolve_where_they_did_and_are_the_buss_own() {
fn one_type<T>(_: std::marker::PhantomData<T>, _: std::marker::PhantomData<T>) {}
use std::marker::PhantomData as Named;
one_type(Named::<Envelope>, Named::<onemessagebus_agent::Envelope>);
one_type(Named::<Labels>, Named::<onemessagebus_agent::Labels>);
one_type(Named::<Source>, Named::<onemessagebus_agent::Source>);
one_type(Named::<Phase>, Named::<onemessagebus_agent::Phase>);
one_type(Named::<ArtifactRef>, Named::<onemessagebus::ArtifactRef>);
one_type(Named::<EventKind>, Named::<onemessagebus::Kind>);
one_type(
Named::<EventFilter>,
Named::<onemessagebus_agent::EventFilter>,
);
one_type(Named::<Matcher>, Named::<onemessagebus_agent::Matcher>);
one_type(Named::<Envelope>, Named::<onevcs::Envelope>);
one_type(Named::<Envelope>, Named::<oneagentgraph::event::Envelope>);
assert_eq!(ENVELOPE_VERSIONS_READ.first(), Some(&ENVELOPE_VERSION));
assert_eq!(onepipeline::event::MAX_PAYLOAD_TEXT_BYTES, 4096);
assert_eq!(
PipelineKind::from_wire(&EventKind::from("run-started")),
PIPELINE_KINDS.first().copied()
);
assert_eq!(ArtifactId("gate-log".into()).0, "gate-log");
assert_eq!(onepipeline::filter::DEFAULT_PROFILE, "planner");
assert_eq!(onepipeline::filter::DETAILED_PROFILE, "detailed");
assert_eq!(
LAUNCH_CONFIG_SCHEMA_VERSIONS_READ.first(),
Some(&LAUNCH_CONFIG_SCHEMA_VERSION)
);
assert_eq!(LaunchConfig::default().filters, Filters::default());
}
#[test]
fn the_three_merged_streams_are_the_three_libraries_the_contract_composes() {
assert!(CONTRACT.contains("merges the three event streams"));
for (library, source) in [
("oneagentgraph", Source::Agentgraph),
("onevcs", Source::Vcs),
("onepipeline", Source::Pipeline),
] {
assert!(
CONTRACT.contains(library),
"the contract no longer names `{library}` as a composed library"
);
let _ = source;
}
assert_eq!(
serde_json::to_value(Source::Agentgraph).expect("serializes"),
json!("agentgraph")
);
assert_eq!(
serde_json::to_value(Source::Vcs).expect("serializes"),
json!("vcs")
);
assert_eq!(
serde_json::to_value(Source::Pipeline).expect("serializes"),
json!("pipeline")
);
serde_json::from_value::<Source>(json!("harness")).expect_err("an unknown source is refused");
}
#[test]
fn the_contract_enumerates_exactly_this_librarys_own_event_kinds() {
assert_eq!(PIPELINE_KINDS.len(), 35, "the closed set changed size");
let listed: BTreeSet<String> = backticked()
.into_iter()
.filter(|token| {
token.chars().all(|c| c.is_ascii_lowercase() || c == '-') && token.contains('-')
})
.collect();
let proposed: BTreeSet<String> = ["40.", "47.", "55.", "65.", "70."]
.into_iter()
.flat_map(|entry| {
serde_json::from_value::<Vec<String>>(divergence_block(entry)["event_kinds"].clone())
.unwrap_or_else(|e| panic!("entry {entry} names the kinds it adds: {e}"))
})
.collect();
let undocumented: BTreeSet<String> = PIPELINE_KINDS
.iter()
.map(|kind| kind.as_str().to_string())
.filter(|kind| !listed.contains(kind))
.collect();
assert_eq!(
undocumented, proposed,
"the kinds this crate emits that docs/contract.md does not list are not entry 40's"
);
assert_eq!(PipelineKind::RunStarted.as_str(), "run-started");
assert_eq!(
PipelineKind::from_wire(&EventKind("node-settled".into())),
Some(PipelineKind::NodeSettled)
);
assert_eq!(
PipelineKind::from_wire(&EventKind("gate-finished".into())),
None
);
}
#[test]
fn the_envelopes_phase_is_the_siblings_own_vocabulary_and_all_of_it() {
let spelled = |phase: Phase| match phase {
Phase::Development => "development",
Phase::Integrate => "integrate",
Phase::Review => "review",
Phase::Release => "release",
};
let theirs = onevcs::Phase::every();
assert_eq!(
theirs.len(),
4,
"the sibling's phase vocabulary changed size"
);
for phase in theirs {
let wire = serde_json::to_value(phase).expect("the sibling's phase serializes");
let mine: Phase = serde_json::from_value(wire.clone())
.unwrap_or_else(|e| panic!("this copy does not read the sibling's {wire}: {e}"));
assert_eq!(json!(spelled(mine)), wire, "the two copies spell it apart");
let round: onevcs::Phase = serde_json::from_value(json!(spelled(mine)))
.expect("the sibling reads what this copy writes");
assert_eq!(round, phase);
}
let without = json!({
"v": ENVELOPE_VERSION,
"ts": "2026-08-07T12:00:01.500Z",
"stream": "onevcs-1a2b",
"seq": 3,
"source": "vcs",
"kind": "session-opened",
"labels": {},
"payload": {},
"artifacts": []
});
let envelope: Envelope = serde_json::from_value(without.clone()).expect("parses");
assert_eq!(envelope.dimensions.phase, None);
assert_eq!(
serde_json::to_value(&envelope).expect("serializes"),
without
);
let mut with = without.clone();
with["phase"] = json!("release");
let envelope: Envelope = serde_json::from_value(with.clone()).expect("parses");
assert_eq!(envelope.dimensions.phase, Some(Phase::Release));
assert_eq!(serde_json::to_value(&envelope).expect("serializes"), with);
}
#[test]
fn a_relayed_envelope_keeps_its_producers_own_kind() {
let wire = json!({
"v": ENVELOPE_VERSION,
"ts": "2026-08-07T12:00:01.500Z",
"stream": "onevcs-1a2b",
"seq": 3,
"source": "vcs",
"kind": "gate-finished",
"labels": {},
"payload": {},
"artifacts": []
});
let envelope: Envelope = serde_json::from_value(wire.clone()).expect("parses");
assert_eq!(envelope.source, Source::Vcs);
assert_eq!(envelope.kind, EventKind("gate-finished".into()));
assert_eq!(serde_json::to_value(&envelope).expect("serializes"), wire);
}
fn scratch(name: &str) -> PathBuf {
let dir = std::env::temp_dir().join(format!(
"onepipeline-contract-{name}-{}-{:?}",
std::process::id(),
std::thread::current().id()
));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).expect("a scratch root");
dir
}
fn member_settled(stream: &str, seq: u64, named: &Path) -> Envelope {
let mut wire = json!({
"v": ENVELOPE_VERSION,
"ts": "2026-08-18T09:00:00.000Z",
"stream": stream,
"seq": seq,
"source": "agentgraph",
"kind": MEMBER_SETTLED,
"labels": {"node": "build", "member": "worker"},
"payload": {},
"artifacts": [{"id": format!("report-{stream}"), "kind": "report", "bytes": 0}]
});
wire["payload"][REPORT_PATH] = json!(named.display().to_string());
serde_json::from_value(wire).expect("the settlement parses")
}
#[test]
fn a_consumer_retains_a_report_and_reads_it_back_from_the_path_it_derives() {
let root = scratch("retention-journey");
let produced = root.join("producer");
std::fs::create_dir_all(&produced).expect("a producer scratch");
let named = produced.join(ACCEPTED_REPORT_FILE);
let body = r#"{"results":[{"harness":"claude-code","text":"Ran the gate."}]}"#;
std::fs::write(&named, body).expect("the report the producer wrote");
let runs = root.join("runs");
let paths = RunPaths::under(&runs, "demo");
assert_eq!(paths.run, "demo");
assert_eq!(paths.dir, runs.join("demo"));
assert!(paths.reports_dir().starts_with(&paths.dir));
let stream = "node-scope/1786925518098 3163646";
retain(&paths, &member_settled(stream, 7, &named));
let kept = paths.report_for(stream, 7);
assert_eq!(
std::fs::read_to_string(&kept).expect("this run's own copy of the report"),
body,
"the copy at the derived path is not the report the producer wrote"
);
let leaf = kept
.strip_prefix(paths.reports_dir())
.expect("the copy is under the run's own reports directory");
assert_eq!(
leaf.components().count(),
1,
"the derived name is not a single segment: {leaf:?}"
);
std::fs::remove_file(&named).expect("the producer's own copy goes away");
assert!(std::fs::read_to_string(&kept).is_ok());
std::fs::remove_dir_all(&root).ok();
}
#[test]
fn a_derived_report_path_is_one_segment_under_the_runs_own_storage() {
let paths = RunPaths::under(Path::new("/nowhere"), "demo");
for stream in [
"oneagentgraph-1",
"../../elsewhere",
"..",
"",
"node scope:1786925518098/3163646",
] {
let kept = paths.report_for(stream, 3);
let leaf = kept
.strip_prefix(paths.reports_dir())
.unwrap_or_else(|_| panic!("'{stream}' derived a path outside the run: {kept:?}"));
assert_eq!(
leaf.components().count(),
1,
"'{stream}' derived more than one segment: {leaf:?}"
);
assert_ne!(
kept,
paths.report_for(stream, 4),
"'{stream}' resolves two settlements to one file"
);
}
}
#[test]
fn the_published_writer_refuses_anything_that_is_not_the_producers_own_plain_file() {
let root = scratch("retention-refusals");
let paths = RunPaths::under(&root.join("runs"), "demo");
let secret = root.join("secret.json");
std::fs::write(&secret, r#"{"transcript":{"messages":[]}}"#)
.expect("a file the producing library never wrote");
let planted = root.join("planted");
std::fs::create_dir_all(&planted).expect("somewhere to plant a link");
let link = planted.join(ACCEPTED_REPORT_FILE);
#[cfg(unix)]
std::os::unix::fs::symlink(&secret, &link).expect("a symlink");
#[cfg(windows)]
std::os::windows::fs::symlink_file(&secret, &link).expect("a symlink");
let directory = root.join("as-a-directory").join(ACCEPTED_REPORT_FILE);
std::fs::create_dir_all(&directory).expect("a directory wearing the accepted name");
for (seq, (case, named)) in [
("a base name the producing library never writes", secret),
("a symlink wearing the accepted name", link),
("a directory wearing the accepted name", directory),
(
"nothing at all",
root.join("gone").join(ACCEPTED_REPORT_FILE),
),
]
.into_iter()
.enumerate()
{
let seq = seq as u64;
retain(&paths, &member_settled("oneagentgraph-1", seq, &named));
let kept = paths.report_for("oneagentgraph-1", seq);
assert!(
std::fs::symlink_metadata(&kept).is_err(),
"{case}: '{}' reached the run's own storage at {kept:?}",
named.display()
);
}
std::fs::remove_dir_all(&root).ok();
}
#[test]
fn the_published_writer_refuses_a_report_past_the_bound_it_publishes() {
let root = scratch("retention-oversize");
let paths = RunPaths::under(&root.join("runs"), "demo");
let produced = root.join("producer");
std::fs::create_dir_all(&produced).expect("a producer scratch");
let named = produced.join(ACCEPTED_REPORT_FILE);
let file = std::fs::File::create(&named).expect("the stored report");
file.set_len(MAX_REPORT_BYTES + 1)
.expect("a report past the bound");
drop(file);
retain(&paths, &member_settled("oneagentgraph-1", 4, &named));
let kept = paths.report_for("oneagentgraph-1", 4);
assert!(
std::fs::symlink_metadata(&kept).is_err(),
"a report past {MAX_REPORT_BYTES} bytes reached the run's own storage"
);
std::fs::remove_dir_all(&root).ok();
}
#[test]
fn the_published_writer_ingests_only_an_oneagentgraph_settlement() {
let root = scratch("retention-kinds");
let paths = RunPaths::under(&root.join("runs"), "demo");
let produced = root.join("producer");
std::fs::create_dir_all(&produced).expect("a producer scratch");
let named = produced.join(ACCEPTED_REPORT_FILE);
std::fs::write(&named, "{}").expect("the report the producer wrote");
let mut ours = member_settled("onepipeline-1", 1, &named);
ours.source = Source::Pipeline;
retain(&paths, &ours);
let mut other = member_settled("oneagentgraph-1", 2, &named);
other.kind = EventKind("turn-completed".into());
retain(&paths, &other);
assert!(
!paths.reports_dir().exists(),
"an envelope that is not an agentgraph {MEMBER_SETTLED} was ingested as a report"
);
std::fs::remove_dir_all(&root).ok();
}
#[test]
fn the_contract_names_the_retention_path_and_the_release_it_ships_in() {
let manifest =
std::fs::read_to_string(repo_root().join("Cargo.toml")).expect("the manifest ships");
let declared = manifest
.split_once("\n[package]")
.expect("the manifest declares this package")
.1
.lines()
.find_map(|line| line.trim().strip_prefix("version = \"")?.strip_suffix('"'))
.expect("the package declares a version");
assert_eq!(
onepipeline::VERSION,
declared,
"`VERSION` is not this crate's own package version"
);
assert_contract_names(
"published retention path",
&[
"views::RunPaths",
"the run id `run` and the run's own directory `dir`",
"RunPaths::new",
"RunPaths::under",
"reports_dir()",
"report_for(STREAM, SEQ)",
"reports/<sanitised stream>-<seq>.json",
"report::retain(&RunPaths, &Envelope)",
"report::MEMBER_SETTLED",
"report::REPORT_PATH",
"report::ACCEPTED_REPORT_FILE",
"report::MAX_REPORT_BYTES",
"onepipeline::VERSION",
],
);
assert!(
CONTRACT.contains("the caller holds the producing process's authority for the path"),
"docs/contract.md no longer states `retain`'s precondition"
);
assert!(
CONTRACT.contains("the sanitiser is not public"),
"docs/contract.md no longer says the sanitiser is unreachable"
);
}
#[test]
fn the_driver_contracts_invocation_parses_exactly_as_written() {
let documented = "onepipeline start PROJECT [--attach|--detach] \
[--dag-graph off|REF] [--pr-author-graph REF] \
[--heartbeat-interval 1800] \
[--set PATH=VALUE]... [--node-set PATH=VALUE]... \
[--acknowledge-concurrent]";
assert!(CONTRACT.contains(documented), "the driver invocation moved");
let cli = Cli::try_parse_from([
"onepipeline",
"start",
"otg:plan-store",
"--detach",
"--dag-graph",
"graphs/dag-scope.yaml",
"--pr-author-graph",
"graphs/pr-author.yaml",
"--heartbeat-interval",
"1800",
"--set",
"members.monitor.agent.model=dag one",
"--set=members.check-in.model=dag=two",
"--node-set",
"members.worker.agent.model=node one",
"--node-set=members.worker.judge.model=node=two",
"--acknowledge-concurrent",
])
.expect("the documented invocation parses");
let Command::Start(args) = cli.command else {
panic!("expected `start`");
};
assert_eq!(args.project, "otg:plan-store");
assert!(args.detach);
assert!(!args.attach);
assert_eq!(args.dag_graph, "graphs/dag-scope.yaml");
assert_eq!(
args.pr_author_graph.as_deref(),
Some("graphs/pr-author.yaml")
);
assert_eq!(args.heartbeat_interval, 1_800);
assert!(args.acknowledge_concurrent);
assert_eq!(
args.dag_sets,
[
"members.monitor.agent.model=dag one",
"members.check-in.model=dag=two"
]
);
assert_eq!(
args.node_sets,
[
"members.worker.agent.model=node one",
"members.worker.judge.model=node=two"
]
);
assert_eq!(DEFAULT_HEARTBEAT_INTERVAL_SECONDS, 1_800);
assert!(
CONTRACT.contains("`--dag-graph` defaults to `off`"),
"the contract no longer states the shipped default"
);
let defaulted = Cli::try_parse_from(["onepipeline", "start", "plans:demo"]).expect("parses");
let Command::Start(args) = defaulted.command else {
panic!("expected `start`");
};
assert_eq!(
args.dag_graph, DAG_GRAPH_OFF,
"a plan runs with no agent graph unless one is asked for"
);
assert_eq!(
args.pr_author_graph, None,
"a change request is drafted by no graph unless one is asked for"
);
assert_eq!(args.heartbeat_interval, DEFAULT_HEARTBEAT_INTERVAL_SECONDS);
}
#[test]
fn the_round_verbs_are_gone_from_the_command_surface() {
for retired in [
vec!["round", "run", "run-1"],
vec!["round", "next", "run-1"],
] {
Cli::try_parse_from(std::iter::once("onepipeline").chain(retired.iter().copied()))
.expect_err("a round verb still parses");
}
Cli::try_parse_from(["onepipeline", "start", "p.json", "--round-budget", "10"])
.expect_err("--round-budget still parses");
assert!(
!CONTRACT.contains("round run") && !CONTRACT.contains("--round-budget"),
"the contract still names a retired verb or flag"
);
}
#[test]
fn attach_and_detach_are_the_alternatives_the_contract_writes_them_as() {
Cli::try_parse_from(["onepipeline", "start", "p.json", "--attach"]).expect("attach parses");
Cli::try_parse_from(["onepipeline", "start", "p.json", "--attach", "--detach"])
.expect_err("`--attach|--detach` are alternatives, not a pair");
}
#[test]
fn every_command_the_contract_names_parses() {
let invocations: &[(&str, &[&str])] = &[
("start", &["start", "plans:demo"]),
("adopt", &["adopt", "run-1"]),
("next", &["next", "run-1"]),
("reply", &["reply", "run-1"]),
("reply FILE", &["reply", "run-1", "edits.json"]),
(
"surface",
&[
"surface",
"run-1",
"--kind",
"check-in",
"--message",
"all clear",
],
),
("attest", &["attest", "run-1", "approve"]),
("stop", &["stop", "run-1"]),
("stop --force", &["stop", "run-1", "--force"]),
("shutdown RUN", &["shutdown", "run-1"]),
("shutdown --mine", &["shutdown", "--mine"]),
("shutdown --host", &["shutdown", "--host"]),
(
"shutdown --host --grace",
&["shutdown", "--host", "--grace", "60"],
),
(
"shutdown --mine --force",
&["shutdown", "--mine", "--force"],
),
("runs", &["runs"]),
("runs --mine", &["runs", "--mine"]),
("status", &["status"]),
("host", &["host"]),
("monitor", &["monitor", "run-1"]),
("results", &["results", "run-1"]),
("goals", &["goals"]),
("transcript", &["transcript", "run-1"]),
("transcript NODE", &["transcript", "run-1", "build"]),
("telemetry", &["telemetry"]),
("telemetry --breakdown", &["telemetry", "--breakdown"]),
];
for (name, args) in invocations {
let argv: Vec<&str> = std::iter::once("onepipeline")
.chain(args.iter().copied())
.collect();
Cli::try_parse_from(&argv).unwrap_or_else(|e| panic!("`{name}` does not parse: {e}"));
}
}
#[test]
fn the_contract_names_every_command_and_view_this_crate_offers() {
assert_contract_names(
"channel command",
&[
"`onepipeline next RUN [--filter NAME|SPEC] [--all]`",
"reply RUN [FILE]",
"surface RUN --kind KIND --message TEXT",
"attest RUN REF",
"stop RUN",
],
);
assert_contract_names("driver verb", &["onepipeline adopt RUN"]);
let tokens = backticked();
for view in ["runs", "status", "host", "results", "goals"] {
assert!(
tokens.contains(view),
"the contract no longer lists the `{view}` view"
);
}
assert!(tokens.contains("monitor RUN [--filter NAME|SPEC] [--all]"));
assert!(tokens.contains("telemetry [--breakdown]"));
assert!(tokens.contains("transcript RUN [NODE]"));
assert!(tokens.contains("runs --mine"));
}
#[test]
fn the_contract_names_every_bucket_and_every_usage_party_the_document_writes() {
let source = std::fs::read_to_string(repo_root().join("src/telemetry.rs"))
.expect("the telemetry view ships");
let tokens = backticked();
for (what, list) in [
("bucket", "pub const ALL: [Self; 8]"),
("party", "pub const ALL: [Self; 4]"),
] {
let declared: Vec<String> = source
.split_once(list)
.unwrap_or_else(|| panic!("telemetry declares its {what} list"))
.1
.split_once("];")
.expect("the list is closed")
.0
.split(',')
.filter_map(|entry| entry.trim().strip_prefix("Self::"))
.map(wire_word)
.collect();
assert!(!declared.is_empty(), "the {what} list is empty");
for name in declared {
assert!(
tokens.contains(&name),
"the contract does not name the `{name}` {what}"
);
}
}
for field in ["input", "output", "cache_read", "cache_write", "cost_usd"] {
assert!(
tokens.contains(field),
"the contract does not name the `{field}` usage field"
);
}
}
fn wire_word(variant: &str) -> String {
let mut out = String::new();
for (at, letter) in variant.char_indices() {
if letter.is_uppercase() && at > 0 {
out.push('_');
}
out.extend(letter.to_lowercase());
}
out
}
#[test]
fn a_command_outside_the_surface_is_refused() {
Cli::try_parse_from(["onepipeline", "publish", "run-1"])
.expect_err("the surface is exactly what the contract names");
}
#[test]
fn the_dag_scope_graph_is_a_monitor_plus_a_resettable_check_in() {
assert!(CONTRACT.contains(
"the shipped example, `graphs/dag-scope.yaml`, is an observer member beside a \
resettable-cron `check-in` member; a host copies it or brings its own, and the \
engine names no member of it"
));
let text = std::fs::read_to_string(repo_root().join("graphs/dag-scope.yaml"))
.expect("the dag-scope graph ships");
let graph: GraphConfig = serde_norway::from_str(&text).expect("it is a valid graph config");
assert_eq!(graph.name, "dag-scope");
let monitor = graph.members.get("monitor").expect("a monitor member");
let Member::Onejudge(monitor) = monitor else {
panic!("the monitor is a two-party member");
};
match &monitor.judge[..] {
[JudgeSide::Command(judge)] => assert_eq!(
judge.command,
[
"onemessagebus",
"serve",
"--codec",
"onejudge",
"--transport-dir",
"${ONEPIPELINE_RUNS_DIR}/${ONEPIPELINE_RUN_ID}/channel",
"surfaces",
],
"the monitor's judge side is exactly the adopted bus server command"
),
other => panic!("the contract makes the judge side one command provider, not {other:?}"),
}
let check_in = graph.members.get("check-in").expect("a check-in member");
let Member::Oneharness(check_in) = check_in else {
panic!("the pacemaker is a single-sided member");
};
let schedule = check_in.schedule.expect("it is a cron member");
assert!(
schedule.resettable,
"the contract makes the check-in resettable"
);
assert_eq!(
schedule.every, DEFAULT_HEARTBEAT_INTERVAL_SECONDS,
"its period is the driver's default heartbeat interval"
);
}
#[test]
fn no_member_word_names_the_observer_graph_in_the_engine_or_its_docs() {
const VERB: &str = "monitor";
const NAMED_THINGS: [&str; 7] = [
"member", "author", "persona", "profile", "graph", "op", "role",
];
fn walk(dir: &Path, into: &mut Vec<PathBuf>) {
for entry in std::fs::read_dir(dir).expect("a directory to walk") {
let path = entry.expect("an entry").path();
if path.is_dir() {
walk(&path, into);
} else if path
.extension()
.is_some_and(|ext| ext == "rs" || ext == "md")
{
into.push(path);
}
}
}
let is_word = |c: char| c.is_alphanumeric() || c == '_';
let names_the_verb = |line: &str, lower: &str, at: usize| -> bool {
let before = &line[..at];
let after = &line[at + VERB.len()..];
let spelled = &line[at..at + VERB.len()];
if before.ends_with("onepipeline ") {
return true;
}
if after.starts_with('(') && (spelled == "monitor" || spelled == "Monitor") {
return true;
}
if spelled != VERB {
return false;
}
if before.ends_with('`') && after.starts_with('`') {
let rest = after[1..].trim_start_matches(|c: char| !c.is_alphanumeric());
let next_word: String = rest.chars().take_while(|c| c.is_alphanumeric()).collect();
return !NAMED_THINGS.contains(&next_word.as_str());
}
if before.ends_with('`')
&& (after.starts_with(" RUN")
|| after.starts_with(" <RUN>")
|| after.starts_with(" --"))
{
return true;
}
if before.ends_with('"') && after.starts_with('"') {
return lower.contains("onepipeline monitor")
|| line.contains("get_name()")
|| line.contains("find_subcommand(");
}
false
};
let mut files = Vec::new();
walk(&repo_root().join("src"), &mut files);
walk(&repo_root().join("docs"), &mut files);
files.sort();
let mut offences = Vec::new();
for path in files {
if path.ends_with("docs/contract-divergences.md") {
continue;
}
let text = std::fs::read_to_string(&path).expect("a source or document reads");
for (number, line) in text.lines().enumerate() {
let lower = line.to_lowercase();
for word in [VERB, "pacemaker"] {
let mut from = 0;
while let Some(found) = lower[from..].find(word) {
let at = from + found;
from = at + word.len();
let whole = !line[..at].chars().next_back().is_some_and(is_word)
&& !line[at + word.len()..].chars().next().is_some_and(is_word);
if !whole || (word == VERB && names_the_verb(line, &lower, at)) {
continue;
}
offences.push(format!(
"{}:{}: `{}` names a member of one host's observer graph: {}",
path.strip_prefix(repo_root()).unwrap_or(&path).display(),
number + 1,
&line[at..at + word.len()],
line.trim()
));
}
}
}
}
assert!(
offences.is_empty(),
"the engine names a member of the observer graph; the only allowance is the \
`onepipeline monitor` view verb:\n{}",
offences.join("\n")
);
}
#[test]
fn the_default_node_scope_graph_is_a_worker_and_a_judge() {
assert!(CONTRACT.contains("a default node-scope config (worker+judge)"));
let text = std::fs::read_to_string(repo_root().join("graphs/node-scope.yaml"))
.expect("the node-scope graph ships");
let graph: GraphConfig = serde_norway::from_str(&text).expect("it is a valid graph config");
assert_eq!(graph.name, "node-scope");
let worker = graph.members.get("worker").expect("a worker member");
let Member::Onejudge(worker) = worker else {
panic!("worker+judge is a two-party member");
};
assert!(
matches!(worker.judge[..], [JudgeSide::Harness(_)]),
"the node-scope judge is one harness-backed side, not a panel: {:?}",
worker.judge
);
assert_eq!(
graph.members.len(),
1,
"worker+judge is one onejudge member"
);
}
const SHIPPED_PERSONAS: [(&str, &str); 3] = [
("orchestrator", "monitor"),
("check-in", "check-in"),
("pr-author", "pr-author"),
];
#[test]
fn every_persona_the_contract_ships_is_present_and_has_both_sides() {
assert!(CONTRACT.contains(
"example personas — an observer (at `personas/orchestrator.yaml`, the shipped file \
the orchestrator persona was rewritten into), `check-in`, `pr-author`"
));
assert!(
CONTRACT
.contains("The files under `graphs/` and `personas/` are **examples a host may copy**"),
"the contract no longer says the shipped graph and personas are examples"
);
for (file, role) in SHIPPED_PERSONAS {
let path = repo_root().join("personas").join(format!("{file}.yaml"));
let text =
std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("{file} persona ships: {e}"));
let persona = Persona::parse(&text, &format!("personas/{file}.yaml"))
.unwrap_or_else(|e| panic!("{file} is not a persona oneagentgraph loads: {e}"));
assert_eq!(
persona.label(),
Some(role),
"personas/{file}.yaml carries the {role} role"
);
let effective = merge("{}\n", "an empty base config", &persona)
.unwrap_or_else(|e| panic!("{file} does not layer onto a base config: {e}"));
assert!(
effective.pointer("/system_prompt").is_some(),
"{file} states the agent's role"
);
assert!(
effective.pointer("/user/persona").is_some(),
"{file} states the supervisor's review bar"
);
}
}
#[test]
fn the_pr_author_never_blocks_publication() {
assert!(
CONTRACT.contains("Drafting is never on the publication path."),
"the contract no longer keeps the drafting dispatch off the publication path"
);
assert!(
CONTRACT.contains(
"the change request opens with no body and the node settles on its \
publication as before"
),
"the contract no longer says what a drafting dispatch that ended badly costs"
);
let text = std::fs::read_to_string(repo_root().join("personas/pr-author.yaml"))
.expect("the pr-author persona ships");
let flattened = text.split_whitespace().collect::<Vec<_>>().join(" ");
assert!(
flattened.contains("not on the publication path"),
"the persona itself says the dispatch is not on the publication path"
);
}
const RULINGS: &[(&str, &str)] = &[
("1.", "ConfigRef"),
("2.", "SessionRequest"),
("3.", "DispatchOutcome"),
("4.", "node_label"),
("5.", "min_free_mem"),
("6.", "PipelineKind"),
("7.", "completed_steps"),
("8.", "cross-dag-satisfied"),
("9.", "publication_wait"),
("23.", "drive GRAPH"),
("24.", "NodeControls"),
("25.", "drive-run RUN"),
("26.", "nothing else able to move"),
("27.", "ending that parked driver politely"),
("28.", "`attempt`, `attempts`"),
("29.", "inherits both"),
("30.", "--launch-config FILE"),
("31.", "shaped event view beside the surface"),
("32.", "any run of characters including none"),
("34.", "body-not-drafted"),
("44.", "the minimum this build requires"),
("63.", "--correlation C"),
("74.", "holds any node that is not `done`"),
(
"75.",
"`onemessagebus`'s own `docs/contract.md` is the one source of their shape",
),
("77.", "The planner channel runs on `onemessagebus`"),
("78.", "Surface kinds are an open vocabulary"),
("79.", "edit-applied"),
("81.", "the CLI is argument parsing over them"),
("82.", "held under `workspace`"),
("83.", "pool-maintenance"),
];
#[test]
fn every_recorded_divergence_is_ruled_on_or_states_the_proposal_it_waits_on() {
let divergences = std::fs::read_to_string(repo_root().join("docs/contract-divergences.md"))
.expect("the divergence record ships");
let sections: Vec<&str> = divergences.split("\n## ").skip(1).collect();
assert!(sections.len() >= RULINGS.len(), "{sections:?}");
let section_of = |number: &str| {
sections
.iter()
.find(|section| section.starts_with(number))
.unwrap_or_else(|| panic!("the record has no divergence {number}"))
};
for section in §ions {
let heading = section.lines().next().expect("a heading");
if RULINGS
.iter()
.any(|(number, _)| heading.starts_with(number))
{
continue;
}
if let Some((_, superseder)) = heading.split_once("— SUPERSEDED BY ") {
let superseder = format!("{}.", superseder.trim());
let later = sections
.iter()
.find(|section| section.starts_with(&superseder))
.unwrap_or_else(|| {
panic!("`{heading}` names entry {superseder}, which the record does not have")
});
assert!(
later.lines().next().expect("a heading").ends_with("— OPEN"),
"`{heading}` is superseded by an entry that is not itself open"
);
assert!(
section.contains("Superseded by entry"),
"divergence `{heading}` is marked superseded and its prose does not say so"
);
continue;
}
assert!(
heading.ends_with("— OPEN"),
"an unruled divergence is not marked open: {heading}"
);
assert!(
section.contains("**Proposal"),
"divergence `{heading}` is open and states no proposal"
);
}
for (number, named) in RULINGS {
let section = section_of(number);
let heading = section.lines().next().expect("a heading");
assert!(
heading.ends_with("— RESOLVED"),
"divergence {number} is not marked resolved: {heading}"
);
assert!(
section.contains("**Ruling:"),
"divergence {number} is marked resolved but records no ruling"
);
assert!(
CONTRACT.contains(named),
"the contract does not name `{named}`, which divergence {number} was ruled onto it"
);
}
assert!(CONTRACT.contains("executor_has_capacity"));
}
#[test]
fn the_draft_closeout_is_what_the_divergence_record_names() {
let block = divergence_block("69.");
let fields: Vec<String> =
serde_json::from_value(block["node_fields"].clone()).expect("entry 69 names its fields");
assert_eq!(fields, vec!["draft".to_string()]);
for field in &fields {
assert!(
CONTRACT.contains(&format!("`{field}`")),
"the contract's reserved-key list does not name `{field}`"
);
}
let written = serde_json::to_value(Node {
id: "held".into(),
repo: Some("github.com/owner/name".into()),
title: Some("feat: hold it".into()),
draft: true,
..Node::default()
})
.expect("a node serialises");
assert_eq!(written["draft"], json!(true));
let read: Node = serde_json::from_value(written).expect("it re-reads");
assert!(read.draft);
let omitted = serde_json::to_value(Node::default()).expect("a node serialises");
assert!(
omitted.get("draft").is_none(),
"`draft` is written when false, so a plan no longer round-trips as the file wrote it"
);
let environment: Vec<String> =
serde_json::from_value(block["environment"].clone()).expect("entry 69 names the names");
assert_eq!(
environment,
vec![
"ONEVCS_SESSION".to_string(),
"ONEPIPELINE_RUNS_DIR".to_string()
]
);
let readme = std::fs::read_to_string(repo_root().join("README.md")).expect("the README ships");
for name in &environment {
assert!(
readme.contains(name),
"the README does not document `{name}`, which entry 69 says every dispatch carries"
);
}
assert_eq!(
block["drafting_task"]["opening"].as_str(),
Some(
"Read this branch's diff and write the change request's body, following the \
repository's own template. The task this branch delivered:"
)
);
}
#[test]
fn the_consumes_divergence_quotes_a_sentence_the_contract_still_carries() {
let record = std::fs::read_to_string(repo_root().join("docs/contract-divergences.md"))
.expect("the divergence record ships");
let entry = record
.split("\n## ")
.find(|entry| entry.starts_with("54."))
.expect("the divergence record carries entry 54");
let quoted = entry
.lines()
.skip_while(|line| !line.starts_with("> "))
.take_while(|line| line.starts_with("> "))
.map(|line| line.trim_start_matches("> "))
.collect::<Vec<_>>()
.join(" ");
assert!(
!quoted.is_empty(),
"entry 54 quotes no sentence of the contract"
);
let contract = CONTRACT.split_whitespace().collect::<Vec<_>>().join(" ");
assert!(
contract.contains("ed),
"entry 54 names a sentence the contract no longer carries: {quoted}"
);
assert!(
!contract.contains("consumes` with it"),
"the contract now states what an edit does to `consumes`; entry 54 has been ruled on"
);
}
#[test]
fn the_templated_adoption_instruction_is_what_the_divergence_record_names() {
let block = divergence_block("53.");
assert_eq!(
block["default_instruction"].as_str(),
Some(DEFAULT_ADOPTION_INSTRUCTION),
"entry 53 names a different default instruction than this crate publishes"
);
assert_eq!(
block["observed_state"].as_str(),
Some(OBSERVED_STATE),
"entry 53 names a different observed-state frame than this crate publishes"
);
assert_eq!(
block["heading"].as_str(),
Some(CROSS_REPO_REFERENCES_HEADING),
);
let variables: Vec<String> =
serde_json::from_value(block["variables"].clone()).expect("entry 53 names its variables");
assert_eq!(
variables, ADOPTION_INSTRUCTION_VARIABLES,
"entry 53 names a different variable set than this crate publishes"
);
let row = &block["row"];
let field = |key: &str| {
row[key]
.as_str()
.unwrap_or_else(|| panic!("entry 53's row states `{key}`"))
.to_owned()
};
let reference = CrossRepoReference {
dependency: field("dependency"),
repository: field("repository"),
branch: field("branch"),
commit: field("commit"),
release_target: field("release_target"),
version: field("version"),
adoption_instructions: Some(
block["adoption_instructions"]
.as_str()
.expect("entry 53 states the template")
.parse()
.expect("the template entry 53 states is one `onevcs` accepts"),
),
};
let rendered = block["rendered"]
.as_str()
.expect("entry 53 states what its template renders to");
assert_eq!(
reference.instruction(),
rendered,
"the template entry 53 states does not render what it says it does"
);
let node = Node {
id: "consumer".into(),
persona: Some("engineer".into()),
task: Some("## What\nbuild against the released engine".into()),
..Node::default()
};
let references = [reference];
let calls: Vec<String> =
serde_json::from_value(block["api"]["calls"].clone()).expect("entry 53 names its calls");
assert_eq!(calls, ["adoption_instructions", "arrival_note"]);
assert_eq!(block["api"]["module"].as_str(), Some("onepipeline::plan"));
for (site, text) in [
("the reference block", node.rendered_task_with(&references)),
("the arrival note", arrival_note(&references)),
] {
assert!(
text.contains(rendered),
"{site} does not carry the producer's own instruction:\n{text}"
);
let opened = text
.find(OBSERVED_STATE)
.unwrap_or_else(|| panic!("{site} states no observed-state frame:\n{text}"));
assert!(
opened < text.find(rendered).expect("the instruction is there"),
"{site} renders the instruction ahead of the frame that holds it:\n{text}"
);
}
assert!(adoption_instructions(&references).contains(rendered));
assert!(adoption_instructions(&[]).is_empty());
let undeclared = CrossRepoReference {
adoption_instructions: None,
..references[0].clone()
};
assert!(adoption_instructions(&[undeclared]).contains(DEFAULT_ADOPTION_INSTRUCTION));
}
#[test]
fn the_adoption_flags_are_exactly_the_open_divergence_the_record_names() {
let divergences = std::fs::read_to_string(repo_root().join("docs/contract-divergences.md"))
.expect("the divergence record ships");
let entry = divergences
.split("\n## ")
.find(|section| section.starts_with("42."))
.expect("the divergence record carries entry 42");
assert!(entry
.lines()
.next()
.is_some_and(|line| line.ends_with("— OPEN")));
assert!(entry.contains("`onepipeline adopt RUN [--attach|--detach]`"));
assert!(CONTRACT.contains("`onepipeline adopt RUN` attaches"));
assert!(!CONTRACT.contains("adopt RUN [--attach|--detach]"));
let readme = std::fs::read_to_string(repo_root().join("README.md")).expect("the README ships");
assert!(readme.contains("the same `--attach`/`--detach` pair `start` does"));
Cli::try_parse_from(["onepipeline", "adopt", "run-1", "--attach"])
.expect("the proposed attached form parses");
Cli::try_parse_from(["onepipeline", "adopt", "run-1", "--detach"])
.expect("the proposed detached form parses");
Cli::try_parse_from(["onepipeline", "adopt", "run-1", "--attach", "--detach"])
.expect_err("the proposed alternatives refuse each other");
}
#[test]
fn the_plan_check_verb_is_the_one_the_contract_spells() {
let contract = CONTRACT.split_whitespace().collect::<Vec<_>>().join(" ");
assert!(
contract.contains("`onepipeline plan check <SOURCE:PROJECT> [--check <PATH>]... [--json]`"),
"the contract no longer states the `plan check` command line"
);
for claim in [
"first the engine's own plan loader",
"`ONEPIPELINE_PLAN_CHECK_SCHEMA=1` in its environment",
"the registered checks do **not** run",
"carry `\"source\": \"engine\"`",
] {
assert!(
contract.contains(claim),
"the contract no longer states '{claim}'"
);
}
let plan = Cli::command()
.get_subcommands()
.find(|sub| sub.get_name() == "plan")
.expect("the binary offers `plan`")
.clone();
let check = plan
.get_subcommands()
.find(|sub| sub.get_name() == "check")
.expect("`plan` offers `check`")
.clone();
let flags: BTreeSet<String> = check
.get_arguments()
.filter_map(|arg| arg.get_long().map(str::to_string))
.collect();
assert!(
flags.contains("check") && flags.contains("json"),
"{flags:?}"
);
let parsed = Cli::parse_from([
"onepipeline",
"plan",
"check",
"otg:plan-store",
"--check",
"./first",
"--check",
"./second",
"--json",
]);
let Command::Plan(onepipeline::cli::PlanCommand::Check(args)) = parsed.command else {
panic!("`plan check` did not parse as itself");
};
assert_eq!(args.project, "otg:plan-store");
assert!(args.json);
assert_eq!(
args.checks,
vec![PathBuf::from("./first"), PathBuf::from("./second")]
);
}
#[test]
fn the_readmes_plan_check_passage_is_a_gated_copy_of_the_contract() {
let raw = std::fs::read_to_string(repo_root().join("README.md")).expect("the README ships");
let readme = raw.split_whitespace().collect::<Vec<_>>().join(" ");
let contract = CONTRACT
.lines()
.find(|line| line.contains("**A plan is checkable without launching it"))
.expect("the contract has a plan-check paragraph")
.split_whitespace()
.collect::<Vec<_>>()
.join(" ");
let passage = readme
.split_once("A plan is checkable before it is launched")
.expect("the README has a plan-check passage")
.1
.split_once("The run's own record does not move")
.expect("that passage ends where the README says it does")
.0
.to_string();
let (before, rest) = passage
.split_once("```bash ")
.expect("the passage shows an example invocation");
let (example, after) = rest
.split_once(" ```")
.expect("that example's fence closes");
let parsed = Cli::try_parse_from(example.split_whitespace()).unwrap_or_else(|error| {
panic!("the README shows `{example}`, which does not parse: {error}")
});
assert!(
matches!(
parsed.command,
Command::Plan(onepipeline::cli::PlanCommand::Check(_))
),
"the README's example is not a `plan check`: {example}"
);
let prose = format!("{before}{after}");
for token in backticked_runs(&prose) {
for part in token
.split("...")
.map(str::trim)
.filter(|part| !part.is_empty())
{
assert!(
contract.contains(part),
"the README's plan-check passage writes `{token}`, and the contract's \
plan-check paragraph does not state '{part}'"
);
}
}
for (stated, licensed) in [
(
"every refusal `start` makes before it dispatches anything, and no other rule",
"every refusal `onepipeline start` would make before dispatching anything, and no other rule",
),
(
"Each repeatable `--check <PATH>` names an executable, resolved against the directory the verb ran in",
"a repeatable `--check <PATH>` flag naming an executable, resolved against the working directory `plan check` was run from",
),
(
"handed the **loaded** plan as one JSON document on its stdin",
"spawned with the loaded plan as a single JSON document on its **stdin**",
),
("every default resolved", "with every default already resolved"),
(
"each node carrying its task's own metadata map verbatim",
"the store's own metadata map for that task, verbatim",
),
(
"`ONEPIPELINE_PLAN_CHECK_SCHEMA=1` in its environment",
"`ONEPIPELINE_PLAN_CHECK_SCHEMA=1` in its environment",
),
(
"answers on stdout with `{\"refusals\": [...]}`",
"On **stdout** a check answers with one JSON object, `{\"refusals\":",
),
("and exit 0", "A check that ran answers with exit status **0**"),
(
"`node` and `field` present on each and null where it is about neither",
"`node` and `field` are always present and may be null",
),
(
"Engine refusals come first and carry `\"source\": \"engine\"`",
"Engine refusals come first and carry `\"source\": \"engine\"`",
),
(
"each check's follow in the order its flags were given, under the path as it was given",
"each check's refusals follow in flag order and carry `\"source\": \"<the path as given>\"`",
),
(
"`--json` prints them as one object carrying `project`, `accepted`, `refusals` and `unrunnable`, always all four",
"`{\"project\": <string>, \"accepted\": <bool>, \"refusals\": [{\"source\",\"node\",\"field\",\"reason\"}, ...], \"unrunnable\":",
),
(
"reported separately from a refusal",
"which is reported separately from a refusal",
),
("never read as an accept", "is never read as an accept"),
(
"A loader refusal short-circuits: there is no loaded plan to hand a check, so each is reported as not run",
"there is no loaded plan to hand it: the registered checks do **not** run, and each is reported as not run",
),
] {
assert!(
prose.contains(stated),
"the README's plan-check passage no longer states '{stated}'"
);
assert!(
contract.contains(licensed),
"the README states '{stated}', and the contract's plan-check paragraph \
no longer states '{licensed}'"
);
}
for (code, meaning, stated) in [
(
EXIT_SUCCESS,
"the loader and every check accepting",
"**0** — the loader and every check accepted",
),
(
EXIT_QUEUED,
"at least one refusal from either source",
"**1** — at least one refusal, from either source",
),
(
EXIT_REFUSED,
"a project that could not be read",
"**2** — the project could not be read at all, or a registered check could not be run",
),
] {
assert!(
prose.contains(&format!("`{code}` is {meaning}")),
"the README's plan-check passage no longer maps exit {code} to {meaning}"
);
assert!(
contract.contains(stated),
"the contract's plan-check paragraph no longer states '{stated}'"
);
}
let check = Cli::command()
.get_subcommands()
.find(|sub| sub.get_name() == "plan")
.expect("the binary offers `plan`")
.clone()
.get_subcommands()
.find(|sub| sub.get_name() == "check")
.expect("`plan` offers `check`")
.clone();
for flag in check
.get_arguments()
.filter_map(|arg| arg.get_long().map(str::to_string))
{
assert!(
prose.contains(&format!("`--{flag}`")) || prose.contains(&format!("`--{flag} ")),
"the README's plan-check passage does not name `--{flag}`, which the verb takes"
);
}
}
fn backticked_runs(prose: &str) -> Vec<String> {
let mut runs = Vec::new();
let mut rest = prose;
while let Some((_, after)) = rest.split_once('`') {
let Some((run, tail)) = after.split_once('`') else {
break;
};
if !run.trim().is_empty() {
runs.push(run.to_string());
}
rest = tail;
}
runs
}
#[test]
fn the_smoke_scripts_command_list_is_the_binarys_whole_surface() {
let script = std::fs::read_to_string(repo_root().join("scripts/smoke-published.sh"))
.expect("the smoke script ships");
let listed = script
.lines()
.find_map(|line| {
line.trim()
.strip_prefix("for command in ")?
.strip_suffix("; do")
})
.expect("the smoke script iterates a `for command in ...; do` list")
.split_whitespace()
.map(str::to_string)
.collect::<BTreeSet<String>>();
let (documented, hidden): (BTreeSet<String>, BTreeSet<String>) = Cli::command()
.get_subcommands()
.map(|sub| (sub.get_name().to_string(), sub.is_hide_set()))
.fold(
Default::default(),
|(mut shown, mut hidden), (name, hide)| {
if hide {
hidden.insert(name);
} else {
shown.insert(name);
}
(shown, hidden)
},
);
assert_eq!(
listed, documented,
"scripts/smoke-published.sh checks a different command set than the CLI offers"
);
for command in &hidden {
assert!(
script.contains(&format!("onepipeline {command} ")),
"scripts/smoke-published.sh never runs the hidden `{command}` command, which \
`--help` does not list for it to check"
);
}
}
#[test]
fn the_readmes_interface_claims_match_the_code_they_describe() {
let raw = std::fs::read_to_string(repo_root().join("README.md")).expect("the README ships");
let readme = raw.split_whitespace().collect::<Vec<_>>().join(" ");
assert!(
readme.contains(&format!(
"exit `{EXIT_NOTHING_DRIVING}` means nothing is driving"
)),
"the README states a different code for an undriven run than the crate uses"
);
assert!(
readme.contains(&format!(
"exits `{EXIT_SUCCESS}` when the reconciler applied it, `{EXIT_SUCCESS}` when it is \
accepted and still queued"
)) && readme.contains(&format!("and `{EXIT_REFUSED}` when it was refused")),
"the README's reply exit-code mapping no longer matches the crate's constants"
);
assert!(
!readme.contains(&format!("`{EXIT_QUEUED}` when it is queued")),
"the README still maps a queued reply to a non-zero status"
);
let surface = Cli::command()
.get_subcommands()
.map(|sub| sub.get_name().to_string())
.collect::<BTreeSet<String>>();
let views = readme
.split_once("Read-only views")
.expect("the README has a read-only views paragraph")
.1
.split_once("without touching a run")
.expect("that paragraph ends where the README says it does")
.0
.to_string();
for view in [
"runs",
"status",
"host",
"monitor",
"results",
"goals",
"transcript",
"agents",
"telemetry",
] {
assert!(
views.contains(&format!("`{view}`")),
"the README's view list omits `{view}`"
);
assert!(
surface.contains(view),
"`{view}` is not a command the binary offers"
);
}
{
use onepipeline::agents;
let passage = readme
.split_once("**Every agent a run launches is visible, automatically")
.expect("the README documents the run's agent visibility")
.1
.split_once("**A listing groups its runs by project.**")
.expect("that passage ends where the README's next one begins")
.0
.to_string();
assert!(
passage.contains(&format!("`<run root>/{}`", agents::SESSIONS_FILE)),
"the README's pointer file is not the one the run writes"
);
assert!(
passage.contains(&format!("never sets `{}`", agents::HISTORY_DIR_ENV)),
"the README does not name the store variable the engine leaves alone"
);
assert!(
passage.contains(&format!("under the `{}` prefix", agents::LABEL_PREFIX)),
"the README's label prefix is not the engine's"
);
let scopes = agents::Scope::ALL
.iter()
.map(|scope| format!("`{}`", scope.as_str()))
.collect::<Vec<_>>();
assert!(
passage.contains(&format!("({}, {} or {})", scopes[0], scopes[1], scopes[2])),
"the README's scope words are not the crate's"
);
let block: Value = serde_json::from_str(&fenced_block_naming("json", "oneharness_history"))
.expect("the run-history block is JSON");
let opt_out = block["oneharness_history"]["opt_out"]
.as_str()
.expect("the contract spells the opt-out");
assert!(
passage.contains(&format!("with `{opt_out}` writes no line")),
"the README's opt-out is not the contract's"
);
for usage in [
"`onepipeline agents RUN [NODE]`",
"`onepipeline agents --project PROJECT`",
] {
assert!(
passage.contains(usage),
"the README's run-history passage does not show {usage}"
);
}
let agents_verb = Cli::command()
.get_subcommands()
.find(|sub| sub.get_name() == "agents")
.expect("the binary offers `agents`")
.clone();
assert!(
agents_verb
.get_arguments()
.any(|arg| arg.get_long() == Some("project")),
"`agents` takes no `--project`, which the README shows"
);
}
assert!(
surface.contains("watch"),
"`watch` is not a command the binary offers"
);
let passage = readme
.split_once("`onepipeline watch RUN` is the bounded wait")
.expect("the README documents the watch verb")
.1
.split_once("## Where a dispatch runs")
.expect("that passage ends where the README's next heading begins")
.0
.to_string();
let watch = Cli::command()
.get_subcommands()
.find(|sub| sub.get_name() == "watch")
.expect("the binary offers `watch`")
.clone();
for flag in watch
.get_arguments()
.filter_map(|arg| arg.get_long().map(str::to_string))
{
assert!(
passage.contains(&format!("`--{flag}`")) || passage.contains(&format!("`--{flag} ")),
"the README's watch passage does not name `--{flag}`, which the verb takes"
);
}
for condition in onepipeline::cli::watch_conditions() {
assert!(
passage.contains(&format!("`--until {condition}`")),
"the README's watch passage does not name `--until {condition}`, which the verb \
accepts"
);
}
for named in passage
.split('`')
.skip(1)
.step_by(2)
.filter_map(|span| span.strip_prefix("--until "))
{
assert!(
onepipeline::cli::watch_conditions().contains(&named),
"the README's watch passage names `--until {named}`, which the verb does not accept"
);
}
for (what, stated) in [
(
"the run settling",
format!("exit `{EXIT_SUCCESS}` when the run settled complete"),
),
(
"nothing driving the run",
format!("`{EXIT_NOTHING_DRIVING}` when nothing is driving it"),
),
(
"a blocking surface waiting",
format!("`{EXIT_SURFACE_WAITING}` when a blocking surface is waiting"),
),
(
"the wait elapsing",
format!("`{EXIT_WATCH_ELAPSED}` when the"),
),
(
"a node the wait named settling",
format!("`{EXIT_NODE_SETTLED}` when a node the wait was told to return on settled"),
),
] {
assert!(
passage.contains(&stated),
"the README's watch passage states a different status than the crate does for \
{what}: it should say '{stated}'"
);
}
let offered: BTreeSet<String> = watch
.get_arguments()
.filter_map(|arg| arg.get_long().map(str::to_string))
.collect();
for mentioned in passage
.split('`')
.skip(1)
.step_by(2)
.filter_map(|span| span.split_whitespace().next())
.filter_map(|word| word.strip_prefix("--"))
{
if mentioned == "heartbeat-interval" {
assert!(
!offered.contains(mentioned),
"`watch` took `start`'s pacemaker flag, which the README says it refuses"
);
continue;
}
assert!(
offered.contains(mentioned),
"the README's watch passage names `--{mentioned}`, which the verb does not take"
);
}
let returned: BTreeSet<String> = [
EXIT_SUCCESS,
EXIT_NOTHING_DRIVING,
EXIT_SURFACE_WAITING,
EXIT_WATCH_ELAPSED,
EXIT_NODE_SETTLED,
]
.iter()
.map(i32::to_string)
.collect();
for mentioned in passage
.split('`')
.skip(1)
.step_by(2)
.filter(|span| span.parse::<i32>().is_ok())
{
assert!(
returned.contains(mentioned),
"the README's watch passage states exit status `{mentioned}`, which this verb \
never returns"
);
}
}
#[test]
fn the_note_delivery_surface_is_what_the_divergence_record_names() {
let block = divergence_block("60.");
let version = block["envelope_version"]
.as_u64()
.expect("entry 60 names the envelope version") as u32;
assert!(
onepipeline::channel::REPLY_ENVELOPE_VERSIONS_READ.contains(&version),
"the build no longer reads the envelope version entry 60 declares"
);
assert!(
onepipeline::channel::REPLY_ENVELOPE_VERSION >= version,
"the build writes an envelope version older than the one entry 60 moved it to"
);
assert!(
CONTRACT.contains(r#"{"version": 1, "commands": [...]}"#),
"the contract's envelope sentence moved; entry 60 names the version it replaces"
);
let fixtures: Vec<Value> =
serde_json::from_value(block["ops"].clone()).expect("entry 60 names the op it adds");
let monitor_may: BTreeSet<String> = serde_json::from_value(block["monitor_may_issue"].clone())
.expect("entry 60 says which of them the monitor may issue");
assert!(!fixtures.is_empty(), "{block}");
for fixture in &fixtures {
let op = fixture["op"].as_str().expect("the fixture names its op");
assert!(
!OPS.contains(&op),
"`{op}` is on the contract's own list, so it is no divergence"
);
let edit: Edit = serde_json::from_value(fixture.clone())
.unwrap_or_else(|e| panic!("`{op}` deserializes: {e}"));
assert_eq!(op_of(&edit), op, "`{op}` deserialized into another variant");
assert_eq!(
&serde_json::to_value(&edit).expect("serializes"),
fixture,
"`{op}` round-trips unchanged"
);
allows(Author::planner(), &edit)
.unwrap_or_else(|e| panic!("the planner was refused `{op}`: {e}"));
let verdict = allows(Author::from("monitor"), &edit);
if monitor_may.contains(op) {
verdict.unwrap_or_else(|e| panic!("the monitor was refused `{op}`: {e}"));
continue;
}
let refusal = verdict
.expect_err(&format!("the monitor was allowed `{op}`"))
.to_string();
assert!(
refusal.contains(op) && refusal.contains("Surface it to the planner"),
"the refusal does not name `{op}` and what to do instead: {refusal}"
);
}
let envelope: Reply =
serde_json::from_value(json!({"version": version, "commands": block["ops"].clone()}))
.expect("entry 60's ops travel in a reply envelope");
assert_eq!(envelope.commands.len(), fixtures.len());
let fields: BTreeSet<String> =
serde_json::from_value(block["fields"].clone()).expect("entry 60 names the field set");
let carried_keys: BTreeSet<String> = fixtures
.iter()
.flat_map(|fixture| fixture.as_object().expect("an object").keys().cloned())
.filter(|key| key != "op")
.collect();
assert_eq!(
carried_keys, fields,
"entry 60's fixtures and its own field set disagree about what a note carries"
);
let required: Vec<String> =
serde_json::from_value(block["required"].clone()).expect("entry 60 names them");
for field in &required {
for fixture in &fixtures {
let mut without = fixture.clone();
without
.as_object_mut()
.expect("an object")
.remove(field.as_str());
let err = serde_json::from_value::<Edit>(without)
.expect_err(&format!("a note without `{field}` is refused"));
assert!(
err.to_string().contains(field),
"the refusal does not name `{field}`: {err}"
);
}
}
let addressees: Vec<String> =
serde_json::from_value(block["addressees"].clone()).expect("entry 60 names the addressees");
for named in &addressees {
let parsed: Addressee = serde_json::from_value(json!(named))
.unwrap_or_else(|e| panic!("`{named}` is an addressee: {e}"));
assert_eq!(parsed.as_str(), named, "`{named}` round-trips");
}
assert!(addressees.contains(&"worker".to_string()));
let reached: Vec<String> =
serde_json::from_value(block["reached"].clone()).expect("entry 60 names the dispositions");
let carried = [
Reached::Queued,
Reached::Worker,
Reached::Supervisor,
Reached::JudgedWith {
completion_reason: "the work is done".into(),
},
Reached::Carried,
];
assert_eq!(
carried
.iter()
.map(|one| one.as_str().to_string())
.collect::<Vec<_>>(),
reached,
"entry 60 names dispositions this build does not carry, or the other way round"
);
for one in &carried {
let written = serde_json::to_value(one).expect("a disposition serializes");
let read: Reached = serde_json::from_value(written.clone()).expect("and reads back");
assert_eq!(&read, one, "{written} did not round-trip");
}
let tabulated_by = divergence_block("70.");
let words = |party: &Party| -> String {
serde_json::to_value(party)
.expect("a party serializes")
.as_str()
.expect("a party is a word")
.to_string()
};
for (table, answer) in [
(
"shown_at_delivery",
Reached::shown_at_delivery as fn(&Reached) -> &'static [Party],
),
(
"routed_to",
Reached::routed_to as fn(&Reached) -> &'static [Party],
),
] {
let tabulated: std::collections::BTreeMap<String, Vec<String>> =
serde_json::from_value(tabulated_by[table].clone())
.unwrap_or_else(|e| panic!("entry 70 tabulates `{table}` per disposition: {e}"));
assert_eq!(
tabulated.keys().cloned().collect::<Vec<_>>(),
{
let mut named = reached.clone();
named.sort();
named
},
"entry 70's `{table}` table and entry 60's dispositions are not one set"
);
for one in &carried {
assert_eq!(
&answer(one).iter().map(words).collect::<Vec<_>>(),
&tabulated[one.as_str()],
"`{}`'s `{table}` is not what entry 70 says",
one.as_str()
);
}
}
let refused: Vec<Value> =
serde_json::from_value(block["refused"].clone()).expect("entry 60 names what is refused");
let removed: Vec<String> =
serde_json::from_value(block["removed"].clone()).expect("entry 60 names what it removes");
for fixture in &refused {
let read = serde_json::from_value::<Edit>(fixture.clone());
let err = read
.err()
.unwrap_or_else(|| {
panic!("the envelope's boundary accepted a note it cannot deliver: {fixture}")
})
.to_string();
let op = fixture["op"].as_str().expect("the fixture names its op");
if removed.contains(&op.to_string()) {
assert!(
err.contains(op),
"the removed op was refused without being named: {err}"
);
}
}
assert!(
refused.iter().any(
|fixture| removed.contains(&fixture["op"].as_str().unwrap_or_default().to_string())
),
"entry 60 removes an op and drives no envelope carrying it"
);
let api = &block["api"];
assert_eq!(api["module"].as_str(), Some("onepipeline::note"));
let note = Note::to(Addressee::Worker, "stop editing src/old.rs");
assert!(!note.binds());
assert_eq!(note.addressee, Addressee::Worker);
let bound = note
.clone()
.binding("`version.txt` holds `v: 2`")
.expect("a criterion the seam accepts");
assert!(bound.binds());
assert!(
Note::new(Addressee::Worker, " ").is_err(),
"a blank note is not a note"
);
let answers: Vec<String> =
serde_json::from_value(api["answers"].clone()).expect("entry 60 names what it answers");
let spelled = [
format!("{:?}", Delivered::To(Reached::Worker)),
format!("{:?}", Delivered::Queued),
];
for (answer, spelled) in answers.iter().zip(spelled.iter()) {
assert!(
spelled.starts_with(answer),
"entry 60 names `{answer}`, which this build spells `{spelled}`"
);
}
assert_eq!(answers.len(), spelled.len());
assert_eq!(api["call"].as_str(), Some("deliver"));
assert_eq!(api["with"].as_str(), Some("deliver_with"));
let _: fn(&RunPaths, &str, &Note) -> onepipeline::Result<Delivered> =
onepipeline::note::deliver;
let _: fn(
&RunPaths,
&str,
&Note,
onepipeline::channel::Deliver,
bool,
) -> onepipeline::Result<Delivered> = onepipeline::note::deliver_with;
}
fn verbs_paragraph() -> &'static str {
CONTRACT
.split("\n\n")
.find(|paragraph| {
paragraph.starts_with(
"**The post-launch verbs are the SDK, and the CLI is argument parsing over them.**",
)
})
.expect("docs/contract.md states the post-launch verbs")
}
fn verb_functions_in_source() -> BTreeSet<String> {
std::fs::read_to_string(repo_root().join("src/verbs.rs"))
.expect("the verbs ship")
.lines()
.filter_map(|line| line.strip_prefix("pub fn "))
.map(|rest| {
rest.chars()
.take_while(|c| c.is_ascii_alphanumeric() || *c == '_')
.collect::<String>()
})
.collect()
}
fn verb_functions_in_contract() -> BTreeSet<String> {
backticked_in(verbs_paragraph())
.into_iter()
.filter_map(|span| {
let name: String = span
.chars()
.take_while(|c| c.is_ascii_alphanumeric() || *c == '_')
.collect();
let rest = &span[name.len()..];
let signature = rest.starts_with('(') && span.contains("->");
let renderer =
name.starts_with("render_") && (rest.is_empty() || rest.starts_with('('));
(!name.is_empty() && (signature || renderer)).then_some(name)
})
.collect()
}
#[test]
fn the_contract_names_every_post_launch_verb_the_sdk_publishes_and_no_other() {
use onemessagebus::Correlation;
use onepipeline::channel::SurfaceKind;
use onepipeline::filter::EventFilter;
use onepipeline::verbs::{
Adopt, Adopted, ChannelQueue, Goals, Grouping, Host, Monitored, Next, Receipt, Results,
Retained, Shutdown, ShutdownRequest, Status, StopRequest, Stopped, Surfaced, Transcript,
Unwatched, WatchFrame, WatchLines, WatchOutcome, WatchRequest,
};
use onepipeline::views::{DriverLiveness, Projects};
use onepipeline::Result;
let _: fn(&Path, &str, bool) -> Projects = verbs::runs;
let _: fn(&Projects, Grouping, &str) -> String = verbs::render_runs;
let _: fn(&Path, Option<&str>) -> Result<Status> = verbs::status;
let _: fn(&Status) -> String = verbs::render_status;
let _: fn(&Path) -> Host = verbs::host;
let _: fn(&Host) -> String = verbs::render_host;
let _: fn(&Path, Option<&str>) -> Result<Goals> = verbs::goals;
let _: fn(&Goals) -> String = verbs::render_goals;
let _: fn(&RunPaths) -> Result<Results> = verbs::results;
let _: fn(&Results) -> String = verbs::render_results;
let _: fn(&RunPaths, Option<&str>) -> Result<Transcript> = verbs::transcript;
let _: fn(&Transcript) -> String = verbs::render_transcript;
let _: fn(&Path, Option<&str>) -> Result<Vec<RunTelemetry>> = verbs::telemetry;
let _: fn(&[RunTelemetry], bool) -> Result<String> = verbs::render_telemetry;
let _: fn(&RunTelemetry) -> String = verbs::render_telemetry_breakdown;
let _: fn(&RunPaths, &[Envelope]) -> RunTelemetry = onepipeline::telemetry::of_run;
let _: fn(&RunPaths, &EventFilter, Option<&str>) -> Result<Monitored> = verbs::monitor;
let _: fn(&Monitored) -> String = verbs::render_monitor;
let _: fn(&RunPaths, &EventFilter) -> Result<Next> = verbs::next;
let _: fn(&Next) -> String = verbs::render_next;
let _: fn(&RunPaths) -> Result<ChannelQueue> = verbs::channel;
let _: fn(&ChannelQueue) -> Result<String> = verbs::render_channel;
type WatchSink<'a> = &'a mut dyn FnMut(WatchFrame<'_>) -> Result<()>;
let _: fn(&RunPaths, &WatchRequest, WatchSink<'_>) -> Result<WatchOutcome> = verbs::watch;
let _: fn(&WatchFrame<'_>) -> Result<WatchLines> = verbs::render_watch_frame;
let _: fn(&Path, &str) -> Result<Unwatched> = verbs::unwatched;
let _: fn(&Unwatched) -> String = verbs::render_unwatched;
let _: fn(&RunPaths, Option<&Correlation>, &str) -> Result<Receipt> = verbs::reply;
let _: fn(&Receipt) -> Result<String> = verbs::render_receipt;
let _: fn(&RunPaths, &str) -> Result<Receipt> = verbs::attest;
let _: fn(&RunPaths, SurfaceKind, String) -> Result<Surfaced> = verbs::surface;
let _: fn(&Surfaced) -> String = verbs::render_surfaced;
let _: fn(&RunPaths, StopRequest<'_>) -> Result<Stopped> = verbs::stop;
let _: fn(&Stopped) -> String = verbs::render_stopped;
let _: fn(&Path, ShutdownRequest) -> Result<Shutdown> = verbs::shutdown;
let _: fn(&Shutdown) -> String = verbs::render_shutdown;
let _: fn(&RunPaths, Adopt) -> Result<Adopted> = verbs::adopt;
let _: fn(&Adopted) -> String = verbs::render_adopted;
let _: fn(&RunPaths, Retained) -> Result<i32> = verbs::drive_run;
let _: fn(&RunSummary) -> DriverLiveness = onepipeline::views::liveness_of;
let _: fn(&RunPaths) -> Result<Plan> = onepipeline::views::plan_of;
let in_source = verb_functions_in_source();
let in_contract = verb_functions_in_contract();
assert_eq!(
in_contract, in_source,
"the verbs paragraph and src/verbs.rs disagree\n named and not published: {:?}\n published and not named: {:?}",
in_contract.difference(&in_source).collect::<Vec<_>>(),
in_source.difference(&in_contract).collect::<Vec<_>>()
);
for verb in [
"next",
"reply",
"surface",
"attest",
"stop",
"shutdown",
"render_shutdown",
"adopt",
"drive_run",
"watch",
"unwatched",
"runs",
"status",
"host",
"monitor",
"channel",
"results",
"goals",
"transcript",
"telemetry",
] {
assert!(
in_source.contains(verb),
"src/verbs.rs publishes no `{verb}`"
);
}
assert_contract_names(
"verbs paragraph's",
&[
"`onepipeline::verbs`",
"`tests/parity.rs`",
"`telemetry::of_run`",
"`views::liveness_of(&RunSummary) -> DriverLiveness`",
"`views::plan_of(&RunPaths) -> Plan`",
"`channel::{Surface, QueuedReply, QueuedCommands, CommandOutcome, CommandResult, CommandVerdict}`",
"`channel queue RUN`",
],
);
}
#[test]
fn the_grouped_listing_is_what_the_contract_states() {
assert_contract_names(
"grouped listing's",
&[
"`views::Projects { root, groups: Vec<ProjectGroup>, skipped }`",
"`ProjectGroup { project: Option<String>, name: Option<String>, last_write_at: Option<u64>, runs: Vec<RunSummary> }`",
"`Projects::of(&Listing)`",
"`Projects::flat()`",
"`views::GROUP_HEADER`",
"`runs --flat`",
"(no project)",
],
);
assert_eq!(NO_PROJECT, "(no project)");
assert!(
GROUP_HEADER
.starts_with(|c: char| !c.is_alphanumeric() && c != '.' && c != '_' && c != '-'),
"a group header must open with something no run id can: {GROUP_HEADER:?}"
);
let golden: RunSummary =
serde_json::from_str(include_str!("golden/run-summary-v7.json")).expect("the golden reads");
let row = |run: &str, project: &str, name: Option<&str>, at: Option<u64>| RunSummary {
run_id: run.into(),
project: project.into(),
name: name.map(str::to_owned),
last_write_at: at,
..golden.clone()
};
let listing = Listing {
root: PathBuf::from("/runs"),
summaries: vec![
row("newer-b", "plans:b", Some("B"), Some(300)),
row("orphan", "", None, Some(250)),
row("older-b", "plans:b", None, Some(200)),
row("only-a", "plans:a", Some("A"), Some(100)),
row("undated", "plans:c", None, None),
],
skipped: Vec::new(),
};
let projects = Projects::of(&listing);
assert_eq!(projects.root, listing.root);
type Shape<'a> = (Option<&'a str>, Option<&'a str>, Option<u64>, Vec<&'a str>);
let shape: Vec<Shape<'_>> = projects
.groups
.iter()
.map(|group| {
(
group.project.as_deref(),
group.name.as_deref(),
group.last_write_at,
group.runs.iter().map(|run| run.run_id.as_str()).collect(),
)
})
.collect();
assert_eq!(
shape,
vec![
(
Some("plans:b"),
Some("B"),
Some(300),
vec!["newer-b", "older-b"]
),
(None, None, Some(250), vec!["orphan"]),
(Some("plans:a"), Some("A"), Some(100), vec!["only-a"]),
(Some("plans:c"), None, None, vec!["undated"]),
]
);
assert_eq!(
projects
.flat()
.iter()
.map(|run| run.run_id.as_str())
.collect::<Vec<_>>(),
vec!["newer-b", "orphan", "older-b", "only-a", "undated"],
"the flat list is the listing's own order"
);
let orphans: &ProjectGroup = &projects.groups[1];
assert_eq!(orphans.header(), format!("{GROUP_HEADER}{NO_PROJECT}\n"));
assert_eq!(
projects.groups[0].header(),
format!("{GROUP_HEADER}plans:b — B\n")
);
}
#[test]
fn the_planner_channel_layout_is_this_crates_and_is_what_the_contract_states() {
use onemessagebus::{Layout as _, LocalTransport, Transport};
use onepipeline::channel::layout::{
self, source, Channel, PlannerChannel, Surface, ASKER_ENV, COMMANDS, PLANNER_CHANNEL,
REPLIES, REPLY_ENVELOPE_FAMILY, REPLY_ENVELOPE_VERSION, REPLY_ENVELOPE_VERSIONS_READ,
};
let passage = CONTRACT
.lines()
.find(|line| line.starts_with("**The planner channel runs on `onemessagebus`"))
.expect("the contract states who owns the planner-channel layout");
let named = backticked_in(passage);
assert!(named.contains("onepipeline::channel::layout"));
assert_eq!(PlannerChannel.name(), PLANNER_CHANNEL);
assert!(named.contains(PLANNER_CHANNEL) && named.contains(ASKER_ENV));
for file in layout::FILES {
assert!(
named.contains(file),
"the contract does not name the layout's file `{file}`"
);
}
for spec in layout::queues() {
assert!(
named.contains(&spec.name.to_string()),
"the contract does not name the layout's queue `{}`",
spec.name
);
}
let registry = layout::registry();
for id in [
layout::SURFACE_SCHEMA,
layout::QUEUED_REPLY_SCHEMA,
layout::QUEUED_COMMANDS_SCHEMA,
layout::COMMAND_OUTCOME_SCHEMA,
] {
assert!(registry.schema(&id).is_some(), "{id} is not registered");
assert!(
named.contains(&id.to_string()),
"the contract does not name {id}"
);
}
assert!(named.contains(REPLY_ENVELOPE_FAMILY));
for version in REPLY_ENVELOPE_VERSIONS_READ {
let id = onemessagebus::SchemaId::literal("agent", "reply-envelope", *version);
assert!(registry.schema(&id).is_some(), "{id} is not registered");
let document = format!("schemas/reply-envelope-v{version}.schema.json");
assert!(
named.contains(&document),
"the contract does not name {document}"
);
assert!(
repo_root().join(&document).is_file(),
"{document} does not ship"
);
}
let replies: onemessagebus::QueueName = REPLIES.parse().expect("a queue name");
let grants = PlannerChannel.allowlist();
let refused = PlannerChannel
.prepare(
&replies,
json!({"version": 1, "commands": [{"op": "finding", "message": "m"}]}),
&grants,
)
.expect_err("an edit envelope at version 1");
assert!(
named.contains(&refused),
"the contract does not quote `{refused}`"
);
assert_eq!(REPLY_ENVELOPE_VERSION, 3);
let routed = |envelope: Value| -> Vec<String> {
PlannerChannel
.prepare(&replies, envelope, &grants)
.expect("the planner's reply is routed")
.into_iter()
.map(|(queue, _)| queue.to_string())
.collect()
};
let edit = json!([{"op": "finding", "message": "m"}]);
assert_eq!(
routed(json!({"version": 3, "message": "go on", "completion": false, "commands": edit})),
vec![COMMANDS, REPLIES]
);
assert_eq!(
routed(json!({"version": 3, "commands": edit})),
vec![COMMANDS]
);
assert_eq!(routed(json!({"message": "carry on"})), vec![REPLIES]);
assert!(named.contains("source == check-in"));
let dir = std::env::temp_dir().join(format!(
"onepipeline-contract-layout-{}",
std::process::id()
));
let _ = std::fs::remove_dir_all(&dir);
let transport: std::sync::Arc<dyn Transport> =
std::sync::Arc::new(LocalTransport::open(&dir).expect("the transport opens"));
let channel = Channel::open(&transport).expect("the channel opens");
let surface = |message: &str, from: &str| Surface {
id: 0,
kind: "check-in".to_owned(),
message: message.to_owned(),
source: from.to_owned(),
blocking: false,
queued_at: 1,
workstream: None,
abandoned: false,
asker: None,
correlation: None,
};
for (message, from) in [
("an observer's first", source::PROPOSAL),
("an observer's second", source::PROPOSAL),
("a pacemaker's first", source::CHECK_IN),
("a pacemaker's second", source::CHECK_IN),
] {
channel.push(&surface(message, from)).expect("queued");
}
let mut handed = Vec::new();
while let Some(next) = channel.claim().expect("a claim") {
handed.push(next.message);
}
let _ = std::fs::remove_dir_all(&dir);
assert_eq!(
handed,
vec![
"an observer's first",
"an observer's second",
"a pacemaker's second"
]
);
}
#[test]
fn an_older_records_bus_config_is_read_best_effort_as_the_contract_states() {
let passage = CONTRACT
.split("**A launch record's bus configuration is read best-effort.**")
.nth(1)
.and_then(|rest| rest.split("**").next())
.expect("the contract states how an older record's bus configuration is read");
let named = backticked_in(passage);
let schema = schemars::schema_for!(onemessagebus::CodecConfig).to_value();
let required: BTreeSet<String> = schema["required"]
.as_array()
.expect("the codec schema requires fields")
.iter()
.map(|field| field.as_str().expect("a field name").to_owned())
.collect();
assert_eq!(
required,
BTreeSet::from(["select".to_owned(), "frames".to_owned()])
);
for field in &required {
assert!(
named.contains(field),
"the contract does not name `{field}`"
);
}
let older: Value = serde_json::from_str(
&std::fs::read_to_string(
repo_root().join("tests/recorded/launch/otg-closed-state-writes-status.json"),
)
.expect("the older record ships"),
)
.expect("the older record is JSON");
let (name, codec) = older["bus_config"]["codecs"]
.as_object()
.and_then(|codecs| codecs.iter().next())
.expect("the older record names a codec");
let mut emptied = codec.clone();
emptied["select"] = json!("");
emptied["frames"] = json!({});
let refusal = |codec: Value| {
onemessagebus::ConfiguredCodec::new(
name.parse().expect("a codec name"),
serde_json::from_value(codec).expect("a codec configuration"),
)
.expect_err("a codec with an empty field")
.replace(&format!("codecs.{name}."), "codecs.<name>.")
};
assert!(named.contains(&refusal(emptied.clone())));
emptied["select"] = json!("op");
assert!(named.contains(&refusal(emptied)));
}