use crate::identity::{AgentId, ClaimRef};
use crate::provenance::{ExternalAnchor, ProvenanceLabel};
use crate::time::{TransactionTime, ValidTime};
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Fact {
pub subject: String,
pub predicate: String,
pub value: serde_json::Value,
}
#[derive(Debug, Clone, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
pub enum Cardinality {
Functional,
SetValued,
#[default]
Unknown,
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct Confidence {
pub value_confidence: f32,
pub valid_time_confidence: f32,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
pub enum Criticality {
Low,
Medium,
High,
Critical,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Claim {
claim_ref: ClaimRef,
agent_id: AgentId,
fact: Fact,
cardinality: Cardinality,
provenance: ProvenanceLabel,
external_anchor: ExternalAnchor,
transaction_time: TransactionTime,
valid_time: ValidTime,
confidence: Confidence,
criticality: Criticality,
derived_from: Vec<ClaimRef>,
metadata: Option<serde_json::Value>,
snapshot_schema_version: Option<u32>,
}
impl Claim {
#[allow(clippy::too_many_arguments)]
pub fn new(
claim_ref: ClaimRef,
agent_id: AgentId,
fact: Fact,
cardinality: Cardinality,
provenance: ProvenanceLabel,
external_anchor: ExternalAnchor,
transaction_time: TransactionTime,
valid_time: ValidTime,
confidence: Confidence,
criticality: Criticality,
derived_from: Vec<ClaimRef>,
metadata: Option<serde_json::Value>,
snapshot_schema_version: Option<u32>,
) -> Self {
Self {
claim_ref,
agent_id,
fact,
cardinality,
provenance,
external_anchor,
transaction_time,
valid_time,
confidence,
criticality,
derived_from,
metadata,
snapshot_schema_version,
}
}
pub fn claim_ref(&self) -> &ClaimRef { &self.claim_ref }
pub fn agent_id(&self) -> &AgentId { &self.agent_id }
pub fn fact(&self) -> &Fact { &self.fact }
pub fn cardinality(&self) -> &Cardinality { &self.cardinality }
pub fn provenance(&self) -> &ProvenanceLabel { &self.provenance }
pub fn external_anchor(&self) -> &ExternalAnchor { &self.external_anchor }
pub fn transaction_time(&self) -> &TransactionTime { &self.transaction_time }
pub fn valid_time(&self) -> &ValidTime { &self.valid_time }
pub fn confidence(&self) -> &Confidence { &self.confidence }
pub fn criticality(&self) -> &Criticality { &self.criticality }
pub fn derived_from(&self) -> &[ClaimRef] { &self.derived_from }
pub fn metadata(&self) -> Option<&serde_json::Value> { self.metadata.as_ref() }
pub fn snapshot_schema_version(&self) -> Option<u32> { self.snapshot_schema_version }
}
#[cfg(test)]
mod tests {
use super::*;
use crate::identity::AgentId;
use crate::provenance::{ExternalAnchor, ProvenanceLabel};
use crate::time::{TransactionTime, ValidTime};
use chrono::Utc;
fn make_claim() -> Claim {
Claim::new(
ClaimRef::new_random(),
AgentId("agent-42".into()),
Fact {
subject: "user".into(),
predicate: "email".into(),
value: serde_json::json!("alice@example.com"),
},
Cardinality::Functional,
ProvenanceLabel::ModelDerived,
ExternalAnchor { nearest_external_anchor: None, derivation_depth: 0 },
TransactionTime(Utc::now()),
ValidTime { start: None, end: None, valid_time_confidence: 0.0 },
Confidence { value_confidence: 0.9, valid_time_confidence: 0.0 },
Criticality::Low,
vec![],
None,
None,
)
}
#[test]
fn claim_constructed_and_readable() {
let c = make_claim();
assert_eq!(c.agent_id(), &AgentId("agent-42".into()));
assert_eq!(c.fact().subject, "user");
assert_eq!(c.cardinality(), &Cardinality::Functional);
}
#[test]
fn claim_is_immutable_no_setters() {
let c = make_claim();
let _ = c.claim_ref();
let _ = c.provenance();
}
#[test]
fn cardinality_unknown_is_default() {
let c: Cardinality = Default::default();
assert_eq!(c, Cardinality::Unknown);
}
#[test]
fn claim_round_trip_serde() {
let c = make_claim();
let json = serde_json::to_string(&c).unwrap();
let back: Claim = serde_json::from_str(&json).unwrap();
assert_eq!(c.claim_ref(), back.claim_ref());
assert_eq!(c.agent_id(), back.agent_id());
assert_eq!(c.fact(), back.fact());
}
#[test]
fn criticality_ordering() {
assert!(Criticality::Low < Criticality::Medium);
assert!(Criticality::Medium < Criticality::High);
assert!(Criticality::High < Criticality::Critical);
}
}