Skip to main content

zeitgeist_protocol/
temporal.rs

1//! Temporal tracking — beat grid and rhythm coherence
2
3use serde::{Deserialize, Serialize};
4
5/// Phase enum
6#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
7#[repr(u8)]
8pub enum Phase {
9    Idle = 0,
10    Approaching = 1,
11    Snap = 2,
12    Hold = 3,
13}
14
15impl From<u8> for Phase {
16    fn from(v: u8) -> Self {
17        match v {
18            0 => Phase::Idle,
19            1 => Phase::Approaching,
20            2 => Phase::Snap,
21            _ => Phase::Hold,
22        }
23    }
24}
25
26/// Temporal state captures rhythm alignment with a beat grid.
27#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
28pub struct TemporalState {
29    /// Position in beat grid (0-1)
30    pub beat_pos: f64,
31    /// Current phase
32    pub phase: Phase,
33    /// How well rhythm matches grid (0-1)
34    pub rhythm_coherence: f64,
35}
36
37impl TemporalState {
38    pub fn new(beat_pos: f64, phase: Phase, rhythm_coherence: f64) -> Self {
39        Self { beat_pos, phase, rhythm_coherence }
40    }
41
42    pub fn default() -> Self {
43        Self {
44            beat_pos: 0.0,
45            phase: Phase::Idle,
46            rhythm_coherence: 1.0,
47        }
48    }
49
50    /// Check alignment: beat_pos must be 0-1
51    pub fn check_alignment(&self) -> Vec<String> {
52        let mut violations = Vec::new();
53        if !(0.0..=1.0).contains(&self.beat_pos) {
54            violations.push("temporal.beat_pos must be 0-1".into());
55        }
56        if !(0.0..=1.0).contains(&self.rhythm_coherence) {
57            violations.push("temporal.rhythm_coherence must be 0-1".into());
58        }
59        violations
60    }
61
62    /// Merge: max beat position (latest in grid), take later phase, max coherence.
63    /// All semilattice operations.
64    pub fn merge(&self, other: &Self) -> Self {
65        Self {
66            beat_pos: self.beat_pos.max(other.beat_pos),
67            phase: std::cmp::max(self.phase, other.phase),
68            rhythm_coherence: self.rhythm_coherence.max(other.rhythm_coherence),
69        }
70    }
71}