Skip to main content

weavatrix_memory/projection/memory/
apply.rs

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