Shared memory and context tools for agentic work.
Code Rooms
//! Round-trip coverage for the BINARY graph snapshot (`snapshot_bin`).
//!
//! `snapshot_bin::{save_graph, load_graph}` is the compact binary persistence
//! path used in production by `m1nd-mcp` (persist_handlers), yet it had ZERO test
//! coverage — a silent corruption in the binary format would ship undetected.
//! This proves a graph survives save -> load with nodes, edges, tags, and
//! provenance intact. (Surfaced by the X-RAY proof-coverage pass.)
use m1nd_core::graph::{Graph, NodeProvenanceInput};
use m1nd_core::snapshot_bin;
use m1nd_core::types::{EdgeDirection, EdgeIdx, FiniteF32, NodeId, NodeType};
fn edge_slot(graph: &Graph, source: NodeId, target: NodeId) -> usize {
graph
.csr
.out_range(source)
.find(|&slot| graph.csr.targets[slot] == target)
.expect("edge slot")
}
fn sample_graph() -> Graph {
let mut g = Graph::new();
let node_a = g
.add_node(
"file::a.rs::fn::alpha",
"alpha",
NodeType::Function,
&["rust", "rust:visibility:pub", "xray:state:bedrock"],
1718000000.0,
0.5,
)
.unwrap();
let node_b = g
"file::a.rs::fn::beta",
"beta",
&["rust"],
1718000001.0,
0.0,
g.set_node_provenance(
node_a,
NodeProvenanceInput {
source_path: Some("a.rs"),
line_start: Some(3),
line_end: Some(9),
..Default::default()
},
);
g.add_edge(
node_b,
"calls",
FiniteF32::new(1.0),
EdgeDirection::Forward,
false,
FiniteF32::new(0.0),
g.finalize().unwrap();
g
#[test]
fn binary_snapshot_round_trips_nodes_edges_tags_provenance() {
let dir = std::env::temp_dir().join("m1nd_snapshot_bin_rt");
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("graph.bin");
let g = sample_graph();
snapshot_bin::save_graph(&g, &path).expect("binary save");
assert!(
std::fs::metadata(&path)
.map(|m| m.len() > 0)
.unwrap_or(false),
"binary snapshot file should be written and non-empty"
let r = snapshot_bin::load_graph(&path).expect("binary load");
assert_eq!(r.num_nodes(), g.num_nodes(), "node count must survive");
assert_eq!(r.num_edges(), g.num_edges(), "edge count must survive");
let alpha = r
.resolve_id("file::a.rs::fn::alpha")
.expect("node external_id must survive");
let tags = r.node_tags(alpha);
tags.contains(&"xray:state:bedrock"),
"tags must survive: {tags:?}"
assert!(tags.contains(&"rust:visibility:pub"));
let prov = r.resolve_node_provenance(alpha);
assert_eq!(
prov.line_start,
Some(3),
"provenance line_start must survive"
assert_eq!(prov.line_end, Some(9), "provenance line_end must survive");
r.resolve_id("file::a.rs::fn::beta").is_some(),
"second node must survive"
std::fs::remove_dir_all(&dir).ok();
fn binary_v4_restart_preserves_original_and_learned_weight_separately() {
let mut graph = sample_graph();
let alpha = graph.resolve_id("file::a.rs::fn::alpha").unwrap();
let beta = graph.resolve_id("file::a.rs::fn::beta").unwrap();
let slot = edge_slot(&graph, alpha, beta);
graph.edge_plasticity.current_weight[slot] = FiniteF32::new(1.7);
.atomic_write_weight(EdgeIdx::new(slot as u32), FiniteF32::new(1.7), 64)
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("learned.bin");
snapshot_bin::save_graph(&graph, &path).unwrap();
let restored = snapshot_bin::load_graph(&path).unwrap();
let restored_alpha = restored.resolve_id("file::a.rs::fn::alpha").unwrap();
let restored_beta = restored.resolve_id("file::a.rs::fn::beta").unwrap();
let restored_slot = edge_slot(&restored, restored_alpha, restored_beta);
restored.edge_plasticity.original_weight[restored_slot].get(),
1.0
restored.edge_plasticity.current_weight[restored_slot].get(),
1.7
fn binary_v4_preserves_asymmetric_bidirectional_slots() {
let mut graph = Graph::new();
let alpha = graph
.add_node("alpha", "alpha", NodeType::Function, &[], 0.0, 0.0)
let beta = graph
.add_node("beta", "beta", NodeType::Function, &[], 0.0, 0.0)
.add_edge(
alpha,
beta,
"related",
FiniteF32::new(0.4),
EdgeDirection::Bidirectional,
FiniteF32::new(0.2),
graph.finalize().unwrap();
let forward = edge_slot(&graph, alpha, beta);
let reverse = edge_slot(&graph, beta, alpha);
graph.edge_plasticity.original_weight[forward] = FiniteF32::new(0.4);
graph.edge_plasticity.original_weight[reverse] = FiniteF32::new(0.6);
graph.edge_plasticity.current_weight[forward] = FiniteF32::new(1.2);
graph.edge_plasticity.current_weight[reverse] = FiniteF32::new(0.3);
.atomic_write_weight(EdgeIdx::new(forward as u32), FiniteF32::new(1.2), 64)
.atomic_write_weight(EdgeIdx::new(reverse as u32), FiniteF32::new(0.3), 64)
let path = dir.path().join("bidir.bin");
let restored_alpha = restored.resolve_id("alpha").unwrap();
let restored_beta = restored.resolve_id("beta").unwrap();
let restored_forward = edge_slot(&restored, restored_alpha, restored_beta);
let restored_reverse = edge_slot(&restored, restored_beta, restored_alpha);
restored.edge_plasticity.original_weight[restored_forward].get(),
0.4
restored.edge_plasticity.original_weight[restored_reverse].get(),
0.6
restored.edge_plasticity.current_weight[restored_forward].get(),
1.2
restored.edge_plasticity.current_weight[restored_reverse].get(),
0.3
/// NOTE: this fixture is encoded with the SAME bincode configuration the loader
/// decodes with, so it proves the V3 BRANCH is taken — never that the bytes on
/// disk are the right bytes. The frozen-byte proof is
/// `tests/snapshot_bin_continuity.rs`.
fn binary_loader_uses_explicit_v3_layout_fallback() {
#[derive(serde::Serialize)]
struct LegacyGraph {
version: u32,
nodes: Vec<LegacyNode>,
edges: Vec<LegacyEdge>,
struct LegacyNode {
external_id: String,
label: String,
node_type: u8,
tags: Vec<String>,
last_modified: f64,
change_frequency: f32,
provenance: LegacyProvenance,
#[derive(Default, serde::Serialize)]
struct LegacyProvenance {
source_path: Option<String>,
line_start: Option<u32>,
line_end: Option<u32>,
excerpt: Option<String>,
namespace: Option<String>,
canonical: bool,
struct LegacyEdge {
source_id: String,
target_id: String,
relation: String,
weight: f32,
direction: u8,
inhibitory: bool,
causal_strength: f32,
let node = |id: &str| LegacyNode {
external_id: id.into(),
label: id.into(),
node_type: 2,
tags: vec![],
last_modified: 0.0,
change_frequency: 0.0,
provenance: LegacyProvenance::default(),
};
let legacy = LegacyGraph {
version: 3,
nodes: vec![node("alpha"), node("beta")],
edges: vec![LegacyEdge {
source_id: "alpha".into(),
target_id: "beta".into(),
relation: "calls".into(),
weight: 0.66,
direction: 0,
inhibitory: false,
causal_strength: 0.1,
}],
let path = dir.path().join("legacy-v3.bin");
std::fs::write(
&path,
bincode::serde::encode_to_vec(&legacy, bincode::config::legacy()).unwrap(),
let restored = snapshot_bin::load_graph(&path).expect("load explicit v3 layout");
let alpha = restored.resolve_id("alpha").unwrap();
let beta = restored.resolve_id("beta").unwrap();
let slot = edge_slot(&restored, alpha, beta);
assert_eq!(restored.edge_plasticity.original_weight[slot].get(), 0.66);
assert_eq!(restored.edge_plasticity.current_weight[slot].get(), 0.66);
/// A snapshot file is exactly one payload. bincode stops at the end of the value
/// and ignores whatever follows, so a decode that consumes only part of the file
/// used to look like a clean load — that is the exact shape of the empty-graph
/// misread (3 of 88528 bytes consumed, `version=4, nodes=0, edges=0`, no error).
/// The loader now demands full consumption, so a partial read is a refusal.
fn binary_load_refuses_a_payload_that_does_not_fill_the_file() {
let path = dir.path().join("padded.bin");
let graph = sample_graph();
let mut bytes = std::fs::read(&path).unwrap();
let payload_len = bytes.len();
bytes.extend_from_slice(&[0xAA; 32]);
std::fs::write(&path, &bytes).unwrap();
let message = match snapshot_bin::load_graph(&path) {
Err(error) => error.to_string(),
Ok(graph) => panic!(
"a snapshot that leaves bytes unread must be refused, not accepted as a \
{}-node graph",
graph.num_nodes()
),
message.contains(&payload_len.to_string()) && message.contains(&bytes.len().to_string()),
"the refusal must name both counts, got: {message}"
/// A corrupt file must come back as an `Err`, never as a dead process.
///
/// bincode's allocation guard only runs when the decoder carries a byte limit;
/// with no limit, a garbage length prefix is trusted verbatim. These exact 22
/// bytes yield a length of 7018141077720822895 read out of the ASCII, and
/// aborted the process with SIGABRT — a failure no caller can catch, on a path
/// whose whole promise is that a damaged file degrades gracefully.
fn binary_load_refuses_garbage_instead_of_trusting_its_length_prefix() {
let ascii = b"\x00\x01\x02not a real cache\xff\xfe".to_vec();
// A well-formed version field followed by a node count of u64::MAX.
let mut huge_len = 4u32.to_le_bytes().to_vec();
huge_len.extend_from_slice(&u64::MAX.to_le_bytes());
for (name, bytes) in [("ascii.bin", ascii), ("huge-len.bin", huge_len)] {
let path = dir.path().join(name);
snapshot_bin::load_graph(&path).is_err(),
"{name} must be refused with an error the caller can handle"
fn binary_load_missing_file_is_error_not_panic() {
let missing = std::env::temp_dir().join("m1nd_snapshot_bin_missing_xyz.bin");
let _ = std::fs::remove_file(&missing);
snapshot_bin::load_graph(&missing).is_err(),
"loading a missing binary snapshot must return Err, not panic"