1use crate::mem8::wave::MemoryWave;
6use std::collections::{HashMap, VecDeque};
7use std::sync::{Arc, RwLock};
8use std::time::{Duration, Instant};
9
10pub struct Custodian {
12 pub safe_threshold: f32,
14 pub critical_threshold: f32,
16 pattern_history: RwLock<HashMap<u64, PatternTracker>>,
18 resource_limits: ResourceLimits,
20}
21
22struct PatternTracker {
24 hash: u64,
26 count: usize,
28 last_seen: Instant,
30 intervals: VecDeque<Duration>,
32}
33
34struct ResourceLimits {
36 max_active_memories: usize,
38 max_cycles_per_second: usize,
40 max_growth_rate: f32,
42}
43
44impl Default for Custodian {
45 fn default() -> Self {
46 Self::new()
47 }
48}
49
50impl Custodian {
51 pub fn new() -> Self {
52 Self {
53 safe_threshold: 5.0,
54 critical_threshold: 10.0,
55 pattern_history: RwLock::new(HashMap::new()),
56 resource_limits: ResourceLimits {
57 max_active_memories: 10_000,
58 max_cycles_per_second: 1_000,
59 max_growth_rate: 1.5,
60 },
61 }
62 }
63
64 pub fn guard_memory(&self, memory: &MemoryWave) -> GuardDecision {
66 let pattern_hash = self.calculate_pattern_hash(memory);
67 let repetition_score = self.calculate_repetition_score(pattern_hash);
68
69 if repetition_score < self.safe_threshold {
70 GuardDecision::Allow
71 } else if repetition_score < self.critical_threshold {
72 GuardDecision::Throttle(self.calculate_throttle_factor(repetition_score))
73 } else {
74 GuardDecision::Block(BlockReason::ExcessiveRepetition)
75 }
76 }
77
78 fn calculate_pattern_hash(&self, memory: &MemoryWave) -> u64 {
80 use std::collections::hash_map::DefaultHasher;
81 use std::hash::{Hash, Hasher};
82
83 let mut hasher = DefaultHasher::new();
84
85 ((memory.frequency * 100.0) as u32).hash(&mut hasher);
87 ((memory.amplitude * 100.0) as u32).hash(&mut hasher);
88 ((memory.valence * 100.0) as i32).hash(&mut hasher);
89
90 hasher.finish()
91 }
92
93 fn calculate_repetition_score(&self, pattern_hash: u64) -> f32 {
95 let mut history = self.pattern_history.write().unwrap();
96 let now = Instant::now();
97
98 let tracker = history
99 .entry(pattern_hash)
100 .or_insert_with(|| PatternTracker {
101 hash: pattern_hash,
102 count: 0,
103 last_seen: now,
104 intervals: VecDeque::with_capacity(10),
105 });
106
107 let interval = now.duration_since(tracker.last_seen);
109 tracker.intervals.push_back(interval);
110 if tracker.intervals.len() > 10 {
111 tracker.intervals.pop_front();
112 }
113 tracker.count += 1;
114 tracker.last_seen = now;
115
116 let frequency_factor = tracker.count as f32 / 10.0;
118 let interval_factor = if tracker.intervals.len() > 1 {
119 let avg_interval = tracker
120 .intervals
121 .iter()
122 .map(|d| d.as_secs_f32())
123 .sum::<f32>()
124 / tracker.intervals.len() as f32;
125
126 (1.0 / (avg_interval + 0.1)).min(10.0)
128 } else {
129 1.0
130 };
131
132 frequency_factor * interval_factor
133 }
134
135 fn calculate_throttle_factor(&self, score: f32) -> f32 {
137 let normalized =
138 (score - self.safe_threshold) / (self.critical_threshold - self.safe_threshold);
139 normalized.clamp(0.1, 0.9)
140 }
141
142 pub fn check_resources(&self, active_count: usize, growth_rate: f32) -> GuardDecision {
144 if active_count > self.resource_limits.max_active_memories {
145 GuardDecision::Block(BlockReason::MemoryOverload)
146 } else if growth_rate > self.resource_limits.max_growth_rate {
147 GuardDecision::Throttle(0.5)
148 } else {
149 GuardDecision::Allow
150 }
151 }
152}
153
154#[derive(Debug, Clone)]
156pub enum GuardDecision {
157 Allow,
159 Throttle(f32),
161 Block(BlockReason),
163}
164
165#[derive(Debug, Clone)]
167pub enum BlockReason {
168 ExcessiveRepetition,
169 MemoryOverload,
170 CognitiveLoop,
171 ResourceExhaustion,
172}
173
174pub struct RepetitionPrevention {
176 break_threshold: f32,
178 patterns: RwLock<Vec<PatternInstance>>,
180 noise_level: f32,
182}
183
184#[derive(Clone)]
185struct PatternInstance {
186 pattern: Vec<f32>,
187 repeat_count: usize,
188 last_seen: Instant,
189}
190
191impl Default for RepetitionPrevention {
192 fn default() -> Self {
193 Self::new()
194 }
195}
196
197impl RepetitionPrevention {
198 pub fn new() -> Self {
199 Self {
200 break_threshold: 0.8,
201 patterns: RwLock::new(Vec::new()),
202 noise_level: 0.1,
203 }
204 }
205
206 pub fn check_pattern(&self, wave_sequence: &[f32]) -> PatternBreakDecision {
208 let mut patterns = self.patterns.write().unwrap();
209
210 for pattern in patterns.iter_mut() {
212 if self.patterns_match(&pattern.pattern, wave_sequence) {
213 pattern.repeat_count += 1;
214 pattern.last_seen = Instant::now();
215
216 let p_break = self.calculate_break_probability(pattern.repeat_count);
218
219 if p_break > self.break_threshold {
220 return PatternBreakDecision::BreakPattern {
221 noise_level: self.noise_level,
222 shift_attention: true,
223 suppress_duration: Duration::from_secs(5),
224 };
225 }
226 }
227 }
228
229 patterns.push(PatternInstance {
231 pattern: wave_sequence.to_vec(),
232 repeat_count: 1,
233 last_seen: Instant::now(),
234 });
235
236 patterns.retain(|p| p.last_seen.elapsed() < Duration::from_secs(300));
238
239 PatternBreakDecision::Continue
240 }
241
242 fn patterns_match(&self, p1: &[f32], p2: &[f32]) -> bool {
244 if p1.len() != p2.len() {
245 return false;
246 }
247
248 let tolerance = 0.1;
249 p1.iter()
250 .zip(p2.iter())
251 .all(|(a, b)| (a - b).abs() < tolerance)
252 }
253
254 fn calculate_break_probability(&self, repeat_count: usize) -> f32 {
256 let threshold_count = 5.0;
257 let lambda = 0.5;
258
259 if repeat_count as f32 <= threshold_count {
260 0.0
261 } else {
262 let excess = repeat_count as f32 - threshold_count;
263 1.0 - (-lambda * excess * excess).exp()
264 }
265 }
266}
267
268#[derive(Debug)]
270pub enum PatternBreakDecision {
271 Continue,
273 BreakPattern {
275 noise_level: f32,
276 shift_attention: bool,
277 suppress_duration: Duration,
278 },
279}
280
281pub struct EmotionalMemoryTherapy {
283 target_emotional_level: f32,
285 therapy_tau: Duration,
287 max_amplification: f32,
289 sessions: RwLock<HashMap<u64, TherapySession>>,
291}
292
293struct TherapySession {
294 memory_id: u64,
295 start_time: Instant,
296 initial_amplitude: f32,
297 target_amplitude: f32,
298 current_phase: TherapyPhase,
299}
300
301#[derive(Debug, Clone)]
302enum TherapyPhase {
303 Assessment,
304 GradualExposure,
305 Integration,
306 Resolution,
307}
308
309impl Default for EmotionalMemoryTherapy {
310 fn default() -> Self {
311 Self::new()
312 }
313}
314
315impl EmotionalMemoryTherapy {
316 pub fn new() -> Self {
317 Self {
318 target_emotional_level: 0.7,
319 therapy_tau: Duration::from_secs(300),
320 max_amplification: 2.0,
321 sessions: RwLock::new(HashMap::new()),
322 }
323 }
324
325 pub fn calculate_reintroduction(&self, memory: &MemoryWave, memory_id: u64) -> f32 {
327 let mut sessions = self.sessions.write().unwrap();
328
329 let session = sessions.entry(memory_id).or_insert_with(|| TherapySession {
330 memory_id,
331 start_time: Instant::now(),
332 initial_amplitude: memory.amplitude,
333 target_amplitude: memory.amplitude * self.target_emotional_level,
334 current_phase: TherapyPhase::Assessment,
335 });
336
337 let elapsed = session.start_time.elapsed().as_secs_f32();
338 let tau = self.therapy_tau.as_secs_f32();
339
340 let base_amplitude = session.initial_amplitude;
342 let exposure_factor = 1.0 - (-elapsed / tau).exp();
343 let emotion_ratio =
344 (self.target_emotional_level / memory.arousal.max(0.1)).min(self.max_amplification);
345
346 base_amplitude * exposure_factor * emotion_ratio
347 }
348
349 pub fn needs_therapy(&self, memory: &MemoryWave) -> bool {
351 memory.arousal > 0.8 && memory.valence.abs() > 0.7
353 }
354
355 pub fn update_phase(&self, memory_id: u64, processing_success: bool) {
357 let mut sessions = self.sessions.write().unwrap();
358
359 if let Some(session) = sessions.get_mut(&memory_id) {
360 session.current_phase = match (&session.current_phase, processing_success) {
361 (TherapyPhase::Assessment, true) => TherapyPhase::GradualExposure,
362 (TherapyPhase::GradualExposure, true) => TherapyPhase::Integration,
363 (TherapyPhase::Integration, true) => TherapyPhase::Resolution,
364 (TherapyPhase::Resolution, _) => {
365 sessions.remove(&memory_id);
367 return;
368 }
369 _ => session.current_phase.clone(), };
371 }
372 }
373}
374
375pub struct TemporalBlanketRecovery {
377 suppression_history: RwLock<HashMap<u64, SuppressionRecord>>,
379 alpha: f32,
381 beta: f32,
382}
383
384struct SuppressionRecord {
385 memory_id: u64,
386 suppression_time: Instant,
387 original_blanket: f32,
388 suppression_reason: String,
389}
390
391impl Default for TemporalBlanketRecovery {
392 fn default() -> Self {
393 Self::new()
394 }
395}
396
397impl TemporalBlanketRecovery {
398 pub fn new() -> Self {
399 Self {
400 suppression_history: RwLock::new(HashMap::new()),
401 alpha: 0.1, beta: 0.5, }
404 }
405
406 pub fn record_suppression(&self, memory_id: u64, original_blanket: f32, reason: String) {
408 let mut history = self.suppression_history.write().unwrap();
409
410 history.insert(
411 memory_id,
412 SuppressionRecord {
413 memory_id,
414 suppression_time: Instant::now(),
415 original_blanket,
416 suppression_reason: reason,
417 },
418 );
419 }
420
421 pub fn restore_blanket(&self, memory_id: u64, contextual_need: f32) -> Option<f32> {
423 let history = self.suppression_history.read().unwrap();
424
425 if let Some(record) = history.get(&memory_id) {
426 let elapsed = record.suppression_time.elapsed().as_secs_f32();
427
428 let decay_factor = (-self.alpha * elapsed).exp();
430 let need_factor = self.beta * contextual_need;
431
432 let restored = record.original_blanket * decay_factor + need_factor;
433
434 Some(restored.clamp(0.0, 1.0))
435 } else {
436 None
437 }
438 }
439
440 pub fn should_restore(&self, memory_id: u64, contextual_importance: f32) -> bool {
442 let history = self.suppression_history.read().unwrap();
443
444 if let Some(record) = history.get(&memory_id) {
445 let min_suppression_time = Duration::from_secs(60);
447 record.suppression_time.elapsed() > min_suppression_time && contextual_importance > 0.7
448 } else {
449 false
450 }
451 }
452}
453
454pub struct DivergenceTracker {
456 baseline: RwLock<SystemBaseline>,
458 current: RwLock<SystemMeasurement>,
460 thresholds: DivergenceThresholds,
462}
463
464#[derive(Clone)]
465struct SystemBaseline {
466 relationship_values: HashMap<String, f32>,
467 activity_levels: HashMap<String, f32>,
468 emotional_state: EmotionalBaseline,
469 established_at: Instant,
470}
471
472#[derive(Clone)]
473pub struct SystemMeasurement {
474 pub relationship_values: HashMap<String, f32>,
475 pub activity_levels: HashMap<String, f32>,
476 pub emotional_state: EmotionalState,
477 pub measured_at: Instant,
478}
479
480#[derive(Clone)]
481struct EmotionalBaseline {
482 valence: f32,
483 arousal: f32,
484 coherence: f32,
485}
486
487#[derive(Clone)]
488pub struct EmotionalState {
489 pub valence: f32,
490 pub arousal: f32,
491 pub coherence: f32,
492 pub divergence: f32,
493}
494
495struct DivergenceThresholds {
496 normal_max: f32, unusual_max: f32, high_risk_min: f32, }
500
501impl Default for DivergenceTracker {
502 fn default() -> Self {
503 Self::new()
504 }
505}
506
507impl DivergenceTracker {
508 pub fn new() -> Self {
509 Self {
510 baseline: RwLock::new(SystemBaseline {
511 relationship_values: HashMap::new(),
512 activity_levels: HashMap::new(),
513 emotional_state: EmotionalBaseline {
514 valence: 0.0,
515 arousal: 0.5,
516 coherence: 0.8,
517 },
518 established_at: Instant::now(),
519 }),
520 current: RwLock::new(SystemMeasurement {
521 relationship_values: HashMap::new(),
522 activity_levels: HashMap::new(),
523 emotional_state: EmotionalState {
524 valence: 0.0,
525 arousal: 0.5,
526 coherence: 0.8,
527 divergence: 0.0,
528 },
529 measured_at: Instant::now(),
530 }),
531 thresholds: DivergenceThresholds {
532 normal_max: 50.0,
533 unusual_max: 150.0,
534 high_risk_min: 151.0,
535 },
536 }
537 }
538
539 pub fn calculate_divergence(&self) -> u8 {
541 let baseline = self.baseline.read().unwrap();
542 let current = self.current.read().unwrap();
543
544 let mut total_divergence = 0.0;
545
546 for (key, baseline_val) in &baseline.relationship_values {
548 if let Some(current_val) = current.relationship_values.get(key) {
549 let r_diff = (current_val - baseline_val).abs();
550 total_divergence += 2.0 * r_diff;
551 }
552 }
553
554 for (key, baseline_val) in &baseline.activity_levels {
556 if let Some(current_val) = current.activity_levels.get(key) {
557 let a_diff = (current_val - baseline_val).abs();
558 total_divergence += a_diff;
559 }
560 }
561
562 let e_diff = ((current.emotional_state.valence - baseline.emotional_state.valence).abs()
564 + (current.emotional_state.arousal - baseline.emotional_state.arousal).abs()
565 + (baseline.emotional_state.coherence - current.emotional_state.coherence).abs())
566 / 3.0;
567
568 total_divergence += e_diff * 50.0;
569
570 total_divergence.min(255.0) as u8
571 }
572
573 pub fn get_divergence_category(&self) -> DivergenceCategory {
575 let score = self.calculate_divergence();
576
577 match score {
578 0..=50 => DivergenceCategory::Normal,
579 51..=150 => DivergenceCategory::Unusual,
580 151..=255 => DivergenceCategory::HighRisk,
581 }
582 }
583
584 pub fn update_measurement(&self, measurement: SystemMeasurement) {
586 let mut current = self.current.write().unwrap();
587 *current = measurement;
588 }
589
590 pub fn reset_baseline(&self) {
592 let current = self.current.read().unwrap();
593 let mut baseline = self.baseline.write().unwrap();
594
595 baseline.relationship_values = current.relationship_values.clone();
596 baseline.activity_levels = current.activity_levels.clone();
597 baseline.emotional_state = EmotionalBaseline {
598 valence: current.emotional_state.valence,
599 arousal: current.emotional_state.arousal,
600 coherence: current.emotional_state.coherence,
601 };
602 baseline.established_at = Instant::now();
603 }
604}
605
606#[derive(Debug, Clone)]
607pub enum DivergenceCategory {
608 Normal, Unusual, HighRisk, }
612
613pub struct CollectiveEmotionalIntelligence {
615 individuals: RwLock<HashMap<String, IndividualState>>,
617 safety_threshold: f32,
619 harmony_weights: HarmonyWeights,
621}
622
623#[derive(Clone)]
624struct IndividualState {
625 id: String,
626 emotional_state: EmotionalState,
627 safety_level: f32,
628 trust_coefficient: f32,
629 last_update: Instant,
630}
631
632struct HarmonyWeights {
633 emotional_resonance: f32, interaction_pattern: f32, trust_coefficient: f32, adaptation_rate: f32, }
638
639impl Default for CollectiveEmotionalIntelligence {
640 fn default() -> Self {
641 Self::new()
642 }
643}
644
645impl CollectiveEmotionalIntelligence {
646 pub fn new() -> Self {
647 Self {
648 individuals: RwLock::new(HashMap::new()),
649 safety_threshold: 200.0 / 255.0, harmony_weights: HarmonyWeights {
651 emotional_resonance: 0.3,
652 interaction_pattern: 0.25,
653 trust_coefficient: 0.25,
654 adaptation_rate: 0.2,
655 },
656 }
657 }
658
659 pub fn calculate_collective_state(&self) -> CollectiveState {
661 let individuals = self.individuals.read().unwrap();
662
663 if individuals.is_empty() {
664 return CollectiveState::default();
665 }
666
667 let mut total_valence = 0.0;
669 let mut total_arousal = 0.0;
670 let mut min_safety: f32 = 1.0;
671
672 for individual in individuals.values() {
673 total_valence += individual.emotional_state.valence;
674 total_arousal += individual.emotional_state.arousal;
675 min_safety = min_safety.min(individual.safety_level);
676 }
677
678 let n = individuals.len() as f32;
679 let avg_valence = total_valence / n;
680 let avg_arousal = total_arousal / n;
681
682 let collective_emotion = (avg_valence * min_safety, avg_arousal * min_safety);
684
685 CollectiveState {
686 emotional_valence: collective_emotion.0,
687 emotional_arousal: collective_emotion.1,
688 psychological_safety: min_safety,
689 group_size: individuals.len(),
690 harmony_score: self.calculate_harmony(),
691 }
692 }
693
694 fn calculate_harmony(&self) -> f32 {
696 let individuals = self.individuals.read().unwrap();
697
698 if individuals.len() < 2 {
699 return 1.0; }
701
702 let emotional_resonance = self.calculate_emotional_resonance(&individuals);
704 let interaction_quality = 0.8; let avg_trust = individuals
706 .values()
707 .map(|i| i.trust_coefficient)
708 .sum::<f32>()
709 / individuals.len() as f32;
710 let adaptation_rate = 0.7; self.harmony_weights.emotional_resonance * emotional_resonance
714 + self.harmony_weights.interaction_pattern * interaction_quality
715 + self.harmony_weights.trust_coefficient * avg_trust
716 + self.harmony_weights.adaptation_rate * adaptation_rate
717 }
718
719 fn calculate_emotional_resonance(&self, individuals: &HashMap<String, IndividualState>) -> f32 {
721 let states: Vec<_> = individuals.values().collect();
722 let n = states.len();
723
724 if n < 2 {
725 return 1.0;
726 }
727
728 let mut total_similarity = 0.0;
729 let mut pairs = 0;
730
731 for i in 0..n {
732 for j in i + 1..n {
733 let valence_diff =
734 (states[i].emotional_state.valence - states[j].emotional_state.valence).abs();
735 let arousal_diff =
736 (states[i].emotional_state.arousal - states[j].emotional_state.arousal).abs();
737
738 let similarity = 1.0 - (valence_diff + arousal_diff) / 2.0;
739 total_similarity += similarity;
740 pairs += 1;
741 }
742 }
743
744 total_similarity / pairs as f32
745 }
746
747 pub fn update_individual(
749 &self,
750 id: String,
751 emotional_state: EmotionalState,
752 safety_level: f32,
753 ) {
754 let mut individuals = self.individuals.write().unwrap();
755
756 if let Some(individual) = individuals.get_mut(&id) {
757 individual.emotional_state = emotional_state;
758 individual.safety_level = safety_level;
759 individual.last_update = Instant::now();
760
761 individual.trust_coefficient = (individual.trust_coefficient * 0.9 + 0.1).min(1.0);
763 } else {
764 individuals.insert(
765 id.clone(),
766 IndividualState {
767 id,
768 emotional_state,
769 safety_level,
770 trust_coefficient: 0.5, last_update: Instant::now(),
772 },
773 );
774 }
775 }
776
777 pub fn is_psychologically_safe(&self) -> bool {
779 let collective = self.calculate_collective_state();
780 collective.psychological_safety >= self.safety_threshold
781 }
782}
783
784#[derive(Debug, Default)]
785pub struct CollectiveState {
786 pub emotional_valence: f32,
787 pub emotional_arousal: f32,
788 pub psychological_safety: f32,
789 pub group_size: usize,
790 pub harmony_score: f32,
791}
792
793pub struct SafetySystem {
795 pub custodian: Arc<Custodian>,
796 pub repetition_prevention: Arc<RepetitionPrevention>,
797 pub emotional_therapy: Arc<EmotionalMemoryTherapy>,
798 pub temporal_recovery: Arc<TemporalBlanketRecovery>,
799 pub divergence_tracker: Arc<DivergenceTracker>,
800 pub collective_intelligence: Arc<CollectiveEmotionalIntelligence>,
801}
802
803impl Default for SafetySystem {
804 fn default() -> Self {
805 Self::new()
806 }
807}
808
809impl SafetySystem {
810 pub fn new() -> Self {
811 Self {
812 custodian: Arc::new(Custodian::new()),
813 repetition_prevention: Arc::new(RepetitionPrevention::new()),
814 emotional_therapy: Arc::new(EmotionalMemoryTherapy::new()),
815 temporal_recovery: Arc::new(TemporalBlanketRecovery::new()),
816 divergence_tracker: Arc::new(DivergenceTracker::new()),
817 collective_intelligence: Arc::new(CollectiveEmotionalIntelligence::new()),
818 }
819 }
820
821 pub fn check_memory_safety(&self, memory: &MemoryWave, memory_id: u64) -> SafetyAssessment {
823 let guard_decision = self.custodian.guard_memory(memory);
825
826 let divergence = self.divergence_tracker.get_divergence_category();
828
829 let collectively_safe = self.collective_intelligence.is_psychologically_safe();
831
832 let needs_therapy = self.emotional_therapy.needs_therapy(memory);
834
835 SafetyAssessment {
836 guard_decision,
837 divergence_category: divergence,
838 collectively_safe,
839 needs_therapy,
840 recommendations: self.generate_recommendations(memory, memory_id),
841 }
842 }
843
844 fn generate_recommendations(
846 &self,
847 memory: &MemoryWave,
848 memory_id: u64,
849 ) -> Vec<SafetyRecommendation> {
850 let mut recommendations = Vec::new();
851
852 if self
854 .temporal_recovery
855 .should_restore(memory_id, memory.amplitude)
856 {
857 recommendations.push(SafetyRecommendation::RestoreSuppressedMemory);
858 }
859
860 let pattern_check = self
862 .repetition_prevention
863 .check_pattern(&[memory.frequency, memory.amplitude]);
864 if matches!(pattern_check, PatternBreakDecision::BreakPattern { .. }) {
865 recommendations.push(SafetyRecommendation::InjectNoiseToBreakPattern);
866 }
867
868 if memory.arousal > 0.9 && memory.valence.abs() > 0.8 {
870 recommendations.push(SafetyRecommendation::ApplyGraduatedExposure);
871 }
872
873 recommendations
874 }
875}
876
877#[derive(Debug)]
878pub struct SafetyAssessment {
879 pub guard_decision: GuardDecision,
880 pub divergence_category: DivergenceCategory,
881 pub collectively_safe: bool,
882 pub needs_therapy: bool,
883 pub recommendations: Vec<SafetyRecommendation>,
884}
885
886#[derive(Debug, Clone)]
887pub enum SafetyRecommendation {
888 RestoreSuppressedMemory,
889 InjectNoiseToBreakPattern,
890 ApplyGraduatedExposure,
891 ReduceSystemLoad,
892 IncreaseMonitoring,
893}
894
895#[cfg(test)]
896mod tests {
897 use super::*;
898
899 #[test]
900 fn test_custodian_repetition_detection() {
901 let custodian = Custodian::new();
902 let mut wave = MemoryWave::new(440.0, 0.8);
903 wave.valence = 0.5;
904
905 match custodian.guard_memory(&wave) {
907 GuardDecision::Allow => {}
908 _ => panic!("First access should be allowed"),
909 }
910
911 for _ in 0..10 {
913 let _ = custodian.guard_memory(&wave);
914 }
915
916 match custodian.guard_memory(&wave) {
917 GuardDecision::Throttle(_) | GuardDecision::Block(_) => {}
918 GuardDecision::Allow => panic!("Repetitive access should be throttled or blocked"),
919 }
920 }
921
922 #[test]
923 fn test_pattern_breaking() {
924 let prevention = RepetitionPrevention::new();
925 let pattern = vec![440.0, 0.8, 440.0, 0.8];
926
927 for _ in 0..10 {
929 let decision = prevention.check_pattern(&pattern);
930 if matches!(decision, PatternBreakDecision::BreakPattern { .. }) {
931 return; }
933 }
934
935 panic!("Pattern breaking should have been triggered");
936 }
937
938 #[test]
939 fn test_emotional_therapy() {
940 let mut therapy = EmotionalMemoryTherapy::new();
942 therapy.therapy_tau = std::time::Duration::from_millis(100); let mut wave = MemoryWave::new(600.0, 0.9);
945 wave.arousal = 0.9;
946 wave.valence = -0.8;
947
948 assert!(therapy.needs_therapy(&wave));
949
950 std::thread::sleep(std::time::Duration::from_millis(50));
952
953 let reintro = therapy.calculate_reintroduction(&wave, 123);
954 assert!(reintro > 0.0, "reintro was {}", reintro);
955 assert!(reintro <= wave.amplitude * therapy.max_amplification);
956 }
957
958 #[test]
959 fn test_divergence_tracking() {
960 let tracker = DivergenceTracker::new();
961
962 assert!(matches!(
964 tracker.get_divergence_category(),
965 DivergenceCategory::Normal
966 ));
967
968 let mut measurement = SystemMeasurement {
970 relationship_values: HashMap::new(),
971 activity_levels: HashMap::new(),
972 emotional_state: EmotionalState {
973 valence: 0.9, arousal: 0.9,
975 coherence: 0.2,
976 divergence: 0.0,
977 },
978 measured_at: Instant::now(),
979 };
980
981 measurement
982 .relationship_values
983 .insert("test".to_string(), 0.9);
984 measurement.activity_levels.insert("test".to_string(), 0.9);
985
986 tracker.update_measurement(measurement);
987
988 let divergence = tracker.calculate_divergence();
989 assert!(divergence > 0);
990 }
991
992 #[test]
993 fn test_collective_emotional_intelligence() {
994 let cei = CollectiveEmotionalIntelligence::new();
995
996 cei.update_individual(
998 "user1".to_string(),
999 EmotionalState {
1000 valence: 0.5,
1001 arousal: 0.6,
1002 coherence: 0.8,
1003 divergence: 0.0,
1004 },
1005 0.9,
1006 );
1007
1008 cei.update_individual(
1009 "user2".to_string(),
1010 EmotionalState {
1011 valence: 0.4,
1012 arousal: 0.5,
1013 coherence: 0.7,
1014 divergence: 0.0,
1015 },
1016 0.85,
1017 );
1018
1019 let collective = cei.calculate_collective_state();
1020 assert_eq!(collective.group_size, 2);
1021 assert!(collective.psychological_safety > 0.0);
1022 assert!(collective.harmony_score > 0.0);
1023 }
1024}