1use std::fmt;
13use std::ops::BitOr;
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
26#[repr(u8)]
27pub enum NodeClass {
28 Origin = 0b0001,
32
33 Transmutation = 0b0010,
37
38 Propagation = 0b0100,
42
43 Witness = 0b1000,
47}
48
49impl NodeClass {
50 pub fn name(&self) -> &'static str {
52 match self {
53 NodeClass::Origin => "Origin",
54 NodeClass::Transmutation => "Transmutation",
55 NodeClass::Propagation => "Propagation",
56 NodeClass::Witness => "Witness",
57 }
58 }
59
60 pub fn all() -> &'static [NodeClass] {
62 &[
63 NodeClass::Origin,
64 NodeClass::Transmutation,
65 NodeClass::Propagation,
66 NodeClass::Witness,
67 ]
68 }
69}
70
71#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
73pub struct NodeClassSet(u8);
74
75impl NodeClassSet {
76 pub fn empty() -> Self {
78 Self(0)
79 }
80
81 pub fn with(self, class: NodeClass) -> Self {
83 Self(self.0 | class as u8)
84 }
85
86 pub fn contains(&self, class: NodeClass) -> bool {
88 (self.0 & class as u8) != 0
89 }
90
91 pub fn is_empty(&self) -> bool {
93 self.0 == 0
94 }
95
96 pub fn smartphone() -> Self {
98 Self::empty()
99 .with(NodeClass::Origin)
100 .with(NodeClass::Transmutation)
101 .with(NodeClass::Witness)
102 }
103
104 pub fn relay_server() -> Self {
105 Self::empty().with(NodeClass::Propagation)
106 }
107
108 pub fn ai_agent() -> Self {
109 Self::empty()
110 .with(NodeClass::Origin)
111 .with(NodeClass::Transmutation)
112 .with(NodeClass::Witness)
113 }
114
115 pub fn archive() -> Self {
116 Self::empty()
117 .with(NodeClass::Propagation)
118 .with(NodeClass::Witness)
119 }
120}
121
122impl BitOr for NodeClass {
123 type Output = NodeClassSet;
124
125 fn bitor(self, rhs: Self) -> Self::Output {
126 NodeClassSet::empty().with(self).with(rhs)
127 }
128}
129
130impl BitOr<NodeClass> for NodeClassSet {
131 type Output = NodeClassSet;
132
133 fn bitor(self, rhs: NodeClass) -> Self::Output {
134 self.with(rhs)
135 }
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
146pub enum EventOperator {
147 Composition,
150
151 Transmutation,
154
155 CausalPrecedence,
158
159 CoPresence,
162
163 Degradation,
166}
167
168impl EventOperator {
169 pub fn symbol(&self) -> &'static str {
171 match self {
172 EventOperator::Composition => "⊕",
173 EventOperator::Transmutation => "⊗",
174 EventOperator::CausalPrecedence => "≺",
175 EventOperator::CoPresence => "∥",
176 EventOperator::Degradation => "⊘",
177 }
178 }
179
180 pub fn name(&self) -> &'static str {
182 match self {
183 EventOperator::Composition => "Composition",
184 EventOperator::Transmutation => "Transmutation",
185 EventOperator::CausalPrecedence => "Causal Precedence",
186 EventOperator::CoPresence => "Co-presence",
187 EventOperator::Degradation => "Degradation",
188 }
189 }
190}
191
192#[derive(Debug, Clone, Copy, PartialEq)]
203pub struct PresenceVector {
204 pub liveness: f32,
206
207 pub immediacy: f32,
209
210 pub coherence: f32,
212
213 pub relational_continuity: f32,
215
216 pub emotional_bandwidth: f32,
218}
219
220impl PresenceVector {
221 pub fn new(
223 liveness: f32,
224 immediacy: f32,
225 coherence: f32,
226 relational: f32,
227 emotional: f32,
228 ) -> Self {
229 Self {
230 liveness: liveness.clamp(0.0, 1.0),
231 immediacy: immediacy.clamp(0.0, 1.0),
232 coherence: coherence.clamp(0.0, 1.0),
233 relational_continuity: relational.clamp(0.0, 1.0),
234 emotional_bandwidth: emotional.clamp(0.0, 1.0),
235 }
236 }
237
238 pub fn full() -> Self {
240 Self::new(1.0, 1.0, 1.0, 1.0, 1.0)
241 }
242
243 pub fn minimal() -> Self {
245 Self::new(0.1, 0.0, 0.0, 0.0, 0.0)
246 }
247
248 pub fn zero() -> Self {
250 Self::new(0.0, 0.0, 0.0, 0.0, 0.0)
251 }
252
253 pub fn score(&self) -> f32 {
255 (self.liveness
256 + self.immediacy
257 + self.coherence
258 + self.relational_continuity
259 + self.emotional_bandwidth)
260 / 5.0
261 }
262
263 pub fn is_alive(&self) -> bool {
265 self.liveness > 0.0
266 || self.immediacy > 0.0
267 || self.coherence > 0.0
268 || self.relational_continuity > 0.0
269 || self.emotional_bandwidth > 0.0
270 }
271
272 pub fn as_array(&self) -> [f32; 5] {
274 [
275 self.liveness,
276 self.immediacy,
277 self.coherence,
278 self.relational_continuity,
279 self.emotional_bandwidth,
280 ]
281 }
282
283 pub fn min_component(&self) -> f32 {
285 self.as_array().into_iter().fold(f32::MAX, f32::min)
286 }
287
288 pub fn max_component(&self) -> f32 {
290 self.as_array().into_iter().fold(f32::MIN, f32::max)
291 }
292}
293
294impl Default for PresenceVector {
295 fn default() -> Self {
296 Self::full()
297 }
298}
299
300impl fmt::Display for PresenceVector {
301 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
302 write!(
303 f,
304 "P = ⟨L:{:.2}, I:{:.2}, C:{:.2}, R:{:.2}, E:{:.2}⟩ (score: {:.2})",
305 self.liveness,
306 self.immediacy,
307 self.coherence,
308 self.relational_continuity,
309 self.emotional_bandwidth,
310 self.score()
311 )
312 }
313}
314
315#[allow(non_camel_case_types)]
324#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
325#[repr(u8)]
326pub enum DegradationLevel {
327 L0_FullPerception = 0,
329
330 L1_DistortedPerception = 1,
332
333 L2_FragmentedPerception = 2,
335
336 L3_SymbolicPresence = 3,
338
339 L4_MinimalPresence = 4,
341
342 L5_LatentPresence = 5,
344}
345
346impl DegradationLevel {
347 pub fn level(&self) -> u8 {
349 *self as u8
350 }
351
352 pub fn name(&self) -> &'static str {
354 match self {
355 Self::L0_FullPerception => "Full Perception",
356 Self::L1_DistortedPerception => "Distorted Perception",
357 Self::L2_FragmentedPerception => "Fragmented Perception",
358 Self::L3_SymbolicPresence => "Symbolic Presence",
359 Self::L4_MinimalPresence => "Minimal Presence",
360 Self::L5_LatentPresence => "Latent Presence",
361 }
362 }
363
364 pub fn degrade(&self) -> Option<Self> {
367 match self {
368 Self::L0_FullPerception => Some(Self::L1_DistortedPerception),
369 Self::L1_DistortedPerception => Some(Self::L2_FragmentedPerception),
370 Self::L2_FragmentedPerception => Some(Self::L3_SymbolicPresence),
371 Self::L3_SymbolicPresence => Some(Self::L4_MinimalPresence),
372 Self::L4_MinimalPresence => Some(Self::L5_LatentPresence),
373 Self::L5_LatentPresence => None, }
375 }
376
377 pub fn improve(&self) -> Option<Self> {
380 match self {
381 Self::L0_FullPerception => None, Self::L1_DistortedPerception => Some(Self::L0_FullPerception),
383 Self::L2_FragmentedPerception => Some(Self::L1_DistortedPerception),
384 Self::L3_SymbolicPresence => Some(Self::L2_FragmentedPerception),
385 Self::L4_MinimalPresence => Some(Self::L3_SymbolicPresence),
386 Self::L5_LatentPresence => Some(Self::L4_MinimalPresence),
387 }
388 }
389
390 pub fn is_worse_than(&self, other: Self) -> bool {
392 self.level() > other.level()
393 }
394
395 pub fn is_better_than(&self, other: Self) -> bool {
397 self.level() < other.level()
398 }
399
400 pub fn all() -> &'static [Self] {
402 &[
403 Self::L0_FullPerception,
404 Self::L1_DistortedPerception,
405 Self::L2_FragmentedPerception,
406 Self::L3_SymbolicPresence,
407 Self::L4_MinimalPresence,
408 Self::L5_LatentPresence,
409 ]
410 }
411}
412
413impl fmt::Display for DegradationLevel {
414 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
415 write!(f, "L{}: {}", self.level(), self.name())
416 }
417}
418
419#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
427pub enum ChaosCategory {
428 Ontological,
431
432 Temporal,
435
436 Topological,
439
440 Adversarial,
443
444 Perceptual,
447}
448
449impl ChaosCategory {
450 pub fn name(&self) -> &'static str {
452 match self {
453 Self::Ontological => "Ontological Chaos",
454 Self::Temporal => "Temporal Chaos",
455 Self::Topological => "Topological Chaos",
456 Self::Adversarial => "Adversarial Chaos",
457 Self::Perceptual => "Perceptual Chaos",
458 }
459 }
460
461 pub fn presence_floor(&self) -> DegradationLevel {
463 match self {
464 Self::Ontological => DegradationLevel::L4_MinimalPresence,
465 Self::Temporal => DegradationLevel::L3_SymbolicPresence,
466 Self::Topological => DegradationLevel::L5_LatentPresence,
467 Self::Adversarial => DegradationLevel::L3_SymbolicPresence,
468 Self::Perceptual => DegradationLevel::L2_FragmentedPerception,
469 }
470 }
471
472 pub fn all() -> &'static [Self] {
474 &[
475 Self::Ontological,
476 Self::Temporal,
477 Self::Topological,
478 Self::Adversarial,
479 Self::Perceptual,
480 ]
481 }
482}
483
484#[derive(Debug, Clone)]
486pub struct ChaosSuccessCriteria {
487 pub min_presence: PresenceVector,
489
490 pub max_degradation: DegradationLevel,
492
493 pub lineage_intact: bool,
495
496 pub identity_continuous: bool,
498}
499
500impl ChaosSuccessCriteria {
501 pub fn default_for(category: ChaosCategory) -> Self {
503 Self {
504 min_presence: PresenceVector::minimal(),
505 max_degradation: category.presence_floor(),
506 lineage_intact: true,
507 identity_continuous: true,
508 }
509 }
510}
511
512#[derive(Debug, Clone)]
514pub struct ChaosTestResult {
515 pub passed: bool,
517
518 pub presence: PresenceVector,
520
521 pub level: DegradationLevel,
523
524 pub lineage_intact: bool,
526
527 pub identity_continuous: bool,
529}
530
531impl ChaosTestResult {
532 pub fn meets_criteria(&self, criteria: &ChaosSuccessCriteria) -> bool {
534 self.presence.is_alive()
535 && self.level <= criteria.max_degradation
536 && (!criteria.lineage_intact || self.lineage_intact)
537 && (!criteria.identity_continuous || self.identity_continuous)
538 }
539}
540
541#[cfg(test)]
542mod tests {
543 use super::*;
544
545 #[test]
546 fn test_node_class_set() {
547 let smartphone = NodeClassSet::smartphone();
548 assert!(smartphone.contains(NodeClass::Origin));
549 assert!(smartphone.contains(NodeClass::Transmutation));
550 assert!(smartphone.contains(NodeClass::Witness));
551 assert!(!smartphone.contains(NodeClass::Propagation));
552
553 let relay = NodeClassSet::relay_server();
554 assert!(relay.contains(NodeClass::Propagation));
555 assert!(!relay.contains(NodeClass::Origin));
556 }
557
558 #[test]
559 fn test_presence_vector() {
560 let full = PresenceVector::full();
561 assert_eq!(full.score(), 1.0);
562 assert!(full.is_alive());
563
564 let minimal = PresenceVector::minimal();
565 assert!(minimal.is_alive());
566 assert!(minimal.score() < 0.1);
567
568 let zero = PresenceVector::zero();
569 assert!(!zero.is_alive());
570 }
571
572 #[test]
573 fn test_degradation_ladder() {
574 let mut level = DegradationLevel::L0_FullPerception;
575
576 let mut count = 0;
578 while let Some(next) = level.degrade() {
579 assert!(next.is_worse_than(level));
580 level = next;
581 count += 1;
582 }
583 assert_eq!(count, 5);
584 assert_eq!(level, DegradationLevel::L5_LatentPresence);
585
586 while let Some(prev) = level.improve() {
588 assert!(prev.is_better_than(level));
589 level = prev;
590 }
591 assert_eq!(level, DegradationLevel::L0_FullPerception);
592 }
593
594 #[test]
595 fn test_chaos_categories() {
596 for category in ChaosCategory::all() {
597 let floor = category.presence_floor();
598 assert!(floor.level() <= 5);
600 }
601 }
602
603 #[test]
604 fn test_event_operators() {
605 assert_eq!(EventOperator::Composition.symbol(), "⊕");
606 assert_eq!(EventOperator::CausalPrecedence.symbol(), "≺");
607 assert_eq!(EventOperator::Degradation.symbol(), "⊘");
608 }
609
610 #[test]
611 fn test_presence_display() {
612 let p = PresenceVector::new(0.9, 0.8, 0.7, 0.6, 0.5);
613 let display = format!("{}", p);
614 assert!(display.contains("L:0.90"));
615 assert!(display.contains("score:"));
616 }
617}