Skip to main content

ainl_memory/
snapshot.rs

1//! Serializable graph snapshots and validation reports.
2
3use crate::node::AinlMemoryNode;
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use std::borrow::Cow;
7use uuid::Uuid;
8
9/// Schema version string embedded in [`AgentGraphSnapshot`] for forward compatibility.
10pub const SNAPSHOT_SCHEMA_VERSION: &str = "1.0";
11
12fn default_snapshot_schema_cow() -> Cow<'static, str> {
13    Cow::Borrowed(SNAPSHOT_SCHEMA_VERSION)
14}
15
16/// Full export of one agent's subgraph (nodes + interconnecting edges).
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct AgentGraphSnapshot {
19    pub agent_id: String,
20    pub exported_at: DateTime<Utc>,
21    #[serde(default = "default_snapshot_schema_cow")]
22    pub schema_version: Cow<'static, str>,
23    pub nodes: Vec<AinlMemoryNode>,
24    pub edges: Vec<SnapshotEdge>,
25}
26
27/// One directed edge in a snapshot (maps to `ainl_graph_edges` rows).
28#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct SnapshotEdge {
30    pub source_id: Uuid,
31    pub target_id: Uuid,
32    pub edge_type: String,
33    #[serde(default = "default_edge_weight")]
34    pub weight: f32,
35    #[serde(default)]
36    pub metadata: Option<serde_json::Value>,
37}
38
39fn default_edge_weight() -> f32 {
40    1.0
41}
42
43/// One edge row that references a missing `ainl_graph_nodes` endpoint (see [`GraphValidationReport`]).
44#[derive(Debug, Clone, PartialEq, Eq)]
45pub struct DanglingEdgeDetail {
46    pub source_id: String,
47    pub target_id: String,
48    pub edge_type: String,
49}
50
51/// Result of [`crate::SqliteGraphStore::validate_graph`].
52#[derive(Debug, Clone)]
53pub struct GraphValidationReport {
54    pub agent_id: String,
55    pub node_count: usize,
56    pub edge_count: usize,
57    /// `(source_id, target_id)` edge endpoint pairs that reference a missing node row.
58    pub dangling_edges: Vec<(String, String)>,
59    /// Same dangling rows as [`Self::dangling_edges`], including edge label for diagnostics.
60    pub dangling_edge_details: Vec<DanglingEdgeDetail>,
61    /// Edges that touch this agent’s node set on exactly one side while both node rows exist
62    /// (often a shared/global neighbor or another agent’s node — informational, not invalid).
63    pub cross_agent_boundary_edges: usize,
64    /// Node ids (for this agent) that do not appear in any edge as source or target.
65    pub orphan_nodes: Vec<String>,
66    pub is_valid: bool,
67}