use crate::verifier::{
admit, AdmissionOutcome, EvidenceRequirement, UnmetRequirement, VerifierVerdict,
};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum StateSurface {
Memory,
Skills,
Tools,
Verification,
Routing,
Tasks,
}
impl StateSurface {
pub const fn as_str(&self) -> &'static str {
match self {
StateSurface::Memory => "memory",
StateSurface::Skills => "skills",
StateSurface::Tools => "tools",
StateSurface::Verification => "verification",
StateSurface::Routing => "routing",
StateSurface::Tasks => "tasks",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CommitAuthority {
Execution,
Review,
Coordination,
Scheduling,
SystemConfig,
}
impl CommitAuthority {
pub const fn as_str(&self) -> &'static str {
match self {
CommitAuthority::Execution => "execution",
CommitAuthority::Review => "review",
CommitAuthority::Coordination => "coordination",
CommitAuthority::Scheduling => "scheduling",
CommitAuthority::SystemConfig => "system_config",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SelfCommit {
Forbidden,
WithPassingEvidence,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct SurfaceRule {
pub surface: StateSurface,
pub produced_by: CommitAuthority,
pub committed_by: CommitAuthority,
pub self_commit: SelfCommit,
#[serde(default)]
pub requires: Vec<EvidenceRequirement>,
}
impl SurfaceRule {
pub fn is_ungated(&self) -> bool {
self.self_commit == SelfCommit::WithPassingEvidence && self.requires.is_empty()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct StateCandidate {
pub surface: StateSurface,
pub id: String,
pub produced_by: CommitAuthority,
#[serde(default)]
pub committed_by: Option<CommitAuthority>,
#[serde(default)]
pub verdicts: Vec<VerifierVerdict>,
}
impl StateCandidate {
pub fn new(surface: StateSurface, id: impl Into<String>, produced_by: CommitAuthority) -> Self {
Self {
surface,
id: id.into(),
produced_by,
committed_by: None,
verdicts: Vec::new(),
}
}
pub fn with_verdicts(mut self, verdicts: impl IntoIterator<Item = VerifierVerdict>) -> Self {
self.verdicts = verdicts.into_iter().collect();
self
}
pub fn committed_by(mut self, who: CommitAuthority) -> Self {
self.committed_by = Some(who);
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(tag = "refusal", rename_all = "snake_case")]
pub enum AdmissionRefusal {
NoRule {
surface: StateSurface,
},
NotCommitted,
WrongCommitter {
expected: CommitAuthority,
actual: CommitAuthority,
},
SelfCommitForbidden {
role: CommitAuthority,
},
UnexpectedProducer {
expected: CommitAuthority,
actual: CommitAuthority,
},
EvidenceRejected {
failures: Vec<String>,
},
InsufficientEvidence {
unmet: Vec<UnmetRequirement>,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub struct StateAdmission {
pub admitted: bool,
pub id: String,
pub surface: StateSurface,
pub refusals: Vec<AdmissionRefusal>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct OwnershipTable {
rules: BTreeMap<StateSurface, SurfaceRule>,
}
impl OwnershipTable {
pub fn new() -> Self {
Self::default()
}
pub fn set(&mut self, rule: SurfaceRule) {
self.rules.insert(rule.surface, rule);
}
pub fn with(mut self, rule: SurfaceRule) -> Self {
self.set(rule);
self
}
pub fn rule(&self, surface: StateSurface) -> Option<&SurfaceRule> {
self.rules.get(&surface)
}
pub fn rules(&self) -> impl Iterator<Item = &SurfaceRule> {
self.rules.values()
}
pub fn ungated_surfaces(&self) -> Vec<StateSurface> {
self.rules
.values()
.filter(|r| r.is_ungated())
.map(|r| r.surface)
.collect()
}
}
pub fn admit_state(table: &OwnershipTable, candidate: &StateCandidate) -> StateAdmission {
let mut refusals = Vec::new();
let Some(rule) = table.rule(candidate.surface) else {
return StateAdmission {
admitted: false,
id: candidate.id.clone(),
surface: candidate.surface,
refusals: vec![AdmissionRefusal::NoRule {
surface: candidate.surface,
}],
};
};
if candidate.produced_by != rule.produced_by {
refusals.push(AdmissionRefusal::UnexpectedProducer {
expected: rule.produced_by,
actual: candidate.produced_by,
});
}
let evidence = admit(&rule.requires, &candidate.verdicts);
match evidence.outcome {
AdmissionOutcome::Admit => {}
AdmissionOutcome::Reject => refusals.push(AdmissionRefusal::EvidenceRejected {
failures: evidence.failures.clone(),
}),
AdmissionOutcome::NeedsMoreEvidence => {
refusals.push(AdmissionRefusal::InsufficientEvidence {
unmet: evidence.unmet.clone(),
})
}
}
let evidence_passed = evidence.outcome == AdmissionOutcome::Admit;
match candidate.committed_by {
None => refusals.push(AdmissionRefusal::NotCommitted),
Some(committer) if committer == candidate.produced_by => match rule.self_commit {
SelfCommit::Forbidden => {
refusals.push(AdmissionRefusal::SelfCommitForbidden { role: committer })
}
SelfCommit::WithPassingEvidence => {
if !evidence_passed && committer != rule.committed_by {
refusals.push(AdmissionRefusal::WrongCommitter {
expected: rule.committed_by,
actual: committer,
});
}
}
},
Some(committer) if committer != rule.committed_by => {
refusals.push(AdmissionRefusal::WrongCommitter {
expected: rule.committed_by,
actual: committer,
})
}
Some(_) => {}
}
StateAdmission {
admitted: refusals.is_empty(),
id: candidate.id.clone(),
surface: candidate.surface,
refusals,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{EvidenceTier, VerifierDescriptor, VerifierOutcome, VerifierVerdict};
fn tests_pass() -> VerifierVerdict {
VerifierVerdict::pass(VerifierDescriptor::binding("cargo_test", "tests"))
}
fn tests_fail() -> VerifierVerdict {
VerifierVerdict::fail(
VerifierDescriptor::binding("cargo_test", "tests"),
"2 failed",
)
}
fn memory_rule() -> SurfaceRule {
SurfaceRule {
surface: StateSurface::Memory,
produced_by: CommitAuthority::Execution,
committed_by: CommitAuthority::Review,
self_commit: SelfCommit::Forbidden,
requires: vec![EvidenceRequirement::new("tests")],
}
}
fn tasks_rule() -> SurfaceRule {
SurfaceRule {
surface: StateSurface::Tasks,
produced_by: CommitAuthority::Execution,
committed_by: CommitAuthority::Scheduling,
self_commit: SelfCommit::WithPassingEvidence,
requires: vec![EvidenceRequirement::new("tests")],
}
}
fn table() -> OwnershipTable {
OwnershipTable::new().with(memory_rule()).with(tasks_rule())
}
#[test]
fn an_ungoverned_surface_refuses_rather_than_admits() {
let c = StateCandidate::new(StateSurface::Routing, "r1", CommitAuthority::Coordination)
.committed_by(CommitAuthority::Coordination);
let d = admit_state(&table(), &c);
assert!(!d.admitted);
assert_eq!(
d.refusals,
vec![AdmissionRefusal::NoRule {
surface: StateSurface::Routing
}]
);
}
#[test]
fn an_empty_table_refuses_everything() {
let c = StateCandidate::new(StateSurface::Memory, "m1", CommitAuthority::Execution)
.committed_by(CommitAuthority::Review)
.with_verdicts([tests_pass()]);
assert!(!admit_state(&OwnershipTable::new(), &c).admitted);
}
#[test]
fn evidence_plus_the_owning_committer_admits() {
let c = StateCandidate::new(StateSurface::Memory, "m1", CommitAuthority::Execution)
.committed_by(CommitAuthority::Review)
.with_verdicts([tests_pass()]);
let d = admit_state(&table(), &c);
assert!(d.admitted, "{:?}", d.refusals);
assert_eq!(d.id, "m1");
assert_eq!(d.surface, StateSurface::Memory);
}
#[test]
fn authority_without_evidence_is_refused() {
let c = StateCandidate::new(StateSurface::Memory, "m1", CommitAuthority::Execution)
.committed_by(CommitAuthority::Review);
let d = admit_state(&table(), &c);
assert!(!d.admitted);
assert!(matches!(
d.refusals.as_slice(),
[AdmissionRefusal::InsufficientEvidence { .. }]
));
}
#[test]
fn evidence_without_a_committer_is_refused() {
let c = StateCandidate::new(StateSurface::Memory, "m1", CommitAuthority::Execution)
.with_verdicts([tests_pass()]);
let d = admit_state(&table(), &c);
assert!(!d.admitted);
assert_eq!(d.refusals, vec![AdmissionRefusal::NotCommitted]);
}
#[test]
fn the_wrong_committer_is_refused_even_with_good_evidence() {
let c = StateCandidate::new(StateSurface::Memory, "m1", CommitAuthority::Execution)
.committed_by(CommitAuthority::Coordination)
.with_verdicts([tests_pass()]);
let d = admit_state(&table(), &c);
assert!(!d.admitted);
assert_eq!(
d.refusals,
vec![AdmissionRefusal::WrongCommitter {
expected: CommitAuthority::Review,
actual: CommitAuthority::Coordination,
}]
);
}
#[test]
fn self_commit_is_refused_where_forbidden_however_good_the_evidence() {
let c = StateCandidate::new(StateSurface::Memory, "m1", CommitAuthority::Execution)
.committed_by(CommitAuthority::Execution)
.with_verdicts([tests_pass()]);
let d = admit_state(&table(), &c);
assert!(!d.admitted);
assert_eq!(
d.refusals,
vec![AdmissionRefusal::SelfCommitForbidden {
role: CommitAuthority::Execution
}]
);
}
#[test]
fn self_commit_is_allowed_where_permitted_and_evidence_passes() {
let c = StateCandidate::new(StateSurface::Tasks, "t1", CommitAuthority::Execution)
.committed_by(CommitAuthority::Execution)
.with_verdicts([tests_pass()]);
let d = admit_state(&table(), &c);
assert!(d.admitted, "{:?}", d.refusals);
}
#[test]
fn self_commit_without_passing_evidence_is_refused() {
let c = StateCandidate::new(StateSurface::Tasks, "t1", CommitAuthority::Execution)
.committed_by(CommitAuthority::Execution);
let d = admit_state(&table(), &c);
assert!(!d.admitted);
assert!(d.refusals.contains(&AdmissionRefusal::WrongCommitter {
expected: CommitAuthority::Scheduling,
actual: CommitAuthority::Execution,
}));
assert!(d
.refusals
.iter()
.any(|r| matches!(r, AdmissionRefusal::InsufficientEvidence { .. })));
}
#[test]
fn a_failing_authoritative_verdict_is_reported_as_rejection_not_a_gap() {
let c = StateCandidate::new(StateSurface::Memory, "m1", CommitAuthority::Execution)
.committed_by(CommitAuthority::Review)
.with_verdicts([tests_fail()]);
let d = admit_state(&table(), &c);
assert!(!d.admitted);
assert_eq!(
d.refusals,
vec![AdmissionRefusal::EvidenceRejected {
failures: vec!["cargo_test".to_string()]
}]
);
}
#[test]
fn an_unexpected_producer_is_refused() {
let c = StateCandidate::new(StateSurface::Memory, "m1", CommitAuthority::SystemConfig)
.committed_by(CommitAuthority::Review)
.with_verdicts([tests_pass()]);
let d = admit_state(&table(), &c);
assert!(!d.admitted);
assert!(d.refusals.contains(&AdmissionRefusal::UnexpectedProducer {
expected: CommitAuthority::Execution,
actual: CommitAuthority::SystemConfig,
}));
}
#[test]
fn refusals_accumulate_rather_than_short_circuit() {
let c = StateCandidate::new(StateSurface::Memory, "m1", CommitAuthority::SystemConfig)
.committed_by(CommitAuthority::Coordination);
let d = admit_state(&table(), &c);
assert_eq!(d.refusals.len(), 3, "{:?}", d.refusals);
}
#[test]
fn an_advisory_verdict_cannot_satisfy_a_requirement() {
let mut judge = VerifierDescriptor::binding("model_judge", "tests");
judge.authority = crate::VerifierAuthority::Advisory;
judge.tier = EvidenceTier::Heuristic;
let c = StateCandidate::new(StateSurface::Memory, "m1", CommitAuthority::Execution)
.committed_by(CommitAuthority::Review)
.with_verdicts([VerifierVerdict::pass(judge)]);
let d = admit_state(&table(), &c);
assert!(!d.admitted);
assert!(d
.refusals
.iter()
.any(|r| matches!(r, AdmissionRefusal::InsufficientEvidence { .. })));
}
#[test]
fn a_skipped_verdict_never_satisfies() {
let mut v = tests_pass();
v.outcome = VerifierOutcome::Skipped;
let c = StateCandidate::new(StateSurface::Memory, "m1", CommitAuthority::Execution)
.committed_by(CommitAuthority::Review)
.with_verdicts([v]);
assert!(!admit_state(&table(), &c).admitted);
}
#[test]
fn is_ungated_finds_the_surfaces_that_only_look_governed() {
let sloppy = SurfaceRule {
surface: StateSurface::Tools,
produced_by: CommitAuthority::SystemConfig,
committed_by: CommitAuthority::SystemConfig,
self_commit: SelfCommit::WithPassingEvidence,
requires: Vec::new(),
};
assert!(sloppy.is_ungated());
assert!(!memory_rule().is_ungated());
let t = table().with(sloppy);
assert_eq!(t.ungated_surfaces(), vec![StateSurface::Tools]);
}
#[test]
fn an_ungated_rule_does_admit_a_self_commit_with_nothing_attached() {
let t = OwnershipTable::new().with(SurfaceRule {
surface: StateSurface::Tools,
produced_by: CommitAuthority::SystemConfig,
committed_by: CommitAuthority::SystemConfig,
self_commit: SelfCommit::WithPassingEvidence,
requires: Vec::new(),
});
let c = StateCandidate::new(StateSurface::Tools, "t1", CommitAuthority::SystemConfig)
.committed_by(CommitAuthority::SystemConfig);
assert!(admit_state(&t, &c).admitted);
}
#[test]
fn one_surface_cannot_hold_two_contradictory_rules() {
let mut t = OwnershipTable::new().with(memory_rule());
let mut replacement = memory_rule();
replacement.committed_by = CommitAuthority::Coordination;
t.set(replacement.clone());
assert_eq!(t.rules().count(), 1);
assert_eq!(t.rule(StateSurface::Memory), Some(&replacement));
}
#[test]
fn admit_state_is_deterministic() {
let c = StateCandidate::new(StateSurface::Memory, "m1", CommitAuthority::SystemConfig)
.committed_by(CommitAuthority::Coordination);
assert_eq!(admit_state(&table(), &c), admit_state(&table(), &c));
}
#[test]
fn labels_match_serde_representation() {
assert_eq!(
serde_json::to_value(StateSurface::Verification).unwrap(),
serde_json::json!(StateSurface::Verification.as_str())
);
assert_eq!(
serde_json::to_value(CommitAuthority::SystemConfig).unwrap(),
serde_json::json!(CommitAuthority::SystemConfig.as_str())
);
}
#[test]
fn a_table_round_trips_through_serde() {
let t = table();
let back: OwnershipTable =
serde_json::from_str(&serde_json::to_string(&t).unwrap()).unwrap();
assert_eq!(back, t);
}
}