use assay_core::agent_assertions::model::TraceAssertion;
use std::path::{Path, PathBuf};
fn repo_root() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.and_then(|p| p.parent())
.expect("repo root")
.to_path_buf()
}
const METRICS_DOC: &str = "docs/metrics/index.md";
const AGENTS_DOC: &str = "docs/architecture/agents.md";
const SHIPPED_TYPES: &[&str] = &[
"trace_must_call_tool",
"trace_must_not_call_tool",
"trace_tool_sequence",
"trace_max_steps",
"args_valid",
"sequence_valid",
"tool_blocklist",
];
struct Block {
doc: &'static str,
line: usize,
body: String,
}
fn yaml_blocks(doc: &'static str) -> Vec<Block> {
let text = std::fs::read_to_string(repo_root().join(doc))
.unwrap_or_else(|e| panic!("cannot read {doc}: {e}"));
let mut out = Vec::new();
let mut current: Option<(usize, Vec<&str>)> = None;
for (idx, line) in text.lines().enumerate() {
match current.take() {
None => {
if line.trim_start().starts_with("```yaml") {
current = Some((idx + 1, Vec::new()));
}
}
Some((start, mut acc)) => {
if line.trim_start().starts_with("```") {
out.push(Block {
doc,
line: start,
body: acc.join("\n"),
});
} else {
acc.push(line);
current = Some((start, acc));
}
}
}
}
assert!(
!out.is_empty(),
"{doc}: no fenced yaml blocks found — the extractor or the document moved"
);
out
}
fn check_block(b: &Block) {
let looks_like_config = b.body.contains("configVersion:") || b.body.contains("\ntests:");
if looks_like_config {
let tmp = tempfile::tempdir().expect("tempdir");
let path = tmp.path().join("eval.yaml");
std::fs::write(&path, &b.body).expect("write config");
if let Err(e) = assay_core::config::load_config(&path, false, false) {
panic!(
"{}:{} — documented config does not load: {e}\n---\n{}\n---",
b.doc, b.line, b.body
);
}
return;
}
assert!(
b.body.contains("type:"),
"{}:{} — fenced yaml block is neither a config nor an assertion:\n{}",
b.doc,
b.line,
b.body
);
if let Err(e) = serde_yaml::from_str::<TraceAssertion>(&b.body) {
panic!(
"{}:{} — documented assertion does not parse: {e}\n---\n{}\n---",
b.doc, b.line, b.body
);
}
}
#[test]
fn every_documented_assertion_example_parses() {
for doc in [METRICS_DOC, AGENTS_DOC] {
for block in yaml_blocks(doc) {
check_block(&block);
}
}
}
#[test]
fn every_shipped_variant_is_documented() {
let text = std::fs::read_to_string(repo_root().join(METRICS_DOC)).expect("read metrics doc");
for ty in SHIPPED_TYPES {
assert!(
text.contains(&format!("### `{ty}`")),
"{METRICS_DOC}: `{ty}` exists in TraceAssertion but has no section in the catalogue"
);
}
}
#[test]
fn types_documented_as_unimplemented_are_actually_rejected() {
for ty in [
"trace_no_tool_call",
"trace_tool_args_match",
"trace_tool_args_schema",
"trace_tool_call_count",
"trace_no_tool_errors",
] {
let yaml = format!("type: {ty}\n");
assert!(
serde_yaml::from_str::<TraceAssertion>(&yaml).is_err(),
"`{ty}` is listed as not implemented but the parser accepts it"
);
let text =
std::fs::read_to_string(repo_root().join(METRICS_DOC)).expect("read metrics doc");
assert!(
text.contains(&format!("`{ty}`")),
"{METRICS_DOC}: `{ty}` is rejected by the parser but is not listed under \
\"Not implemented\", so a reader has no way to learn what to write instead"
);
}
}