use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum ComputeLane {
Reflex = 0,
Retrieval = 1,
Heavy = 2,
Human = 3,
}
impl ComputeLane {
#[inline]
pub const fn latency_budget_us(&self) -> u64 {
match self {
ComputeLane::Reflex => 1_000, ComputeLane::Retrieval => 10_000, ComputeLane::Heavy => 100_000, ComputeLane::Human => u64::MAX, }
}
#[inline]
pub const fn latency_budget_ms(&self) -> u64 {
match self {
ComputeLane::Reflex => 1,
ComputeLane::Retrieval => 10,
ComputeLane::Heavy => 100,
ComputeLane::Human => u64::MAX,
}
}
#[inline]
pub const fn allows_automatic_execution(&self) -> bool {
!matches!(self, ComputeLane::Human)
}
#[inline]
pub const fn is_reflex(&self) -> bool {
matches!(self, ComputeLane::Reflex)
}
#[inline]
pub const fn is_escalated(&self) -> bool {
!matches!(self, ComputeLane::Reflex)
}
pub const fn escalate(&self) -> Option<ComputeLane> {
match self {
ComputeLane::Reflex => Some(ComputeLane::Retrieval),
ComputeLane::Retrieval => Some(ComputeLane::Heavy),
ComputeLane::Heavy => Some(ComputeLane::Human),
ComputeLane::Human => None,
}
}
pub const fn deescalate(&self) -> Option<ComputeLane> {
match self {
ComputeLane::Reflex => None,
ComputeLane::Retrieval => Some(ComputeLane::Reflex),
ComputeLane::Heavy => Some(ComputeLane::Retrieval),
ComputeLane::Human => Some(ComputeLane::Heavy),
}
}
pub const fn from_u8(value: u8) -> Option<ComputeLane> {
match value {
0 => Some(ComputeLane::Reflex),
1 => Some(ComputeLane::Retrieval),
2 => Some(ComputeLane::Heavy),
3 => Some(ComputeLane::Human),
_ => None,
}
}
#[inline]
pub const fn as_u8(&self) -> u8 {
*self as u8
}
pub const fn name(&self) -> &'static str {
match self {
ComputeLane::Reflex => "Reflex",
ComputeLane::Retrieval => "Retrieval",
ComputeLane::Heavy => "Heavy",
ComputeLane::Human => "Human",
}
}
pub const fn trigger_description(&self) -> &'static str {
match self {
ComputeLane::Reflex => "Default lane - low energy, no trigger needed",
ComputeLane::Retrieval => "Transient energy spike above reflex threshold",
ComputeLane::Heavy => "Sustained incoherence above retrieval threshold",
ComputeLane::Human => "Persistent incoherence exceeding all automatic thresholds",
}
}
}
impl Default for ComputeLane {
fn default() -> Self {
ComputeLane::Reflex
}
}
impl fmt::Display for ComputeLane {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Lane {} ({})", self.as_u8(), self.name())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct LaneThresholds {
pub reflex: f32,
pub retrieval: f32,
pub heavy: f32,
}
impl LaneThresholds {
pub const fn new(reflex: f32, retrieval: f32, heavy: f32) -> Self {
Self {
reflex,
retrieval,
heavy,
}
}
pub const fn conservative() -> Self {
Self {
reflex: 0.1,
retrieval: 0.3,
heavy: 0.6,
}
}
pub const fn aggressive() -> Self {
Self {
reflex: 0.5,
retrieval: 0.8,
heavy: 0.95,
}
}
pub fn validate(&self) -> Result<(), ThresholdError> {
if self.reflex < 0.0 || self.reflex > 1.0 {
return Err(ThresholdError::OutOfRange {
name: "reflex",
value: self.reflex,
});
}
if self.retrieval < 0.0 || self.retrieval > 1.0 {
return Err(ThresholdError::OutOfRange {
name: "retrieval",
value: self.retrieval,
});
}
if self.heavy < 0.0 || self.heavy > 1.0 {
return Err(ThresholdError::OutOfRange {
name: "heavy",
value: self.heavy,
});
}
if self.reflex >= self.retrieval {
return Err(ThresholdError::InvalidOrdering {
lower: "reflex",
upper: "retrieval",
});
}
if self.retrieval >= self.heavy {
return Err(ThresholdError::InvalidOrdering {
lower: "retrieval",
upper: "heavy",
});
}
Ok(())
}
#[inline]
pub fn lane_for_energy(&self, energy: f32) -> ComputeLane {
let is_above_reflex = (energy >= self.reflex) as u8;
let is_above_retrieval = (energy >= self.retrieval) as u8;
let is_above_heavy = (energy >= self.heavy) as u8;
let lane_index = is_above_reflex + is_above_retrieval + is_above_heavy;
match lane_index {
0 => ComputeLane::Reflex,
1 => ComputeLane::Retrieval,
2 => ComputeLane::Heavy,
_ => ComputeLane::Human,
}
}
#[inline]
pub fn lane_for_energy_lookup(&self, energy: f32) -> ComputeLane {
let thresholds = [self.reflex, self.retrieval, self.heavy];
let mut lane = 0u8;
for &t in &thresholds {
lane += (energy >= t) as u8;
}
ComputeLane::from_u8(lane).unwrap_or(ComputeLane::Human)
}
pub fn threshold_for_lane(&self, lane: ComputeLane) -> f32 {
match lane {
ComputeLane::Reflex => 0.0, ComputeLane::Retrieval => self.reflex,
ComputeLane::Heavy => self.retrieval,
ComputeLane::Human => self.heavy,
}
}
}
impl Default for LaneThresholds {
fn default() -> Self {
Self {
reflex: 0.2,
retrieval: 0.5,
heavy: 0.8,
}
}
}
#[derive(Debug, Clone, thiserror::Error)]
pub enum ThresholdError {
#[error("Threshold '{name}' value {value} is out of range [0.0, 1.0]")]
OutOfRange { name: &'static str, value: f32 },
#[error("Invalid threshold ordering: {lower} must be less than {upper}")]
InvalidOrdering {
lower: &'static str,
upper: &'static str,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum EscalationReason {
EnergyThreshold {
energy: u32, threshold: u32,
},
PersistentIncoherence {
duration_ms: u64,
window_ms: u64,
},
GrowingIncoherence {
growth_rate: i32, },
ExternalTrigger {
source: String,
},
SystemOverride {
reason: String,
},
}
impl EscalationReason {
pub fn energy(energy: f32, threshold: f32) -> Self {
Self::EnergyThreshold {
energy: (energy * 1000.0) as u32,
threshold: (threshold * 1000.0) as u32,
}
}
pub fn persistent(duration_ms: u64, window_ms: u64) -> Self {
Self::PersistentIncoherence {
duration_ms,
window_ms,
}
}
pub fn growing(growth_rate: f32) -> Self {
Self::GrowingIncoherence {
growth_rate: (growth_rate * 1000.0) as i32,
}
}
pub fn is_persistence_based(&self) -> bool {
matches!(self, Self::PersistentIncoherence { .. })
}
pub fn is_external(&self) -> bool {
matches!(self, Self::ExternalTrigger { .. } | Self::SystemOverride { .. })
}
}
impl fmt::Display for EscalationReason {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::EnergyThreshold { energy, threshold } => {
write!(
f,
"Energy {:.3} exceeded threshold {:.3}",
*energy as f32 / 1000.0,
*threshold as f32 / 1000.0
)
}
Self::PersistentIncoherence {
duration_ms,
window_ms,
} => {
write!(
f,
"Persistent incoherence for {}ms (window: {}ms)",
duration_ms, window_ms
)
}
Self::GrowingIncoherence { growth_rate } => {
write!(
f,
"Growing incoherence at {:.3}/s",
*growth_rate as f32 / 1000.0
)
}
Self::ExternalTrigger { source } => {
write!(f, "External trigger from: {}", source)
}
Self::SystemOverride { reason } => {
write!(f, "System override: {}", reason)
}
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LaneTransition {
pub from_lane: ComputeLane,
pub to_lane: ComputeLane,
pub reason: EscalationReason,
pub timestamp_ms: u64,
pub energy: f32,
}
impl LaneTransition {
pub fn new(
from_lane: ComputeLane,
to_lane: ComputeLane,
reason: EscalationReason,
energy: f32,
) -> Self {
Self {
from_lane,
to_lane,
reason,
timestamp_ms: Self::current_timestamp_ms(),
energy,
}
}
fn current_timestamp_ms() -> u64 {
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_millis() as u64)
.unwrap_or(0)
}
pub fn is_escalation(&self) -> bool {
self.to_lane > self.from_lane
}
pub fn is_deescalation(&self) -> bool {
self.to_lane < self.from_lane
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lane_ordering() {
assert!(ComputeLane::Reflex < ComputeLane::Retrieval);
assert!(ComputeLane::Retrieval < ComputeLane::Heavy);
assert!(ComputeLane::Heavy < ComputeLane::Human);
}
#[test]
fn test_lane_escalation() {
assert_eq!(
ComputeLane::Reflex.escalate(),
Some(ComputeLane::Retrieval)
);
assert_eq!(ComputeLane::Retrieval.escalate(), Some(ComputeLane::Heavy));
assert_eq!(ComputeLane::Heavy.escalate(), Some(ComputeLane::Human));
assert_eq!(ComputeLane::Human.escalate(), None);
}
#[test]
fn test_lane_deescalation() {
assert_eq!(ComputeLane::Reflex.deescalate(), None);
assert_eq!(
ComputeLane::Retrieval.deescalate(),
Some(ComputeLane::Reflex)
);
assert_eq!(
ComputeLane::Heavy.deescalate(),
Some(ComputeLane::Retrieval)
);
assert_eq!(ComputeLane::Human.deescalate(), Some(ComputeLane::Heavy));
}
#[test]
fn test_lane_automatic_execution() {
assert!(ComputeLane::Reflex.allows_automatic_execution());
assert!(ComputeLane::Retrieval.allows_automatic_execution());
assert!(ComputeLane::Heavy.allows_automatic_execution());
assert!(!ComputeLane::Human.allows_automatic_execution());
}
#[test]
fn test_default_thresholds() {
let thresholds = LaneThresholds::default();
assert!(thresholds.validate().is_ok());
}
#[test]
fn test_threshold_validation() {
let valid = LaneThresholds::new(0.1, 0.5, 0.9);
assert!(valid.validate().is_ok());
let invalid = LaneThresholds::new(0.5, 0.3, 0.9);
assert!(invalid.validate().is_err());
let out_of_range = LaneThresholds::new(-0.1, 0.5, 0.9);
assert!(out_of_range.validate().is_err());
}
#[test]
fn test_lane_for_energy() {
let thresholds = LaneThresholds::new(0.2, 0.5, 0.8);
assert_eq!(thresholds.lane_for_energy(0.1), ComputeLane::Reflex);
assert_eq!(thresholds.lane_for_energy(0.3), ComputeLane::Retrieval);
assert_eq!(thresholds.lane_for_energy(0.6), ComputeLane::Heavy);
assert_eq!(thresholds.lane_for_energy(0.9), ComputeLane::Human);
}
#[test]
fn test_escalation_reason_display() {
let reason = EscalationReason::energy(0.75, 0.5);
assert!(reason.to_string().contains("exceeded threshold"));
let persistent = EscalationReason::persistent(5000, 3000);
assert!(persistent.to_string().contains("5000ms"));
}
#[test]
fn test_lane_transition() {
let transition = LaneTransition::new(
ComputeLane::Reflex,
ComputeLane::Retrieval,
EscalationReason::energy(0.3, 0.2),
0.3,
);
assert!(transition.is_escalation());
assert!(!transition.is_deescalation());
}
}