Skip to main content

evidential_protocol/
types.rs

1//! Core types for the Evidential Protocol.
2//!
3//! Every AI-generated claim declares *how it knows* via an [`EvidenceClass`],
4//! confidence score, and provenance chain. These types implement the EP/1.0
5//! wire format.
6
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::fmt;
10
11// ---------------------------------------------------------------------------
12// EvidenceClass
13// ---------------------------------------------------------------------------
14
15/// Classification of how a piece of evidence was obtained.
16///
17/// Ordered from strongest (Direct) to weakest (Conjecture). The ordering
18/// intentionally mirrors epistemic certainty so that `min()`/`max()` on
19/// collections of classes yield the weakest/strongest respectively.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
21#[serde(rename_all = "lowercase")]
22pub enum EvidenceClass {
23    /// First-hand observation or authoritative API response.
24    Direct = 4,
25    /// Logically derived from direct evidence.
26    Inferred = 3,
27    /// Second-hand information from a named source.
28    Reported = 2,
29    /// Speculative or hypothetical — must include reasoning.
30    Conjecture = 1,
31}
32
33impl fmt::Display for EvidenceClass {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        match self {
36            Self::Direct => write!(f, "direct"),
37            Self::Inferred => write!(f, "inferred"),
38            Self::Reported => write!(f, "reported"),
39            Self::Conjecture => write!(f, "conjecture"),
40        }
41    }
42}
43
44impl EvidenceClass {
45    /// Numeric strength ranking (4 = strongest).
46    pub fn strength(&self) -> u8 {
47        match self {
48            Self::Direct => 4,
49            Self::Inferred => 3,
50            Self::Reported => 2,
51            Self::Conjecture => 1,
52        }
53    }
54
55    /// Minimum confidence a claim of this class should carry.
56    pub fn confidence_floor(&self) -> f64 {
57        match self {
58            Self::Direct => 0.9,
59            Self::Inferred => 0.5,
60            Self::Reported => 0.3,
61            Self::Conjecture => 0.1,
62        }
63    }
64
65    /// Weight multiplier used in aggregate scoring.
66    pub fn weight(&self) -> f64 {
67        match self {
68            Self::Direct => 1.0,
69            Self::Inferred => 0.7,
70            Self::Reported => 0.4,
71            Self::Conjecture => 0.15,
72        }
73    }
74}
75
76// ---------------------------------------------------------------------------
77// EvidenceSource
78// ---------------------------------------------------------------------------
79
80/// A single provenance entry within an [`Evidence`] chain.
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct EvidenceSource {
83    /// Classification of this particular source.
84    pub class: EvidenceClass,
85    /// Human-readable source identifier (e.g. "coingecko-api").
86    pub source: String,
87    /// Freeform detail about what was retrieved.
88    pub detail: String,
89    /// Optional ISO-8601 timestamp of when the source was consulted.
90    pub timestamp: Option<String>,
91}
92
93// ---------------------------------------------------------------------------
94// Evidence
95// ---------------------------------------------------------------------------
96
97/// The epistemic metadata attached to a single claim.
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct Evidence {
100    /// Overall classification.
101    pub class: EvidenceClass,
102    /// Confidence score in `[0.0, 1.0]`.
103    pub confidence: f64,
104    /// Short identifier of the producing agent or tool.
105    pub source: String,
106    /// Required for [`EvidenceClass::Conjecture`]; explains the reasoning.
107    pub reasoning: Option<String>,
108    /// ISO-8601 timestamp of when the evidence was produced.
109    pub timestamp: String,
110    /// Optional time-to-live in seconds before the evidence expires.
111    pub ttl: Option<u64>,
112    /// Optional provenance chain of upstream sources.
113    pub sources: Option<Vec<EvidenceSource>>,
114}
115
116// ---------------------------------------------------------------------------
117// EvidentialClaim
118// ---------------------------------------------------------------------------
119
120/// A single claim with its supporting [`Evidence`].
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct EvidentialClaim {
123    /// The assertion being made.
124    pub claim: String,
125    /// Epistemic metadata backing the claim.
126    pub evidence: Evidence,
127    /// Optional list of reference URLs or identifiers.
128    pub refs: Option<Vec<String>>,
129}
130
131// ---------------------------------------------------------------------------
132// EvidentialResponse
133// ---------------------------------------------------------------------------
134
135/// A complete EP/1.0 response envelope wrapping arbitrary data with
136/// epistemic metadata.
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct EvidentialResponse<T: Serialize> {
139    /// Protocol version — always `"1.0"` for this implementation.
140    #[serde(default = "default_ep_version")]
141    pub ep_version: String,
142    /// The payload data.
143    pub data: T,
144    /// All claims made in this response.
145    pub claims: Vec<EvidentialClaim>,
146    /// Weakest class among all claims.
147    pub aggregate_class: EvidenceClass,
148    /// Weighted mean confidence across all claims.
149    pub aggregate_confidence: f64,
150    /// Identifier of the agent/system that produced this response.
151    pub producer: String,
152    /// ISO-8601 timestamp of when this response was produced.
153    pub produced_at: String,
154}
155
156fn default_ep_version() -> String {
157    "1.0".to_string()
158}
159
160// ---------------------------------------------------------------------------
161// TrustScore
162// ---------------------------------------------------------------------------
163
164/// Aggregate trust assessment computed from a set of claims.
165#[derive(Debug, Clone, Serialize, Deserialize)]
166pub struct TrustScore {
167    /// Weighted trust score in `[0.0, 1.0]`.
168    pub score: f64,
169    /// Total number of claims evaluated.
170    pub total_claims: usize,
171    /// Count of claims by evidence class.
172    pub breakdown: HashMap<EvidenceClass, usize>,
173    /// `true` if any claim is Conjecture or score < 0.5.
174    pub requires_review: bool,
175}
176
177// ---------------------------------------------------------------------------
178// DegradationReason / DegradationEvent
179// ---------------------------------------------------------------------------
180
181/// Reason an evidence class was downgraded.
182#[derive(Debug, Clone, Serialize, Deserialize)]
183pub enum DegradationReason {
184    /// The evidence's TTL has expired.
185    TtlExpired,
186    /// The evidence is older than 24 hours with no TTL.
187    Stale24h,
188    /// The upstream source is no longer reachable.
189    SourceUnavailable,
190}
191
192/// Record of a claim's evidence class being downgraded.
193#[derive(Debug, Clone, Serialize, Deserialize)]
194pub struct DegradationEvent {
195    /// Identifier for the claim that was degraded.
196    pub claim_id: String,
197    /// Original evidence class before degradation.
198    pub from_class: EvidenceClass,
199    /// New evidence class after degradation.
200    pub to_class: EvidenceClass,
201    /// Why the degradation happened.
202    pub reason: DegradationReason,
203    /// ISO-8601 timestamp of when degradation was detected.
204    pub timestamp: String,
205}
206
207// ---------------------------------------------------------------------------
208// ContentEvidenceMarker
209// ---------------------------------------------------------------------------
210
211/// Inline marker embedded in content to annotate evidence provenance.
212///
213/// Wire format: `[EP:<class>:<source>:<confidence>]`
214#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct ContentEvidenceMarker {
216    /// Evidence class for this content segment.
217    pub class: EvidenceClass,
218    /// Source identifier.
219    pub source: String,
220    /// Confidence score in `[0.0, 1.0]`.
221    pub confidence: f64,
222}