mockforge_world_state/
model.rs

1//! World State Model - Core data structures for representing unified state
2//!
3//! This module defines the core data structures that represent the unified
4//! world state of MockForge, including nodes, edges, layers, and snapshots.
5
6use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9use std::collections::HashMap;
10
11/// Complete world state snapshot at a point in time
12///
13/// This represents the entire state of the MockForge world at a specific
14/// moment, including all personas, entities, relationships, and system state.
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct WorldStateSnapshot {
17    /// Unique identifier for this snapshot
18    pub id: String,
19    /// Timestamp when this snapshot was created
20    pub timestamp: DateTime<Utc>,
21    /// All state nodes in this snapshot
22    pub nodes: Vec<StateNode>,
23    /// All state edges (relationships) in this snapshot
24    pub edges: Vec<StateEdge>,
25    /// State layers and their visibility
26    pub layers: HashMap<StateLayer, bool>,
27    /// Additional metadata about this snapshot
28    #[serde(default)]
29    pub metadata: HashMap<String, Value>,
30}
31
32impl WorldStateSnapshot {
33    /// Create a new empty snapshot
34    pub fn new() -> Self {
35        Self {
36            id: uuid::Uuid::new_v4().to_string(),
37            timestamp: Utc::now(),
38            nodes: Vec::new(),
39            edges: Vec::new(),
40            layers: HashMap::new(),
41            metadata: HashMap::new(),
42        }
43    }
44
45    /// Get all nodes in a specific layer
46    pub fn nodes_in_layer(&self, layer: &StateLayer) -> Vec<&StateNode> {
47        self.nodes.iter().filter(|node| node.layer == *layer).collect()
48    }
49
50    /// Get all edges connected to a node
51    pub fn edges_for_node(&self, node_id: &str) -> Vec<&StateEdge> {
52        self.edges
53            .iter()
54            .filter(|edge| edge.from == node_id || edge.to == node_id)
55            .collect()
56    }
57
58    /// Get a node by ID
59    pub fn get_node(&self, node_id: &str) -> Option<&StateNode> {
60        self.nodes.iter().find(|node| node.id == node_id)
61    }
62}
63
64impl Default for WorldStateSnapshot {
65    fn default() -> Self {
66        Self::new()
67    }
68}
69
70/// A node in the world state graph
71///
72/// Represents any stateful entity in MockForge, such as a persona, entity,
73/// session, or system component.
74#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
75pub struct StateNode {
76    /// Unique identifier for this node
77    pub id: String,
78    /// Human-readable label
79    pub label: String,
80    /// Type of node (persona, entity, session, etc.)
81    pub node_type: NodeType,
82    /// Layer this node belongs to
83    pub layer: StateLayer,
84    /// Current state value (if applicable)
85    pub state: Option<String>,
86    /// Additional properties/metadata
87    #[serde(default)]
88    pub properties: HashMap<String, Value>,
89    /// Timestamp when this node was created
90    pub created_at: DateTime<Utc>,
91    /// Timestamp when this node was last updated
92    pub updated_at: DateTime<Utc>,
93}
94
95impl StateNode {
96    /// Create a new state node
97    pub fn new(id: String, label: String, node_type: NodeType, layer: StateLayer) -> Self {
98        let now = Utc::now();
99        Self {
100            id,
101            label,
102            node_type,
103            layer,
104            state: None,
105            properties: HashMap::new(),
106            created_at: now,
107            updated_at: now,
108        }
109    }
110
111    /// Set a property on this node
112    pub fn set_property(&mut self, key: String, value: Value) {
113        self.properties.insert(key, value);
114        self.updated_at = Utc::now();
115    }
116
117    /// Get a property from this node
118    pub fn get_property(&self, key: &str) -> Option<&Value> {
119        self.properties.get(key)
120    }
121
122    /// Set the current state of this node
123    pub fn set_state(&mut self, state: String) {
124        self.state = Some(state);
125        self.updated_at = Utc::now();
126    }
127}
128
129/// Type of node in the world state
130#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
131#[serde(rename_all = "snake_case")]
132pub enum NodeType {
133    /// A persona profile
134    Persona,
135    /// An entity (user, order, payment, etc.)
136    Entity,
137    /// A session or connection
138    Session,
139    /// A protocol handler
140    Protocol,
141    /// A behavior rule or tree
142    Behavior,
143    /// A schema definition
144    Schema,
145    /// Recorded data or fixture
146    Recorded,
147    /// AI modifier or configuration
148    AiModifier,
149    /// System component
150    System,
151}
152
153/// An edge (relationship) between two nodes
154///
155/// Represents relationships between state entities, such as persona
156/// relationships, entity ownership, or protocol connections.
157#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
158pub struct StateEdge {
159    /// Source node ID
160    pub from: String,
161    /// Target node ID
162    pub to: String,
163    /// Type of relationship
164    pub relationship_type: String,
165    /// Additional edge properties
166    #[serde(default)]
167    pub properties: HashMap<String, Value>,
168    /// Timestamp when this edge was created
169    pub created_at: DateTime<Utc>,
170}
171
172impl StateEdge {
173    /// Create a new state edge
174    pub fn new(from: String, to: String, relationship_type: String) -> Self {
175        Self {
176            from,
177            to,
178            relationship_type,
179            properties: HashMap::new(),
180            created_at: Utc::now(),
181        }
182    }
183
184    /// Set a property on this edge
185    pub fn set_property(&mut self, key: String, value: Value) {
186        self.properties.insert(key, value);
187    }
188}
189
190/// State layer grouping related state
191///
192/// Layers organize state into logical groups for visualization and filtering.
193#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)]
194#[serde(rename_all = "snake_case")]
195pub enum StateLayer {
196    /// Personas and persona relationships
197    Personas,
198    /// Lifecycle states and transitions
199    Lifecycle,
200    /// Reality levels and continuum
201    Reality,
202    /// Time and temporal state
203    Time,
204    /// Multi-protocol state
205    Protocols,
206    /// Behavior trees and rules
207    Behavior,
208    /// Generative schemas
209    Schemas,
210    /// Recorded data and fixtures
211    Recorded,
212    /// AI modifiers and configurations
213    AiModifiers,
214    /// System-level state
215    System,
216}
217
218impl StateLayer {
219    /// Get all available layers
220    pub fn all() -> Vec<Self> {
221        vec![
222            Self::Personas,
223            Self::Lifecycle,
224            Self::Reality,
225            Self::Time,
226            Self::Protocols,
227            Self::Behavior,
228            Self::Schemas,
229            Self::Recorded,
230            Self::AiModifiers,
231            Self::System,
232        ]
233    }
234
235    /// Get human-readable name for this layer
236    pub fn name(&self) -> &'static str {
237        match self {
238            Self::Personas => "Personas",
239            Self::Lifecycle => "Lifecycle",
240            Self::Reality => "Reality",
241            Self::Time => "Time",
242            Self::Protocols => "Protocols",
243            Self::Behavior => "Behavior",
244            Self::Schemas => "Schemas",
245            Self::Recorded => "Recorded",
246            Self::AiModifiers => "AI Modifiers",
247            Self::System => "System",
248        }
249    }
250}
251
252#[cfg(test)]
253mod tests {
254    use super::*;
255
256    #[test]
257    fn test_world_state_snapshot_new() {
258        let snapshot = WorldStateSnapshot::new();
259        assert!(!snapshot.id.is_empty());
260        assert!(snapshot.nodes.is_empty());
261        assert!(snapshot.edges.is_empty());
262        assert!(snapshot.layers.is_empty());
263        assert!(snapshot.metadata.is_empty());
264    }
265
266    #[test]
267    fn test_world_state_snapshot_default() {
268        let snapshot = WorldStateSnapshot::default();
269        assert!(!snapshot.id.is_empty());
270    }
271
272    #[test]
273    fn test_world_state_snapshot_nodes_in_layer() {
274        let mut snapshot = WorldStateSnapshot::new();
275
276        let node1 = StateNode::new(
277            "node1".to_string(),
278            "Persona 1".to_string(),
279            NodeType::Persona,
280            StateLayer::Personas,
281        );
282        let node2 = StateNode::new(
283            "node2".to_string(),
284            "Entity 1".to_string(),
285            NodeType::Entity,
286            StateLayer::Lifecycle,
287        );
288        let node3 = StateNode::new(
289            "node3".to_string(),
290            "Persona 2".to_string(),
291            NodeType::Persona,
292            StateLayer::Personas,
293        );
294
295        snapshot.nodes.push(node1);
296        snapshot.nodes.push(node2);
297        snapshot.nodes.push(node3);
298
299        let persona_nodes = snapshot.nodes_in_layer(&StateLayer::Personas);
300        assert_eq!(persona_nodes.len(), 2);
301
302        let lifecycle_nodes = snapshot.nodes_in_layer(&StateLayer::Lifecycle);
303        assert_eq!(lifecycle_nodes.len(), 1);
304
305        let reality_nodes = snapshot.nodes_in_layer(&StateLayer::Reality);
306        assert!(reality_nodes.is_empty());
307    }
308
309    #[test]
310    fn test_world_state_snapshot_edges_for_node() {
311        let mut snapshot = WorldStateSnapshot::new();
312
313        let edge1 = StateEdge::new("node1".to_string(), "node2".to_string(), "owns".to_string());
314        let edge2 =
315            StateEdge::new("node2".to_string(), "node3".to_string(), "references".to_string());
316        let edge3 =
317            StateEdge::new("node1".to_string(), "node3".to_string(), "relates_to".to_string());
318
319        snapshot.edges.push(edge1);
320        snapshot.edges.push(edge2);
321        snapshot.edges.push(edge3);
322
323        let node1_edges = snapshot.edges_for_node("node1");
324        assert_eq!(node1_edges.len(), 2);
325
326        let node2_edges = snapshot.edges_for_node("node2");
327        assert_eq!(node2_edges.len(), 2);
328
329        let node4_edges = snapshot.edges_for_node("node4");
330        assert!(node4_edges.is_empty());
331    }
332
333    #[test]
334    fn test_world_state_snapshot_get_node() {
335        let mut snapshot = WorldStateSnapshot::new();
336
337        let node = StateNode::new(
338            "test-node".to_string(),
339            "Test Node".to_string(),
340            NodeType::Entity,
341            StateLayer::Lifecycle,
342        );
343        snapshot.nodes.push(node);
344
345        let found = snapshot.get_node("test-node");
346        assert!(found.is_some());
347        assert_eq!(found.unwrap().label, "Test Node");
348
349        let not_found = snapshot.get_node("nonexistent");
350        assert!(not_found.is_none());
351    }
352
353    #[test]
354    fn test_state_node_new() {
355        let node = StateNode::new(
356            "node-123".to_string(),
357            "My Node".to_string(),
358            NodeType::Persona,
359            StateLayer::Personas,
360        );
361
362        assert_eq!(node.id, "node-123");
363        assert_eq!(node.label, "My Node");
364        assert_eq!(node.node_type, NodeType::Persona);
365        assert_eq!(node.layer, StateLayer::Personas);
366        assert!(node.state.is_none());
367        assert!(node.properties.is_empty());
368    }
369
370    #[test]
371    fn test_state_node_set_property() {
372        let mut node = StateNode::new(
373            "node".to_string(),
374            "Node".to_string(),
375            NodeType::Entity,
376            StateLayer::Lifecycle,
377        );
378
379        let original_updated_at = node.updated_at;
380
381        // Small delay to ensure timestamp changes
382        std::thread::sleep(std::time::Duration::from_millis(1));
383
384        node.set_property("key".to_string(), serde_json::json!("value"));
385
386        assert_eq!(node.get_property("key"), Some(&serde_json::json!("value")));
387        assert!(node.updated_at >= original_updated_at);
388    }
389
390    #[test]
391    fn test_state_node_get_property() {
392        let mut node = StateNode::new(
393            "node".to_string(),
394            "Node".to_string(),
395            NodeType::Entity,
396            StateLayer::Lifecycle,
397        );
398
399        assert!(node.get_property("nonexistent").is_none());
400
401        node.set_property("exists".to_string(), serde_json::json!(42));
402        assert_eq!(node.get_property("exists"), Some(&serde_json::json!(42)));
403    }
404
405    #[test]
406    fn test_state_node_set_state() {
407        let mut node = StateNode::new(
408            "node".to_string(),
409            "Node".to_string(),
410            NodeType::Entity,
411            StateLayer::Lifecycle,
412        );
413
414        assert!(node.state.is_none());
415
416        node.set_state("active".to_string());
417        assert_eq!(node.state, Some("active".to_string()));
418    }
419
420    #[test]
421    fn test_node_type_serialize() {
422        let node_type = NodeType::Persona;
423        let json = serde_json::to_string(&node_type).unwrap();
424        assert_eq!(json, "\"persona\"");
425
426        let node_type = NodeType::AiModifier;
427        let json = serde_json::to_string(&node_type).unwrap();
428        assert_eq!(json, "\"ai_modifier\"");
429    }
430
431    #[test]
432    fn test_node_type_deserialize() {
433        let node_type: NodeType = serde_json::from_str("\"persona\"").unwrap();
434        assert_eq!(node_type, NodeType::Persona);
435
436        let node_type: NodeType = serde_json::from_str("\"entity\"").unwrap();
437        assert_eq!(node_type, NodeType::Entity);
438
439        let node_type: NodeType = serde_json::from_str("\"behavior\"").unwrap();
440        assert_eq!(node_type, NodeType::Behavior);
441    }
442
443    #[test]
444    fn test_node_type_all_variants() {
445        // Test all variants can be serialized and deserialized
446        let variants = vec![
447            NodeType::Persona,
448            NodeType::Entity,
449            NodeType::Session,
450            NodeType::Protocol,
451            NodeType::Behavior,
452            NodeType::Schema,
453            NodeType::Recorded,
454            NodeType::AiModifier,
455            NodeType::System,
456        ];
457
458        for variant in variants {
459            let json = serde_json::to_string(&variant).unwrap();
460            let deserialized: NodeType = serde_json::from_str(&json).unwrap();
461            assert_eq!(variant, deserialized);
462        }
463    }
464
465    #[test]
466    fn test_state_edge_new() {
467        let edge = StateEdge::new("node1".to_string(), "node2".to_string(), "owns".to_string());
468
469        assert_eq!(edge.from, "node1");
470        assert_eq!(edge.to, "node2");
471        assert_eq!(edge.relationship_type, "owns");
472        assert!(edge.properties.is_empty());
473    }
474
475    #[test]
476    fn test_state_edge_set_property() {
477        let mut edge = StateEdge::new("a".to_string(), "b".to_string(), "relates".to_string());
478
479        edge.set_property("weight".to_string(), serde_json::json!(1.5));
480        assert_eq!(edge.properties.get("weight"), Some(&serde_json::json!(1.5)));
481    }
482
483    #[test]
484    fn test_state_layer_all() {
485        let layers = StateLayer::all();
486        assert_eq!(layers.len(), 10);
487        assert!(layers.contains(&StateLayer::Personas));
488        assert!(layers.contains(&StateLayer::Lifecycle));
489        assert!(layers.contains(&StateLayer::Reality));
490        assert!(layers.contains(&StateLayer::Time));
491        assert!(layers.contains(&StateLayer::Protocols));
492        assert!(layers.contains(&StateLayer::Behavior));
493        assert!(layers.contains(&StateLayer::Schemas));
494        assert!(layers.contains(&StateLayer::Recorded));
495        assert!(layers.contains(&StateLayer::AiModifiers));
496        assert!(layers.contains(&StateLayer::System));
497    }
498
499    #[test]
500    fn test_state_layer_name() {
501        assert_eq!(StateLayer::Personas.name(), "Personas");
502        assert_eq!(StateLayer::Lifecycle.name(), "Lifecycle");
503        assert_eq!(StateLayer::Reality.name(), "Reality");
504        assert_eq!(StateLayer::Time.name(), "Time");
505        assert_eq!(StateLayer::Protocols.name(), "Protocols");
506        assert_eq!(StateLayer::Behavior.name(), "Behavior");
507        assert_eq!(StateLayer::Schemas.name(), "Schemas");
508        assert_eq!(StateLayer::Recorded.name(), "Recorded");
509        assert_eq!(StateLayer::AiModifiers.name(), "AI Modifiers");
510        assert_eq!(StateLayer::System.name(), "System");
511    }
512
513    #[test]
514    fn test_state_layer_serialize() {
515        let layer = StateLayer::Personas;
516        let json = serde_json::to_string(&layer).unwrap();
517        assert_eq!(json, "\"personas\"");
518
519        let layer = StateLayer::AiModifiers;
520        let json = serde_json::to_string(&layer).unwrap();
521        assert_eq!(json, "\"ai_modifiers\"");
522    }
523
524    #[test]
525    fn test_state_layer_deserialize() {
526        let layer: StateLayer = serde_json::from_str("\"personas\"").unwrap();
527        assert_eq!(layer, StateLayer::Personas);
528
529        let layer: StateLayer = serde_json::from_str("\"ai_modifiers\"").unwrap();
530        assert_eq!(layer, StateLayer::AiModifiers);
531    }
532
533    #[test]
534    fn test_state_layer_hash() {
535        use std::collections::HashSet;
536        let mut set = HashSet::new();
537        set.insert(StateLayer::Personas);
538        set.insert(StateLayer::Lifecycle);
539        set.insert(StateLayer::Personas); // duplicate
540        assert_eq!(set.len(), 2);
541    }
542
543    #[test]
544    fn test_world_state_snapshot_serialize() {
545        let snapshot = WorldStateSnapshot::new();
546        let json = serde_json::to_string(&snapshot).unwrap();
547        assert!(json.contains("\"id\""));
548        assert!(json.contains("\"timestamp\""));
549        assert!(json.contains("\"nodes\""));
550        assert!(json.contains("\"edges\""));
551    }
552
553    #[test]
554    fn test_state_node_clone() {
555        let node = StateNode::new(
556            "node".to_string(),
557            "Node".to_string(),
558            NodeType::Entity,
559            StateLayer::Lifecycle,
560        );
561        let cloned = node.clone();
562        assert_eq!(node.id, cloned.id);
563        assert_eq!(node.label, cloned.label);
564    }
565
566    #[test]
567    fn test_state_edge_clone() {
568        let edge = StateEdge::new("a".to_string(), "b".to_string(), "relates".to_string());
569        let cloned = edge.clone();
570        assert_eq!(edge.from, cloned.from);
571        assert_eq!(edge.to, cloned.to);
572    }
573
574    #[test]
575    fn test_state_layer_ordering() {
576        // Test that layers can be ordered (for sorting)
577        let mut layers = vec![
578            StateLayer::System,
579            StateLayer::Personas,
580            StateLayer::Lifecycle,
581        ];
582        layers.sort();
583        assert_eq!(layers[0], StateLayer::Personas);
584    }
585}