use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrustScore {
pub agent_id: String,
pub score: f64,
pub tier: TrustTier,
pub components: TrustComponents,
pub tier_thresholds: TierThresholds,
pub trajectory: TrustTrajectory,
pub assessed_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TrustComponents {
pub operational: OperationalComponent,
pub cognitive: CognitiveComponent,
pub economic: EconomicComponent,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OperationalComponent {
pub score: f64,
pub factors: OperationalFactors,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OperationalFactors {
pub uptime_ratio: f64,
pub error_rate: f64,
pub avg_latency_ms: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CognitiveComponent {
pub score: f64,
pub factors: CognitiveFactors,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CognitiveFactors {
pub task_completion_rate: f64,
pub context_utilization: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EconomicComponent {
pub score: f64,
pub factors: EconomicFactors,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EconomicFactors {
pub payment_history_score: f64,
pub credit_utilization: f64,
pub economic_mode: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TierThresholds {
pub certified: f64,
pub trusted: f64,
pub provisional: f64,
pub unverified: f64,
}
impl Default for TierThresholds {
fn default() -> Self {
Self {
certified: 0.90,
trusted: 0.75,
provisional: 0.50,
unverified: 0.0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TrustTier {
Unverified,
Provisional,
Trusted,
Certified,
}
impl TrustTier {
pub fn from_score(score: f64) -> Self {
if score >= 0.90 {
Self::Certified
} else if score >= 0.75 {
Self::Trusted
} else if score >= 0.50 {
Self::Provisional
} else {
Self::Unverified
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TrustTrajectory {
Improving,
Stable,
Degrading,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn trust_tier_from_score_certified() {
assert_eq!(TrustTier::from_score(0.95), TrustTier::Certified);
assert_eq!(TrustTier::from_score(0.90), TrustTier::Certified);
}
#[test]
fn trust_tier_from_score_trusted() {
assert_eq!(TrustTier::from_score(0.82), TrustTier::Trusted);
assert_eq!(TrustTier::from_score(0.75), TrustTier::Trusted);
}
#[test]
fn trust_tier_from_score_provisional() {
assert_eq!(TrustTier::from_score(0.60), TrustTier::Provisional);
assert_eq!(TrustTier::from_score(0.50), TrustTier::Provisional);
}
#[test]
fn trust_tier_from_score_unverified() {
assert_eq!(TrustTier::from_score(0.49), TrustTier::Unverified);
assert_eq!(TrustTier::from_score(0.0), TrustTier::Unverified);
}
#[test]
fn trust_tier_serde_roundtrip() {
for tier in [
TrustTier::Unverified,
TrustTier::Provisional,
TrustTier::Trusted,
TrustTier::Certified,
] {
let json = serde_json::to_string(&tier).unwrap();
let back: TrustTier = serde_json::from_str(&json).unwrap();
assert_eq!(tier, back);
}
}
#[test]
fn trust_trajectory_serde_roundtrip() {
for trajectory in [
TrustTrajectory::Improving,
TrustTrajectory::Stable,
TrustTrajectory::Degrading,
] {
let json = serde_json::to_string(&trajectory).unwrap();
let back: TrustTrajectory = serde_json::from_str(&json).unwrap();
assert_eq!(trajectory, back);
}
}
#[test]
fn tier_thresholds_default() {
let thresholds = TierThresholds::default();
assert!((thresholds.certified - 0.90).abs() < f64::EPSILON);
assert!((thresholds.trusted - 0.75).abs() < f64::EPSILON);
assert!((thresholds.provisional - 0.50).abs() < f64::EPSILON);
assert!((thresholds.unverified - 0.0).abs() < f64::EPSILON);
}
#[test]
fn trust_score_serde_roundtrip() {
let score = TrustScore {
agent_id: "agent-123".into(),
score: 0.82,
tier: TrustTier::Trusted,
components: TrustComponents {
operational: OperationalComponent {
score: 0.90,
factors: OperationalFactors {
uptime_ratio: 0.95,
error_rate: 0.02,
avg_latency_ms: 450,
},
},
cognitive: CognitiveComponent {
score: 0.78,
factors: CognitiveFactors {
task_completion_rate: 0.85,
context_utilization: 0.72,
},
},
economic: EconomicComponent {
score: 0.79,
factors: EconomicFactors {
payment_history_score: 0.88,
credit_utilization: 0.65,
economic_mode: "sovereign".into(),
},
},
},
tier_thresholds: TierThresholds::default(),
trajectory: TrustTrajectory::Improving,
assessed_at: Utc::now(),
};
let json = serde_json::to_string(&score).unwrap();
let back: TrustScore = serde_json::from_str(&json).unwrap();
assert_eq!(back.agent_id, "agent-123");
assert!((back.score - 0.82).abs() < f64::EPSILON);
assert_eq!(back.tier, TrustTier::Trusted);
assert_eq!(back.trajectory, TrustTrajectory::Improving);
}
}