//! Core logic and types for Episteme (StemeDB). //! //! This crate defines the fundamental data structures like `Assertion`, //! `SignatureEntry`, and the core traits for the knowledge graph. /// Zero-copy serialization utilities. pub mod serde; /// Shared test helpers (builders, factories) for the workspace. pub mod testing; /// Core data types for StemeDB assertions and signatures. pub mod types; /// A simple hello world function for testing the core crate. pub fn hello_world() -> String { "Hello from Episteme Core!".to_string() } #[cfg(test)] mod tests { use super::*; use crate::types::{ Assertion, Epoch, LifecycleStage, ObjectValue, SignatureEntry, SourceClass, Supersession, SupersessionType, Vote, }; use rkyv::check_archived_root; use rkyv::ser::serializers::AllocSerializer; use rkyv::ser::Serializer; use rkyv::Deserialize; #[test] fn test_hello_world() { assert_eq!(hello_world(), "Hello from Episteme Core!"); } #[test] fn test_assertion_serialization_roundtrip() { let assertion = Assertion { subject: "Tesla_Inc".to_string(), predicate: "has_revenue".to_string(), object: ObjectValue::Number(96.7), parent_hash: None, source_hash: [0u8; 32], source_class: SourceClass::Clinical, visual_hash: Some([1u8; 8]), epoch: Some([2u8; 32]), lifecycle: LifecycleStage::Approved, signatures: vec![SignatureEntry { agent_id: [2u8; 32], signature: [3u8; 64], timestamp: 123456789, }], confidence: 0.95, timestamp: 123456789, vector: Some(vec![0.1, 0.2, 0.3]), }; // Serialize let mut serializer = AllocSerializer::<4096>::default(); serializer.serialize_value(&assertion).expect("Failed to serialize"); let bytes = serializer.into_serializer().into_inner(); // Validate let archived = check_archived_root::(&bytes) .expect("Failed to validate archived assertion"); // Deserialize let deserialized: Assertion = archived.deserialize(&mut rkyv::Infallible).expect("Failed to deserialize"); assert_eq!(assertion, deserialized); assert_eq!(deserialized.subject, "Tesla_Inc"); assert_eq!(deserialized.visual_hash, Some([1u8; 8])); assert_eq!(deserialized.epoch, Some([2u8; 32])); assert_eq!(deserialized.lifecycle, LifecycleStage::Approved); } #[test] fn test_lifecycle_stage_serialization_roundtrip() { // Test all lifecycle stages survive serialization let stages = [ LifecycleStage::Proposed, LifecycleStage::UnderReview, LifecycleStage::Approved, LifecycleStage::Deprecated, LifecycleStage::Rejected, ]; for stage in stages { let assertion = Assertion { subject: "test".to_string(), predicate: "lifecycle_test".to_string(), object: ObjectValue::Text(format!("{:?}", stage)), parent_hash: None, source_hash: [0u8; 32], source_class: SourceClass::Expert, visual_hash: None, epoch: None, lifecycle: stage, signatures: vec![], confidence: 1.0, timestamp: 0, vector: None, }; let mut serializer = AllocSerializer::<4096>::default(); serializer.serialize_value(&assertion).expect("Failed to serialize"); let bytes = serializer.into_serializer().into_inner(); let archived = check_archived_root::(&bytes) .expect("Failed to validate archived assertion"); let deserialized: Assertion = archived.deserialize(&mut rkyv::Infallible).expect("Failed to deserialize"); assert_eq!( deserialized.lifecycle, stage, "Lifecycle stage {:?} should survive round-trip", stage ); } } #[test] fn test_lifecycle_stage_default() { // Verify that Default gives us Proposed (the safe default) assert_eq!(LifecycleStage::default(), LifecycleStage::Proposed); } #[test] fn test_epoch_serialization_roundtrip() { let epoch = Epoch { id: [1u8; 32], name: "Newtonian Physics".to_string(), supersedes: Some([0u8; 32]), supersession_type: Some(SupersessionType::Refinement), start_timestamp: 1000, end_timestamp: None, }; // Serialize let mut serializer = AllocSerializer::<4096>::default(); serializer.serialize_value(&epoch).expect("Failed to serialize"); let bytes = serializer.into_serializer().into_inner(); // Validate let archived = check_archived_root::(&bytes).expect("Failed to validate archived epoch"); // Deserialize let deserialized: Epoch = archived.deserialize(&mut rkyv::Infallible).expect("Failed to deserialize"); assert_eq!(epoch, deserialized); assert_eq!(deserialized.name, "Newtonian Physics"); assert_eq!(deserialized.supersession_type, Some(SupersessionType::Refinement)); } #[test] fn test_supersession_serialization_roundtrip() { let supersession = Supersession { target_hash: [1u8; 32], supersession_type: SupersessionType::Invalidate, reason: "Proposal treated as approved. See incident INC-2024-001".to_string(), new_hash: Some([2u8; 32]), timestamp: 1704067200, agent_id: [3u8; 32], signature: [4u8; 64], }; // Serialize let mut serializer = AllocSerializer::<4096>::default(); serializer.serialize_value(&supersession).expect("Failed to serialize"); let bytes = serializer.into_serializer().into_inner(); // Validate let archived = check_archived_root::(&bytes) .expect("Failed to validate archived supersession"); // Deserialize let deserialized: Supersession = archived.deserialize(&mut rkyv::Infallible).expect("Failed to deserialize"); assert_eq!(supersession, deserialized); assert_eq!(deserialized.target_hash, [1u8; 32]); assert_eq!(deserialized.supersession_type, SupersessionType::Invalidate); assert_eq!(deserialized.reason, "Proposal treated as approved. See incident INC-2024-001"); assert_eq!(deserialized.new_hash, Some([2u8; 32])); } #[test] fn test_supersession_type_all_variants() { // Test all supersession types survive serialization let types = [ SupersessionType::Invalidate, SupersessionType::Temporal, SupersessionType::Refinement, SupersessionType::RequiresReview, SupersessionType::Additive, ]; for stype in types { let supersession = Supersession { target_hash: [0u8; 32], supersession_type: stype, reason: format!("{:?} test", stype), new_hash: None, timestamp: 0, agent_id: [0u8; 32], signature: [0u8; 64], }; let mut serializer = AllocSerializer::<4096>::default(); serializer.serialize_value(&supersession).expect("Failed to serialize"); let bytes = serializer.into_serializer().into_inner(); let archived = check_archived_root::(&bytes) .expect("Failed to validate archived supersession"); let deserialized: Supersession = archived.deserialize(&mut rkyv::Infallible).expect("Failed to deserialize"); assert_eq!( deserialized.supersession_type, stype, "SupersessionType {:?} should survive round-trip", stype ); } } #[test] fn test_vote_serialization_roundtrip() { let vote = Vote { assertion_hash: [1u8; 32], agent_id: [2u8; 32], weight: 0.8, signature: [3u8; 64], timestamp: 123456789, }; // Serialize let mut serializer = AllocSerializer::<4096>::default(); serializer.serialize_value(&vote).expect("Failed to serialize"); let bytes = serializer.into_serializer().into_inner(); // Validate let archived = check_archived_root::(&bytes).expect("Failed to validate archived vote"); // Deserialize let deserialized: Vote = archived.deserialize(&mut rkyv::Infallible).expect("Failed to deserialize"); assert_eq!(vote, deserialized); assert_eq!(deserialized.assertion_hash, [1u8; 32]); assert_eq!(deserialized.weight, 0.8); } } // test hook