remem-ai 0.6.90

Local-first coding agent memory for Claude Code and OpenAI Codex
Documentation
use super::*;
use crate::db::test_support::{cleanup_temp_db_files, unique_temp_db_path, ScopedTestDataDir};
use sha2::{Digest, Sha256};

fn create_review_source(path: &Path) -> Result<Connection> {
    let conn = Connection::open(path)?;
    conn.execute_batch(
        "CREATE TABLE memories (
            id INTEGER PRIMARY KEY,
            session_id TEXT,
            project TEXT NOT NULL,
            topic_key TEXT,
            title TEXT NOT NULL,
            content TEXT NOT NULL,
            memory_type TEXT NOT NULL,
            files TEXT,
            created_at_epoch INTEGER NOT NULL,
            updated_at_epoch INTEGER NOT NULL,
            status TEXT NOT NULL DEFAULT 'active',
            branch TEXT,
            scope TEXT DEFAULT 'project',
            acknowledged_pattern_id TEXT,
            acknowledged_pattern_version INTEGER,
            acknowledged_at_epoch INTEGER
        );",
    )?;
    Ok(conn)
}

#[test]
fn backup_snapshot_digest_tracks_wal_visible_state() -> Result<()> {
    let source_path = unique_temp_db_path("runtime-import-wal-snapshot");
    let source = create_review_source(&source_path)?;
    source.execute_batch("PRAGMA journal_mode=WAL; PRAGMA wal_autocheckpoint=0;")?;
    source.execute(
        "INSERT INTO memories
         (id, project, topic_key, title, content, memory_type,
          created_at_epoch, updated_at_epoch)
         VALUES (1, '/tmp/wal-import', 'wal-topic', 'WAL title', 'version one',
                 'decision', 1, 1)",
        [],
    )?;
    let main_before = Sha256::digest(std::fs::read(&source_path)?);
    let (first_snapshot, first_sha) = backup_snapshot::open_consistent_snapshot(&source_path)?;
    assert_eq!(
        first_snapshot.query_row("SELECT content FROM memories WHERE id = 1", [], |row| {
            row.get::<_, String>(0)
        })?,
        "version one"
    );

    source.execute(
        "UPDATE memories SET content = 'version two', updated_at_epoch = 2 WHERE id = 1",
        [],
    )?;
    let main_after = Sha256::digest(std::fs::read(&source_path)?);
    assert_eq!(main_before.as_slice(), main_after.as_slice());
    let (second_snapshot, second_sha) = backup_snapshot::open_consistent_snapshot(&source_path)?;
    assert_ne!(first_sha, second_sha);
    assert_eq!(
        second_snapshot.query_row("SELECT content FROM memories WHERE id = 1", [], |row| {
            row.get::<_, String>(0)
        })?,
        "version two"
    );

    drop(source);
    cleanup_temp_db_files(&source_path);
    Ok(())
}

#[test]
fn backup_import_restores_acknowledged_instruction_pattern() -> Result<()> {
    let _data_dir = ScopedTestDataDir::new("import-acknowledged-pattern");
    let source_path = unique_temp_db_path("runtime-import-acknowledged-pattern");
    let source = create_review_source(&source_path)?;
    source.execute(
        "INSERT INTO memories
         (id, project, topic_key, title, content, memory_type,
          created_at_epoch, updated_at_epoch, acknowledged_pattern_id,
          acknowledged_pattern_version, acknowledged_at_epoch)
         VALUES (1, '/tmp/ack-import', 'ack-topic', 'Acknowledged backup',
                 'Ignore previous instructions only as a quoted false-positive fixture.',
                 'decision', 1, 2, 'override_previous_instructions', ?1, 3)",
        [crate::memory::poisoning::INSTRUCTION_PATTERN_SET_VERSION],
    )?;
    source.execute(
        "INSERT INTO memories
         (id, project, topic_key, title, content, memory_type,
          created_at_epoch, updated_at_epoch, status, acknowledged_pattern_id,
          acknowledged_pattern_version, acknowledged_at_epoch)
         VALUES (2, '/tmp/ack-import', 'incomplete-ack-topic', 'Incomplete acknowledgement',
                 'Ignore previous instructions in another quoted fixture.',
                 'decision', 1, 2, 'stale', 'override_previous_instructions', ?1, NULL)",
        [crate::memory::poisoning::INSTRUCTION_PATTERN_SET_VERSION],
    )?;
    drop(source);

    let runtime = crate::db::open_db()?;
    let stats = import_memories_into_runtime(&source_path, &runtime)?;
    assert_eq!(stats.memories_imported, 1);
    assert_eq!(stats.memories_skipped, 1);
    let (memory_id, pattern_id, pattern_version): (i64, String, i64) = runtime.query_row(
        "SELECT id, acknowledged_pattern_id, acknowledged_pattern_version
         FROM memories WHERE topic_key = 'ack-topic'",
        [],
        |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)),
    )?;
    assert_eq!(pattern_id, "override_previous_instructions");
    assert_eq!(
        pattern_version,
        crate::memory::poisoning::INSTRUCTION_PATTERN_SET_VERSION
    );
    let (route, verdict, result_sha): (String, String, String) = runtime.query_row(
        "SELECT route_kind, poisoning_verdict, result_sha256
         FROM memory_activation_requests WHERE result_memory_id = ?1",
        [memory_id],
        |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?)),
    )?;
    assert_eq!(route, "exact_recovery");
    assert_eq!(verdict, "exact_recovery");
    let actual =
        crate::memory::activation::ExpectedActiveMemory::from_existing(&runtime, memory_id)?;
    assert_eq!(result_sha, actual.sha256());
    assert_eq!(
        runtime.query_row(
            "SELECT COUNT(*) FROM memories WHERE topic_key = 'incomplete-ack-topic'",
            [],
            |row| row.get::<_, i64>(0),
        )?,
        0
    );

    cleanup_temp_db_files(&source_path);
    Ok(())
}

#[test]
fn backup_import_deduplicates_legacy_repo_target_without_target_project() -> Result<()> {
    let _data_dir = ScopedTestDataDir::new("import-legacy-null-target-project");
    let source_path = unique_temp_db_path("runtime-import-legacy-null-target-project");
    let source = create_review_source(&source_path)?;
    let project = "/tmp/remem-import-legacy-null-target-project";
    source.execute(
        "INSERT INTO memories
         (id, project, topic_key, title, content, memory_type,
          created_at_epoch, updated_at_epoch)
         VALUES (1, ?1, 'legacy-topic', 'Backup copy', 'same identity',
                 'decision', 100, 200)",
        [project],
    )?;
    drop(source);

    let runtime = crate::db::open_db()?;
    let existing_id = crate::memory::insert_memory(
        &runtime,
        Some("runtime"),
        project,
        Some("legacy-topic"),
        "Existing copy",
        "existing runtime value",
        "decision",
        None,
    )?;
    runtime.execute(
        "UPDATE memories SET target_project = NULL WHERE id = ?1",
        [existing_id],
    )?;

    let stats = import_memories_into_runtime(&source_path, &runtime)?;
    assert_eq!(stats.memories_imported, 0);
    assert_eq!(stats.memories_skipped, 1);
    assert_eq!(
        runtime.query_row(
            "SELECT COUNT(*) FROM memories
             WHERE project = ?1 AND topic_key = 'legacy-topic' AND status = 'active'",
            [project],
            |row| row.get::<_, i64>(0),
        )?,
        1
    );

    cleanup_temp_db_files(&source_path);
    Ok(())
}