#[cfg(feature = "alloc")]
use alloc::{format, string::String, vec::Vec};
use super::{
AgentId, DispatchError, DispatchId, DispatchResult, LaneId, ReviewFinding, ReviewMode,
ReviewVerdict, Role, RunId, WorkKind,
};
use super::{
CODER_RESULT_SCHEMA, DEBUGGING_EVIDENCE_SCHEMA, DISCOVERY_REPORT_SCHEMA, LANE_LEDGER_SCHEMA,
REVIEW_FINDING_SCHEMA, WORKER_RESULT_SCHEMA,
};
macro_rules! role_result {
($name:ident, $schema:ident, role: $role:expr, skill: $skill:literal) => {
role_result!($name, $schema);
impl $name {
pub const ROLE: Role = $role;
pub const STARTUP_SKILL: &'static str = $skill;
pub fn validate_header(&self) -> DispatchResult<()> {
self.validate_schema()?;
if self.role != Self::ROLE {
return Err(DispatchError::InvalidRecord(format!(
"`{}` carries role `{}`, expected `{}`",
Self::SCHEMA,
self.role,
Self::ROLE
)));
}
if self.startup_skill != Self::STARTUP_SKILL {
return Err(DispatchError::InvalidRecord(format!(
"`{}` carries startup skill `{}`, expected `{}`",
Self::SCHEMA,
self.startup_skill,
Self::STARTUP_SKILL
)));
}
Ok(())
}
}
};
($name:ident, $schema:ident, skill: $skill:literal) => {
role_result!($name, $schema);
impl $name {
pub const STARTUP_SKILL: &'static str = $skill;
pub fn validate_header(&self) -> DispatchResult<()> {
self.validate_schema()?;
if self.startup_skill != Self::STARTUP_SKILL {
return Err(DispatchError::InvalidRecord(format!(
"`{}` carries startup skill `{}`, expected `{}`",
Self::SCHEMA,
self.startup_skill,
Self::STARTUP_SKILL
)));
}
Ok(())
}
}
};
($name:ident, $schema:ident) => {
impl $name {
pub const SCHEMA: &'static str = $schema;
pub fn validate_schema(&self) -> DispatchResult<()> {
if self.schema == Self::SCHEMA {
Ok(())
} else {
Err(DispatchError::InvalidRecord(format!(
"unsupported schema `{}`, expected `{}`",
self.schema,
Self::SCHEMA
)))
}
}
}
};
}
macro_rules! result_status {
($(#[$meta:meta])* $name:ident { $($variant:ident),+ $(,)? }) => {
$(#[$meta])*
#[derive(
Clone,
Copy,
Debug,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
serde::Deserialize,
serde::Serialize,
strum::AsRefStr,
strum::Display,
strum::EnumCount,
strum::EnumIs,
strum::EnumString,
strum::IntoStaticStr,
strum::VariantNames,
)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
pub enum $name {
$($variant),+
}
};
}
result_status! {
CoderStatus { Green, Blocked, NeedsAmendment }
}
result_status! {
WorkerStatus { Complete, Partial, Blocked, NeedsAmendment }
}
result_status! {
DiscoveryStatus { Complete, Partial, Blocked }
}
result_status! {
DebuggingStatus { Reproduced, RootCauseFound, Fixed, Unresolved, Blocked }
}
result_status! {
LaneLedgerStatus { Ready, Running, Reviewing, Redo, Blocked, Accepted, HandedOff }
}
result_status! {
SourceRetrieval { Retrieved, Unavailable }
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct ResultBudget {
pub tool_calls: u32,
pub seconds: u32,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct CoderResult {
pub schema: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub run: RunId,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub lane: LaneId,
pub node: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub role: Role,
pub outcome: String,
pub task_digest: String,
pub startup_skill: String,
pub skill_bundle_digest: String,
pub worktree: String,
pub baseline_commit: String,
pub owned_paths: Vec<String>,
pub changed_paths: Vec<String>,
pub status: CoderStatus,
}
role_result!(
CoderResult,
CODER_RESULT_SCHEMA,
role: Role::Coder,
skill: "implementing"
);
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct WorkerResult {
pub schema: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub run: RunId,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub lane: LaneId,
pub node: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub role: Role,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub work_kind: WorkKind,
pub deliverable: String,
pub source_paths: Vec<String>,
pub owned_scope: Vec<String>,
pub budget: ResultBudget,
pub output_shape: String,
pub status: WorkerStatus,
pub task_digest: String,
pub startup_skill: String,
pub skill_bundle_digest: String,
}
role_result!(
WorkerResult,
WORKER_RESULT_SCHEMA,
role: Role::Worker,
skill: "artifact-work"
);
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DiscoverySource {
pub identifier: String,
pub version: String,
pub retrieval_status: SourceRetrieval,
pub evidence_location: Option<String>,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DiscoveryClaim {
pub claim: String,
pub citation: String,
pub observed: String,
pub interpretation: String,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DiscoveryConflict {
pub sources: Vec<String>,
pub contradiction: String,
pub freshness_gap: Option<String>,
pub disposition: String,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DiscoveryLimits {
pub scope: String,
pub budget: String,
pub compatibility: String,
pub unresolved_questions: Vec<String>,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DiscoveryEvidence {
pub report_sha256: String,
pub source_pointers: Vec<String>,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DiscoveryReport {
pub schema: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub run: RunId,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub lane: LaneId,
pub question: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub role: Role,
pub source_list: Vec<String>,
pub output_path: String,
pub budget: ResultBudget,
pub startup_skill: String,
pub skill_bundle_digest: String,
pub task_digest: String,
pub status: DiscoveryStatus,
pub sources: Vec<DiscoverySource>,
pub claims: Vec<DiscoveryClaim>,
pub conflicts: Vec<DiscoveryConflict>,
pub limits: DiscoveryLimits,
pub evidence: DiscoveryEvidence,
}
role_result!(
DiscoveryReport,
DISCOVERY_REPORT_SCHEMA,
role: Role::Discovery,
skill: "researching"
);
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DebuggingReproduction {
pub command: String,
pub input: String,
pub environment_identity: String,
pub binary_identity: String,
pub exit_status: i32,
pub stdout_path: String,
pub stderr_path: String,
pub observed_failure: String,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DebuggingObservation {
pub fact: String,
pub interpretation: String,
pub pointer: String,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DebuggingHypothesis {
pub boundary: String,
pub claim: String,
pub probe: String,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DebuggingFalsification {
pub command: String,
pub exit_status: i32,
pub observation: String,
pub conclusion: String,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DebuggingRootCause {
pub fault_boundary: String,
pub caller_only_rejection: String,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DebuggingFix {
pub changed_paths: Vec<String>,
pub scope: String,
pub minimality: String,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DebuggingRegression {
pub test: String,
pub red_before: String,
pub green_after: String,
pub input_sha256: String,
pub output_sha256: String,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DebuggingGate {
pub command: String,
pub exit_status: i32,
pub semantic_result: String,
pub candidate_identity: String,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DebuggingArtifact {
pub path: String,
pub sha256: String,
pub eval: Option<String>,
pub threshold: Option<String>,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DebuggingResidualRisk {
pub limits: Vec<String>,
pub next_route: String,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct DebuggingEvidence {
pub schema: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub run: RunId,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub lane: LaneId,
pub node: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub role: Role,
pub status: DebuggingStatus,
pub candidate_commit: String,
pub worktree: String,
pub startup_skill: String,
pub debugging_skill_digest: String,
pub input_digest: String,
pub reproduction: DebuggingReproduction,
pub observed: Vec<DebuggingObservation>,
pub hypothesis: Vec<DebuggingHypothesis>,
pub falsification: Vec<DebuggingFalsification>,
pub root_cause: DebuggingRootCause,
pub fix: DebuggingFix,
pub regression: DebuggingRegression,
pub gate: DebuggingGate,
pub evidence: Vec<DebuggingArtifact>,
pub residual_risk: DebuggingResidualRisk,
}
role_result!(
DebuggingEvidence,
DEBUGGING_EVIDENCE_SCHEMA,
role: Role::Coder,
skill: "implementing"
);
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct ReviewFindingReport {
pub schema: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub run: RunId,
#[cfg_attr(feature = "schema", schemars(with = "Option<String>"))]
pub lane: Option<LaneId>,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub mode: ReviewMode,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub reviewer_role: Role,
pub candidate_commit: String,
pub input_digest: String,
pub startup_skill: String,
pub skill_bundle_digest: String,
pub result_channel: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub verdict: ReviewVerdict,
#[cfg_attr(feature = "schema", schemars(with = "Vec<ReviewFindingShape>"))]
pub findings: Vec<ReviewFinding>,
pub report_path: Option<String>,
}
role_result!(ReviewFindingReport, REVIEW_FINDING_SCHEMA, skill: "reviewing");
#[cfg(any(test, feature = "schema"))]
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub(crate) struct ReviewFindingShape {
pub finding_id: String,
pub location: String,
pub hypothesis: String,
pub falsification_command: String,
pub falsification_exit_status: i32,
pub observed_result: String,
pub confidence: String,
pub severity: String,
pub impact: String,
pub acceptance_predicate: String,
pub owner_role: String,
pub route: String,
pub evidence_paths: Vec<String>,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct LaneLedgerEvent {
pub event_id: String,
pub node_id: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub role: Role,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub work_kind: WorkKind,
pub read_scope: Vec<String>,
pub write_scope: Vec<String>,
pub task_digest: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub dispatch_id: DispatchId,
pub result_artifact: Option<String>,
pub review_artifact: Option<String>,
pub command: String,
pub exit_status: i32,
pub semantic_result: String,
pub evidence_digest: String,
pub recorded_at: i64,
pub next_action: String,
pub worktree: Option<String>,
pub output_commit: Option<String>,
pub retry_of: Option<String>,
pub finding: Option<String>,
pub bounded_predicate: Option<String>,
pub re_review: Option<String>,
pub route: Option<String>,
pub reason: Option<String>,
pub preserved_evidence: Option<Vec<String>>,
pub parent_response: Option<String>,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct LaneGateOutcome {
pub exit_status: i32,
pub semantic_result: String,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct LaneAcceptance {
pub reviewed_commit: String,
pub path_manifest: Vec<String>,
pub auditor_evidence: Vec<String>,
pub red: LaneGateOutcome,
pub green: LaneGateOutcome,
pub startup_skill: String,
pub skill_bundle_digest: String,
pub risks: Vec<String>,
pub rollback: String,
pub restart: String,
pub handoff: String,
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
#[serde(deny_unknown_fields)]
pub struct LaneLedger {
pub schema: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub run: RunId,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub lane: LaneId,
pub outcome: String,
#[cfg_attr(feature = "schema", schemars(with = "String"))]
pub owner: AgentId,
pub baseline_commit: String,
pub plan_digest: String,
pub skill_bundle_digest: String,
pub status: LaneLedgerStatus,
pub events: Vec<LaneLedgerEvent>,
pub acceptance: Option<LaneAcceptance>,
}
role_result!(LaneLedger, LANE_LEDGER_SCHEMA);
#[cfg(test)]
mod tests {
use super::*;
use serde_json::{Value, json};
fn assert_document<T>(document: &Value, schema: &str, required: &[&str], optional: &[&str])
where
T: serde::Serialize + serde::de::DeserializeOwned + core::fmt::Debug,
{
let parsed: T =
serde_json::from_value(document.clone()).expect("contract fixture must deserialize");
assert_eq!(
&serde_json::to_value(&parsed).expect("contract fixture must reserialize"),
document,
"the document does not round-trip through its type"
);
assert_eq!(
document.get("schema").and_then(Value::as_str),
Some(schema),
"the document does not carry its own identifier"
);
let mut keys: Vec<&str> = document
.as_object()
.expect("fixture is an object")
.keys()
.map(String::as_str)
.collect();
keys.sort_unstable();
let mut declared: Vec<&str> = required.iter().chain(optional.iter()).copied().collect();
declared.sort_unstable();
assert_eq!(
keys, declared,
"the fixture and the declared field lists disagree"
);
for key in required {
let mut broken = document.clone();
broken
.as_object_mut()
.expect("fixture is an object")
.remove(*key)
.unwrap_or_else(|| panic!("fixture has no `{key}` to remove"));
assert!(
serde_json::from_value::<T>(broken).is_err(),
"`{key}` deserialized while absent, so it is not actually required"
);
}
for key in optional {
let mut trimmed = document.clone();
trimmed
.as_object_mut()
.expect("fixture is an object")
.remove(*key)
.unwrap_or_else(|| panic!("fixture has no `{key}` to remove"));
serde_json::from_value::<T>(trimmed)
.unwrap_or_else(|error| panic!("`{key}` is required, not optional: {error}"));
}
}
#[cfg(feature = "schema")]
fn assert_schema_required(schema: schemars::Schema, required: &[&str]) {
let value = serde_json::to_value(schema).expect("schema serializes");
let mut actual: Vec<&str> = value
.get("required")
.and_then(Value::as_array)
.expect("a derived object schema names its required fields")
.iter()
.map(|entry| entry.as_str().expect("required entries are strings"))
.collect();
actual.sort_unstable();
let mut expected = required.to_vec();
expected.sort_unstable();
assert_eq!(actual, expected);
assert_eq!(
value.get("additionalProperties"),
Some(&Value::Bool(false)),
"a result contract that accepts unknown fields is not closed"
);
}
const CODER_REQUIRED: &[&str] = &[
"schema",
"run",
"lane",
"node",
"role",
"outcome",
"task_digest",
"startup_skill",
"skill_bundle_digest",
"worktree",
"baseline_commit",
"owned_paths",
"changed_paths",
"status",
];
const WORKER_REQUIRED: &[&str] = &[
"schema",
"run",
"lane",
"node",
"role",
"work_kind",
"deliverable",
"source_paths",
"owned_scope",
"budget",
"output_shape",
"status",
"task_digest",
"startup_skill",
"skill_bundle_digest",
];
const DISCOVERY_REQUIRED: &[&str] = &[
"schema",
"run",
"lane",
"question",
"role",
"source_list",
"output_path",
"budget",
"startup_skill",
"skill_bundle_digest",
"task_digest",
"status",
"sources",
"claims",
"conflicts",
"limits",
"evidence",
];
const DEBUGGING_REQUIRED: &[&str] = &[
"schema",
"run",
"lane",
"node",
"role",
"status",
"candidate_commit",
"worktree",
"startup_skill",
"debugging_skill_digest",
"input_digest",
"reproduction",
"observed",
"hypothesis",
"falsification",
"root_cause",
"fix",
"regression",
"gate",
"evidence",
"residual_risk",
];
const REVIEW_REQUIRED: &[&str] = &[
"schema",
"run",
"mode",
"reviewer_role",
"candidate_commit",
"input_digest",
"startup_skill",
"skill_bundle_digest",
"result_channel",
"verdict",
"findings",
];
const REVIEW_OPTIONAL: &[&str] = &["lane", "report_path"];
const LEDGER_REQUIRED: &[&str] = &[
"schema",
"run",
"lane",
"outcome",
"owner",
"baseline_commit",
"plan_digest",
"skill_bundle_digest",
"status",
"events",
];
const LEDGER_OPTIONAL: &[&str] = &["acceptance"];
const DIGEST: &str = "a3f1e2d4c5b6a7089192a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f8";
const COMMIT: &str = "1f0a2b3c4d5e6f708192a3b4c5d6e7f809a1b2c3";
fn coder_document() -> Value {
json!({
"schema": CODER_RESULT_SCHEMA,
"run": "v661",
"lane": "wf-schemars",
"node": "n-04",
"role": "coder",
"outcome": "the six role result contracts deserialize or fail",
"task_digest": DIGEST,
"startup_skill": "implementing",
"skill_bundle_digest": DIGEST,
"worktree": "target/lanes/wf-schemars",
"baseline_commit": COMMIT,
"owned_paths": ["crates/core/src/dispatch/result.rs"],
"changed_paths": ["crates/core/src/dispatch/result.rs"],
"status": "green"
})
}
fn worker_document() -> Value {
json!({
"schema": WORKER_RESULT_SCHEMA,
"run": "v661",
"lane": "wf-schemars",
"node": "n-05",
"role": "worker",
"work_kind": "artifact",
"deliverable": "one bounded contract reference page",
"source_paths": ["content/skills/artifact-work/references/result-contract.md"],
"owned_scope": ["docs/contracts.md"],
"budget": {"tool_calls": 40, "seconds": 900},
"output_shape": "sections: shape, evidence, status",
"status": "complete",
"task_digest": DIGEST,
"startup_skill": "artifact-work",
"skill_bundle_digest": DIGEST
})
}
fn discovery_document() -> Value {
json!({
"schema": DISCOVERY_REPORT_SCHEMA,
"run": "v661",
"lane": "wf-schemars",
"question": "does schemars 1 keep Option fields out of `required`",
"role": "discovery",
"source_list": ["schemars-1.2.2"],
"output_path": "runs/v661/discovery/schemars.md",
"budget": {"tool_calls": 12, "seconds": 300},
"startup_skill": "researching",
"skill_bundle_digest": DIGEST,
"task_digest": DIGEST,
"status": "complete",
"sources": [{
"identifier": "schemars-1.2.2",
"version": "1.2.2",
"retrieval_status": "retrieved",
"evidence_location": "vendor/schemars/src/generate.rs"
}],
"claims": [{
"claim": "the default generator uses the deserialize contract",
"citation": "generate.rs:88",
"observed": "contract: Contract::Deserialize",
"interpretation": "Option fields are omitted from `required`"
}],
"conflicts": [{
"sources": ["schemars-0.9.0", "schemars-1.2.2"],
"contradiction": "0.9 spells the wrapper differently",
"freshness_gap": null,
"disposition": "the locked 1.2.2 wins"
}],
"limits": {
"scope": "schema generation only",
"budget": "12 of 12 tool calls",
"compatibility": "schemars 1.x only",
"unresolved_questions": []
},
"evidence": {
"report_sha256": DIGEST,
"source_pointers": ["vendor/schemars/src/generate.rs"]
}
})
}
fn debugging_document() -> Value {
json!({
"schema": DEBUGGING_EVIDENCE_SCHEMA,
"run": "v661",
"lane": "wf-schemars",
"node": "n-06",
"role": "coder",
"status": "fixed",
"candidate_commit": COMMIT,
"worktree": "target/lanes/wf-schemars",
"startup_skill": "implementing",
"debugging_skill_digest": DIGEST,
"input_digest": DIGEST,
"reproduction": {
"command": "cargo nextest run -p shepherd-core --all-features",
"input": "crates/core/src/dispatch/result.rs",
"environment_identity": "darwin-25.5.0",
"binary_identity": "cargo-nextest 0.9",
"exit_status": 101,
"stdout_path": "runs/v661/out.log",
"stderr_path": "runs/v661/err.log",
"observed_failure": "missing field `status`"
},
"observed": [{
"fact": "the fixture omitted `status`",
"interpretation": "the fixture, not the type, was wrong",
"pointer": "crates/core/src/dispatch/result.rs:1"
}],
"hypothesis": [{
"boundary": "serde derive",
"claim": "a plain field is required",
"probe": "remove the key and deserialize"
}],
"falsification": [{
"command": "cargo nextest run -p shepherd-core --all-features",
"exit_status": 0,
"observation": "deserialization returned Err",
"conclusion": "the field is required"
}],
"root_cause": {
"fault_boundary": "the fixture builder",
"caller_only_rejection": "every caller failed, so it is not one caller"
},
"fix": {
"changed_paths": ["crates/core/src/dispatch/result.rs"],
"scope": "test fixture only",
"minimality": "one key restored, no type change"
},
"regression": {
"test": "coder_result_document_matches_its_contract",
"red_before": "missing field `status`",
"green_after": "1 passed",
"input_sha256": DIGEST,
"output_sha256": DIGEST
},
"gate": {
"command": "cargo nextest run -p shepherd-core --all-features",
"exit_status": 0,
"semantic_result": "every result contract test passed",
"candidate_identity": COMMIT
},
"evidence": [{
"path": "runs/v661/out.log",
"sha256": DIGEST,
"eval": null,
"threshold": null
}],
"residual_risk": {
"limits": ["schemars 1.x only"],
"next_route": "none"
}
})
}
fn review_finding_entry() -> Value {
json!({
"finding_id": "f-01",
"location": "crates/core/src/dispatch/result.rs:1",
"hypothesis": "the document shape is unenforced",
"falsification_command": "cargo nextest run -p shepherd-core --all-features",
"falsification_exit_status": 0,
"observed_result": "deserialization accepted a document with no fields",
"confidence": "structurally-verifiable",
"severity": "important",
"impact": "a producer and a verifier drift without failing",
"acceptance_predicate": "removing any required key fails deserialization",
"owner_role": "coder",
"route": "wf-schemars",
"evidence_paths": ["runs/v661/out.log"]
})
}
fn review_document() -> Value {
json!({
"schema": REVIEW_FINDING_SCHEMA,
"run": "v661",
"lane": "wf-schemars",
"mode": "auditor-posthoc",
"reviewer_role": "auditor",
"candidate_commit": COMMIT,
"input_digest": DIGEST,
"startup_skill": "reviewing",
"skill_bundle_digest": DIGEST,
"result_channel": "native-result",
"verdict": "redo",
"findings": [review_finding_entry()],
"report_path": "runs/v661/review/wf-schemars.md"
})
}
fn ledger_document() -> Value {
json!({
"schema": LANE_LEDGER_SCHEMA,
"run": "v661",
"lane": "wf-schemars",
"outcome": "the six role result contracts have a derived shape",
"owner": "conductor-wf-schemars",
"baseline_commit": COMMIT,
"plan_digest": DIGEST,
"skill_bundle_digest": DIGEST,
"status": "accepted",
"events": [{
"event_id": "e-01",
"node_id": "n-04",
"role": "coder",
"work_kind": "production-code",
"read_scope": ["content/skills"],
"write_scope": ["crates/core/src/dispatch/result.rs"],
"task_digest": DIGEST,
"dispatch_id": "d-01",
"result_artifact": "runs/v661/result/n-04.json",
"review_artifact": null,
"command": "cargo nextest run -p shepherd-core --all-features",
"exit_status": 0,
"semantic_result": "every result contract test passed",
"evidence_digest": DIGEST,
"recorded_at": 1_756_000_000,
"next_action": "hand off to root",
"worktree": "target/lanes/wf-schemars",
"output_commit": COMMIT,
"retry_of": null,
"finding": null,
"bounded_predicate": null,
"re_review": null,
"route": null,
"reason": null,
"preserved_evidence": null,
"parent_response": null
}],
"acceptance": {
"reviewed_commit": COMMIT,
"path_manifest": ["crates/core/src/dispatch/result.rs"],
"auditor_evidence": ["runs/v661/review/wf-schemars.md"],
"red": {"exit_status": 101, "semantic_result": "missing field `status`"},
"green": {"exit_status": 0, "semantic_result": "every test passed"},
"startup_skill": "lane-execution",
"skill_bundle_digest": DIGEST,
"risks": ["schemars 1.x only"],
"rollback": "revert the module and its declaration",
"restart": "none",
"handoff": "root commits"
}
})
}
#[test]
fn each_type_is_bound_to_exactly_one_record_constant() {
assert_eq!(CoderResult::SCHEMA, CODER_RESULT_SCHEMA);
assert_eq!(WorkerResult::SCHEMA, WORKER_RESULT_SCHEMA);
assert_eq!(DiscoveryReport::SCHEMA, DISCOVERY_REPORT_SCHEMA);
assert_eq!(DebuggingEvidence::SCHEMA, DEBUGGING_EVIDENCE_SCHEMA);
assert_eq!(ReviewFindingReport::SCHEMA, REVIEW_FINDING_SCHEMA);
assert_eq!(LaneLedger::SCHEMA, LANE_LEDGER_SCHEMA);
let bound = [
CoderResult::SCHEMA,
WorkerResult::SCHEMA,
DiscoveryReport::SCHEMA,
DebuggingEvidence::SCHEMA,
ReviewFindingReport::SCHEMA,
LaneLedger::SCHEMA,
];
let mut sorted = bound.to_vec();
sorted.sort_unstable();
sorted.dedup();
assert_eq!(sorted.len(), bound.len(), "two types share an identifier");
}
#[test]
fn coder_result_matches_its_contract() {
let document = coder_document();
assert_document::<CoderResult>(&document, CODER_RESULT_SCHEMA, CODER_REQUIRED, &[]);
let parsed: CoderResult = serde_json::from_value(document).expect("fixture");
parsed.validate_header().expect("header matches");
}
#[test]
fn worker_result_matches_its_contract() {
let document = worker_document();
assert_document::<WorkerResult>(&document, WORKER_RESULT_SCHEMA, WORKER_REQUIRED, &[]);
let parsed: WorkerResult = serde_json::from_value(document).expect("fixture");
parsed.validate_header().expect("header matches");
}
#[test]
fn discovery_report_matches_its_contract() {
let document = discovery_document();
assert_document::<DiscoveryReport>(
&document,
DISCOVERY_REPORT_SCHEMA,
DISCOVERY_REQUIRED,
&[],
);
let parsed: DiscoveryReport = serde_json::from_value(document).expect("fixture");
parsed.validate_header().expect("header matches");
}
#[test]
fn debugging_evidence_matches_its_contract() {
let document = debugging_document();
assert_document::<DebuggingEvidence>(
&document,
DEBUGGING_EVIDENCE_SCHEMA,
DEBUGGING_REQUIRED,
&[],
);
let parsed: DebuggingEvidence = serde_json::from_value(document).expect("fixture");
parsed.validate_header().expect("header matches");
}
#[test]
fn review_finding_report_matches_its_contract() {
let document = review_document();
assert_document::<ReviewFindingReport>(
&document,
REVIEW_FINDING_SCHEMA,
REVIEW_REQUIRED,
REVIEW_OPTIONAL,
);
let parsed: ReviewFindingReport = serde_json::from_value(document).expect("fixture");
parsed.validate_header().expect("header matches");
}
#[test]
fn lane_ledger_matches_its_contract() {
let document = ledger_document();
assert_document::<LaneLedger>(
&document,
LANE_LEDGER_SCHEMA,
LEDGER_REQUIRED,
LEDGER_OPTIONAL,
);
let parsed: LaneLedger = serde_json::from_value(document).expect("fixture");
parsed.validate_schema().expect("schema matches");
}
#[test]
fn a_document_carrying_another_contracts_identifier_is_rejected() {
let mut document = coder_document();
document["schema"] = json!(WORKER_RESULT_SCHEMA);
let parsed: CoderResult = serde_json::from_value(document).expect("shape still parses");
assert!(parsed.validate_schema().is_err());
}
#[test]
fn a_document_carrying_another_roles_identity_is_rejected() {
let mut document = coder_document();
document["role"] = json!("worker");
let parsed: CoderResult = serde_json::from_value(document).expect("shape still parses");
assert!(parsed.validate_header().is_err());
let mut document = coder_document();
document["startup_skill"] = json!("artifact-work");
let parsed: CoderResult = serde_json::from_value(document).expect("shape still parses");
assert!(parsed.validate_header().is_err());
}
#[test]
fn an_unknown_field_is_rejected_by_every_contract() {
for mut document in [
coder_document(),
worker_document(),
discovery_document(),
debugging_document(),
review_document(),
ledger_document(),
] {
document["not_in_the_contract"] = json!(true);
assert!(
serde_json::from_value::<serde_json::Map<String, Value>>(document.clone()).is_ok()
);
let rejected = serde_json::from_value::<CoderResult>(document.clone()).is_err()
&& serde_json::from_value::<WorkerResult>(document.clone()).is_err()
&& serde_json::from_value::<DiscoveryReport>(document.clone()).is_err()
&& serde_json::from_value::<DebuggingEvidence>(document.clone()).is_err()
&& serde_json::from_value::<ReviewFindingReport>(document.clone()).is_err()
&& serde_json::from_value::<LaneLedger>(document).is_err();
assert!(rejected, "an unknown field was accepted somewhere");
}
}
#[test]
fn review_finding_shape_matches_the_review_finding_type() {
let entry = review_finding_entry();
let real: ReviewFinding =
serde_json::from_value(entry.clone()).expect("the real finding type accepts it");
let witness: ReviewFindingShape =
serde_json::from_value(entry.clone()).expect("the schema witness accepts it");
assert_eq!(serde_json::to_value(&real).expect("real"), entry);
assert_eq!(serde_json::to_value(&witness).expect("witness"), entry);
}
#[test]
fn review_finding_report_matches_the_review_result_document() {
let mut document = review_document();
document["schema"] = json!(super::super::REVIEW_RESULT_SCHEMA);
let review_result: super::super::ReviewResult =
serde_json::from_value(document.clone()).expect("ReviewResult accepts it");
assert_eq!(
serde_json::to_value(&review_result).expect("value"),
document
);
document["schema"] = json!(REVIEW_FINDING_SCHEMA);
let report: ReviewFindingReport =
serde_json::from_value(document.clone()).expect("ReviewFindingReport accepts it");
assert_eq!(serde_json::to_value(&report).expect("value"), document);
}
#[cfg(feature = "schema")]
#[test]
fn every_derived_schema_names_the_required_fields() {
assert_schema_required(schemars::schema_for!(CoderResult), CODER_REQUIRED);
assert_schema_required(schemars::schema_for!(WorkerResult), WORKER_REQUIRED);
assert_schema_required(schemars::schema_for!(DiscoveryReport), DISCOVERY_REQUIRED);
assert_schema_required(schemars::schema_for!(DebuggingEvidence), DEBUGGING_REQUIRED);
assert_schema_required(schemars::schema_for!(ReviewFindingReport), REVIEW_REQUIRED);
assert_schema_required(schemars::schema_for!(LaneLedger), LEDGER_REQUIRED);
}
#[cfg(feature = "schema")]
#[test]
fn the_review_finding_schema_carries_the_finding_shape() {
let value =
serde_json::to_value(schemars::schema_for!(ReviewFindingReport)).expect("schema");
let reference = value
.pointer("/properties/findings/items/$ref")
.and_then(Value::as_str)
.expect("findings items reference a named definition");
let name = reference
.rsplit('/')
.next()
.expect("a $ref names a definition");
let mut required: Vec<&str> = value
.pointer(&format!("/$defs/{name}/required"))
.and_then(Value::as_array)
.expect("the finding definition names its required fields")
.iter()
.map(|entry| entry.as_str().expect("string"))
.collect();
required.sort_unstable();
assert_eq!(
required,
[
"acceptance_predicate",
"confidence",
"evidence_paths",
"falsification_command",
"falsification_exit_status",
"finding_id",
"hypothesis",
"impact",
"location",
"observed_result",
"owner_role",
"route",
"severity",
]
);
}
}