#![allow(missing_docs)]
use mempill_types::{Cardinality, Claim, Disposition, ProvenanceLabel};
use crate::config::EngineConfig;
#[derive(Debug, Clone)]
pub(crate) struct Proposal {
pub candidate: Claim,
pub incumbent: Option<mempill_types::Belief>,
pub conflict_type: ConflictType,
pub measured_confidence: f32,
pub cardinality_proposal: Cardinality,
pub oracle_present: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum ConflictType {
NoConflict,
SameLineConflict,
CrossLineConflict,
DependsOnSuperseded,
Succession,
}
#[derive(Debug, Clone)]
pub(crate) struct GateDecision {
pub route: Route,
pub disposition: Disposition,
pub rationale: serde_json::Value,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum Route {
CheapPath,
Inferred,
RecallTainted,
HeavyPath,
Quarantine,
}
pub(crate) fn adjudicate(proposal: &Proposal, config: &EngineConfig) -> GateDecision {
if proposal.candidate.provenance().is_recall_reentry() {
return GateDecision {
route: Route::RecallTainted,
disposition: Disposition::CommittedCheap,
rationale: serde_json::json!({ "route": "recall_reentry" }),
};
}
if is_temporally_incoherent(&proposal.candidate, config) {
return GateDecision {
route: Route::Quarantine,
disposition: Disposition::Quarantined,
rationale: serde_json::json!({
"route": "quarantine",
"reason": "incoherent_temporal_window",
}),
};
}
if *proposal.candidate.provenance() == ProvenanceLabel::ModelDerived {
return GateDecision {
route: Route::Inferred,
disposition: Disposition::CommittedInferred,
rationale: serde_json::json!({
"route": "inferred",
"derivation_depth": proposal.candidate.external_anchor().derivation_depth,
}),
};
}
if proposal.conflict_type == ConflictType::NoConflict || proposal.incumbent.is_none() {
return GateDecision {
route: Route::CheapPath,
disposition: Disposition::CommittedCheap,
rationale: serde_json::json!({ "route": "cheap_path" }),
};
}
if proposal.conflict_type == ConflictType::Succession {
return GateDecision {
route: Route::CheapPath,
disposition: Disposition::CommittedCheap,
rationale: serde_json::json!({
"route": "succession_cheap_path",
"reason": "trusted_temporal_succession",
}),
};
}
let is_fresh_external_contradiction = proposal.candidate.provenance().is_cheap_path_eligible()
&& matches!(
proposal.conflict_type,
ConflictType::SameLineConflict | ConflictType::CrossLineConflict
);
if is_fresh_external_contradiction && !proposal.oracle_present {
return GateDecision {
route: Route::HeavyPath,
disposition: Disposition::Contested,
rationale: serde_json::json!({
"route": "heavy_path_contested_oracle_absent",
"conflict_type": format!("{:?}", proposal.conflict_type),
"measured_confidence": proposal.measured_confidence,
"oracle_present": false,
}),
};
}
GateDecision {
route: Route::HeavyPath,
disposition: Disposition::QueuedForAdjudication,
rationale: serde_json::json!({
"route": "heavy_path",
"conflict_type": format!("{:?}", proposal.conflict_type),
"corroboration_count": 0, "measured_confidence": proposal.measured_confidence,
"oracle_present": proposal.oracle_present,
}),
}
}
fn is_temporally_incoherent(claim: &Claim, config: &EngineConfig) -> bool {
if claim.valid_time().valid_time_confidence < config.valid_time_confidence_threshold {
return false; }
if let (Some(start), Some(end)) = (&claim.valid_time().start, &claim.valid_time().end) {
if start > end {
return true;
}
}
if let Some(start) = &claim.valid_time().start {
if start > &claim.transaction_time().0 {
return true;
}
}
false
}
#[cfg(test)]
mod tests {
use super::*;
use mempill_types::{
AgentId, Cardinality, Claim, ClaimRef, Confidence, Criticality, ExternalAnchor,
ExternalKind, Fact, ProvenanceLabel, TransactionTime, ValidTime,
};
use chrono::{TimeZone, Utc};
fn tx_time_at(year: i32, month: u32, day: u32) -> TransactionTime {
TransactionTime(Utc.with_ymd_and_hms(year, month, day, 0, 0, 0).unwrap())
}
fn make_claim(
provenance: ProvenanceLabel,
valid_time: ValidTime,
tx_time: TransactionTime,
) -> Claim {
Claim::new(
ClaimRef::new_random(),
AgentId("agent-1".into()),
Fact {
subject: "user".into(),
predicate: "location".into(),
value: serde_json::json!("Paris"),
},
Cardinality::Functional,
provenance,
ExternalAnchor {
nearest_external_anchor: None,
derivation_depth: 0,
},
tx_time,
valid_time,
Confidence {
value_confidence: 0.9,
valid_time_confidence: 0.9,
},
Criticality::Medium,
vec![],
None,
None,
)
}
fn external_claim(valid_time: ValidTime, tx_time: TransactionTime) -> Claim {
make_claim(
ProvenanceLabel::External(ExternalKind::ExternalFirstHand),
valid_time,
tx_time,
)
}
fn model_derived_claim() -> Claim {
make_claim(
ProvenanceLabel::ModelDerived,
ValidTime { start: None, end: None, valid_time_confidence: 0.0 },
tx_time_at(2026, 1, 1),
)
}
fn recall_reentry_claim() -> Claim {
make_claim(
ProvenanceLabel::RecallReEntry,
ValidTime { start: None, end: None, valid_time_confidence: 0.0 },
tx_time_at(2026, 1, 1),
)
}
fn no_conflict_proposal(claim: Claim) -> Proposal {
Proposal {
candidate: claim,
incumbent: None,
conflict_type: ConflictType::NoConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
}
}
fn config() -> EngineConfig {
EngineConfig::default() }
#[test]
fn adjudicate_is_deterministic_same_inputs_same_output() {
let tx = tx_time_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = external_claim(vt, tx);
let proposal = no_conflict_proposal(claim);
let cfg = config();
let d1 = adjudicate(&proposal, &cfg);
let d2 = adjudicate(&proposal, &cfg);
assert_eq!(d1.route, d2.route);
assert_eq!(d1.disposition, d2.disposition);
assert_eq!(d1.rationale.to_string(), d2.rationale.to_string());
}
#[test]
fn adjudicate_deterministic_across_multiple_fixed_input_sets() {
let cfg = config();
let tx = tx_time_at(2026, 6, 1);
let inputs: Vec<Proposal> = vec![
no_conflict_proposal(external_claim(
ValidTime { start: None, end: None, valid_time_confidence: 0.0 },
tx.clone(),
)),
no_conflict_proposal(model_derived_claim()),
no_conflict_proposal(recall_reentry_claim()),
];
for proposal in &inputs {
let d1 = adjudicate(proposal, &cfg);
let d2 = adjudicate(proposal, &cfg);
assert_eq!(
d1.rationale.to_string(),
d2.rationale.to_string(),
"non-deterministic for route {:?}",
d1.route
);
assert_eq!(d1.route, d2.route);
assert_eq!(d1.disposition, d2.disposition);
}
}
#[test]
fn b7_start_after_end_is_quarantined() {
let tx = tx_time_at(2026, 6, 1);
let start = Utc.with_ymd_and_hms(2026, 5, 10, 0, 0, 0).unwrap();
let end = Utc.with_ymd_and_hms(2026, 5, 1, 0, 0, 0).unwrap(); let vt = ValidTime {
start: Some(start),
end: Some(end),
valid_time_confidence: 0.9, };
let claim = external_claim(vt, tx);
let proposal = no_conflict_proposal(claim);
let decision = adjudicate(&proposal, &config());
assert_eq!(decision.route, Route::Quarantine);
assert_eq!(decision.disposition, Disposition::Quarantined);
}
#[test]
fn b7_valid_time_start_after_tx_time_is_quarantined() {
let tx = tx_time_at(2026, 1, 1);
let future_start = Utc.with_ymd_and_hms(2026, 6, 1, 0, 0, 0).unwrap(); let vt = ValidTime {
start: Some(future_start),
end: None,
valid_time_confidence: 0.9, };
let claim = external_claim(vt, tx);
let proposal = no_conflict_proposal(claim);
let decision = adjudicate(&proposal, &config());
assert_eq!(decision.route, Route::Quarantine, "valid_time_start > tx_time must quarantine");
assert_eq!(decision.disposition, Disposition::Quarantined);
}
#[test]
fn b7_low_confidence_valid_time_not_quarantined() {
let tx = tx_time_at(2026, 1, 1);
let future_start = Utc.with_ymd_and_hms(2026, 12, 1, 0, 0, 0).unwrap();
let vt = ValidTime {
start: Some(future_start),
end: None,
valid_time_confidence: 0.3, };
let claim = external_claim(vt, tx);
let proposal = no_conflict_proposal(claim);
let decision = adjudicate(&proposal, &config());
assert_eq!(decision.route, Route::CheapPath);
assert_eq!(decision.disposition, Disposition::CommittedCheap);
}
#[test]
fn b7_coherent_temporal_window_passes() {
let tx = tx_time_at(2026, 6, 1);
let start = Utc.with_ymd_and_hms(2025, 1, 1, 0, 0, 0).unwrap(); let end = Utc.with_ymd_and_hms(2026, 5, 1, 0, 0, 0).unwrap(); let vt = ValidTime {
start: Some(start),
end: Some(end),
valid_time_confidence: 0.9,
};
let claim = external_claim(vt, tx);
let proposal = no_conflict_proposal(claim);
let decision = adjudicate(&proposal, &config());
assert_eq!(decision.route, Route::CheapPath);
assert_eq!(decision.disposition, Disposition::CommittedCheap);
}
fn incumbent_belief() -> mempill_types::Belief {
use mempill_types::{CurrencySignal, CurrencyState};
mempill_types::Belief {
claim_ref: ClaimRef::new_random(),
fact: Fact {
subject: "user".into(),
predicate: "location".into(),
value: serde_json::json!("Berlin"),
},
provenance: ProvenanceLabel::External(ExternalKind::UserAsserted),
valid_time: ValidTime { start: None, end: None, valid_time_confidence: 0.0 },
transaction_time: tx_time_at(2025, 1, 1),
confidence: Confidence { value_confidence: 0.8, valid_time_confidence: 0.0 },
currency_signal: CurrencySignal {
last_refreshed_at: tx_time_at(2025, 1, 1),
state: CurrencyState::Fresh,
corroboration_count: 0,
},
criticality: Criticality::Medium,
}
}
#[test]
fn b11_fresh_external_oracle_absent_routes_to_contested() {
let tx = tx_time_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = external_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent_belief()),
conflict_type: ConflictType::SameLineConflict,
measured_confidence: 0.85,
cardinality_proposal: Cardinality::Functional,
oracle_present: false, };
let decision = adjudicate(&proposal, &config());
assert_eq!(decision.route, Route::HeavyPath);
assert_eq!(decision.disposition, Disposition::Contested,
"oracle absent + fresh external contradiction MUST route to Contested immediately (B11)");
}
#[test]
fn b11_fresh_external_oracle_present_routes_to_queued() {
let tx = tx_time_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = external_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent_belief()),
conflict_type: ConflictType::SameLineConflict,
measured_confidence: 0.85,
cardinality_proposal: Cardinality::Functional,
oracle_present: true, };
let decision = adjudicate(&proposal, &config());
assert_eq!(decision.route, Route::HeavyPath);
assert_eq!(decision.disposition, Disposition::QueuedForAdjudication,
"oracle present should route to QueuedForAdjudication, not Contested");
}
#[test]
fn b11_cross_line_conflict_oracle_absent_routes_to_contested() {
let tx = tx_time_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = external_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent_belief()),
conflict_type: ConflictType::CrossLineConflict,
measured_confidence: 0.7,
cardinality_proposal: Cardinality::SetValued,
oracle_present: false,
};
let decision = adjudicate(&proposal, &config());
assert_eq!(decision.disposition, Disposition::Contested);
}
#[test]
fn corroboration_does_not_change_route_vs_same_case_without_corroboration() {
let tx = tx_time_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim_a = external_claim(vt.clone(), tx.clone());
let claim_b = external_claim(vt.clone(), tx.clone());
let proposal_a = Proposal {
candidate: claim_a,
incumbent: Some(incumbent_belief()),
conflict_type: ConflictType::SameLineConflict,
measured_confidence: 0.85,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let proposal_b = Proposal {
candidate: claim_b,
incumbent: Some(incumbent_belief()),
conflict_type: ConflictType::SameLineConflict,
measured_confidence: 0.85,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d_a = adjudicate(&proposal_a, &config());
let d_b = adjudicate(&proposal_b, &config());
assert_eq!(d_a.route, d_b.route, "corroboration must not change route");
assert_eq!(d_a.disposition, d_b.disposition, "corroboration must not change disposition");
}
#[test]
fn cheap_path_requires_external_provenance() {
let proposal = no_conflict_proposal(model_derived_claim());
let decision = adjudicate(&proposal, &config());
assert_eq!(decision.route, Route::Inferred);
assert_eq!(decision.disposition, Disposition::CommittedInferred);
assert_ne!(decision.route, Route::CheapPath);
}
#[test]
fn recall_reentry_is_not_cheap_path_eligible() {
let proposal = no_conflict_proposal(recall_reentry_claim());
let decision = adjudicate(&proposal, &config());
assert_eq!(decision.route, Route::RecallTainted);
assert_ne!(decision.route, Route::CheapPath);
}
#[test]
fn external_no_conflict_takes_cheap_path() {
let tx = tx_time_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = external_claim(vt, tx);
let proposal = no_conflict_proposal(claim);
let decision = adjudicate(&proposal, &config());
assert_eq!(decision.route, Route::CheapPath);
assert_eq!(decision.disposition, Disposition::CommittedCheap);
}
#[test]
fn proposal_carries_oracle_present_field() {
let tx = tx_time_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = external_claim(vt, tx);
let p = Proposal {
candidate: claim,
incumbent: None,
conflict_type: ConflictType::NoConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: true,
};
assert!(p.oracle_present, "oracle_present must be readable as a Proposal field (A24)");
}
}
#[cfg(test)]
mod adversarial {
use super::*;
use mempill_types::{
AgentId, Cardinality, Claim, ClaimRef, Confidence, Criticality, CurrencySignal,
CurrencyState, ExternalAnchor, ExternalKind, Fact, ProvenanceLabel, TransactionTime,
ValidTime,
};
use chrono::{TimeZone, Utc};
fn tx_at(year: i32, month: u32, day: u32) -> TransactionTime {
TransactionTime(Utc.with_ymd_and_hms(year, month, day, 0, 0, 0).unwrap())
}
fn dt(year: i32, month: u32, day: u32) -> chrono::DateTime<chrono::Utc> {
Utc.with_ymd_and_hms(year, month, day, 0, 0, 0).unwrap()
}
fn make_claim_with_confidence(
provenance: ProvenanceLabel,
valid_time: ValidTime,
tx_time: TransactionTime,
vt_confidence: f32,
) -> Claim {
Claim::new(
ClaimRef::new_random(),
AgentId("agent-adv".into()),
Fact {
subject: "subject".into(),
predicate: "predicate".into(),
value: serde_json::json!("value"),
},
Cardinality::Functional,
provenance,
ExternalAnchor { nearest_external_anchor: None, derivation_depth: 0 },
tx_time,
valid_time,
Confidence { value_confidence: 0.9, valid_time_confidence: vt_confidence },
Criticality::Medium,
vec![],
None,
None,
)
}
fn ext_claim(vt: ValidTime, tx: TransactionTime) -> Claim {
let vt_conf = vt.valid_time_confidence;
make_claim_with_confidence(
ProvenanceLabel::External(ExternalKind::ExternalFirstHand),
vt,
tx,
vt_conf,
)
}
fn user_asserted_claim(vt: ValidTime, tx: TransactionTime) -> Claim {
let vt_conf = vt.valid_time_confidence;
make_claim_with_confidence(
ProvenanceLabel::External(ExternalKind::UserAsserted),
vt,
tx,
vt_conf,
)
}
fn recall_claim() -> Claim {
make_claim_with_confidence(
ProvenanceLabel::RecallReEntry,
ValidTime { start: None, end: None, valid_time_confidence: 0.0 },
tx_at(2026, 1, 1),
0.0,
)
}
fn model_claim() -> Claim {
make_claim_with_confidence(
ProvenanceLabel::ModelDerived,
ValidTime { start: None, end: None, valid_time_confidence: 0.0 },
tx_at(2026, 1, 1),
0.0,
)
}
fn incumbent() -> mempill_types::Belief {
mempill_types::Belief {
claim_ref: ClaimRef::new_random(),
fact: Fact {
subject: "subject".into(),
predicate: "predicate".into(),
value: serde_json::json!("old_value"),
},
provenance: ProvenanceLabel::External(ExternalKind::UserAsserted),
valid_time: ValidTime { start: None, end: None, valid_time_confidence: 0.0 },
transaction_time: tx_at(2025, 1, 1),
confidence: Confidence { value_confidence: 0.8, valid_time_confidence: 0.0 },
currency_signal: CurrencySignal {
last_refreshed_at: tx_at(2025, 1, 1),
state: CurrencyState::Fresh,
corroboration_count: 0,
},
criticality: Criticality::Medium,
}
}
fn cfg() -> EngineConfig {
EngineConfig::default() }
#[test]
fn p1_repeated_calls_same_proposal_always_identical() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = ext_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()),
conflict_type: ConflictType::SameLineConflict,
measured_confidence: 0.88,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let reference = adjudicate(&proposal, &cfg());
for i in 0..100 {
let d = adjudicate(&proposal, &cfg());
assert_eq!(d.route, reference.route, "non-deterministic route on iteration {i}");
assert_eq!(d.disposition, reference.disposition,
"non-deterministic disposition on iteration {i}");
assert_eq!(d.rationale.to_string(), reference.rationale.to_string(),
"non-deterministic rationale JSON on iteration {i}");
}
}
#[test]
fn p1_rationale_json_key_order_is_stable() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = ext_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()),
conflict_type: ConflictType::SameLineConflict,
measured_confidence: 0.75,
cardinality_proposal: Cardinality::Functional,
oracle_present: true,
};
let d1 = adjudicate(&proposal, &cfg());
let d2 = adjudicate(&proposal, &cfg());
assert_eq!(d1.rationale.to_string(), d2.rationale.to_string(),
"rationale JSON key order must be stable (G1 replay basis)");
}
#[test]
fn p1_heavy_path_contested_rationale_is_deterministic() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
for conflict_type in [ConflictType::SameLineConflict, ConflictType::CrossLineConflict] {
let claim = ext_claim(vt.clone(), tx.clone());
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()),
conflict_type: conflict_type.clone(),
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d1 = adjudicate(&proposal, &cfg());
let d2 = adjudicate(&proposal, &cfg());
assert_eq!(d1.rationale.to_string(), d2.rationale.to_string(),
"rationale non-deterministic for {conflict_type:?}");
}
}
#[test]
fn p2_start_equals_end_is_not_quarantined() {
let tx = tx_at(2026, 6, 1);
let instant = dt(2025, 3, 15);
let vt = ValidTime {
start: Some(instant),
end: Some(instant),
valid_time_confidence: 0.9,
};
let claim = ext_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: None,
conflict_type: ConflictType::NoConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_ne!(d.route, Route::Quarantine,
"start == end is a valid zero-duration window; must NOT be quarantined (B7 only fires on start > end)");
assert_eq!(d.route, Route::CheapPath);
}
#[test]
fn p2_start_equals_tx_time_is_not_quarantined() {
let tx = tx_at(2026, 6, 1);
let same_moment = dt(2026, 6, 1); let vt = ValidTime {
start: Some(same_moment),
end: None,
valid_time_confidence: 0.9,
};
let claim = ext_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: None,
conflict_type: ConflictType::NoConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_ne!(d.route, Route::Quarantine,
"start == tx_time is allowed (B7 only fires on start > tx_time, not >=)");
assert_eq!(d.route, Route::CheapPath);
}
#[test]
fn p2_confidence_exactly_at_threshold_triggers_temporal_check() {
let tx = tx_at(2026, 1, 1);
let future_start = dt(2026, 12, 1); let vt = ValidTime {
start: Some(future_start),
end: None,
valid_time_confidence: 0.7, };
let claim = ext_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: None,
conflict_type: ConflictType::NoConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_eq!(d.route, Route::Quarantine,
"confidence == 0.7 (threshold) must NOT bypass temporal check; incoherent window must quarantine");
}
#[test]
fn p2_confidence_just_below_threshold_bypasses_temporal_check() {
let tx = tx_at(2026, 1, 1);
let future_start = dt(2026, 12, 1); let vt = ValidTime {
start: Some(future_start),
end: None,
valid_time_confidence: 0.6999, };
let claim = ext_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: None,
conflict_type: ConflictType::NoConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_ne!(d.route, Route::Quarantine,
"confidence 0.6999 < 0.7 (threshold): temporal check must be skipped; claim must not quarantine");
assert_eq!(d.route, Route::CheapPath);
}
#[test]
fn p2_far_past_start_far_future_end_is_coherent() {
let tx = tx_at(2026, 6, 1);
let far_past = dt(1900, 1, 1);
let far_future = dt(9999, 12, 31);
let vt = ValidTime {
start: Some(far_past),
end: Some(far_future),
valid_time_confidence: 0.9,
};
let claim = ext_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: None,
conflict_type: ConflictType::NoConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_eq!(d.route, Route::CheapPath,
"wide but coherent valid-time window must not quarantine");
}
#[test]
fn p2_recall_reentry_with_incoherent_window_bypasses_quarantine() {
let tx = tx_at(2026, 1, 1);
let future_start = dt(2026, 12, 1); let vt = ValidTime {
start: Some(future_start),
end: None,
valid_time_confidence: 0.9,
};
let claim = make_claim_with_confidence(
ProvenanceLabel::RecallReEntry,
vt,
tx,
0.9,
);
let proposal = Proposal {
candidate: claim,
incumbent: None,
conflict_type: ConflictType::NoConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_eq!(d.route, Route::RecallTainted,
"RecallReEntry is caught at step 1 before temporal check (§6 ordering); must not quarantine");
assert_eq!(d.disposition, Disposition::CommittedCheap);
}
#[test]
fn p2_model_derived_with_incoherent_window_is_quarantined_not_inferred() {
let tx = tx_at(2026, 1, 1);
let future_start = dt(2026, 12, 1); let vt = ValidTime {
start: Some(future_start),
end: None,
valid_time_confidence: 0.9,
};
let claim = make_claim_with_confidence(
ProvenanceLabel::ModelDerived,
vt,
tx,
0.9,
);
let proposal = Proposal {
candidate: claim,
incumbent: None,
conflict_type: ConflictType::NoConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_eq!(d.route, Route::Quarantine,
"ModelDerived with incoherent temporal window must quarantine (step 2 before step 3)");
assert_ne!(d.route, Route::Inferred,
"incoherent ModelDerived must NOT silently route to Inferred");
}
#[test]
fn p3_user_asserted_same_line_oracle_absent_routes_to_contested() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = user_asserted_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()),
conflict_type: ConflictType::SameLineConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_eq!(d.route, Route::HeavyPath);
assert_eq!(d.disposition, Disposition::Contested,
"UserAsserted is External(*) and thus cheap-path eligible; B11(a) must fire");
}
#[test]
fn p3_user_asserted_cross_line_oracle_absent_routes_to_contested() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = user_asserted_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()),
conflict_type: ConflictType::CrossLineConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_eq!(d.disposition, Disposition::Contested,
"CrossLineConflict + UserAsserted + oracle absent must be Contested (B11a)");
}
#[test]
fn p3_depends_on_superseded_oracle_absent_routes_to_queued_not_contested() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = ext_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()),
conflict_type: ConflictType::DependsOnSuperseded,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_eq!(d.route, Route::HeavyPath);
assert_eq!(d.disposition, Disposition::QueuedForAdjudication,
"DependsOnSuperseded is NOT a fresh contradiction; B11(a) must not fire; expect QueuedForAdjudication");
assert_ne!(d.disposition, Disposition::Contested,
"B11(a) must not over-fire for DependsOnSuperseded");
}
#[test]
fn p3_depends_on_superseded_oracle_present_routes_to_queued() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = ext_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()),
conflict_type: ConflictType::DependsOnSuperseded,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: true,
};
let d = adjudicate(&proposal, &cfg());
assert_eq!(d.disposition, Disposition::QueuedForAdjudication);
}
#[test]
fn p3_oracle_present_true_never_produces_contested() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
for conflict_type in [
ConflictType::SameLineConflict,
ConflictType::CrossLineConflict,
ConflictType::DependsOnSuperseded,
ConflictType::Succession,
] {
let claim = ext_claim(vt.clone(), tx.clone());
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()),
conflict_type: conflict_type.clone(),
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: true,
};
let d = adjudicate(&proposal, &cfg());
assert_ne!(d.disposition, Disposition::Contested,
"oracle_present=true must NEVER produce Contested (B11b); fired for {conflict_type:?}");
}
}
#[test]
fn p3_model_derived_conflict_oracle_absent_routes_to_inferred_not_contested() {
let claim = model_claim();
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()),
conflict_type: ConflictType::SameLineConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_eq!(d.route, Route::Inferred,
"ModelDerived is caught at step 3 before step 5; heavy path must not fire");
assert_ne!(d.disposition, Disposition::Contested,
"ModelDerived must NEVER produce Contested (V3-4)");
}
#[test]
fn p4_high_confidence_implying_corroboration_does_not_flip_route() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim_low = ext_claim(vt.clone(), tx.clone());
let proposal_low = Proposal {
candidate: claim_low,
incumbent: Some(incumbent()),
conflict_type: ConflictType::SameLineConflict,
measured_confidence: 0.5,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let claim_high = ext_claim(vt.clone(), tx.clone());
let proposal_high = Proposal {
candidate: claim_high,
incumbent: Some(incumbent()),
conflict_type: ConflictType::SameLineConflict,
measured_confidence: 0.999,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d_low = adjudicate(&proposal_low, &cfg());
let d_high = adjudicate(&proposal_high, &cfg());
assert_eq!(d_low.route, d_high.route,
"measured_confidence (proxy for corroboration) must not change Route");
assert_eq!(d_low.disposition, d_high.disposition,
"measured_confidence must not change Disposition");
}
#[test]
fn p4_rationale_records_corroboration_count_zero_always() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = ext_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()),
conflict_type: ConflictType::SameLineConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: true, };
let d = adjudicate(&proposal, &cfg());
let corr = d.rationale.get("corroboration_count");
assert!(
corr.is_some() && corr.unwrap() == 0,
"corroboration_count must be 0 in rationale (modifier-only, no gate input). Got: {:?}",
d.rationale
);
}
#[test]
fn p4_measured_confidence_only_affects_rationale_not_route() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let confidences = [0.0f32, 0.5, 0.7, 0.99, 1.0];
let routes: Vec<Route> = confidences.iter().map(|&mc| {
let claim = ext_claim(vt.clone(), tx.clone());
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()),
conflict_type: ConflictType::SameLineConflict,
measured_confidence: mc,
cardinality_proposal: Cardinality::Functional,
oracle_present: true,
};
adjudicate(&proposal, &cfg()).route
}).collect();
let first = &routes[0];
for (i, route) in routes.iter().enumerate() {
assert_eq!(route, first,
"measured_confidence[{}]={} produced different route {:?} vs {:?}",
i, confidences[i], route, first);
}
}
#[test]
fn p5_all_conflict_types_produce_valid_route_no_panic() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let all_conflict_types = [
ConflictType::NoConflict,
ConflictType::SameLineConflict,
ConflictType::CrossLineConflict,
ConflictType::DependsOnSuperseded,
ConflictType::Succession,
];
for conflict_type in &all_conflict_types {
for oracle_present in [false, true] {
let claim = ext_claim(vt.clone(), tx.clone());
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()),
conflict_type: conflict_type.clone(),
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present,
};
let d = adjudicate(&proposal, &cfg());
let valid = matches!(
d.route,
Route::CheapPath
| Route::Inferred
| Route::RecallTainted
| Route::HeavyPath
| Route::Quarantine
);
assert!(valid,
"unexpected/invalid route {:?} for {:?} oracle={}", d.route, conflict_type, oracle_present);
}
}
}
#[test]
fn p5_all_provenance_types_no_conflict_no_incumbent_produce_valid_route() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let provenances = [
ProvenanceLabel::External(ExternalKind::ExternalFirstHand),
ProvenanceLabel::External(ExternalKind::UserAsserted),
ProvenanceLabel::RecallReEntry,
ProvenanceLabel::ModelDerived,
];
for prov in &provenances {
let claim = make_claim_with_confidence(prov.clone(), vt.clone(), tx.clone(), 0.0);
let proposal = Proposal {
candidate: claim,
incumbent: None,
conflict_type: ConflictType::NoConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
let valid = matches!(
d.route,
Route::CheapPath | Route::Inferred | Route::RecallTainted | Route::HeavyPath | Route::Quarantine
);
assert!(valid, "invalid route for provenance {:?}: {:?}", prov, d.route);
}
}
#[test]
fn p5_no_conflict_with_incumbent_still_routes_cheap_path() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = ext_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()), conflict_type: ConflictType::NoConflict, measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_eq!(d.route, Route::CheapPath,
"NoConflict with incumbent present must still take CheapPath (step 4: NoConflict OR no incumbent)");
assert_eq!(d.disposition, Disposition::CommittedCheap);
}
#[test]
fn p5_same_line_conflict_no_incumbent_routes_cheap_path() {
let tx = tx_at(2026, 6, 1);
let vt = ValidTime { start: None, end: None, valid_time_confidence: 0.0 };
let claim = ext_claim(vt, tx);
let proposal = Proposal {
candidate: claim,
incumbent: None, conflict_type: ConflictType::SameLineConflict, measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_eq!(d.route, Route::CheapPath,
"SameLineConflict with no incumbent must route CheapPath (step 4: incumbent.is_none())");
}
#[test]
fn p5_recall_reentry_with_heavy_conflict_type_still_routes_recall_tainted() {
let claim = recall_claim();
let proposal = Proposal {
candidate: claim,
incumbent: Some(incumbent()),
conflict_type: ConflictType::SameLineConflict,
measured_confidence: 0.9,
cardinality_proposal: Cardinality::Functional,
oracle_present: false,
};
let d = adjudicate(&proposal, &cfg());
assert_eq!(d.route, Route::RecallTainted,
"RecallReEntry is always caught at step 1; must not reach heavy path even with SameLineConflict");
assert_eq!(d.disposition, Disposition::CommittedCheap);
}
}