Skip to main content

agentic_identity/continuity/
types.rs

1//! Data structures for temporal continuity.
2
3use serde::{Deserialize, Serialize};
4
5use crate::identity::IdentityId;
6use crate::receipt::ReceiptId;
7
8// ---------------------------------------------------------------------------
9// Experience Event
10// ---------------------------------------------------------------------------
11
12/// Unique identifier for an experience event.
13#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
14pub struct ExperienceId(pub String);
15
16impl std::fmt::Display for ExperienceId {
17    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
18        write!(f, "{}", self.0)
19    }
20}
21
22/// An experience event in the continuity chain.
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct ExperienceEvent {
25    pub id: ExperienceId,
26    pub identity: IdentityId,
27    pub event_type: ExperienceType,
28    pub timestamp: u64,
29    pub duration: Option<u64>,
30    pub content_hash: String,
31    /// Intensity of the experience (0.0 – 1.0).
32    pub intensity: f32,
33
34    // Chain links
35    pub previous_experience_id: Option<ExperienceId>,
36    pub previous_experience_hash: Option<String>,
37    pub sequence_number: u64,
38    pub cumulative_hash: String,
39
40    pub signature: String,
41}
42
43// ---------------------------------------------------------------------------
44// Experience types
45// ---------------------------------------------------------------------------
46
47/// Type of experience event (10 variants).
48#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
49pub enum ExperienceType {
50    Perception {
51        source: PerceptionSource,
52    },
53    Cognition {
54        cognition_type: CognitionType,
55    },
56    Action {
57        receipt_id: ReceiptId,
58    },
59    Communication {
60        direction: CommunicationDirection,
61        counterparty: IdentityId,
62    },
63    Memory {
64        operation: MemoryOpType,
65    },
66    Learning {
67        learning_type: LearningType,
68        domain: String,
69    },
70    Planning {
71        planning_type: PlanningType,
72    },
73    Emotion {
74        emotion_type: String,
75    },
76    Idle {
77        reason: String,
78    },
79    System {
80        event: SystemEvent,
81    },
82}
83
84impl ExperienceType {
85    /// Return a stable string tag for hashing.
86    pub fn as_tag(&self) -> &str {
87        match self {
88            Self::Perception { .. } => "perception",
89            Self::Cognition { .. } => "cognition",
90            Self::Action { .. } => "action",
91            Self::Communication { .. } => "communication",
92            Self::Memory { .. } => "memory",
93            Self::Learning { .. } => "learning",
94            Self::Planning { .. } => "planning",
95            Self::Emotion { .. } => "emotion",
96            Self::Idle { .. } => "idle",
97            Self::System { .. } => "system",
98        }
99    }
100}
101
102#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
103pub enum PerceptionSource {
104    Visual,
105    Auditory,
106    Text,
107    Sensor,
108}
109
110#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
111pub enum CognitionType {
112    Thought,
113    Reasoning,
114    Inference,
115    Recall,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
119pub enum CommunicationDirection {
120    Inbound,
121    Outbound,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
125pub enum MemoryOpType {
126    Store,
127    Retrieve,
128    Update,
129    Delete,
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
133pub enum LearningType {
134    Supervised,
135    Unsupervised,
136    Reinforcement,
137    SelfDirected,
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
141pub enum PlanningType {
142    GoalSetting,
143    PlanCreation,
144    PlanUpdate,
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
148pub enum SystemEvent {
149    Startup,
150    Shutdown,
151    Checkpoint,
152    Error { message: String },
153}
154
155// ---------------------------------------------------------------------------
156// Continuity State
157// ---------------------------------------------------------------------------
158
159/// Summary of an identity's continuity chain.
160#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct ContinuityState {
162    pub identity: IdentityId,
163    pub genesis_experience_id: ExperienceId,
164    pub genesis_hash: String,
165    pub genesis_timestamp: u64,
166    pub latest_experience_id: ExperienceId,
167    pub latest_hash: String,
168    pub latest_timestamp: u64,
169    pub total_experiences: u64,
170}
171
172// ---------------------------------------------------------------------------
173// Continuity Anchor
174// ---------------------------------------------------------------------------
175
176/// Unique identifier for a continuity anchor.
177#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
178pub struct AnchorId(pub String);
179
180impl std::fmt::Display for AnchorId {
181    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
182        write!(f, "{}", self.0)
183    }
184}
185
186/// A checkpoint in the continuity chain.
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct ContinuityAnchor {
189    pub id: AnchorId,
190    pub identity: IdentityId,
191    pub anchor_type: AnchorType,
192    pub experience_id: ExperienceId,
193    pub cumulative_hash: String,
194    pub experience_count: u64,
195    pub timestamp: u64,
196    pub previous_anchor: Option<AnchorId>,
197    pub external_witness: Option<String>,
198    pub signature: String,
199}
200
201/// Type of continuity anchor.
202#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
203pub enum AnchorType {
204    Genesis,
205    TimeBased { interval_hours: u32 },
206    ExperienceCount { interval: u64 },
207    Manual,
208    External { witness: IdentityId },
209}
210
211impl AnchorType {
212    /// Return a stable string tag.
213    pub fn as_tag(&self) -> &str {
214        match self {
215            Self::Genesis => "genesis",
216            Self::TimeBased { .. } => "time_based",
217            Self::ExperienceCount { .. } => "experience_count",
218            Self::Manual => "manual",
219            Self::External { .. } => "external",
220        }
221    }
222}
223
224// ---------------------------------------------------------------------------
225// Heartbeat
226// ---------------------------------------------------------------------------
227
228/// Unique identifier for a heartbeat record.
229#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
230pub struct HeartbeatId(pub String);
231
232impl std::fmt::Display for HeartbeatId {
233    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
234        write!(f, "{}", self.0)
235    }
236}
237
238/// Periodic heartbeat record.
239#[derive(Debug, Clone, Serialize, Deserialize)]
240pub struct HeartbeatRecord {
241    pub id: HeartbeatId,
242    pub identity: IdentityId,
243    pub timestamp: u64,
244    pub sequence_number: u64,
245    pub continuity_hash: String,
246    pub experience_count: u64,
247    pub experiences_since_last: u64,
248    pub status: HeartbeatStatus,
249    pub health: HealthMetrics,
250    pub signature: String,
251}
252
253/// Heartbeat status.
254#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
255pub enum HeartbeatStatus {
256    Active,
257    Idle,
258    Suspended,
259    Degraded,
260}
261
262impl HeartbeatStatus {
263    /// Return a stable string tag.
264    pub fn as_tag(&self) -> &str {
265        match self {
266            Self::Active => "active",
267            Self::Idle => "idle",
268            Self::Suspended => "suspended",
269            Self::Degraded => "degraded",
270        }
271    }
272}
273
274/// Health metrics included in a heartbeat.
275#[derive(Debug, Clone, Serialize, Deserialize)]
276pub struct HealthMetrics {
277    pub memory_usage_bytes: u64,
278    pub experience_rate_per_hour: f64,
279    pub error_count: u64,
280    pub latency_ms: u64,
281}
282
283// ---------------------------------------------------------------------------
284// Continuity Claim
285// ---------------------------------------------------------------------------
286
287/// Unique identifier for a continuity claim.
288#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
289pub struct ClaimId(pub String);
290
291impl std::fmt::Display for ClaimId {
292    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
293        write!(f, "{}", self.0)
294    }
295}
296
297/// A claim asserting continuity over a range.
298#[derive(Debug, Clone, Serialize, Deserialize)]
299pub struct ContinuityClaim {
300    pub id: ClaimId,
301    pub identity: IdentityId,
302    pub claim_type: ClaimType,
303    pub start_anchor: String,
304    pub start_timestamp: u64,
305    pub start_experience: u64,
306    pub end_anchor: String,
307    pub end_timestamp: u64,
308    pub end_experience: u64,
309    pub experience_count: u64,
310    pub max_gap_seconds: u64,
311    pub signature: String,
312}
313
314/// Type of continuity claim.
315#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
316pub enum ClaimType {
317    FullContinuity,
318    RangeContinuity,
319    SinceContinuity,
320}
321
322impl ClaimType {
323    /// Return a stable string tag.
324    pub fn as_tag(&self) -> &str {
325        match self {
326            Self::FullContinuity => "full",
327            Self::RangeContinuity => "range",
328            Self::SinceContinuity => "since",
329        }
330    }
331}
332
333// ---------------------------------------------------------------------------
334// Gap
335// ---------------------------------------------------------------------------
336
337/// A gap detected in the continuity chain.
338#[derive(Debug, Clone, Serialize, Deserialize)]
339pub struct Gap {
340    pub start: u64,
341    pub end: u64,
342    pub gap_type: GapType,
343    pub severity: GapSeverity,
344    pub impact: String,
345}
346
347/// Type of continuity gap.
348#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
349pub enum GapType {
350    Temporal,
351    Sequence,
352    Hash,
353    Heartbeat,
354}
355
356/// Severity of a gap.
357#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
358pub enum GapSeverity {
359    Minor,
360    Moderate,
361    Major,
362    Critical,
363}
364
365// ---------------------------------------------------------------------------
366// Verification
367// ---------------------------------------------------------------------------
368
369/// Result of verifying a continuity claim.
370#[derive(Debug, Clone)]
371pub struct ContinuityVerification {
372    pub claim_id: ClaimId,
373    pub chain_valid: bool,
374    pub anchors_valid: bool,
375    pub signatures_valid: bool,
376    pub gaps: Vec<Gap>,
377    pub result: ContinuityResult,
378    pub verified_at: u64,
379    pub errors: Vec<String>,
380}
381
382impl ContinuityVerification {
383    /// Whether the overall verification passed.
384    pub fn is_valid(&self) -> bool {
385        self.chain_valid && self.anchors_valid && self.signatures_valid && self.gaps.is_empty()
386    }
387}
388
389/// Overall continuity result.
390#[derive(Debug, Clone, PartialEq)]
391pub enum ContinuityResult {
392    Continuous,
393    Discontinuous {
394        gap_count: usize,
395        max_gap_seconds: u64,
396    },
397    Uncertain {
398        reason: String,
399    },
400}