Add grid agent milestone acceptance gate (#135)
Some checks failed
CI / rust-skia (Rust only) (push) Successful in 2m47s
CI / required (push) Failing after 52s

This commit is contained in:
2026-08-18 12:43:25 +02:00
parent 00707fd8df
commit b56b28043f
9 changed files with 972 additions and 3 deletions

View File

@@ -0,0 +1,130 @@
use metacrate_grid_agent::{
ACCEPTANCE_SCHEMA_VERSION, ACCEPTANCE_SECRET_CANARY, AcceptanceBudgets,
AcceptanceEvidenceWriter, AcceptanceRecord, AcceptanceStatus, LiveGridOptIns,
run_deterministic_acceptance,
};
use std::collections::BTreeMap;
use std::fs;
use std::path::PathBuf;
use std::time::{SystemTime, UNIX_EPOCH};
fn temporary(name: &str) -> PathBuf {
std::env::temp_dir().join(format!(
"metacrate-acceptance-{}-{name}",
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos()
))
}
#[tokio::test]
async fn deterministic_gate_writes_ordered_redacted_evidence_and_drains() {
let path = temporary("gate.jsonl");
run_deterministic_acceptance(&path, AcceptanceBudgets::default())
.await
.expect("acceptance gate");
let text = fs::read_to_string(&path).expect("evidence");
assert!(!text.contains(ACCEPTANCE_SECRET_CANARY));
let records = text
.lines()
.map(|line| serde_json::from_str::<AcceptanceRecord>(line).expect("record"))
.collect::<Vec<_>>();
assert_eq!(records.len(), 7);
assert!(
records
.iter()
.all(|record| record.status == AcceptanceStatus::Passed)
);
assert_eq!(
records
.iter()
.map(|record| record.sequence)
.collect::<Vec<_>>(),
vec![1, 2, 3, 4, 5, 6, 7]
);
for required in [
"headless_startup",
"control_conformance",
"chat_scheduling",
"clean_shutdown",
"maintenance_reconnect",
"policy_redaction_and_protocol_audit",
] {
assert!(records.iter().any(|record| record.stage == required));
}
assert!(
run_deterministic_acceptance(&path, AcceptanceBudgets::default())
.await
.is_err(),
"evidence is never overwritten"
);
fs::remove_file(path).unwrap();
}
#[test]
fn live_actions_require_exact_independent_confirmations() {
let mut values = BTreeMap::new();
values.insert("METACRATE_AGENT_LIVE_CHAT_IM", "CHAT-IM");
let action_without_login =
LiveGridOptIns::from_environment(|name| values.get(name).map(ToString::to_string));
assert!(action_without_login.validate().is_err());
values.insert("METACRATE_AGENT_LIVE_LOGIN", "LOGIN");
values.insert("METACRATE_AGENT_LIVE_BUILD", "wrong");
let confirmed =
LiveGridOptIns::from_environment(|name| values.get(name).map(ToString::to_string))
.validate()
.unwrap();
assert!(confirmed.login && confirmed.chat_and_im);
assert!(!confirmed.reversible_build);
}
#[test]
fn evidence_writer_rejects_secret_markers_and_schema_is_committed() {
let path = temporary("unsafe.jsonl");
let mut writer = AcceptanceEvidenceWriter::create(&path).unwrap();
let record = AcceptanceRecord {
schema_version: ACCEPTANCE_SCHEMA_VERSION,
sequence: 1,
unix_millis: 0,
package_version: "test".into(),
source_revision: "test".into(),
rust_toolchain: "test".into(),
command: "test".into(),
profile: "test".into(),
grid_type: "test".into(),
endpoint_capabilities: Vec::new(),
stage: "canary".into(),
status: AcceptanceStatus::Failed,
duration_millis: 0,
budget_millis: None,
outcome_code: ACCEPTANCE_SECRET_CANARY.into(),
evidence_sha256: "0".repeat(64),
metrics: serde_json::Map::new(),
limitations: Vec::new(),
};
assert!(writer.write(&record).is_err());
drop(writer);
fs::remove_file(path).unwrap();
let workspace = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..");
let schema =
fs::read_to_string(workspace.join("config/grid-agent-acceptance-evidence.schema.json"))
.unwrap();
let schema: serde_json::Value = serde_json::from_str(&schema).unwrap();
assert_eq!(
schema["properties"]["schema_version"]["const"],
ACCEPTANCE_SCHEMA_VERSION
);
let report = fs::read_to_string(workspace.join("docs/grid-agent-acceptance.md")).unwrap();
for required in [
"Deterministic gate",
"Live-grid matrix",
"Resource budgets",
"Remaining limitations",
"#128",
"#134",
] {
assert!(report.contains(required), "report missing {required}");
}
}

View File

@@ -52,10 +52,10 @@ fn package_has_only_reviewed_rust_dependencies_and_no_build_script() {
#[test]
fn runtime_source_has_no_subprocess_or_native_abi_escape_hatch() {
let source = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("src");
let mut files = Vec::with_capacity(37);
let mut files = Vec::with_capacity(38);
collect_rust_files(&source, &mut files);
assert!(
files.len() <= 37,
files.len() <= 38,
"source-file count needs a reviewed bound update"
);
for path in files {