use crate::types::{
EdgeId, Hash, LineageId, NodeId, PolicyBundleId, ScopeId, Timestamp, WitnessId,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum DomainEvent {
NodeCreated {
node_id: NodeId,
namespace: String,
dimension: usize,
timestamp: Timestamp,
},
NodeUpdated {
node_id: NodeId,
previous_hash: Hash,
new_hash: Hash,
timestamp: Timestamp,
},
NodeRemoved {
node_id: NodeId,
timestamp: Timestamp,
},
EdgeCreated {
edge_id: EdgeId,
source: NodeId,
target: NodeId,
weight: f32,
timestamp: Timestamp,
},
EdgeRemoved {
edge_id: EdgeId,
timestamp: Timestamp,
},
EdgeWeightUpdated {
edge_id: EdgeId,
previous_weight: f32,
new_weight: f32,
timestamp: Timestamp,
},
EnergyComputed {
total_energy: f32,
edge_count: usize,
fingerprint: Hash,
duration_us: u64,
timestamp: Timestamp,
},
EnergyUpdated {
trigger_node: NodeId,
affected_edges: usize,
new_energy: f32,
energy_delta: f32,
timestamp: Timestamp,
},
DriftDetected {
magnitude: f32,
affected_modes: Vec<usize>,
timestamp: Timestamp,
},
HotspotIdentified {
edge_id: EdgeId,
energy: f32,
rank: usize,
timestamp: Timestamp,
},
PolicyCreated {
bundle_id: PolicyBundleId,
version: String,
required_approvals: usize,
timestamp: Timestamp,
},
PolicySigned {
bundle_id: PolicyBundleId,
approver: String,
signature_count: usize,
timestamp: Timestamp,
},
PolicyApproved {
bundle_id: PolicyBundleId,
timestamp: Timestamp,
},
PolicyActivated {
bundle_id: PolicyBundleId,
previous_policy: Option<PolicyBundleId>,
timestamp: Timestamp,
},
PolicyDeprecated {
bundle_id: PolicyBundleId,
replacement: PolicyBundleId,
timestamp: Timestamp,
},
WitnessCreated {
witness_id: WitnessId,
action_hash: Hash,
energy: f32,
allowed: bool,
lane: u8,
previous_witness: Option<WitnessId>,
timestamp: Timestamp,
},
LineageCreated {
lineage_id: LineageId,
entity_ref: String,
operation: String,
witness_id: WitnessId,
timestamp: Timestamp,
},
ActionAllowed {
action_hash: Hash,
scope: ScopeId,
lane: u8,
energy: f32,
witness_id: WitnessId,
timestamp: Timestamp,
},
ActionDenied {
action_hash: Hash,
scope: ScopeId,
reason: String,
energy: f32,
witness_id: WitnessId,
timestamp: Timestamp,
},
EscalationTriggered {
action_hash: Hash,
from_lane: u8,
to_lane: u8,
reason: String,
timestamp: Timestamp,
},
HumanReviewRequested {
action_hash: Hash,
scope: ScopeId,
energy: f32,
persistence_secs: u64,
timestamp: Timestamp,
},
RegimeStarted {
regime_id: String,
initial_energy: f32,
timestamp: Timestamp,
},
RegimeEnded {
regime_id: String,
quality: f32,
timestamp: Timestamp,
},
PatternLearned {
pattern_type: String,
quality: f32,
timestamp: Timestamp,
},
ThresholdAdapted {
scope: ScopeId,
previous_reflex: f32,
new_reflex: f32,
trigger: f32,
timestamp: Timestamp,
},
FabricTickCompleted {
tick: u32,
global_energy: f32,
active_tiles: usize,
duration_us: u64,
timestamp: Timestamp,
},
EvidenceThresholdCrossed {
tile_id: u8,
e_value: f64,
timestamp: Timestamp,
},
}
impl DomainEvent {
pub fn event_type(&self) -> &'static str {
match self {
Self::NodeCreated { .. } => "NodeCreated",
Self::NodeUpdated { .. } => "NodeUpdated",
Self::NodeRemoved { .. } => "NodeRemoved",
Self::EdgeCreated { .. } => "EdgeCreated",
Self::EdgeRemoved { .. } => "EdgeRemoved",
Self::EdgeWeightUpdated { .. } => "EdgeWeightUpdated",
Self::EnergyComputed { .. } => "EnergyComputed",
Self::EnergyUpdated { .. } => "EnergyUpdated",
Self::DriftDetected { .. } => "DriftDetected",
Self::HotspotIdentified { .. } => "HotspotIdentified",
Self::PolicyCreated { .. } => "PolicyCreated",
Self::PolicySigned { .. } => "PolicySigned",
Self::PolicyApproved { .. } => "PolicyApproved",
Self::PolicyActivated { .. } => "PolicyActivated",
Self::PolicyDeprecated { .. } => "PolicyDeprecated",
Self::WitnessCreated { .. } => "WitnessCreated",
Self::LineageCreated { .. } => "LineageCreated",
Self::ActionAllowed { .. } => "ActionAllowed",
Self::ActionDenied { .. } => "ActionDenied",
Self::EscalationTriggered { .. } => "EscalationTriggered",
Self::HumanReviewRequested { .. } => "HumanReviewRequested",
Self::RegimeStarted { .. } => "RegimeStarted",
Self::RegimeEnded { .. } => "RegimeEnded",
Self::PatternLearned { .. } => "PatternLearned",
Self::ThresholdAdapted { .. } => "ThresholdAdapted",
Self::FabricTickCompleted { .. } => "FabricTickCompleted",
Self::EvidenceThresholdCrossed { .. } => "EvidenceThresholdCrossed",
}
}
pub fn timestamp(&self) -> Timestamp {
match self {
Self::NodeCreated { timestamp, .. }
| Self::NodeUpdated { timestamp, .. }
| Self::NodeRemoved { timestamp, .. }
| Self::EdgeCreated { timestamp, .. }
| Self::EdgeRemoved { timestamp, .. }
| Self::EdgeWeightUpdated { timestamp, .. }
| Self::EnergyComputed { timestamp, .. }
| Self::EnergyUpdated { timestamp, .. }
| Self::DriftDetected { timestamp, .. }
| Self::HotspotIdentified { timestamp, .. }
| Self::PolicyCreated { timestamp, .. }
| Self::PolicySigned { timestamp, .. }
| Self::PolicyApproved { timestamp, .. }
| Self::PolicyActivated { timestamp, .. }
| Self::PolicyDeprecated { timestamp, .. }
| Self::WitnessCreated { timestamp, .. }
| Self::LineageCreated { timestamp, .. }
| Self::ActionAllowed { timestamp, .. }
| Self::ActionDenied { timestamp, .. }
| Self::EscalationTriggered { timestamp, .. }
| Self::HumanReviewRequested { timestamp, .. }
| Self::RegimeStarted { timestamp, .. }
| Self::RegimeEnded { timestamp, .. }
| Self::PatternLearned { timestamp, .. }
| Self::ThresholdAdapted { timestamp, .. }
| Self::FabricTickCompleted { timestamp, .. }
| Self::EvidenceThresholdCrossed { timestamp, .. } => *timestamp,
}
}
pub fn content_hash(&self) -> Hash {
let serialized = serde_json::to_vec(self).unwrap_or_default();
Hash::digest(&serialized)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventMetadata {
pub sequence: u64,
pub content_hash: Hash,
pub signature: Option<Vec<u8>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EventRecord {
pub event: DomainEvent,
pub metadata: EventMetadata,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_event_serialization() {
let event = DomainEvent::NodeCreated {
node_id: NodeId::new(),
namespace: "test".to_string(),
dimension: 64,
timestamp: Timestamp::now(),
};
let json = serde_json::to_string(&event).unwrap();
let decoded: DomainEvent = serde_json::from_str(&json).unwrap();
assert_eq!(event.event_type(), decoded.event_type());
}
#[test]
fn test_event_content_hash() {
let event = DomainEvent::EnergyComputed {
total_energy: 0.5,
edge_count: 100,
fingerprint: Hash::zero(),
duration_us: 1000,
timestamp: Timestamp::now(),
};
let h1 = event.content_hash();
let h2 = event.content_hash();
assert_eq!(h1, h2);
}
}