Skip to main content

autonomic_core/
trust.rs

1//! Trust scoring types for the Autonomic public API.
2//!
3//! A `TrustScore` is a composite reliability score for an agent derived
4//! from the three-pillar homeostatic state (operational, cognitive, economic).
5//! The score is public and requires no authentication.
6
7use chrono::{DateTime, Utc};
8use serde::{Deserialize, Serialize};
9
10/// Composite trust score for an agent.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct TrustScore {
13    /// Agent identifier.
14    pub agent_id: String,
15    /// Composite reliability score (0.0 - 1.0).
16    pub score: f64,
17    /// Trust tier derived from composite score.
18    pub tier: TrustTier,
19    /// Per-pillar component scores.
20    pub components: TrustComponents,
21    /// Tier threshold definitions.
22    pub tier_thresholds: TierThresholds,
23    /// Score trajectory based on recent history.
24    pub trajectory: TrustTrajectory,
25    /// Timestamp of assessment.
26    pub assessed_at: DateTime<Utc>,
27}
28
29/// Per-pillar component breakdown.
30#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct TrustComponents {
32    /// Operational health component.
33    pub operational: OperationalComponent,
34    /// Cognitive health component.
35    pub cognitive: CognitiveComponent,
36    /// Economic health component.
37    pub economic: EconomicComponent,
38}
39
40/// Operational health component score.
41#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct OperationalComponent {
43    /// Normalized score (0.0 - 1.0).
44    pub score: f64,
45    /// Contributing factors.
46    pub factors: OperationalFactors,
47}
48
49/// Factors contributing to the operational score.
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct OperationalFactors {
52    /// Ratio of successful operations to total (0.0 - 1.0).
53    pub uptime_ratio: f64,
54    /// Current error rate (0.0 - 1.0).
55    pub error_rate: f64,
56    /// Average latency in milliseconds (derived from last tick delta).
57    pub avg_latency_ms: u64,
58}
59
60/// Cognitive health component score.
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct CognitiveComponent {
63    /// Normalized score (0.0 - 1.0).
64    pub score: f64,
65    /// Contributing factors.
66    pub factors: CognitiveFactors,
67}
68
69/// Factors contributing to the cognitive score.
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct CognitiveFactors {
72    /// Task completion rate (0.0 - 1.0).
73    pub task_completion_rate: f64,
74    /// Context utilization efficiency (0.0 - 1.0).
75    pub context_utilization: f64,
76}
77
78/// Economic health component score.
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct EconomicComponent {
81    /// Normalized score (0.0 - 1.0).
82    pub score: f64,
83    /// Contributing factors.
84    pub factors: EconomicFactors,
85}
86
87/// Factors contributing to the economic score.
88#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct EconomicFactors {
90    /// Payment history reliability score (0.0 - 1.0).
91    pub payment_history_score: f64,
92    /// Credit utilization ratio (0.0 - 1.0).
93    pub credit_utilization: f64,
94    /// Current economic operating mode.
95    pub economic_mode: String,
96}
97
98/// Tier threshold definitions for transparency.
99#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct TierThresholds {
101    /// Minimum score for Certified tier.
102    pub certified: f64,
103    /// Minimum score for Trusted tier.
104    pub trusted: f64,
105    /// Minimum score for Provisional tier.
106    pub provisional: f64,
107    /// Minimum score for Unverified tier.
108    pub unverified: f64,
109}
110
111impl Default for TierThresholds {
112    fn default() -> Self {
113        Self {
114            certified: 0.90,
115            trusted: 0.75,
116            provisional: 0.50,
117            unverified: 0.0,
118        }
119    }
120}
121
122/// Trust tier derived from composite score.
123#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
124#[serde(rename_all = "snake_case")]
125pub enum TrustTier {
126    /// No data or score below 0.50.
127    Unverified,
128    /// Score 0.50 - 0.75.
129    Provisional,
130    /// Score 0.75 - 0.90.
131    Trusted,
132    /// Score >= 0.90.
133    Certified,
134}
135
136impl TrustTier {
137    /// Derive tier from a composite score.
138    pub fn from_score(score: f64) -> Self {
139        if score >= 0.90 {
140            Self::Certified
141        } else if score >= 0.75 {
142            Self::Trusted
143        } else if score >= 0.50 {
144            Self::Provisional
145        } else {
146            Self::Unverified
147        }
148    }
149}
150
151/// Score trajectory indicating improvement or degradation.
152#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
153#[serde(rename_all = "snake_case")]
154pub enum TrustTrajectory {
155    /// Score is improving over recent events.
156    Improving,
157    /// Score is stable.
158    Stable,
159    /// Score is degrading.
160    Degrading,
161}
162
163#[cfg(test)]
164mod tests {
165    use super::*;
166
167    #[test]
168    fn trust_tier_from_score_certified() {
169        assert_eq!(TrustTier::from_score(0.95), TrustTier::Certified);
170        assert_eq!(TrustTier::from_score(0.90), TrustTier::Certified);
171    }
172
173    #[test]
174    fn trust_tier_from_score_trusted() {
175        assert_eq!(TrustTier::from_score(0.82), TrustTier::Trusted);
176        assert_eq!(TrustTier::from_score(0.75), TrustTier::Trusted);
177    }
178
179    #[test]
180    fn trust_tier_from_score_provisional() {
181        assert_eq!(TrustTier::from_score(0.60), TrustTier::Provisional);
182        assert_eq!(TrustTier::from_score(0.50), TrustTier::Provisional);
183    }
184
185    #[test]
186    fn trust_tier_from_score_unverified() {
187        assert_eq!(TrustTier::from_score(0.49), TrustTier::Unverified);
188        assert_eq!(TrustTier::from_score(0.0), TrustTier::Unverified);
189    }
190
191    #[test]
192    fn trust_tier_serde_roundtrip() {
193        for tier in [
194            TrustTier::Unverified,
195            TrustTier::Provisional,
196            TrustTier::Trusted,
197            TrustTier::Certified,
198        ] {
199            let json = serde_json::to_string(&tier).unwrap();
200            let back: TrustTier = serde_json::from_str(&json).unwrap();
201            assert_eq!(tier, back);
202        }
203    }
204
205    #[test]
206    fn trust_trajectory_serde_roundtrip() {
207        for trajectory in [
208            TrustTrajectory::Improving,
209            TrustTrajectory::Stable,
210            TrustTrajectory::Degrading,
211        ] {
212            let json = serde_json::to_string(&trajectory).unwrap();
213            let back: TrustTrajectory = serde_json::from_str(&json).unwrap();
214            assert_eq!(trajectory, back);
215        }
216    }
217
218    #[test]
219    fn tier_thresholds_default() {
220        let thresholds = TierThresholds::default();
221        assert!((thresholds.certified - 0.90).abs() < f64::EPSILON);
222        assert!((thresholds.trusted - 0.75).abs() < f64::EPSILON);
223        assert!((thresholds.provisional - 0.50).abs() < f64::EPSILON);
224        assert!((thresholds.unverified - 0.0).abs() < f64::EPSILON);
225    }
226
227    #[test]
228    fn trust_score_serde_roundtrip() {
229        let score = TrustScore {
230            agent_id: "agent-123".into(),
231            score: 0.82,
232            tier: TrustTier::Trusted,
233            components: TrustComponents {
234                operational: OperationalComponent {
235                    score: 0.90,
236                    factors: OperationalFactors {
237                        uptime_ratio: 0.95,
238                        error_rate: 0.02,
239                        avg_latency_ms: 450,
240                    },
241                },
242                cognitive: CognitiveComponent {
243                    score: 0.78,
244                    factors: CognitiveFactors {
245                        task_completion_rate: 0.85,
246                        context_utilization: 0.72,
247                    },
248                },
249                economic: EconomicComponent {
250                    score: 0.79,
251                    factors: EconomicFactors {
252                        payment_history_score: 0.88,
253                        credit_utilization: 0.65,
254                        economic_mode: "sovereign".into(),
255                    },
256                },
257            },
258            tier_thresholds: TierThresholds::default(),
259            trajectory: TrustTrajectory::Improving,
260            assessed_at: Utc::now(),
261        };
262
263        let json = serde_json::to_string(&score).unwrap();
264        let back: TrustScore = serde_json::from_str(&json).unwrap();
265        assert_eq!(back.agent_id, "agent-123");
266        assert!((back.score - 0.82).abs() < f64::EPSILON);
267        assert_eq!(back.tier, TrustTier::Trusted);
268        assert_eq!(back.trajectory, TrustTrajectory::Improving);
269    }
270}