weavatrix_memory/projection/memory/
apply.rs1use super::{MemoryProjection, state::NodeRevision};
2use crate::{
3 domain::MemoryEvent,
4 error::{MemoryError, Result},
5 event::StoredEvent,
6 projection::Projection,
7};
8
9impl Projection<MemoryEvent> for MemoryProjection {
10 fn prepare_replay(&mut self, events: &[StoredEvent<MemoryEvent>]) {
11 let mut nodes = 0;
12 let mut facts = 0;
13 for event in events {
14 match event.payload {
15 MemoryEvent::NodeUpserted { .. } => nodes += 1,
16 MemoryEvent::FactRecorded { .. } => facts += 1,
17 MemoryEvent::FactRetracted { .. } => {}
18 }
19 }
20 self.nodes.reserve(nodes);
21 self.facts.reserve(facts);
22 self.node_lookup.reserve(nodes);
23 self.fact_lookup.reserve(facts);
24 self.incident_offsets.reserve(nodes);
25 }
26
27 fn apply(&mut self, event: &StoredEvent<MemoryEvent>) -> Result<()> {
28 if event.metadata.event_type != event.payload.event_type() {
29 return Err(MemoryError::InvalidValue {
30 field: "event_type",
31 reason: "must match the memory event payload",
32 });
33 }
34 match &event.payload {
35 MemoryEvent::NodeUpserted { node } => self.insert_node(NodeRevision {
36 node: node.clone(),
37 recorded_at: event.metadata.recorded_at,
38 position: event.metadata.global_position,
39 })?,
40 MemoryEvent::FactRecorded { fact } => {
41 if fact.recorded_at != event.metadata.recorded_at
42 || fact.agent_id != event.metadata.agent_id
43 || fact.session_id != event.metadata.session_id
44 {
45 return Err(MemoryError::InvalidValue {
46 field: "fact.envelope",
47 reason: "fact provenance must match its event envelope",
48 });
49 }
50 self.insert_fact(fact.clone())?;
51 }
52 MemoryEvent::FactRetracted {
53 fact_id,
54 valid_until,
55 evidence,
56 } => {
57 self.apply_retraction(event.metadata.recorded_at, fact_id, *valid_until, evidence)?;
58 }
59 }
60 self.last_global_position = Some(event.metadata.global_position);
61 Ok(())
62 }
63
64 fn apply_owned(&mut self, event: StoredEvent<MemoryEvent>) -> Result<()> {
65 let StoredEvent { metadata, payload } = event;
66 if metadata.event_type != payload.event_type() {
67 return Err(MemoryError::InvalidValue {
68 field: "event_type",
69 reason: "must match the memory event payload",
70 });
71 }
72 match payload {
73 MemoryEvent::NodeUpserted { node } => self.insert_node(NodeRevision {
74 node,
75 recorded_at: metadata.recorded_at,
76 position: metadata.global_position,
77 })?,
78 MemoryEvent::FactRecorded { fact } => {
79 if fact.recorded_at != metadata.recorded_at
80 || fact.agent_id != metadata.agent_id
81 || fact.session_id != metadata.session_id
82 {
83 return Err(MemoryError::InvalidValue {
84 field: "fact.envelope",
85 reason: "fact provenance must match its event envelope",
86 });
87 }
88 self.insert_fact(fact)?;
89 }
90 MemoryEvent::FactRetracted {
91 fact_id,
92 valid_until,
93 evidence,
94 } => {
95 self.apply_retraction(metadata.recorded_at, &fact_id, valid_until, &evidence)?;
96 }
97 }
98 self.last_global_position = Some(metadata.global_position);
99 Ok(())
100 }
101}