1use chrono::{DateTime, Utc};
8use serde::{Deserialize, Serialize};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct TrustScore {
13 pub agent_id: String,
15 pub score: f64,
17 pub tier: TrustTier,
19 pub components: TrustComponents,
21 pub tier_thresholds: TierThresholds,
23 pub trajectory: TrustTrajectory,
25 pub assessed_at: DateTime<Utc>,
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
31pub struct TrustComponents {
32 pub operational: OperationalComponent,
34 pub cognitive: CognitiveComponent,
36 pub economic: EconomicComponent,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
42pub struct OperationalComponent {
43 pub score: f64,
45 pub factors: OperationalFactors,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct OperationalFactors {
52 pub uptime_ratio: f64,
54 pub error_rate: f64,
56 pub avg_latency_ms: u64,
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct CognitiveComponent {
63 pub score: f64,
65 pub factors: CognitiveFactors,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct CognitiveFactors {
72 pub task_completion_rate: f64,
74 pub context_utilization: f64,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct EconomicComponent {
81 pub score: f64,
83 pub factors: EconomicFactors,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct EconomicFactors {
90 pub payment_history_score: f64,
92 pub credit_utilization: f64,
94 pub economic_mode: String,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct TierThresholds {
101 pub certified: f64,
103 pub trusted: f64,
105 pub provisional: f64,
107 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
124#[serde(rename_all = "snake_case")]
125pub enum TrustTier {
126 Unverified,
128 Provisional,
130 Trusted,
132 Certified,
134}
135
136impl TrustTier {
137 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
153#[serde(rename_all = "snake_case")]
154pub enum TrustTrajectory {
155 Improving,
157 Stable,
159 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}