1use crate::identity::{AgentId, ClaimRef};
8use crate::provenance::{ExternalAnchor, ProvenanceLabel};
9use crate::time::{TransactionTime, ValidTime};
10
11#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
13pub struct Fact {
14 pub subject: String,
16 pub predicate: String,
18 pub value: serde_json::Value,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
27pub enum Cardinality {
28 Functional,
30 SetValued,
32 #[default]
34 Unknown,
35}
36
37#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
43pub struct Confidence {
44 pub value_confidence: f32,
46 pub valid_time_confidence: f32,
48}
49
50#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
52pub enum Criticality {
53 Low,
55 Medium,
57 High,
59 Critical,
61}
62
63#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
70pub struct Claim {
71 claim_ref: ClaimRef,
72 agent_id: AgentId,
73 fact: Fact,
74 cardinality: Cardinality,
75 provenance: ProvenanceLabel,
76 external_anchor: ExternalAnchor,
77 transaction_time: TransactionTime,
78 valid_time: ValidTime,
79 confidence: Confidence,
80 criticality: Criticality,
81 derived_from: Vec<ClaimRef>,
82 metadata: Option<serde_json::Value>,
83 snapshot_schema_version: Option<u32>,
84}
85
86impl Claim {
87 #[allow(clippy::too_many_arguments)]
89 pub fn new(
90 claim_ref: ClaimRef,
91 agent_id: AgentId,
92 fact: Fact,
93 cardinality: Cardinality,
94 provenance: ProvenanceLabel,
95 external_anchor: ExternalAnchor,
96 transaction_time: TransactionTime,
97 valid_time: ValidTime,
98 confidence: Confidence,
99 criticality: Criticality,
100 derived_from: Vec<ClaimRef>,
101 metadata: Option<serde_json::Value>,
102 snapshot_schema_version: Option<u32>,
103 ) -> Self {
104 Self {
105 claim_ref,
106 agent_id,
107 fact,
108 cardinality,
109 provenance,
110 external_anchor,
111 transaction_time,
112 valid_time,
113 confidence,
114 criticality,
115 derived_from,
116 metadata,
117 snapshot_schema_version,
118 }
119 }
120
121 pub fn claim_ref(&self) -> &ClaimRef { &self.claim_ref }
125 pub fn agent_id(&self) -> &AgentId { &self.agent_id }
127 pub fn fact(&self) -> &Fact { &self.fact }
129 pub fn cardinality(&self) -> &Cardinality { &self.cardinality }
131 pub fn provenance(&self) -> &ProvenanceLabel { &self.provenance }
133 pub fn external_anchor(&self) -> &ExternalAnchor { &self.external_anchor }
135 pub fn transaction_time(&self) -> &TransactionTime { &self.transaction_time }
137 pub fn valid_time(&self) -> &ValidTime { &self.valid_time }
139 pub fn confidence(&self) -> &Confidence { &self.confidence }
141 pub fn criticality(&self) -> &Criticality { &self.criticality }
143 pub fn derived_from(&self) -> &[ClaimRef] { &self.derived_from }
145 pub fn metadata(&self) -> Option<&serde_json::Value> { self.metadata.as_ref() }
147 pub fn snapshot_schema_version(&self) -> Option<u32> { self.snapshot_schema_version }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154 use crate::identity::AgentId;
155 use crate::provenance::{ExternalAnchor, ProvenanceLabel};
156 use crate::time::{TransactionTime, ValidTime};
157 use chrono::Utc;
158
159 fn make_claim() -> Claim {
160 Claim::new(
161 ClaimRef::new_random(),
162 AgentId("agent-42".into()),
163 Fact {
164 subject: "user".into(),
165 predicate: "email".into(),
166 value: serde_json::json!("alice@example.com"),
167 },
168 Cardinality::Functional,
169 ProvenanceLabel::ModelDerived,
170 ExternalAnchor { nearest_external_anchor: None, derivation_depth: 0 },
171 TransactionTime(Utc::now()),
172 ValidTime { start: None, end: None, valid_time_confidence: 0.0 },
173 Confidence { value_confidence: 0.9, valid_time_confidence: 0.0 },
174 Criticality::Low,
175 vec![],
176 None,
177 None,
178 )
179 }
180
181 #[test]
182 fn claim_constructed_and_readable() {
183 let c = make_claim();
184 assert_eq!(c.agent_id(), &AgentId("agent-42".into()));
185 assert_eq!(c.fact().subject, "user");
186 assert_eq!(c.cardinality(), &Cardinality::Functional);
187 }
188
189 #[test]
190 fn claim_is_immutable_no_setters() {
191 let c = make_claim();
193 let _ = c.claim_ref();
195 let _ = c.provenance();
196 }
197
198 #[test]
199 fn cardinality_unknown_is_default() {
200 let c: Cardinality = Default::default();
201 assert_eq!(c, Cardinality::Unknown);
202 }
203
204 #[test]
205 fn claim_round_trip_serde() {
206 let c = make_claim();
207 let json = serde_json::to_string(&c).unwrap();
208 let back: Claim = serde_json::from_str(&json).unwrap();
209 assert_eq!(c.claim_ref(), back.claim_ref());
210 assert_eq!(c.agent_id(), back.agent_id());
211 assert_eq!(c.fact(), back.fact());
212 }
213
214 #[test]
215 fn criticality_ordering() {
216 assert!(Criticality::Low < Criticality::Medium);
217 assert!(Criticality::Medium < Criticality::High);
218 assert!(Criticality::High < Criticality::Critical);
219 }
220}