Skip to main content

subcog/models/
events.rs

1//! Memory event types for audit and observability.
2
3use std::sync::Arc;
4
5use super::{Domain, MemoryId, Namespace};
6use crate::current_timestamp;
7use uuid::Uuid;
8
9/// Shared event metadata required for observability.
10#[derive(Debug, Clone)]
11pub struct EventMeta {
12    /// Unique identifier for this event.
13    pub event_id: String,
14    /// Optional correlation identifier for request/trace linking.
15    pub correlation_id: Option<String>,
16    /// Event source component.
17    pub source: &'static str,
18    /// Timestamp (Unix epoch seconds).
19    pub timestamp: u64,
20}
21
22impl EventMeta {
23    /// Creates new event metadata using the current timestamp.
24    #[must_use]
25    pub fn new(source: &'static str, correlation_id: Option<String>) -> Self {
26        Self::with_timestamp(source, correlation_id, current_timestamp())
27    }
28
29    /// Creates new event metadata with a specified timestamp.
30    #[must_use]
31    pub fn with_timestamp(
32        source: &'static str,
33        correlation_id: Option<String>,
34        timestamp: u64,
35    ) -> Self {
36        Self {
37            event_id: Uuid::new_v4().to_string(),
38            correlation_id,
39            source,
40            timestamp,
41        }
42    }
43}
44
45/// Events emitted during memory operations.
46#[derive(Debug, Clone)]
47pub enum MemoryEvent {
48    /// A memory was captured.
49    Captured {
50        /// Event metadata.
51        meta: EventMeta,
52        /// The ID of the captured memory.
53        memory_id: MemoryId,
54        /// The namespace.
55        namespace: Namespace,
56        /// The domain.
57        domain: Domain,
58        /// Content length in bytes.
59        content_length: usize,
60    },
61    /// A memory was retrieved via search.
62    Retrieved {
63        /// Event metadata.
64        meta: EventMeta,
65        /// The ID of the retrieved memory.
66        memory_id: MemoryId,
67        /// The search query that matched (`Arc<str>` for zero-copy sharing, PERF-C1).
68        query: Arc<str>,
69        /// The similarity score.
70        score: f32,
71    },
72    /// A memory was updated.
73    Updated {
74        /// Event metadata.
75        meta: EventMeta,
76        /// The ID of the updated memory.
77        memory_id: MemoryId,
78        /// Fields that were modified.
79        modified_fields: Vec<String>,
80    },
81    /// A memory was archived.
82    Archived {
83        /// Event metadata.
84        meta: EventMeta,
85        /// The ID of the archived memory.
86        memory_id: MemoryId,
87        /// Reason for archiving.
88        reason: String,
89    },
90    /// A memory was deleted.
91    Deleted {
92        /// Event metadata.
93        meta: EventMeta,
94        /// The ID of the deleted memory.
95        memory_id: MemoryId,
96        /// Reason for deletion.
97        reason: String,
98    },
99    /// Content was redacted for security.
100    Redacted {
101        /// Event metadata.
102        meta: EventMeta,
103        /// The ID of the affected memory.
104        memory_id: MemoryId,
105        /// Type of content redacted.
106        redaction_type: String,
107    },
108    /// Memories were synchronized with remote.
109    Synced {
110        /// Event metadata.
111        meta: EventMeta,
112        /// Number of memories pushed.
113        pushed: usize,
114        /// Number of memories pulled.
115        pulled: usize,
116        /// Number of conflicts resolved.
117        conflicts: usize,
118    },
119    /// Consolidation occurred.
120    Consolidated {
121        /// Event metadata.
122        meta: EventMeta,
123        /// Number of memories processed.
124        processed: usize,
125        /// Number of memories archived.
126        archived: usize,
127        /// Number of memories merged.
128        merged: usize,
129    },
130    /// MCP server started.
131    McpStarted {
132        /// Event metadata.
133        meta: EventMeta,
134        /// Transport type (stdio/http).
135        transport: String,
136        /// HTTP port if applicable.
137        port: Option<u16>,
138    },
139    /// MCP authentication failed.
140    McpAuthFailed {
141        /// Event metadata.
142        meta: EventMeta,
143        /// Optional client identifier.
144        client_id: Option<String>,
145        /// Failure reason.
146        reason: String,
147    },
148    /// MCP tool execution completed.
149    McpToolExecuted {
150        /// Event metadata.
151        meta: EventMeta,
152        /// Tool name.
153        tool_name: String,
154        /// Execution status (success/error).
155        status: String,
156        /// Execution duration in milliseconds.
157        duration_ms: u64,
158        /// Optional error string.
159        error: Option<String>,
160    },
161    /// MCP request error (invalid params, tool failure, etc.).
162    McpRequestError {
163        /// Event metadata.
164        meta: EventMeta,
165        /// Operation name.
166        operation: String,
167        /// Error message.
168        error: String,
169    },
170    /// Hook invocation event.
171    HookInvoked {
172        /// Event metadata.
173        meta: EventMeta,
174        /// Hook name.
175        hook: String,
176    },
177    /// Hook classification event.
178    HookClassified {
179        /// Event metadata.
180        meta: EventMeta,
181        /// Hook name.
182        hook: String,
183        /// Classification label.
184        classification: String,
185        /// Classifier source (keyword/llm/hybrid).
186        classifier: String,
187        /// Confidence score.
188        confidence: f32,
189    },
190    /// Hook capture decision event.
191    HookCaptureDecision {
192        /// Event metadata.
193        meta: EventMeta,
194        /// Hook name.
195        hook: String,
196        /// Decision outcome.
197        decision: String,
198        /// Namespace selected for capture.
199        namespace: Option<String>,
200        /// Memory ID if captured.
201        memory_id: Option<MemoryId>,
202    },
203    /// Hook failure event.
204    HookFailed {
205        /// Event metadata.
206        meta: EventMeta,
207        /// Hook name.
208        hook: String,
209        /// Error message.
210        error: String,
211    },
212}
213
214impl MemoryEvent {
215    /// Returns the event type name.
216    #[must_use]
217    pub const fn event_type(&self) -> &'static str {
218        match self {
219            Self::Captured { .. } => "captured",
220            Self::Retrieved { .. } => "retrieved",
221            Self::Updated { .. } => "updated",
222            Self::Archived { .. } => "archived",
223            Self::Deleted { .. } => "deleted",
224            Self::Redacted { .. } => "redacted",
225            Self::Synced { .. } => "synced",
226            Self::Consolidated { .. } => "consolidated",
227            Self::McpStarted { .. } => "mcp.started",
228            Self::McpAuthFailed { .. } => "mcp.auth_failed",
229            Self::McpToolExecuted { .. } => "mcp.tool_executed",
230            Self::McpRequestError { .. } => "mcp.request_error",
231            Self::HookInvoked { .. } => "hook.invoked",
232            Self::HookClassified { .. } => "hook.classified",
233            Self::HookCaptureDecision { .. } => "hook.capture_decision",
234            Self::HookFailed { .. } => "hook.failed",
235        }
236    }
237
238    /// Returns the timestamp of the event.
239    #[must_use]
240    pub const fn timestamp(&self) -> u64 {
241        match self {
242            Self::Captured { meta, .. }
243            | Self::Retrieved { meta, .. }
244            | Self::Updated { meta, .. }
245            | Self::Archived { meta, .. }
246            | Self::Deleted { meta, .. }
247            | Self::Redacted { meta, .. }
248            | Self::Synced { meta, .. }
249            | Self::Consolidated { meta, .. }
250            | Self::McpStarted { meta, .. }
251            | Self::McpAuthFailed { meta, .. }
252            | Self::McpToolExecuted { meta, .. }
253            | Self::McpRequestError { meta, .. }
254            | Self::HookInvoked { meta, .. }
255            | Self::HookClassified { meta, .. }
256            | Self::HookCaptureDecision { meta, .. }
257            | Self::HookFailed { meta, .. } => meta.timestamp,
258        }
259    }
260
261    /// Returns the event metadata.
262    #[must_use]
263    pub const fn meta(&self) -> &EventMeta {
264        match self {
265            Self::Captured { meta, .. }
266            | Self::Retrieved { meta, .. }
267            | Self::Updated { meta, .. }
268            | Self::Archived { meta, .. }
269            | Self::Deleted { meta, .. }
270            | Self::Redacted { meta, .. }
271            | Self::Synced { meta, .. }
272            | Self::Consolidated { meta, .. }
273            | Self::McpStarted { meta, .. }
274            | Self::McpAuthFailed { meta, .. }
275            | Self::McpToolExecuted { meta, .. }
276            | Self::McpRequestError { meta, .. }
277            | Self::HookInvoked { meta, .. }
278            | Self::HookClassified { meta, .. }
279            | Self::HookCaptureDecision { meta, .. }
280            | Self::HookFailed { meta, .. } => meta,
281        }
282    }
283}