Add M1 plan, given tests and fixtures, AGENTS.md and implementer log

Seven task files for the implementing model under docs/plans/M1/, with
the test files, byte-exact fixtures, Makefile, deny.toml and gate-script
self-test they copy into place. All of it was verified against a private
reference implementation: the gate passes after every task in order.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-09-17 01:22:43 -07:00
co-authored by Claude Fable 5.1
parent 19104a9629
commit 3e26c2e3c0
36 changed files with 2129 additions and 2 deletions
@@ -0,0 +1,177 @@
//! Tests for IPC messages against byte-exact fixtures. Do not edit these or the fixtures.
use proto::{
CallId, DataClass, DenyReason, Envelope, ErrorCode, Message, SessionId, Timestamp, ToolRequest,
ToolResponse, WireError,
};
fn fixture(name: &str) -> String {
let path = format!("{}/tests/fixtures/wire/{name}", env!("CARGO_MANIFEST_DIR"));
let text = std::fs::read_to_string(&path).unwrap_or_else(|e| panic!("{path}: {e}"));
text.trim_end_matches('\n').to_string()
}
/// The fixture must decode to `want`, and `want` must encode to exactly the fixture's bytes.
fn check(name: &str, want: Envelope) {
let text = fixture(name);
let got: Envelope = serde_json::from_str(&text).unwrap_or_else(|e| panic!("{name}: {e}"));
assert_eq!(got, want, "{name}: decoded value");
assert_eq!(
serde_json::to_string(&want).unwrap(),
text,
"{name}: encoded bytes"
);
}
fn response(id: u64, r#final: bool, body: ToolResponse) -> Envelope {
Envelope {
v: 1,
id,
r#final,
msg: Message::ToolResponse(body),
}
}
#[test]
fn tool_request() {
let body = ToolRequest {
session: SessionId::new("mm-thread-42").unwrap(),
call: CallId(3),
tool: "read_file".to_string(),
arguments: r#"{"path":"/etc/hosts"}"#.to_string(),
};
check(
"tool_request.json",
Envelope {
v: 1,
id: 7,
r#final: true,
msg: Message::ToolRequest(body),
},
);
}
#[test]
fn tool_response_pending() {
let body = ToolResponse::PendingApproval {
approval: "ap-0001".to_string(),
expires: Timestamp::parse("2026-09-17T08:35:00.000Z").unwrap(),
};
check("tool_response_pending.json", response(7, false, body));
}
#[test]
fn tool_response_result() {
let body = ToolResponse::Result {
content: "127.0.0.1 localhost\n".to_string(),
class: DataClass::Private,
untrusted: true,
truncated: false,
};
check("tool_response_result.json", response(7, true, body));
}
#[test]
fn tool_response_failed() {
let body = ToolResponse::Failed {
message: "exit status 2".to_string(),
};
check("tool_response_failed.json", response(8, true, body));
}
#[test]
fn tool_response_denied() {
let body = ToolResponse::Denied {
reason: DenyReason::TaintTooHigh,
};
check("tool_response_denied.json", response(9, true, body));
}
#[test]
fn error_message() {
let body = WireError {
code: ErrorCode::BadVersion,
detail: "expected 1".to_string(),
};
check(
"error.json",
Envelope {
v: 1,
id: 0,
r#final: true,
msg: Message::Error(body),
},
);
}
#[test]
fn deny_reasons_and_error_codes_are_snake_case() {
let reasons = [
(DenyReason::NoGrant, "no_grant"),
(DenyReason::GrantExpired, "grant_expired"),
(DenyReason::TaintTooHigh, "taint_too_high"),
(DenyReason::DeniedByGrant, "denied_by_grant"),
(DenyReason::ApprovalRefused, "approval_refused"),
(DenyReason::ApprovalExpired, "approval_expired"),
];
for (value, text) in reasons {
assert_eq!(
serde_json::to_string(&value).unwrap(),
format!("\"{text}\"")
);
}
let codes = [
(ErrorCode::BadFrame, "bad_frame"),
(ErrorCode::BadVersion, "bad_version"),
(ErrorCode::BadMessage, "bad_message"),
(ErrorCode::Internal, "internal"),
];
for (value, text) in codes {
assert_eq!(
serde_json::to_string(&value).unwrap(),
format!("\"{text}\"")
);
}
}
#[test]
fn unknown_and_missing_fields_are_rejected() {
let good = fixture("tool_request.json");
assert!(serde_json::from_str::<Envelope>(&good).is_ok());
let bad = [
// extra field in the envelope
good.replacen("{\"v\":1,", "{\"v\":1,\"extra\":0,", 1),
// extra field beside kind and body
good.replacen(
"\"kind\":\"tool_request\",",
"\"kind\":\"tool_request\",\"x\":1,",
1,
),
// extra field in the body
good.replacen("\"call\":3,", "\"call\":3,\"priority\":9,", 1),
// missing field in the body
good.replacen("\"call\":3,", "", 1),
// missing `final`
good.replacen("\"final\":true,", "", 1),
// unknown kind
good.replacen("tool_request", "tool_demand", 1),
// invalid session id inside a message
good.replacen("mm-thread-42", "../../etc", 1),
];
for text in bad {
assert!(
serde_json::from_str::<Envelope>(&text).is_err(),
"accepted {text}"
);
}
}
#[test]
fn unknown_field_in_a_response_variant_is_rejected() {
let good = fixture("tool_response_denied.json");
let bad = good.replacen("\"reason\":", "\"note\":\"x\",\"reason\":", 1);
assert!(serde_json::from_str::<Envelope>(&good).is_ok());
assert!(serde_json::from_str::<Envelope>(&bad).is_err());
let bad_status = good.replacen("denied", "refused", 1);
assert!(serde_json::from_str::<Envelope>(&bad_status).is_err());
}