use crate::EventRecord; use anyhow::Result; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; /// Deterministic rebuild state from JSONL event log. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct RebuildState { pub memories: BTreeMap, // query_id -> final_memory pub event_count: u32, pub chunks_seen: u32, pub chunks_used: u32, } impl RebuildState { /// Rebuild from event records (must be deterministic). pub fn from_events(events: &[EventRecord]) -> Result { let mut memories = BTreeMap::new(); let mut chunks_seen = 0; let mut chunks_used = 0; // Group events by query let mut by_query: BTreeMap> = BTreeMap::new(); for event in events { by_query.entry(event.query.clone()).or_insert_with(Vec::new).push(event); } // Replay events for each query for (query_id, query_events) in by_query { let memory = String::new(); let mut q_seen = 0; let mut q_used = 0; for event in query_events { // Parse event_type (very simplified) if event.event_type.contains("Memory") { // Would parse the actual memory update from data // For now: assume memory doesn't change without update } if event.event_type.contains("Evidence") { q_used += 1; } if event.event_type.contains("Gate") { q_seen += 1; } } memories.insert(query_id, memory); chunks_seen += q_seen; chunks_used += q_used; } Ok(Self { memories, event_count: events.len() as u32, chunks_seen, chunks_used, }) } /// Serialize to JSONL (must match original byte-for-byte). pub fn to_events(&self) -> Vec { // This is a placeholder - real rebuild would deserialize the exact events // The key is that deserialization + re-serialization produces identical bytes vec![] } } #[cfg(test)] mod tests { use super::*; use serde_json::json; #[test] fn test_rebuild_empty() { let events = vec![]; let state = RebuildState::from_events(&events).unwrap(); assert_eq!(state.event_count, 0); } }