use std::collections::HashMap;
use std::fmt;
const CONDITIONAL_FITNESS_THRESHOLD: f64 = 0.85;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SyncMove;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct LogOnlyMove;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ModelOnlyMove;
#[derive(Debug, Clone, Default)]
pub struct ConformanceVerdicts {
pub fitness: Option<f64>,
pub precision: Option<f64>,
pub generalization: Option<f64>,
pub simplicity: Option<f64>,
pub f1: Option<f64>,
pub deviations: Vec<DeviationRecord>,
}
impl ConformanceVerdicts {
pub fn new() -> Self {
Self::default()
}
pub fn is_perfect(&self) -> bool {
self.deviations.is_empty()
&& matches!(self.fitness, Some(f) if (f - 1.0).abs() < f64::EPSILON)
}
pub fn admission_verdict(&self) -> AdmissionVerdict {
match self.fitness {
Some(f) if f >= 0.95 => AdmissionVerdict::Pass,
Some(f) if f >= CONDITIONAL_FITNESS_THRESHOLD => AdmissionVerdict::Conditional,
Some(f) if f < CONDITIONAL_FITNESS_THRESHOLD => AdmissionVerdict::Reject,
Some(_) => AdmissionVerdict::Unknown,
None => AdmissionVerdict::Unavailable,
}
}
}
impl fmt::Display for ConformanceVerdicts {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let fmt_score = |slot: &Option<f64>| match slot {
Some(v) => format!("{:.2}%", v * 100.0),
None => "—".to_string(),
};
write!(
f,
"fitness={} precision={} generalization={} simplicity={} f1={} deviations={}",
fmt_score(&self.fitness),
fmt_score(&self.precision),
fmt_score(&self.generalization),
fmt_score(&self.simplicity),
fmt_score(&self.f1),
self.deviations.len()
)
}
}
#[derive(Debug, Clone)]
pub struct DeviationRecord {
pub trace_index: usize,
pub log_activity: Option<String>,
pub model_transition: Option<String>,
pub move_type: AlignmentMoveType,
pub cost: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AlignmentMoveType {
SynchronousMove,
LogOnlyMove,
ModelOnlyMove,
}
impl fmt::Display for AlignmentMoveType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AlignmentMoveType::SynchronousMove => write!(f, "sync"),
AlignmentMoveType::LogOnlyMove => write!(f, "log_only"),
AlignmentMoveType::ModelOnlyMove => write!(f, "model_only"),
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct ConformanceWitness;
impl ConformanceWitness {
pub fn new() -> Self {
Self
}
}
impl fmt::Display for ConformanceWitness {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ConformanceAuthority(v30.1.2)")
}
}
#[derive(Debug, Clone)]
pub struct AlignmentReceipt {
pub alignment_id: String,
pub trace_id: String,
pub log_hash: String,
pub model_hash: String,
pub alignment: Vec<(Option<String>, Option<String>, u32)>,
pub total_cost: u32,
pub moves: MoveCounters,
pub tokens: TokenCounters,
pub fitness: f64,
pub heuristic_accuracy: Option<f64>,
pub engine_version: String,
pub timestamp: String,
pub engine_pubkey: String,
pub signature: String,
}
#[derive(Debug, Clone, Copy, Default)]
pub struct MoveCounters {
pub move_on_both: usize,
pub move_on_log: usize,
pub move_on_model: usize,
}
impl MoveCounters {
pub fn total(&self) -> usize {
self.move_on_both + self.move_on_log + self.move_on_model
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct TokenCounters {
pub produced: u64,
pub consumed: u64,
pub missing: u64,
pub remaining: u64,
}
impl TokenCounters {
pub fn compute_fitness(&self) -> Option<f64> {
if self.consumed == 0 || self.produced == 0 {
return None;
}
let component1 = 1.0 - (self.missing as f64 / self.consumed as f64);
let component2 = 1.0 - (self.remaining as f64 / self.produced as f64);
Some(0.5 * component1 + 0.5 * component2)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AdmissionVerdict {
Pass,
Conditional,
Reject,
Unknown,
Unavailable,
}
impl fmt::Display for AdmissionVerdict {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AdmissionVerdict::Pass => write!(f, "PASS (automatic)"),
AdmissionVerdict::Conditional => write!(f, "CONDITIONAL (board override required)"),
AdmissionVerdict::Reject => write!(f, "REJECT (fitness < 0.85)"),
AdmissionVerdict::Unknown => write!(f, "UNKNOWN"),
AdmissionVerdict::Unavailable => write!(f, "UNAVAILABLE (fitness not computed)"),
}
}
}
pub struct ConformanceAdmissionGate {
pub pass_threshold: f64,
pub conditional_threshold: f64,
pub reject_floor: f64,
}
impl ConformanceAdmissionGate {
pub fn new() -> Self {
Self {
pass_threshold: 0.95,
conditional_threshold: CONDITIONAL_FITNESS_THRESHOLD,
reject_floor: CONDITIONAL_FITNESS_THRESHOLD,
}
}
pub fn with_thresholds(pass: f64, conditional: f64, floor: f64) -> Self {
Self {
pass_threshold: pass,
conditional_threshold: conditional,
reject_floor: floor,
}
}
pub fn evaluate(
&self,
verdict: &ConformanceVerdicts,
board_override_signature: Option<&str>,
) -> Result<(), RefusalReport> {
match verdict.fitness {
Some(f) if f >= self.pass_threshold => Ok(()),
Some(f) if f >= self.conditional_threshold => {
if board_override_signature.is_some() {
Ok(())
} else {
Err(RefusalReport::ConditionalMissingOverride { fitness: f })
}
}
Some(f) => Err(RefusalReport::HardReject {
fitness: f,
policy: "van_der_aalst_0_85_floor",
}),
None => Err(RefusalReport::FitnessUnavailable),
}
}
}
#[derive(Debug, Clone)]
pub enum RefusalReport {
FitnessUnavailable,
ConditionalMissingOverride { fitness: f64 },
HardReject { fitness: f64, policy: &'static str },
InvalidOverrideSignature { fitness: f64 },
TraceMissing { trace_id: String },
ModelMissing { model_hash: String },
BrokenChainOfCustody { context: String },
LaunderingDetected {
claimed_fitness: f64,
recomputed_fitness: f64,
},
}
impl fmt::Display for RefusalReport {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RefusalReport::FitnessUnavailable => {
write!(f, "conformance refusal: fitness metric unavailable")
}
RefusalReport::ConditionalMissingOverride { fitness } => {
write!(
f,
"conformance refusal: conditional admission (fitness={:.4}) \
requires Board override signature",
fitness
)
}
RefusalReport::HardReject { fitness, policy } => {
write!(
f,
"conformance refusal: hard reject (fitness={:.4} < 0.85 per {policy})",
fitness
)
}
RefusalReport::InvalidOverrideSignature { fitness } => {
write!(
f,
"conformance refusal: Board override signature invalid for \
conditional trace (fitness={:.4})",
fitness
)
}
RefusalReport::TraceMissing { trace_id } => {
write!(f, "conformance refusal: trace '{}' missing", trace_id)
}
RefusalReport::ModelMissing { model_hash } => {
write!(f, "conformance refusal: model '{}' missing", model_hash)
}
RefusalReport::BrokenChainOfCustody { context } => {
write!(
f,
"conformance refusal: chain of custody broken ({})",
context
)
}
RefusalReport::LaunderingDetected {
claimed_fitness,
recomputed_fitness,
} => {
write!(
f,
"conformance refusal: raw laundering detected \
(claimed={:.4}, recomputed={:.4})",
claimed_fitness, recomputed_fitness
)
}
}
}
}
impl std::error::Error for RefusalReport {}
#[derive(Debug, Clone)]
pub struct ReachabilityHeuristic {
pub distances: std::collections::BTreeMap<String, u32>,
}
impl ReachabilityHeuristic {
pub fn new(distances: std::collections::BTreeMap<String, u32>) -> Self {
Self { distances }
}
pub fn estimate(&self, current_marking_hash: &str, remaining_trace_length: u32) -> u32 {
let d_min = self
.distances
.get(current_marking_hash)
.copied()
.unwrap_or(0);
((d_min as i32) - (remaining_trace_length as i32)).max(0) as u32
}
}
pub struct ConformanceSafetyLimits {
pub max_trace_length: usize,
pub max_open_queue_states: usize,
pub max_token_counter: u64,
pub use_fixed_point_arithmetic: bool,
}
impl Default for ConformanceSafetyLimits {
fn default() -> Self {
Self {
max_trace_length: 10_000,
max_open_queue_states: 1_000_000,
max_token_counter: u64::MAX,
use_fixed_point_arithmetic: true,
}
}
}
#[derive(Debug, Clone)]
pub struct ConformanceCertificate {
pub module_hash: String,
pub authority_pubkey: String,
pub signature: String,
pub timestamp: String,
pub authority_version: String,
}
impl ConformanceCertificate {
pub fn new(
module_hash: String,
authority_pubkey: String,
signature: String,
timestamp: String,
) -> Self {
Self {
module_hash,
authority_pubkey,
signature,
timestamp,
authority_version: "30.1.2".to_string(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_token_fitness_perfect() {
let tokens = TokenCounters {
produced: 100,
consumed: 100,
missing: 0,
remaining: 0,
};
let fitness = tokens.compute_fitness();
assert!(fitness.is_some());
assert!((fitness.unwrap() - 1.0).abs() < f64::EPSILON);
}
#[test]
fn test_token_fitness_degraded() {
let tokens = TokenCounters {
produced: 100,
consumed: 100,
missing: 10,
remaining: 5,
};
let fitness = tokens.compute_fitness();
assert!(fitness.is_some());
let f = fitness.unwrap();
assert!((f - 0.925).abs() < 0.01);
}
#[test]
fn test_admission_gate_pass() {
let gate = ConformanceAdmissionGate::new();
let mut verdict = ConformanceVerdicts::new();
verdict.fitness = Some(0.97);
let result = gate.evaluate(&verdict, None);
assert!(result.is_ok());
}
#[test]
fn test_admission_gate_conditional_without_override() {
let gate = ConformanceAdmissionGate::new();
let mut verdict = ConformanceVerdicts::new();
verdict.fitness = Some(0.90);
let result = gate.evaluate(&verdict, None);
assert!(result.is_err());
match result {
Err(RefusalReport::ConditionalMissingOverride { .. }) => (),
_ => unreachable!("expected ConditionalMissingOverride"),
}
}
#[test]
fn test_admission_gate_conditional_with_override() {
let gate = ConformanceAdmissionGate::new();
let mut verdict = ConformanceVerdicts::new();
verdict.fitness = Some(0.90);
let result = gate.evaluate(&verdict, Some("valid-signature"));
assert!(result.is_ok());
}
#[test]
fn test_admission_gate_hard_reject() {
let gate = ConformanceAdmissionGate::new();
let mut verdict = ConformanceVerdicts::new();
verdict.fitness = Some(0.75);
let result = gate.evaluate(&verdict, Some("any-signature"));
assert!(result.is_err());
match result {
Err(RefusalReport::HardReject { .. }) => (),
_ => unreachable!("expected HardReject"),
}
}
#[test]
fn test_verdict_display() {
let mut verdict = ConformanceVerdicts::new();
verdict.fitness = Some(0.95);
verdict.precision = Some(CONDITIONAL_FITNESS_THRESHOLD);
verdict.generalization = Some(0.90);
let display_str = verdict.to_string();
assert!(display_str.contains("fitness=95.00%"));
assert!(display_str.contains("precision=85.00%"));
assert!(display_str.contains("generalization=90.00%"));
}
#[test]
fn test_reachability_heuristic() {
let mut distances = std::collections::BTreeMap::new();
distances.insert("M1".to_string(), 5);
distances.insert("M2".to_string(), 3);
let h = ReachabilityHeuristic::new(distances);
assert_eq!(h.estimate("M1", 2), 3); assert_eq!(h.estimate("M2", 1), 2); assert_eq!(h.estimate("M_unknown", 5), 0); }
}