mockforge_world_state/
lib.rs

1//! Pillars: [Reality][DevX]
2//!
3//! World State Engine - Unified visualization of all MockForge state systems
4//!
5//! This crate provides a unified "world state" that aggregates and visualizes
6//! all state systems in MockForge, including personas, lifecycle, reality,
7//! time, multi-protocol state, behavior trees, generative schemas, recorded
8//! data, and AI modifiers. Think of it as a "miniature game engine for your backend."
9//!
10//! # Features
11//!
12//! - **Unified State Aggregation**: Collects state from all MockForge subsystems
13//! - **Graph Visualization**: Represents state as nodes and edges for visualization
14//! - **Real-time Updates**: Streams state changes in real-time
15//! - **Time Travel**: View state at any point in time
16//! - **Query Interface**: Flexible querying of state with filters
17//! - **Export Capabilities**: Export state in various formats (JSON, GraphML, DOT)
18
19pub mod aggregators;
20pub mod engine;
21pub mod model;
22pub mod query;
23
24pub use engine::WorldStateEngine;
25pub use model::{StateEdge, StateLayer, StateNode, WorldStateSnapshot};
26pub use query::WorldStateQuery;
27
28#[cfg(test)]
29mod tests {
30    use super::*;
31    use model::{NodeType, StateEdge, StateLayer, StateNode, WorldStateSnapshot};
32    use query::WorldStateQuery;
33    use std::collections::HashSet;
34
35    #[test]
36    fn test_module_exports() {
37        // Verify all main types are accessible through the crate root
38        let _snapshot: WorldStateSnapshot;
39        let _node: StateNode;
40        let _edge: StateEdge;
41        let _layer: StateLayer;
42        let _engine: WorldStateEngine;
43        let _query: WorldStateQuery;
44    }
45
46    #[test]
47    fn test_create_world_state_snapshot() {
48        let snapshot = WorldStateSnapshot::new();
49        assert!(!snapshot.id.is_empty());
50        assert!(snapshot.nodes.is_empty());
51        assert!(snapshot.edges.is_empty());
52    }
53
54    #[test]
55    fn test_create_state_node() {
56        let node = StateNode::new(
57            "test-id".to_string(),
58            "Test Label".to_string(),
59            NodeType::Persona,
60            StateLayer::Personas,
61        );
62
63        assert_eq!(node.id, "test-id");
64        assert_eq!(node.label, "Test Label");
65        assert_eq!(node.node_type, NodeType::Persona);
66        assert_eq!(node.layer, StateLayer::Personas);
67    }
68
69    #[test]
70    fn test_create_state_edge() {
71        let edge = StateEdge::new(
72            "from-node".to_string(),
73            "to-node".to_string(),
74            "relationship".to_string(),
75        );
76
77        assert_eq!(edge.from, "from-node");
78        assert_eq!(edge.to, "to-node");
79        assert_eq!(edge.relationship_type, "relationship");
80    }
81
82    #[test]
83    fn test_state_layer_all() {
84        let layers = StateLayer::all();
85        assert!(!layers.is_empty());
86        assert!(layers.contains(&StateLayer::Personas));
87        assert!(layers.contains(&StateLayer::Lifecycle));
88    }
89
90    #[test]
91    fn test_world_state_query_builder() {
92        let mut node_types = HashSet::new();
93        node_types.insert(NodeType::Persona);
94
95        let query = WorldStateQuery::new().with_node_types(node_types.clone());
96
97        assert_eq!(query.node_types, Some(node_types));
98    }
99
100    #[test]
101    fn test_world_state_engine_creation() {
102        let engine = WorldStateEngine::new();
103        let layers = engine.get_layers();
104        assert!(layers.is_empty());
105    }
106
107    #[test]
108    fn test_integration_snapshot_with_nodes_and_edges() {
109        let mut snapshot = WorldStateSnapshot::new();
110
111        // Create nodes
112        let node1 = StateNode::new(
113            "user-1".to_string(),
114            "User 1".to_string(),
115            NodeType::Entity,
116            StateLayer::Lifecycle,
117        );
118
119        let node2 = StateNode::new(
120            "order-1".to_string(),
121            "Order 1".to_string(),
122            NodeType::Entity,
123            StateLayer::Lifecycle,
124        );
125
126        // Create edge
127        let edge = StateEdge::new("user-1".to_string(), "order-1".to_string(), "owns".to_string());
128
129        snapshot.nodes.push(node1);
130        snapshot.nodes.push(node2);
131        snapshot.edges.push(edge);
132
133        // Query the snapshot
134        assert_eq!(snapshot.nodes.len(), 2);
135        assert_eq!(snapshot.edges.len(), 1);
136
137        let user_node = snapshot.get_node("user-1");
138        assert!(user_node.is_some());
139        assert_eq!(user_node.unwrap().label, "User 1");
140
141        let user_edges = snapshot.edges_for_node("user-1");
142        assert_eq!(user_edges.len(), 1);
143        assert_eq!(user_edges[0].to, "order-1");
144    }
145
146    #[test]
147    fn test_integration_query_workflow() {
148        let mut snapshot = WorldStateSnapshot::new();
149
150        // Add diverse nodes
151        let persona = StateNode::new(
152            "persona-1".to_string(),
153            "John Doe".to_string(),
154            NodeType::Persona,
155            StateLayer::Personas,
156        );
157
158        let entity = StateNode::new(
159            "entity-1".to_string(),
160            "Payment".to_string(),
161            NodeType::Entity,
162            StateLayer::Lifecycle,
163        );
164
165        let session = StateNode::new(
166            "session-1".to_string(),
167            "Session 123".to_string(),
168            NodeType::Session,
169            StateLayer::Protocols,
170        );
171
172        snapshot.nodes.push(persona.clone());
173        snapshot.nodes.push(entity.clone());
174        snapshot.nodes.push(session.clone());
175
176        // Test layer filtering
177        let persona_layer_nodes = snapshot.nodes_in_layer(&StateLayer::Personas);
178        assert_eq!(persona_layer_nodes.len(), 1);
179        assert_eq!(persona_layer_nodes[0].id, "persona-1");
180
181        let lifecycle_layer_nodes = snapshot.nodes_in_layer(&StateLayer::Lifecycle);
182        assert_eq!(lifecycle_layer_nodes.len(), 1);
183        assert_eq!(lifecycle_layer_nodes[0].id, "entity-1");
184    }
185
186    #[test]
187    fn test_integration_state_node_properties() {
188        let mut node = StateNode::new(
189            "test".to_string(),
190            "Test".to_string(),
191            NodeType::Entity,
192            StateLayer::System,
193        );
194
195        // Set multiple properties
196        node.set_property("status".to_string(), serde_json::json!("active"));
197        node.set_property("count".to_string(), serde_json::json!(42));
198        node.set_property("metadata".to_string(), serde_json::json!({"key": "value"}));
199
200        // Verify properties
201        assert_eq!(node.get_property("status"), Some(&serde_json::json!("active")));
202        assert_eq!(node.get_property("count"), Some(&serde_json::json!(42)));
203        assert!(node.get_property("metadata").is_some());
204        assert!(node.get_property("nonexistent").is_none());
205
206        // Set state
207        node.set_state("running".to_string());
208        assert_eq!(node.state, Some("running".to_string()));
209    }
210
211    #[test]
212    fn test_integration_state_edge_properties() {
213        let mut edge = StateEdge::new("a".to_string(), "b".to_string(), "connects".to_string());
214
215        edge.set_property("weight".to_string(), serde_json::json!(0.75));
216        edge.set_property("bidirectional".to_string(), serde_json::json!(true));
217
218        assert_eq!(edge.properties.get("weight"), Some(&serde_json::json!(0.75)));
219        assert_eq!(edge.properties.get("bidirectional"), Some(&serde_json::json!(true)));
220    }
221
222    #[test]
223    fn test_integration_snapshot_metadata() {
224        let mut snapshot = WorldStateSnapshot::new();
225
226        snapshot.metadata.insert("version".to_string(), serde_json::json!("1.0.0"));
227        snapshot.metadata.insert("environment".to_string(), serde_json::json!("test"));
228
229        assert_eq!(snapshot.metadata.get("version"), Some(&serde_json::json!("1.0.0")));
230        assert_eq!(snapshot.metadata.get("environment"), Some(&serde_json::json!("test")));
231    }
232
233    #[test]
234    fn test_integration_layer_management() {
235        let mut snapshot = WorldStateSnapshot::new();
236
237        // Mark layers as active/inactive
238        snapshot.layers.insert(StateLayer::Personas, true);
239        snapshot.layers.insert(StateLayer::Lifecycle, true);
240        snapshot.layers.insert(StateLayer::Reality, false);
241
242        assert_eq!(snapshot.layers.get(&StateLayer::Personas), Some(&true));
243        assert_eq!(snapshot.layers.get(&StateLayer::Lifecycle), Some(&true));
244        assert_eq!(snapshot.layers.get(&StateLayer::Reality), Some(&false));
245        assert_eq!(snapshot.layers.get(&StateLayer::Time), None);
246    }
247
248    #[test]
249    fn test_all_node_types_coverage() {
250        // Ensure all node types can be created and used
251        let types = vec![
252            NodeType::Persona,
253            NodeType::Entity,
254            NodeType::Session,
255            NodeType::Protocol,
256            NodeType::Behavior,
257            NodeType::Schema,
258            NodeType::Recorded,
259            NodeType::AiModifier,
260            NodeType::System,
261        ];
262
263        for (i, node_type) in types.iter().enumerate() {
264            let node = StateNode::new(
265                format!("node-{}", i),
266                format!("Node {}", i),
267                *node_type,
268                StateLayer::System,
269            );
270            assert_eq!(node.node_type, *node_type);
271        }
272    }
273
274    #[test]
275    fn test_all_state_layers_coverage() {
276        // Ensure all state layers can be used
277        let all_layers = StateLayer::all();
278
279        for layer in &all_layers {
280            let name = layer.name();
281            assert!(!name.is_empty());
282
283            let node =
284                StateNode::new("test".to_string(), "Test".to_string(), NodeType::System, *layer);
285            assert_eq!(node.layer, *layer);
286        }
287
288        // Verify count
289        assert_eq!(all_layers.len(), 10);
290    }
291
292    #[test]
293    fn test_serialization_roundtrip_snapshot() {
294        let mut snapshot = WorldStateSnapshot::new();
295
296        let node = StateNode::new(
297            "node-1".to_string(),
298            "Node 1".to_string(),
299            NodeType::Persona,
300            StateLayer::Personas,
301        );
302        snapshot.nodes.push(node);
303
304        let edge =
305            StateEdge::new("node-1".to_string(), "node-2".to_string(), "relates".to_string());
306        snapshot.edges.push(edge);
307
308        // Serialize
309        let json = serde_json::to_string(&snapshot).unwrap();
310        assert!(!json.is_empty());
311
312        // Deserialize
313        let deserialized: WorldStateSnapshot = serde_json::from_str(&json).unwrap();
314        assert_eq!(snapshot.id, deserialized.id);
315        assert_eq!(snapshot.nodes.len(), deserialized.nodes.len());
316        assert_eq!(snapshot.edges.len(), deserialized.edges.len());
317    }
318
319    #[test]
320    fn test_serialization_roundtrip_query() {
321        let mut node_types = HashSet::new();
322        node_types.insert(NodeType::Persona);
323        node_types.insert(NodeType::Entity);
324
325        let query = WorldStateQuery::new()
326            .with_node_types(node_types)
327            .include_edges(false)
328            .with_max_depth(5);
329
330        // Serialize
331        let json = serde_json::to_string(&query).unwrap();
332
333        // Deserialize
334        let deserialized: WorldStateQuery = serde_json::from_str(&json).unwrap();
335        assert_eq!(query.include_edges, deserialized.include_edges);
336        assert_eq!(query.max_depth, deserialized.max_depth);
337    }
338
339    #[test]
340    fn test_complex_graph_structure() {
341        let mut snapshot = WorldStateSnapshot::new();
342
343        // Create a graph: A -> B -> C
344        //                 A -> D
345        let node_a = StateNode::new(
346            "a".to_string(),
347            "Node A".to_string(),
348            NodeType::Entity,
349            StateLayer::Lifecycle,
350        );
351        let node_b = StateNode::new(
352            "b".to_string(),
353            "Node B".to_string(),
354            NodeType::Entity,
355            StateLayer::Lifecycle,
356        );
357        let node_c = StateNode::new(
358            "c".to_string(),
359            "Node C".to_string(),
360            NodeType::Entity,
361            StateLayer::Lifecycle,
362        );
363        let node_d = StateNode::new(
364            "d".to_string(),
365            "Node D".to_string(),
366            NodeType::Entity,
367            StateLayer::Lifecycle,
368        );
369
370        snapshot.nodes.push(node_a);
371        snapshot.nodes.push(node_b);
372        snapshot.nodes.push(node_c);
373        snapshot.nodes.push(node_d);
374
375        snapshot
376            .edges
377            .push(StateEdge::new("a".to_string(), "b".to_string(), "owns".to_string()));
378        snapshot
379            .edges
380            .push(StateEdge::new("b".to_string(), "c".to_string(), "owns".to_string()));
381        snapshot.edges.push(StateEdge::new(
382            "a".to_string(),
383            "d".to_string(),
384            "references".to_string(),
385        ));
386
387        // Verify graph structure
388        let edges_from_a = snapshot.edges_for_node("a");
389        assert_eq!(edges_from_a.len(), 2);
390
391        let edges_from_b = snapshot.edges_for_node("b");
392        assert_eq!(edges_from_b.len(), 2); // One incoming, one outgoing
393
394        let edges_from_c = snapshot.edges_for_node("c");
395        assert_eq!(edges_from_c.len(), 1); // Only incoming
396
397        let edges_from_d = snapshot.edges_for_node("d");
398        assert_eq!(edges_from_d.len(), 1); // Only incoming
399    }
400
401    #[tokio::test]
402    async fn test_full_integration_workflow() {
403        use aggregators::StateAggregator;
404        use std::sync::Arc;
405
406        // Mock aggregator
407        struct TestAggregator;
408
409        #[async_trait::async_trait]
410        impl StateAggregator for TestAggregator {
411            async fn aggregate(&self) -> anyhow::Result<(Vec<StateNode>, Vec<StateEdge>)> {
412                let node1 = StateNode::new(
413                    "test-1".to_string(),
414                    "Test 1".to_string(),
415                    NodeType::Persona,
416                    StateLayer::Personas,
417                );
418                let node2 = StateNode::new(
419                    "test-2".to_string(),
420                    "Test 2".to_string(),
421                    NodeType::Entity,
422                    StateLayer::Lifecycle,
423                );
424                let edge =
425                    StateEdge::new("test-1".to_string(), "test-2".to_string(), "owns".to_string());
426
427                Ok((vec![node1, node2], vec![edge]))
428            }
429
430            fn layer(&self) -> StateLayer {
431                StateLayer::Personas
432            }
433        }
434
435        // Create engine and register aggregator
436        let mut engine = WorldStateEngine::new();
437        engine.register_aggregator(Arc::new(TestAggregator));
438
439        // Create snapshot
440        let snapshot = engine.create_snapshot().await.unwrap();
441        assert_eq!(snapshot.nodes.len(), 2);
442        assert_eq!(snapshot.edges.len(), 1);
443
444        // Query by node type
445        let mut node_types = HashSet::new();
446        node_types.insert(NodeType::Persona);
447
448        let query = WorldStateQuery::new().with_node_types(node_types);
449        let filtered = engine.query(&query).await.unwrap();
450
451        assert_eq!(filtered.nodes.len(), 1);
452        assert_eq!(filtered.nodes[0].id, "test-1");
453
454        // Get all snapshots
455        let all_snapshots = engine.get_all_snapshots().await;
456        assert_eq!(all_snapshots.len(), 2); // One from create_snapshot, one from query
457    }
458
459    #[test]
460    fn test_node_equality() {
461        let node1 = StateNode::new(
462            "same-id".to_string(),
463            "Label 1".to_string(),
464            NodeType::Persona,
465            StateLayer::Personas,
466        );
467
468        let node2 = StateNode::new(
469            "same-id".to_string(),
470            "Label 1".to_string(),
471            NodeType::Persona,
472            StateLayer::Personas,
473        );
474
475        // Nodes with same data should be equal (if timestamps are close enough)
476        // Note: This test is time-sensitive due to timestamps
477        assert_eq!(node1.id, node2.id);
478        assert_eq!(node1.label, node2.label);
479        assert_eq!(node1.node_type, node2.node_type);
480        assert_eq!(node1.layer, node2.layer);
481    }
482
483    #[test]
484    fn test_edge_equality() {
485        let edge1 = StateEdge::new("a".to_string(), "b".to_string(), "owns".to_string());
486
487        let edge2 = StateEdge::new("a".to_string(), "b".to_string(), "owns".to_string());
488
489        assert_eq!(edge1.from, edge2.from);
490        assert_eq!(edge1.to, edge2.to);
491        assert_eq!(edge1.relationship_type, edge2.relationship_type);
492    }
493
494    #[test]
495    fn test_snapshot_cloning() {
496        let mut snapshot = WorldStateSnapshot::new();
497        let node = StateNode::new(
498            "test".to_string(),
499            "Test".to_string(),
500            NodeType::Entity,
501            StateLayer::System,
502        );
503        snapshot.nodes.push(node);
504
505        let cloned = snapshot.clone();
506        assert_eq!(snapshot.id, cloned.id);
507        assert_eq!(snapshot.nodes.len(), cloned.nodes.len());
508        assert_eq!(snapshot.nodes[0].id, cloned.nodes[0].id);
509    }
510
511    #[test]
512    fn test_query_matches_complex_scenarios() {
513        let mut node_types = HashSet::new();
514        node_types.insert(NodeType::Persona);
515        node_types.insert(NodeType::Entity);
516
517        let mut layers = HashSet::new();
518        layers.insert(StateLayer::Personas);
519
520        let mut ids = HashSet::new();
521        ids.insert("specific-id".to_string());
522
523        // Build complex query
524        let query = WorldStateQuery::new()
525            .with_node_types(node_types.clone())
526            .with_layers(layers.clone())
527            .with_node_ids(ids.clone());
528
529        // Test matching node
530        let matching = StateNode::new(
531            "specific-id".to_string(),
532            "Match".to_string(),
533            NodeType::Persona,
534            StateLayer::Personas,
535        );
536        assert!(query.matches_node(&matching));
537
538        // Test non-matching nodes
539        let wrong_id = StateNode::new(
540            "other-id".to_string(),
541            "Wrong".to_string(),
542            NodeType::Persona,
543            StateLayer::Personas,
544        );
545        assert!(!query.matches_node(&wrong_id));
546
547        let wrong_type = StateNode::new(
548            "specific-id".to_string(),
549            "Wrong".to_string(),
550            NodeType::System,
551            StateLayer::Personas,
552        );
553        assert!(!query.matches_node(&wrong_type));
554
555        let wrong_layer = StateNode::new(
556            "specific-id".to_string(),
557            "Wrong".to_string(),
558            NodeType::Persona,
559            StateLayer::Lifecycle,
560        );
561        assert!(!query.matches_node(&wrong_layer));
562    }
563}