Skip to main content

maple_runtime/allocator/
mod.rs

1//! Attention allocation and management
2//!
3//! CRITICAL INVARIANT: Coupling MUST always be bounded by available attention.
4
5use crate::types::AttentionConfig;
6use crate::types::*;
7use dashmap::DashMap;
8
9/// Attention Allocator manages attention budgets for all Resonators
10///
11/// Attention is the finite capacity of a Resonator to process resonance.
12pub struct AttentionAllocator {
13    /// Per-Resonator attention budgets
14    budgets: DashMap<ResonatorId, AttentionBudget>,
15
16    /// Configuration
17    #[allow(dead_code)]
18    config: AttentionConfig,
19}
20
21impl AttentionAllocator {
22    pub fn new(config: &AttentionConfig) -> Self {
23        Self {
24            budgets: DashMap::new(),
25            config: config.clone(),
26        }
27    }
28
29    /// Allocate attention budget for a new Resonator
30    pub async fn allocate_budget(
31        &self,
32        resonator: &ResonatorId,
33        spec: &AttentionBudgetSpec,
34    ) -> Result<(), String> {
35        let mut budget = AttentionBudget::new(spec.total_capacity);
36
37        if let Some(reserve) = spec.safety_reserve {
38            budget.safety_reserve = reserve;
39        }
40
41        if let Some(threshold) = spec.exhaustion_threshold {
42            budget.exhaustion_threshold = threshold;
43        }
44
45        self.budgets.insert(*resonator, budget);
46
47        tracing::debug!(
48            "Allocated attention budget for {}: {} total",
49            resonator,
50            spec.total_capacity
51        );
52
53        Ok(())
54    }
55
56    /// Allocate attention for a coupling
57    ///
58    /// Returns error if insufficient attention (prevents over-coupling)
59    pub async fn allocate(
60        &self,
61        resonator: &ResonatorId,
62        amount: u64,
63    ) -> Result<AllocationToken, AttentionError> {
64        let budget = self
65            .budgets
66            .get_mut(resonator)
67            .ok_or(AttentionError::ResonatorNotFound)?;
68
69        let available = budget.available();
70
71        if amount > available {
72            return Err(AttentionError::InsufficientAttention {
73                requested: amount,
74                available,
75            });
76        }
77
78        let token = AllocationToken::new(*resonator, amount);
79
80        // Record allocation (would be recorded in ledger in real implementation)
81
82        tracing::trace!(
83            "Allocated {} attention for {} (available: {})",
84            amount,
85            resonator,
86            available - amount
87        );
88
89        Ok(token)
90    }
91
92    /// Allocate more attention to an existing coupling
93    pub async fn allocate_more(
94        &self,
95        resonator: &ResonatorId,
96        amount: u64,
97    ) -> Result<(), AttentionError> {
98        let budget = self
99            .budgets
100            .get_mut(resonator)
101            .ok_or(AttentionError::ResonatorNotFound)?;
102
103        let available = budget.available();
104
105        if amount > available {
106            return Err(AttentionError::InsufficientAttention {
107                requested: amount,
108                available,
109            });
110        }
111
112        // Would record in ledger in real implementation
113
114        Ok(())
115    }
116
117    /// Release attention (partial)
118    pub async fn release_partial(&self, resonator: &ResonatorId, amount: u64) {
119        if let Some(_budget) = self.budgets.get_mut(resonator) {
120            // Would release from specific coupling in real implementation
121            tracing::trace!("Released {} attention for {}", amount, resonator);
122        }
123    }
124
125    /// Release all attention from a coupling
126    pub async fn release_all(&self, resonator: &ResonatorId, amount: u64) {
127        if let Some(_budget) = self.budgets.get_mut(resonator) {
128            // Would release from specific coupling in real implementation
129            tracing::trace!("Released all {} attention for {}", amount, resonator);
130        }
131    }
132
133    /// Check if attention exhaustion is imminent
134    pub fn is_exhaustion_imminent(&self, resonator: &ResonatorId) -> bool {
135        if let Some(budget) = self.budgets.get(resonator) {
136            return budget.is_exhaustion_imminent();
137        }
138        false
139    }
140
141    /// Get available attention for coupling
142    pub async fn available_for_coupling(
143        &self,
144        resonator: &ResonatorId,
145    ) -> Result<u64, AttentionError> {
146        let budget = self
147            .budgets
148            .get(resonator)
149            .ok_or(AttentionError::ResonatorNotFound)?;
150
151        Ok(budget.available())
152    }
153
154    /// Get budget for a Resonator
155    pub async fn get_budget(&self, resonator: &ResonatorId) -> Option<AttentionBudget> {
156        self.budgets.get(resonator).map(|r| r.clone())
157    }
158
159    /// Restore attention budget from continuity record
160    pub async fn restore_budget(
161        &self,
162        resonator: &ResonatorId,
163        budget: &AttentionBudget,
164    ) -> Result<(), String> {
165        self.budgets.insert(*resonator, budget.clone());
166        tracing::debug!("Restored attention budget for {}", resonator);
167        Ok(())
168    }
169
170    /// Rebalance attention across couplings
171    ///
172    /// Called when attention pressure is high to optimize allocation
173    pub async fn rebalance(&self, _resonator: &ResonatorId) {
174        // Placeholder: In real implementation, would:
175        // 1. Sort couplings by importance (meaning convergence, interaction count)
176        // 2. Reduce attention to low-value couplings
177        // 3. This is a graceful degradation mechanism
178        tracing::debug!("Rebalancing attention (placeholder)");
179    }
180
181    /// Remove budget (for cleanup)
182    pub fn remove_budget(&self, resonator: &ResonatorId) {
183        self.budgets.remove(resonator);
184    }
185}