Skip to main content

maple_runtime/fabrics/
presence.rs

1//! Presence Fabric - manages gradient presence state
2//!
3//! Presence is NOT binary (online/offline). It's a gradient.
4
5use dashmap::DashMap;
6use std::time::Instant;
7use crate::types::*;
8use crate::config::PresenceConfig as PresenceFabricConfig;
9
10/// Presence Fabric manages presence states for all Resonators
11///
12/// Key insight: Presence is multidimensional, not binary.
13/// A Resonator can be:
14/// - Discoverable but not responsive
15/// - Responsive but not accepting new couplings
16/// - Present but in silent mode
17pub struct PresenceFabric {
18    /// Presence states for all Resonators
19    states: DashMap<ResonatorId, PresenceStateWithMetadata>,
20
21    /// Configuration
22    config: PresenceFabricConfig,
23}
24
25struct PresenceStateWithMetadata {
26    state: PresenceState,
27    last_update: Instant,
28}
29
30impl PresenceFabric {
31    pub fn new(config: &PresenceFabricConfig) -> Self {
32        Self {
33            states: DashMap::new(),
34            config: config.clone(),
35        }
36    }
37
38    /// Initialize presence for a new Resonator
39    pub async fn initialize_presence(
40        &self,
41        resonator: &ResonatorId,
42        config: &PresenceConfig,
43    ) -> Result<(), String> {
44        let mut state = PresenceState::new();
45        state.discoverability = config.initial_discoverability;
46        state.responsiveness = config.initial_responsiveness;
47        state.silent_mode = config.start_silent;
48
49        let metadata = PresenceStateWithMetadata {
50            state,
51            last_update: Instant::now(),
52        };
53
54        self.states.insert(*resonator, metadata);
55
56        tracing::debug!("Initialized presence for {}", resonator);
57        Ok(())
58    }
59
60    /// Signal presence (MUST be low-cost and non-intrusive)
61    ///
62    /// ARCHITECTURAL RULE: Presence signaling must not be burdensome.
63    pub async fn signal_presence(
64        &self,
65        resonator: ResonatorId,
66        state: PresenceState,
67    ) -> Result<(), PresenceError> {
68        // Check rate limiting
69        if let Some(existing) = self.states.get(&resonator) {
70            let elapsed = existing.last_update.elapsed();
71            let min_interval =
72                std::time::Duration::from_millis(self.config.min_signal_interval_ms);
73
74            if elapsed < min_interval {
75                return Err(PresenceError::RateLimitExceeded);
76            }
77        }
78
79        // Validate: presence signal must be low-cost
80        // (In real implementation, would check if signal is too large, etc.)
81
82        let metadata = PresenceStateWithMetadata {
83            state,
84            last_update: Instant::now(),
85        };
86
87        self.states.insert(resonator, metadata);
88
89        Ok(())
90    }
91
92    /// Enable silent presence (existence without active signaling)
93    ///
94    /// This is important: a Resonator may be present without actively participating.
95    /// Presence does NOT imply willingness to interact.
96    pub async fn enable_silent_presence(&self, resonator: ResonatorId) {
97        if let Some(mut entry) = self.states.get_mut(&resonator) {
98            entry.state.silent_mode = true;
99            entry.state.discoverability = 0.1; // Minimal discoverability
100        }
101    }
102
103    /// Disable silent mode
104    pub async fn disable_silent_presence(&self, resonator: ResonatorId) {
105        if let Some(mut entry) = self.states.get_mut(&resonator) {
106            entry.state.silent_mode = false;
107            entry.state.discoverability = 0.5; // Return to default
108        }
109    }
110
111    /// Get presence state
112    pub fn get_presence(&self, resonator: &ResonatorId) -> Option<PresenceState> {
113        self.states.get(resonator).map(|r| r.state.clone())
114    }
115
116    /// Check if Resonator is present
117    pub fn is_present(&self, resonator: &ResonatorId) -> bool {
118        self.states.contains_key(resonator)
119    }
120
121    /// Update presence gradient (called periodically to adjust presence based on behavior)
122    pub async fn update_presence_gradient(
123        &self,
124        resonator: &ResonatorId,
125        adjustment: PresenceAdjustment,
126    ) {
127        if let Some(mut entry) = self.states.get_mut(resonator) {
128            match adjustment {
129                PresenceAdjustment::IncreaseResponsiveness(delta) => {
130                    entry.state.responsiveness = (entry.state.responsiveness + delta).min(1.0);
131                }
132                PresenceAdjustment::DecreaseResponsiveness(delta) => {
133                    entry.state.responsiveness = (entry.state.responsiveness - delta).max(0.0);
134                }
135                PresenceAdjustment::IncreaseStability(delta) => {
136                    entry.state.stability = (entry.state.stability + delta).min(1.0);
137                }
138                PresenceAdjustment::DecreaseStability(delta) => {
139                    entry.state.stability = (entry.state.stability - delta).max(0.0);
140                }
141                PresenceAdjustment::SetCouplingReadiness(value) => {
142                    entry.state.coupling_readiness = value.clamp(0.0, 1.0);
143                }
144            }
145        }
146    }
147
148    /// Restore presence from continuity record
149    pub async fn restore_presence(
150        &self,
151        resonator: &ResonatorId,
152        state: &PresenceState,
153    ) -> Result<(), String> {
154        let metadata = PresenceStateWithMetadata {
155            state: state.clone(),
156            last_update: Instant::now(),
157        };
158
159        self.states.insert(*resonator, metadata);
160
161        tracing::debug!("Restored presence for {}", resonator);
162        Ok(())
163    }
164
165    /// Remove presence (for cleanup)
166    pub fn remove_presence(&self, resonator: &ResonatorId) {
167        self.states.remove(resonator);
168    }
169
170    /// Get all present Resonators
171    pub fn get_all_present(&self) -> Vec<ResonatorId> {
172        self.states.iter().map(|entry| *entry.key()).collect()
173    }
174
175    /// Count of present Resonators
176    pub fn count(&self) -> usize {
177        self.states.len()
178    }
179}
180
181/// Adjustments to presence gradients
182pub enum PresenceAdjustment {
183    IncreaseResponsiveness(f64),
184    DecreaseResponsiveness(f64),
185    IncreaseStability(f64),
186    DecreaseStability(f64),
187    SetCouplingReadiness(f64),
188}