Skip to main content

elara_core/
models.rs

1//! ELARA Formal Protocol Models v1
2//!
3//! The five foundational models that govern how ELARA perceives and handles reality.
4//! Every module must be explainable through these models.
5//!
6//! # The Five Models
7//!
8//! | Model | ELARA Treats As |
9//! |-------|-----------------|
10//! | Failure | Distortion field |
11//! | Timing | Local perception axis |
12//! | Trust | Cryptographic continuity |
13//! | Event | Ontological truth |
14//! | Media | Perceptual fabric |
15//!
16//! # Derived from Hard Invariants
17//!
18//! - Failure Model ← INV-3: Experience Degrades, Never Collapses
19//! - Timing Model ← INV-1: Reality Never Waits
20//! - Trust Model ← INV-5: Identity Survives Transport
21//! - Event Model ← INV-4: Event Is Truth, State Is Projection
22//! - Media Model ← INV-2: Presence Over Packets
23
24use std::fmt;
25
26/// The five formal protocol models of ELARA.
27///
28/// Every module must be explainable through these models.
29/// If a module cannot answer the model's core question correctly,
30/// it is not part of ELARA core.
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
32#[repr(u8)]
33pub enum ProtocolModel {
34    /// Failure Model: Failure is distortion, not termination.
35    ///
36    /// Core question: "What is your failure model?"
37    /// Valid answer: Distortion, not termination
38    ///
39    /// ELARA assumes all failure conditions are normal:
40    /// - Extreme jitter
41    /// - Arbitrary packet loss
42    /// - Reordering, duplication
43    /// - Network partition
44    /// - Byzantine nodes
45    /// - Device death
46    /// - Clock drift
47    /// - Server death
48    Failure = 1,
49
50    /// Timing Model: Time is local. Order is reconstructed.
51    ///
52    /// Core question: "Whose clock do you depend on?"
53    /// Valid answer: Local only, reconstructed order
54    ///
55    /// Properties:
56    /// - No protocol decision depends on wall-clock correctness
57    /// - Causality > Timestamp
58    /// - Liveness > Consistency
59    /// - Reconstruction > Synchronization
60    Timing = 2,
61
62    /// Trust Model: Identity is cryptographic, not topological.
63    ///
64    /// Core question: "Where does trust come from?"
65    /// Valid answer: Cryptographic continuity
66    ///
67    /// Trust is built from:
68    /// - Continuity of keys
69    /// - Behavior history
70    /// - Event lineage
71    ///
72    /// NOT from: IP, server, TLS channel, login session
73    Trust = 3,
74
75    /// Event Model: Event is truth. State is a story we tell about it.
76    ///
77    /// Core question: "Where is your event-truth?"
78    /// Valid answer: In signed, immutable events
79    ///
80    /// Properties:
81    /// - Append-only reality
82    /// - Forks are legal
83    /// - Convergence is negotiated, not enforced
84    /// - History > Snapshot
85    Event = 4,
86
87    /// Media Model: Media is perception, not data.
88    ///
89    /// Core question: "If media has holes, what still lives?"
90    /// Valid answer: Perception continues
91    ///
92    /// Properties:
93    /// - Silence is valid media
94    /// - Approximation is first-class
95    /// - Prediction is legal
96    /// - Pipelines support stretching, concealment, hallucination
97    Media = 5,
98}
99
100impl ProtocolModel {
101    /// Get the model code (e.g., "MODEL-1")
102    pub fn code(&self) -> &'static str {
103        match self {
104            ProtocolModel::Failure => "MODEL-1",
105            ProtocolModel::Timing => "MODEL-2",
106            ProtocolModel::Trust => "MODEL-3",
107            ProtocolModel::Event => "MODEL-4",
108            ProtocolModel::Media => "MODEL-5",
109        }
110    }
111
112    /// Get the model name
113    pub fn name(&self) -> &'static str {
114        match self {
115            ProtocolModel::Failure => "Failure Model",
116            ProtocolModel::Timing => "Timing Model",
117            ProtocolModel::Trust => "Trust Model",
118            ProtocolModel::Event => "Event Model",
119            ProtocolModel::Media => "Media Model",
120        }
121    }
122
123    /// Get the model axiom
124    pub fn axiom(&self) -> &'static str {
125        match self {
126            ProtocolModel::Failure => "Failure is distortion, not termination",
127            ProtocolModel::Timing => "Time is local. Order is reconstructed",
128            ProtocolModel::Trust => "Identity is cryptographic, not topological",
129            ProtocolModel::Event => "Event is truth. State is a story we tell about it",
130            ProtocolModel::Media => "Media is perception, not data",
131        }
132    }
133
134    /// Get the core compliance question for this model
135    pub fn compliance_question(&self) -> &'static str {
136        match self {
137            ProtocolModel::Failure => "What is your failure model?",
138            ProtocolModel::Timing => "Whose clock do you depend on?",
139            ProtocolModel::Trust => "Where does trust come from?",
140            ProtocolModel::Event => "Where is your event-truth?",
141            ProtocolModel::Media => "If media has holes, what still lives?",
142        }
143    }
144
145    /// Get the valid answer pattern for this model
146    pub fn valid_answer(&self) -> &'static str {
147        match self {
148            ProtocolModel::Failure => "Distortion, not termination",
149            ProtocolModel::Timing => "Local only, reconstructed order",
150            ProtocolModel::Trust => "Cryptographic continuity",
151            ProtocolModel::Event => "In signed, immutable events",
152            ProtocolModel::Media => "Perception continues",
153        }
154    }
155
156    /// Get the related Hard Invariant
157    pub fn related_invariant(&self) -> crate::Invariant {
158        match self {
159            ProtocolModel::Failure => crate::Invariant::ExperienceDegradesNeverCollapses,
160            ProtocolModel::Timing => crate::Invariant::RealityNeverWaits,
161            ProtocolModel::Trust => crate::Invariant::IdentitySurvivesTransport,
162            ProtocolModel::Event => crate::Invariant::EventIsTruth,
163            ProtocolModel::Media => crate::Invariant::PresenceOverPackets,
164        }
165    }
166
167    /// Get all models
168    pub fn all() -> &'static [ProtocolModel] {
169        &[
170            ProtocolModel::Failure,
171            ProtocolModel::Timing,
172            ProtocolModel::Trust,
173            ProtocolModel::Event,
174            ProtocolModel::Media,
175        ]
176    }
177}
178
179impl fmt::Display for ProtocolModel {
180    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181        write!(f, "{}: {}", self.code(), self.name())
182    }
183}
184
185/// Reconstructability class for media atoms.
186///
187/// Defines how a media unit should be handled if missing or incomplete.
188#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
189#[repr(u8)]
190pub enum ReconstructabilityClass {
191    /// Critical for experience - must be felt
192    /// Example: Voice onset, key visual frame
193    MustFeel = 0,
194
195    /// Can be estimated/approximated
196    /// Example: Mid-syllable, motion blur
197    MayApproximate = 1,
198
199    /// Can be synthesized from context
200    /// Example: Silence, static background
201    Reconstructable = 2,
202
203    /// Can be dropped without impact
204    /// Example: Enhancement, cosmetic effects
205    Ignorable = 3,
206}
207
208impl ReconstructabilityClass {
209    /// Get the priority (lower = more important)
210    pub fn priority(&self) -> u8 {
211        *self as u8
212    }
213
214    /// Check if this class can be dropped under pressure
215    pub fn droppable(&self) -> bool {
216        matches!(self, Self::Ignorable | Self::Reconstructable)
217    }
218
219    /// Check if this class requires reconstruction if missing
220    pub fn requires_reconstruction(&self) -> bool {
221        matches!(self, Self::MustFeel | Self::MayApproximate)
222    }
223}
224
225/// Perceptual weight for media atoms.
226///
227/// Indicates the importance of a media unit for human perception.
228#[derive(Debug, Clone, Copy, PartialEq)]
229pub struct PerceptualWeight {
230    /// Emotional importance (0.0 - 1.0)
231    pub emotional: f32,
232
233    /// Presence importance (0.0 - 1.0)
234    pub presence: f32,
235
236    /// Continuity importance (0.0 - 1.0)
237    pub continuity: f32,
238
239    /// Reconstructability class
240    pub class: ReconstructabilityClass,
241}
242
243impl PerceptualWeight {
244    /// Create a new perceptual weight
245    pub fn new(
246        emotional: f32,
247        presence: f32,
248        continuity: f32,
249        class: ReconstructabilityClass,
250    ) -> Self {
251        Self {
252            emotional: emotional.clamp(0.0, 1.0),
253            presence: presence.clamp(0.0, 1.0),
254            continuity: continuity.clamp(0.0, 1.0),
255            class,
256        }
257    }
258
259    /// Critical media - must be delivered
260    pub fn critical() -> Self {
261        Self::new(1.0, 1.0, 1.0, ReconstructabilityClass::MustFeel)
262    }
263
264    /// Important media - should be delivered
265    pub fn important() -> Self {
266        Self::new(0.7, 0.7, 0.7, ReconstructabilityClass::MayApproximate)
267    }
268
269    /// Normal media - can be approximated
270    pub fn normal() -> Self {
271        Self::new(0.5, 0.5, 0.5, ReconstructabilityClass::Reconstructable)
272    }
273
274    /// Cosmetic media - can be dropped
275    pub fn cosmetic() -> Self {
276        Self::new(0.2, 0.2, 0.2, ReconstructabilityClass::Ignorable)
277    }
278
279    /// Calculate overall importance score
280    pub fn importance(&self) -> f32 {
281        (self.emotional + self.presence + self.continuity) / 3.0
282    }
283}
284
285impl Default for PerceptualWeight {
286    fn default() -> Self {
287        Self::normal()
288    }
289}
290
291/// Model compliance result for a module.
292#[derive(Debug, Clone)]
293pub struct ModelCompliance {
294    pub model: ProtocolModel,
295    pub compliant: bool,
296    pub answer: String,
297}
298
299/// Check module compliance against all protocol models.
300///
301/// Returns a list of compliance results for each model.
302pub fn check_model_compliance<F>(mut checker: F) -> Vec<ModelCompliance>
303where
304    F: FnMut(ProtocolModel) -> (bool, String),
305{
306    ProtocolModel::all()
307        .iter()
308        .map(|&model| {
309            let (compliant, answer) = checker(model);
310            ModelCompliance {
311                model,
312                compliant,
313                answer,
314            }
315        })
316        .collect()
317}
318
319/// Marker trait for types that comply with ELARA protocol models.
320pub trait ModelCompliant {
321    /// Answer the failure model question
322    fn failure_model(&self) -> &'static str {
323        "Distortion field - no termination"
324    }
325
326    /// Answer the timing model question
327    fn timing_model(&self) -> &'static str {
328        "Local time only - order reconstructed"
329    }
330
331    /// Answer the trust model question
332    fn trust_model(&self) -> &'static str {
333        "Cryptographic continuity"
334    }
335
336    /// Answer the event model question
337    fn event_model(&self) -> &'static str {
338        "Signed immutable events"
339    }
340
341    /// Answer the media model question
342    fn media_model(&self) -> &'static str {
343        "Perception continues"
344    }
345}
346
347#[cfg(test)]
348mod tests {
349    use super::*;
350
351    #[test]
352    fn test_model_codes() {
353        assert_eq!(ProtocolModel::Failure.code(), "MODEL-1");
354        assert_eq!(ProtocolModel::Timing.code(), "MODEL-2");
355        assert_eq!(ProtocolModel::Trust.code(), "MODEL-3");
356        assert_eq!(ProtocolModel::Event.code(), "MODEL-4");
357        assert_eq!(ProtocolModel::Media.code(), "MODEL-5");
358    }
359
360    #[test]
361    fn test_all_models() {
362        assert_eq!(ProtocolModel::all().len(), 5);
363    }
364
365    #[test]
366    fn test_model_invariant_relationship() {
367        use crate::Invariant;
368
369        assert_eq!(
370            ProtocolModel::Failure.related_invariant(),
371            Invariant::ExperienceDegradesNeverCollapses
372        );
373        assert_eq!(
374            ProtocolModel::Timing.related_invariant(),
375            Invariant::RealityNeverWaits
376        );
377        assert_eq!(
378            ProtocolModel::Trust.related_invariant(),
379            Invariant::IdentitySurvivesTransport
380        );
381        assert_eq!(
382            ProtocolModel::Event.related_invariant(),
383            Invariant::EventIsTruth
384        );
385        assert_eq!(
386            ProtocolModel::Media.related_invariant(),
387            Invariant::PresenceOverPackets
388        );
389    }
390
391    #[test]
392    fn test_reconstructability_priority() {
393        assert!(
394            ReconstructabilityClass::MustFeel.priority()
395                < ReconstructabilityClass::Ignorable.priority()
396        );
397    }
398
399    #[test]
400    fn test_perceptual_weight() {
401        let critical = PerceptualWeight::critical();
402        let cosmetic = PerceptualWeight::cosmetic();
403
404        assert!(critical.importance() > cosmetic.importance());
405        assert!(!critical.class.droppable());
406        assert!(cosmetic.class.droppable());
407    }
408
409    #[test]
410    fn test_check_model_compliance() {
411        let results =
412            check_model_compliance(|model| (true, format!("Compliant with {}", model.name())));
413
414        assert_eq!(results.len(), 5);
415        assert!(results.iter().all(|r| r.compliant));
416    }
417
418    #[test]
419    fn test_model_display() {
420        let model = ProtocolModel::Failure;
421        let display = format!("{}", model);
422        assert!(display.contains("MODEL-1"));
423        assert!(display.contains("Failure Model"));
424    }
425}