Skip to main content

remem/truth/
types.rs

1//! Versioned read DTOs for the CurrentTruth projection (GH933 Phase A).
2
3use serde::Serialize;
4
5/// Version stamp carried by every projection payload. Bump when the DTO shape
6/// or documented resolution contract changes. An implementation correction
7/// that restores the unchanged graph contract retains v1; v2 is reserved for
8/// the approved GH933 0.7 breaking contract and migration.
9pub const TRUTH_PROJECTION_VERSION: u32 = 1;
10
11/// How a claim entered the published knowledge base.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
13#[serde(rename_all = "snake_case")]
14pub enum PublicationState {
15    Candidate,
16    Reviewed,
17    Active,
18}
19
20/// Whether the claim is currently considered to hold.
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
22#[serde(rename_all = "snake_case")]
23pub enum ValidityState {
24    Current,
25    Superseded,
26    Contradicted,
27    Stale,
28    Expired,
29    Unknown,
30}
31
32/// Storage/retention posture. `Archived` does not mean false.
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
34#[serde(rename_all = "snake_case")]
35pub enum RetentionState {
36    Live,
37    Archived,
38    Deleted,
39}
40
41/// Policy visibility. `Suppressed` is a visibility decision, not falsity.
42#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
43#[serde(rename_all = "snake_case")]
44pub enum Visibility {
45    Visible,
46    Suppressed,
47}
48
49/// Three orthogonal lifecycle dimensions plus policy visibility.
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
51pub struct Lifecycle {
52    pub publication: PublicationState,
53    pub validity: ValidityState,
54    pub retention: RetentionState,
55    pub visibility: Visibility,
56}
57
58/// Which canonical table a claim was projected from.
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
60#[serde(rename_all = "snake_case")]
61pub enum ClaimSource {
62    Memory,
63    UserContextClaim,
64}
65
66/// What kind of record backs a piece of evidence.
67#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
68#[serde(rename_all = "snake_case")]
69pub enum EvidenceKind {
70    /// Immutable row in the `captured_events` ledger.
71    CapturedEvent,
72    /// Opaque source reference recorded on a user-context claim.
73    SourceRef,
74    /// Claim-level trust floor derived from `memories.source_trust_class`.
75    SourceTrustClass,
76}
77
78/// Deterministic trust tier used by the resolution policy.
79/// Ordering matters: `Verified > ModelGenerated > Untrusted`.
80#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize)]
81#[serde(rename_all = "snake_case")]
82pub enum EvidenceTrust {
83    Untrusted,
84    ModelGenerated,
85    Verified,
86}
87
88/// Immutable evidence reference attached to a claim.
89#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
90pub struct EvidenceView {
91    /// Stable reference, e.g. `captured_event:42`.
92    pub evidence_ref: String,
93    pub kind: EvidenceKind,
94    /// Human-readable pointer back to the source (event type/role, source
95    /// ref string, or trust class name).
96    pub source_ref: String,
97    pub observed_at_epoch: Option<i64>,
98    pub trust: EvidenceTrust,
99}
100
101/// A claim projected from an existing canonical row.
102#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
103pub struct ClaimView {
104    /// Stable reference to the canonical row, e.g. `memory:7`.
105    pub canonical_ref: String,
106    pub source: ClaimSource,
107    /// Grouping key competing claims share (topic key or claim key).
108    pub subject_key: String,
109    pub statement: String,
110    /// Scope owner: project path for memories, owner key for user claims.
111    pub scope: String,
112    pub branch: Option<String>,
113    pub lifecycle: Lifecycle,
114    pub valid_from_epoch: Option<i64>,
115    pub valid_to_epoch: Option<i64>,
116    pub created_at_epoch: i64,
117    pub updated_at_epoch: i64,
118    pub evidence: Vec<EvidenceView>,
119}
120
121/// Typed relation between two claims.
122#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
123#[serde(rename_all = "snake_case")]
124pub enum ClaimRelationKind {
125    Supports,
126    Refutes,
127    Supersedes,
128    DerivedFrom,
129    AppliesTo,
130}
131
132/// Relation projected from `memory_edges`, trusted `graph_edges`, or
133/// `user_context_claims.supersedes_claim_id`.
134#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
135pub struct RelationView {
136    /// Stable reference, e.g. `memory_edge:3`.
137    pub relation_ref: String,
138    pub kind: ClaimRelationKind,
139    pub from_ref: String,
140    pub to_ref: String,
141    pub created_at_epoch: i64,
142    pub valid_from_epoch: Option<i64>,
143    pub valid_to_epoch: Option<i64>,
144}
145
146/// Why the projection selected (or refused to select) a truth.
147#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
148#[serde(rename_all = "snake_case")]
149pub enum TruthSelectionReason {
150    /// Only one eligible claim survived filtering.
151    OnlySurvivingClaim,
152    /// An explicit supersedes relation removed the competitors.
153    ExplicitSupersedes,
154    /// A strictly better evidence-trust tier decided between survivors.
155    VerifiedEvidencePreferred,
156    /// Equal trust tiers; the newest update won.
157    MostRecent,
158    /// A refutes relation or an unbreakable tie: no silent fold.
159    UnresolvedConflict,
160    /// No eligible claim remained: abstain instead of guessing.
161    InsufficientEvidence,
162}
163
164/// One resolved subject: either a current truth, a surfaced contradiction,
165/// or an abstention.
166#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
167pub struct CurrentTruthView {
168    pub subject_key: String,
169    /// Winning claim; absent for contradictions and abstentions.
170    pub claim: Option<ClaimView>,
171    pub validity: ValidityState,
172    pub evidence: Vec<EvidenceView>,
173    pub supporting_relations: Vec<RelationView>,
174    pub contradicting_relations: Vec<RelationView>,
175    /// All claims that competed but were not selected (canonical refs).
176    pub rejected: Vec<String>,
177    /// Contradicting claims surfaced verbatim when validity is Contradicted.
178    pub conflicting_claims: Vec<ClaimView>,
179    pub selected_reason: TruthSelectionReason,
180}
181
182/// Read-only query selector for a projection run.
183#[derive(Debug, Clone, Default)]
184pub struct TruthQuery {
185    pub project: String,
186    pub branch: Option<String>,
187    /// Reference time; `None` means "now".
188    pub as_of_epoch: Option<i64>,
189    /// Optional subject filter (topic key / claim key).
190    pub subject_key: Option<String>,
191}
192
193/// Full projection output for one scope.
194#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
195pub struct CurrentTruthProjection {
196    pub projection_version: u32,
197    pub project: String,
198    pub branch: Option<String>,
199    pub as_of_epoch: Option<i64>,
200    pub truths: Vec<CurrentTruthView>,
201}