mnemo-core 0.4.0

Core storage, data model, query engine, and indexing for Mnemo
Documentation
//! v0.4.0-rc1 Task A7 (partial) — golden DuckDB persistence fixtures.
//!
//! Exercises the migration round-trip against a checked-in fixture so
//! that schema-evolving v0.4.0+ work cannot land without proving the
//! migrator handles a real on-disk file.
//!
//! Today the only fixture is `v0_3_4.mnemo.db`, generated by
//! `examples/gen_golden_fixture.rs`. The v0.1.1 / v0.3.0 historical
//! fixtures called for in the prompt require the corresponding git
//! tags to actually exist in the repo (they don't, today — see
//! issue #38) and are deferred. This test gives v0.4.0+ at least one
//! real round-trip surface to evolve against.

use std::path::PathBuf;

use mnemo_core::storage::duckdb::DuckDbStorage;
use mnemo_core::storage::migrations::{CURRENT_PERSISTENCE_VERSION, read_persistence_version};

fn fixture_path(name: &str) -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("golden")
        .join(name)
}

#[tokio::test]
async fn v0_3_4_fixture_opens_with_current_persistence_stamp() {
    use mnemo_core::storage::MemoryFilter;
    use mnemo_core::storage::StorageBackend;
    let path = fixture_path("v0_3_4.mnemo.db");
    assert!(
        path.exists(),
        "missing fixture {} — regenerate with `cargo run --example gen_golden_fixture -- {}`",
        path.display(),
        path.display()
    );

    // Copy fixture out of the repo tree so DuckDB doesn't write back into
    // the checked-in file as it normalises the catalog.
    let tmp = tempfile::NamedTempFile::new().unwrap();
    std::fs::copy(&path, tmp.path()).unwrap();

    let storage = DuckDbStorage::open(tmp.path()).expect("open fixture");
    // The migrator must have stamped CURRENT_PERSISTENCE_VERSION on open.
    let conn = duckdb::Connection::open(tmp.path()).expect("reopen for stamp check");
    let stamp = read_persistence_version(&conn).expect("read stamp");
    assert_eq!(
        stamp,
        Some(CURRENT_PERSISTENCE_VERSION),
        "fixture must be stamped to the current persistence version after open"
    );
    drop(conn);

    // The 5 records the generator seeded must still be retrievable.
    let filter = MemoryFilter {
        agent_id: Some("agent-fixture".to_string()),
        ..Default::default()
    };
    let records = storage.list_memories(&filter, 100, 0).await.expect("list");
    assert_eq!(
        records.len(),
        5,
        "v0_3_4 fixture must round-trip exactly 5 records (saw {})",
        records.len()
    );
}