Skip to main content

ainl_memory/
snapshot.rs

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