Skip to main content

elara_core/
event.rs

1//! Event definitions
2//!
3//! Events (ε) are lawful mutations of state in ELARA.
4//! Each event carries source identity, target state, mutation delta,
5//! temporal intent, and authority proof.
6
7use crate::{EventId, NodeId, StateId, StateTime, TimeIntent, VersionVector};
8
9/// Event type classification
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
11#[repr(u8)]
12pub enum EventType {
13    // Core state events
14    StateCreate = 0x01,
15    StateUpdate = 0x02,
16    StateDelete = 0x03,
17
18    // Authority events
19    AuthorityGrant = 0x10,
20    AuthorityRevoke = 0x11,
21
22    // Session events
23    SessionJoin = 0x20,
24    SessionLeave = 0x21,
25    SessionSync = 0x22,
26
27    // Time events
28    TimeSync = 0x30,
29    TimeCorrection = 0x31,
30
31    // Repair events
32    StateRequest = 0x40,
33    StateResponse = 0x41,
34    GapFill = 0x42,
35
36    // Profile-specific events (0x80+)
37    TextAppend = 0x80,
38    TextEdit = 0x81,
39    TextDelete = 0x82,
40    TextReact = 0x83,
41
42    VoiceFrame = 0x90,
43    VoiceMute = 0x91,
44
45    PresenceUpdate = 0xA0,
46    TypingStart = 0xA1,
47    TypingStop = 0xA2,
48
49    VisualKeyframe = 0xB0,
50    VisualDelta = 0xB1,
51
52    StreamStart = 0xC0,
53    StreamEnd = 0xC1,
54
55    FeedAppend = 0xD0,
56    FeedDelete = 0xD1,
57}
58
59impl EventType {
60    pub fn from_byte(b: u8) -> Option<Self> {
61        match b {
62            0x01 => Some(EventType::StateCreate),
63            0x02 => Some(EventType::StateUpdate),
64            0x03 => Some(EventType::StateDelete),
65            0x10 => Some(EventType::AuthorityGrant),
66            0x11 => Some(EventType::AuthorityRevoke),
67            0x20 => Some(EventType::SessionJoin),
68            0x21 => Some(EventType::SessionLeave),
69            0x22 => Some(EventType::SessionSync),
70            0x30 => Some(EventType::TimeSync),
71            0x31 => Some(EventType::TimeCorrection),
72            0x40 => Some(EventType::StateRequest),
73            0x41 => Some(EventType::StateResponse),
74            0x42 => Some(EventType::GapFill),
75            0x80 => Some(EventType::TextAppend),
76            0x81 => Some(EventType::TextEdit),
77            0x82 => Some(EventType::TextDelete),
78            0x83 => Some(EventType::TextReact),
79            0x90 => Some(EventType::VoiceFrame),
80            0x91 => Some(EventType::VoiceMute),
81            0xA0 => Some(EventType::PresenceUpdate),
82            0xA1 => Some(EventType::TypingStart),
83            0xA2 => Some(EventType::TypingStop),
84            0xB0 => Some(EventType::VisualKeyframe),
85            0xB1 => Some(EventType::VisualDelta),
86            0xC0 => Some(EventType::StreamStart),
87            0xC1 => Some(EventType::StreamEnd),
88            0xD0 => Some(EventType::FeedAppend),
89            0xD1 => Some(EventType::FeedDelete),
90            _ => None,
91        }
92    }
93
94    #[inline]
95    pub fn to_byte(self) -> u8 {
96        self as u8
97    }
98
99    /// Is this a core protocol event (vs profile-specific)?
100    pub fn is_core_protocol(self) -> bool {
101        (self as u8) < 0x80
102    }
103}
104
105/// Mutation operation
106#[derive(Clone, Debug)]
107pub enum MutationOp {
108    /// Set/replace value
109    Set(Vec<u8>),
110    /// Increment counter
111    Increment(i64),
112    /// Append to list
113    Append(Vec<u8>),
114    /// Merge (CRDT-style)
115    Merge(Vec<u8>),
116    /// Delete
117    Delete,
118    /// Blend (for continuous state)
119    Blend { value: Vec<u8>, weight: f32 },
120}
121
122impl MutationOp {
123    /// Encode mutation operation for wire format
124    pub fn encode(&self) -> Vec<u8> {
125        let mut buf = Vec::new();
126        match self {
127            MutationOp::Set(data) => {
128                buf.push(0x01);
129                buf.extend_from_slice(&(data.len() as u16).to_le_bytes());
130                buf.extend_from_slice(data);
131            }
132            MutationOp::Increment(delta) => {
133                buf.push(0x02);
134                buf.extend_from_slice(&delta.to_le_bytes());
135            }
136            MutationOp::Append(data) => {
137                buf.push(0x03);
138                buf.extend_from_slice(&(data.len() as u16).to_le_bytes());
139                buf.extend_from_slice(data);
140            }
141            MutationOp::Merge(data) => {
142                buf.push(0x04);
143                buf.extend_from_slice(&(data.len() as u16).to_le_bytes());
144                buf.extend_from_slice(data);
145            }
146            MutationOp::Delete => {
147                buf.push(0x05);
148            }
149            MutationOp::Blend { value, weight } => {
150                buf.push(0x06);
151                buf.extend_from_slice(&weight.to_le_bytes());
152                buf.extend_from_slice(&(value.len() as u16).to_le_bytes());
153                buf.extend_from_slice(value);
154            }
155        }
156        buf
157    }
158
159    /// Decode mutation operation from wire format
160    pub fn decode(buf: &[u8]) -> Option<(Self, usize)> {
161        if buf.is_empty() {
162            return None;
163        }
164
165        match buf[0] {
166            0x01 => {
167                // Set
168                if buf.len() < 3 {
169                    return None;
170                }
171                let len = u16::from_le_bytes([buf[1], buf[2]]) as usize;
172                if buf.len() < 3 + len {
173                    return None;
174                }
175                Some((MutationOp::Set(buf[3..3 + len].to_vec()), 3 + len))
176            }
177            0x02 => {
178                // Increment
179                if buf.len() < 9 {
180                    return None;
181                }
182                let delta = i64::from_le_bytes(buf[1..9].try_into().ok()?);
183                Some((MutationOp::Increment(delta), 9))
184            }
185            0x03 => {
186                // Append
187                if buf.len() < 3 {
188                    return None;
189                }
190                let len = u16::from_le_bytes([buf[1], buf[2]]) as usize;
191                if buf.len() < 3 + len {
192                    return None;
193                }
194                Some((MutationOp::Append(buf[3..3 + len].to_vec()), 3 + len))
195            }
196            0x04 => {
197                // Merge
198                if buf.len() < 3 {
199                    return None;
200                }
201                let len = u16::from_le_bytes([buf[1], buf[2]]) as usize;
202                if buf.len() < 3 + len {
203                    return None;
204                }
205                Some((MutationOp::Merge(buf[3..3 + len].to_vec()), 3 + len))
206            }
207            0x05 => {
208                // Delete
209                Some((MutationOp::Delete, 1))
210            }
211            0x06 => {
212                // Blend
213                if buf.len() < 7 {
214                    return None;
215                }
216                let weight = f32::from_le_bytes(buf[1..5].try_into().ok()?);
217                let len = u16::from_le_bytes([buf[5], buf[6]]) as usize;
218                if buf.len() < 7 + len {
219                    return None;
220                }
221                Some((
222                    MutationOp::Blend {
223                        value: buf[7..7 + len].to_vec(),
224                        weight,
225                    },
226                    7 + len,
227                ))
228            }
229            _ => None,
230        }
231    }
232}
233
234/// Authority proof - cryptographic proof of mutation authority
235#[derive(Clone, Debug)]
236pub struct AuthorityProof {
237    /// Signature over event content
238    pub signature: [u8; 64],
239    /// Optional delegation chain
240    pub delegation_chain: Option<Vec<DelegationLink>>,
241}
242
243impl AuthorityProof {
244    pub fn new(signature: [u8; 64]) -> Self {
245        AuthorityProof {
246            signature,
247            delegation_chain: None,
248        }
249    }
250
251    pub fn with_delegation(mut self, chain: Vec<DelegationLink>) -> Self {
252        self.delegation_chain = Some(chain);
253        self
254    }
255}
256
257/// Link in a delegation chain
258#[derive(Clone, Debug)]
259pub struct DelegationLink {
260    pub delegator: NodeId,
261    pub delegate: NodeId,
262    pub scope: Vec<u8>, // Encoded AuthorityScope
263    pub signature: [u8; 64],
264}
265
266/// Entropy hint for divergence control
267#[derive(Clone, Copy, Debug, Default)]
268pub struct EntropyHint {
269    /// Estimated entropy contribution
270    pub entropy: f32,
271    /// Confidence level (0.0 - 1.0)
272    pub confidence: f32,
273}
274
275impl EntropyHint {
276    pub fn new(entropy: f32, confidence: f32) -> Self {
277        EntropyHint {
278            entropy,
279            confidence,
280        }
281    }
282
283    pub fn certain() -> Self {
284        EntropyHint {
285            entropy: 0.0,
286            confidence: 1.0,
287        }
288    }
289
290    pub fn predicted(entropy: f32) -> Self {
291        EntropyHint {
292            entropy,
293            confidence: 0.5,
294        }
295    }
296}
297
298/// Event - a lawful mutation of state
299#[derive(Clone, Debug)]
300pub struct Event {
301    /// Event identity (for causal ordering)
302    pub id: EventId,
303    /// Event type
304    pub event_type: EventType,
305    /// Source node identity
306    pub source: NodeId,
307    /// Target state atom
308    pub target_state: StateId,
309    /// Expected version before mutation
310    pub version_ref: VersionVector,
311    /// The mutation operation
312    pub mutation: MutationOp,
313    /// Temporal intent
314    pub time_intent: TimeIntent,
315    /// Authority proof
316    pub authority_proof: AuthorityProof,
317    /// Entropy hint
318    pub entropy_hint: EntropyHint,
319}
320
321impl Event {
322    /// Create a new event
323    pub fn new(
324        source: NodeId,
325        seq: u64,
326        event_type: EventType,
327        target_state: StateId,
328        mutation: MutationOp,
329    ) -> Self {
330        Event {
331            id: EventId::new(source, seq),
332            event_type,
333            source,
334            target_state,
335            version_ref: VersionVector::new(),
336            mutation,
337            time_intent: TimeIntent::default(),
338            authority_proof: AuthorityProof::new([0u8; 64]),
339            entropy_hint: EntropyHint::certain(),
340        }
341    }
342
343    /// Set version reference
344    pub fn with_version(mut self, version: VersionVector) -> Self {
345        self.version_ref = version;
346        self
347    }
348
349    /// Set time intent
350    pub fn with_time_intent(mut self, intent: TimeIntent) -> Self {
351        self.time_intent = intent;
352        self
353    }
354
355    /// Set authority proof
356    pub fn with_authority_proof(mut self, proof: AuthorityProof) -> Self {
357        self.authority_proof = proof;
358        self
359    }
360
361    /// Set entropy hint
362    pub fn with_entropy_hint(mut self, hint: EntropyHint) -> Self {
363        self.entropy_hint = hint;
364        self
365    }
366
367    /// Get the absolute time intent given a reference
368    pub fn absolute_time(&self, reference: StateTime) -> StateTime {
369        self.time_intent.to_absolute(reference)
370    }
371}
372
373/// Validated event - passed all checks
374#[derive(Clone, Debug)]
375pub struct ValidatedEvent {
376    pub event: Event,
377    pub validated_at: StateTime,
378}
379
380impl ValidatedEvent {
381    pub fn new(event: Event, validated_at: StateTime) -> Self {
382        ValidatedEvent {
383            event,
384            validated_at,
385        }
386    }
387}
388
389/// Event processing result
390#[derive(Clone, Debug)]
391pub enum EventResult {
392    /// Event was applied successfully
393    Applied,
394    /// Event was merged with existing state
395    Merged,
396    /// Event was used for late correction
397    LateCorrected,
398    /// Event was buffered for future processing
399    Buffered,
400    /// Event was a duplicate (already processed)
401    Duplicate,
402    /// Event was rejected
403    Rejected(RejectReason),
404}
405
406/// Reason for event rejection
407#[derive(Clone, Debug)]
408pub enum RejectReason {
409    /// Source not authorized
410    Unauthorized,
411    /// Invalid signature
412    InvalidSignature,
413    /// Authority was revoked
414    AuthorityRevoked,
415    /// Causality violation
416    CausalityViolation,
417    /// Missing dependency
418    MissingDependency(EventId),
419    /// Out of bounds
420    OutOfBounds,
421    /// Rate limit exceeded
422    RateLimitExceeded,
423    /// Entropy exceeded
424    EntropyExceeded,
425    /// Too late (beyond correction horizon)
426    TooLate,
427    /// Replay detected
428    ReplayDetected,
429}
430
431#[cfg(test)]
432mod tests {
433    use super::*;
434
435    #[test]
436    fn test_event_type_roundtrip() {
437        for event_type in [
438            EventType::StateCreate,
439            EventType::StateUpdate,
440            EventType::TextAppend,
441            EventType::VoiceFrame,
442            EventType::VisualKeyframe,
443            EventType::StreamStart,
444            EventType::FeedAppend,
445        ] {
446            let byte = event_type.to_byte();
447            let recovered = EventType::from_byte(byte).unwrap();
448            assert_eq!(event_type, recovered);
449        }
450    }
451
452    #[test]
453    fn test_mutation_op_encode_decode() {
454        let ops = vec![
455            MutationOp::Set(vec![1, 2, 3, 4]),
456            MutationOp::Increment(42),
457            MutationOp::Append(vec![5, 6, 7]),
458            MutationOp::Delete,
459            MutationOp::Blend {
460                value: vec![8, 9],
461                weight: 0.5,
462            },
463        ];
464
465        for op in ops {
466            let encoded = op.encode();
467            let (decoded, len) = MutationOp::decode(&encoded).unwrap();
468            assert_eq!(len, encoded.len());
469
470            // Compare encoded forms (since MutationOp doesn't implement Eq)
471            assert_eq!(op.encode(), decoded.encode());
472        }
473    }
474
475    #[test]
476    fn test_event_creation() {
477        let source = NodeId::new(1);
478        let target = StateId::new(100);
479        let event = Event::new(
480            source,
481            1,
482            EventType::TextAppend,
483            target,
484            MutationOp::Append(b"Hello".to_vec()),
485        );
486
487        assert_eq!(event.source, source);
488        assert_eq!(event.target_state, target);
489        assert_eq!(event.id.seq, 1);
490    }
491}