remem-ai 0.6.93

Local-first coding agent memory for Claude Code and OpenAI Codex
Documentation
use super::*;

#[test]
fn direct_save_topic_match_ignores_newer_row_outside_repo_owner_route() -> anyhow::Result<()> {
    let _dir = ScopedTestDataDir::new("save-topic-owner-route");
    let conn = db::open_db()?;
    let request = SaveMemoryRequest {
        text: "Initial repo-owned content.".to_string(),
        title: Some("Repo target".to_string()),
        project: Some("proj".to_string()),
        topic_key: Some("owner-route-target".to_string()),
        memory_type: Some("discovery".to_string()),
        scope: Some("project".to_string()),
        local_copy_enabled: Some(false),
        ..SaveMemoryRequest::default()
    };
    let repo_memory = save_memory(&conn, &request)?;
    conn.execute(
        "INSERT INTO memories
         (project, topic_key, title, content, memory_type, created_at_epoch,
          updated_at_epoch, status, scope, source_project, owner_scope,
          owner_key, context_class, source_trust_class)
         VALUES ('proj', 'owner-route-target', 'Tool-owned collision',
                 'Must remain untouched.', 'discovery', 1, 9999999999,
                 'active', 'project', 'proj', 'tool', 'tool:example',
                 'startup_core', 'local_tool_output')",
        [],
    )?;
    let tool_memory = conn.last_insert_rowid();
    let updated = save_memory(
        &conn,
        &SaveMemoryRequest {
            text: "Updated repo-owned content.".to_string(),
            title: Some("Repo target updated".to_string()),
            ..request
        },
    )?;

    assert_eq!(updated.id, repo_memory.id);
    let tool_content: String = conn.query_row(
        "SELECT content FROM memories WHERE id = ?1",
        [tool_memory],
        |row| row.get(0),
    )?;
    assert_eq!(tool_content, "Must remain untouched.");
    Ok(())
}

#[test]
fn agent_direct_save_incompatible_update_clears_candidate_provenance() -> anyhow::Result<()> {
    let _dir = ScopedTestDataDir::new("save-update-candidate-provenance");
    let conn = db::open_db()?;
    conn.execute(
        "INSERT INTO memory_candidates
         (id, scope, memory_type, topic_key, text, evidence_event_ids,
          confidence, risk_class, review_status, created_at_epoch, updated_at_epoch,
          source_trust_class)
         VALUES (41, 'project', 'discovery', 'captured-target',
                 'Automatically captured fact.', '[101,102]', 0.9, 'low',
                 'approved', 1, 1, 'user_prompt')",
        [],
    )?;
    conn.execute(
        "INSERT INTO memories
         (project, topic_key, title, content, memory_type, evidence_event_ids,
          source_candidate_id, confidence, valid_from_epoch,
          created_at_epoch, updated_at_epoch, status, scope,
          source_project, target_project, owner_scope, owner_key, context_class,
          source_trust_class)
         VALUES ('proj', 'captured-target', 'Captured target',
                 'Automatically captured fact.', 'discovery', '[101,102]', 41, 0.9, 1,
                 1, 1, 'active', 'project', 'proj', 'proj', 'repo', 'proj',
                 'startup_core', 'user_prompt')",
        [],
    )?;
    let memory_id = conn.last_insert_rowid();

    let saved = crate::memory::service::save_memory_from_with_reference_time(
        &conn,
        &SaveMemoryRequest {
            text: "Automatically captured fact with an agent-supplied clarification.".to_string(),
            title: Some("Captured target clarified".to_string()),
            project: Some("proj".to_string()),
            topic_key: Some("captured-target".to_string()),
            memory_type: Some("discovery".to_string()),
            scope: Some("project".to_string()),
            local_copy_enabled: Some(false),
            claim_enabled: Some(false),
            idempotency_key: Some("candidate-provenance-update".to_string()),
            ..SaveMemoryRequest::default()
        },
        None,
        crate::memory::service::SaveMemoryCaller::McpAgent,
    )?;

    assert_eq!(saved.id, memory_id);
    assert_eq!(saved.operation, "update");
    let (evidence, candidate_id, confidence, valid_from): (
        Option<String>,
        Option<i64>,
        Option<f64>,
        Option<i64>,
    ) = conn.query_row(
        "SELECT evidence_event_ids, source_candidate_id, confidence, valid_from_epoch
         FROM memories WHERE id = ?1",
        [memory_id],
        |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?, row.get(3)?)),
    )?;
    assert_eq!(
        (evidence, candidate_id, confidence, valid_from),
        (None, None, None, None)
    );
    let stored_result_sha256: String = conn.query_row(
        "SELECT result_sha256 FROM memory_activation_requests WHERE result_memory_id = ?1",
        [memory_id],
        |row| row.get(0),
    )?;
    let actual = crate::memory::activation::ExpectedActiveMemory::from_existing(&conn, memory_id)?;
    assert_eq!(stored_result_sha256, actual.sha256());
    Ok(())
}

#[test]
fn direct_save_replays_original_receipt_after_equivalent_candidate_replacement(
) -> anyhow::Result<()> {
    let _dir = ScopedTestDataDir::new("save-replay-candidate-replacement");
    let conn = db::open_db()?;
    let request = SaveMemoryRequest {
        text: "Stable represented fact.".to_string(),
        title: Some("Stable fact".to_string()),
        project: Some("proj".to_string()),
        topic_key: Some("stable-replay-target".to_string()),
        memory_type: Some("discovery".to_string()),
        scope: Some("project".to_string()),
        local_copy_enabled: Some(false),
        claim_enabled: Some(false),
        idempotency_key: Some("stable-replay-key".to_string()),
        ..SaveMemoryRequest::default()
    };
    let original = save_memory(&conn, &request)?;
    let conflict = save_memory(
        &conn,
        &SaveMemoryRequest {
            text: "Changed caller payload.".to_string(),
            ..request.clone()
        },
    )
    .expect_err("same key with changed caller payload must conflict");
    assert!(conflict
        .to_string()
        .contains("reused with different request"));

    conn.execute(
        "INSERT INTO memory_candidates
         (id, scope, memory_type, topic_key, text, evidence_event_ids,
          confidence, risk_class, review_status, created_at_epoch, updated_at_epoch,
          source_trust_class)
         VALUES (73, 'project', 'discovery', 'stable-replay-target',
                 'Stable represented fact.', '[501]', 0.95, 'low', 'approved',
                 2, 2, 'user_prompt')",
        [],
    )?;
    let expected = crate::memory::activation::ExpectedActiveMemory::new(
        "Stable fact",
        "Stable represented fact.",
        "discovery",
    )
    .with_topic_key(Some("stable-replay-target"))
    .with_candidate_evidence(Some("[501]"), Some(73));
    let promotion = crate::memory::activation::ActiveMemoryWriteRequest {
        activation_id: "candidate:replacement-73".to_string(),
        route_kind: crate::memory::activation::ActivationRouteKind::CandidatePromotion,
        actor_kind: crate::memory::activation::ActivationActorKind::Operator,
        source_operation: "candidate_review".to_string(),
        source_trust: crate::memory::poisoning::SourceTrustClass::UserPrompt,
        result_source_trust: crate::memory::poisoning::SourceTrustClass::UserPrompt,
        source_project: "proj".to_string(),
        route: crate::memory::activation::ActiveMemoryRoute::default_for("proj", None, "project"),
        provenance_kind: crate::memory::activation::ActivationProvenanceKind::Candidate,
        provenance_ref: "candidate:73".to_string(),
        payload_sha256: crate::memory::activation::payload_sha256(&[
            "candidate:73",
            "Stable represented fact.",
        ]),
        expected_memory: expected,
        poisoning_verdict: crate::memory::activation::ActivationPoisoningVerdict::UpstreamValidated,
        superseded_ids: vec![original.id],
    };
    let replacement = crate::memory::activation::execute_one(&conn, &promotion, |_permit| {
        conn.execute(
            "UPDATE memories SET status = 'stale' WHERE id = ?1",
            [original.id],
        )?;
        conn.execute(
            "INSERT INTO memories
             (project, topic_key, title, content, memory_type, evidence_event_ids,
              source_candidate_id, created_at_epoch, updated_at_epoch, status, scope,
              source_project, target_project, owner_scope, owner_key, context_class,
              source_trust_class)
             VALUES ('proj', 'stable-replay-target', 'Stable fact',
                     'Stable represented fact.', 'discovery', '[501]', 73, 2, 2,
                     'active', 'project', 'proj', 'proj', 'repo', 'proj',
                     'startup_core', 'user_prompt')",
            [],
        )?;
        Ok(conn.last_insert_rowid())
    })?;
    let replay = save_memory(&conn, &request)?;
    assert_eq!(replay.id, original.id);
    assert_eq!(replay.operation, "noop");
    assert_eq!(replay.claim_status, "disabled");
    let statuses: (String, String) = conn.query_row(
        "SELECT old.status, replacement.status
         FROM memories AS old, memories AS replacement
         WHERE old.id = ?1 AND replacement.id = ?2",
        rusqlite::params![original.id, replacement.memory_id],
        |row| Ok((row.get(0)?, row.get(1)?)),
    )?;
    assert_eq!(statuses, ("stale".to_string(), "active".to_string()));
    Ok(())
}

#[test]
fn semantic_noop_lesson_reinforcement_validates_the_rewritten_payload() -> anyhow::Result<()> {
    let _dir = ScopedTestDataDir::new("lesson-semantic-noop-payload");
    let conn = db::open_db()?;
    let request = SaveMemoryRequest {
        text: "Lesson: Preserve the exact reinforced payload.".to_string(),
        title: Some("Lesson payload".to_string()),
        project: Some("proj".to_string()),
        topic_key: Some("lesson-payload".to_string()),
        memory_type: Some("lesson".to_string()),
        local_copy_enabled: Some(false),
        claim_enabled: Some(false),
        ..SaveMemoryRequest::default()
    };
    let first = save_memory(&conn, &request)?;
    let incoming = "  lesson: preserve   the exact reinforced payload.  ";
    let second = save_memory(
        &conn,
        &SaveMemoryRequest {
            text: incoming.to_string(),
            ..request
        },
    )?;

    assert_eq!(second.id, first.id);
    assert_eq!(second.operation, "update");
    assert_eq!(
        conn.query_row(
            "SELECT content FROM memories WHERE id = ?1",
            [first.id],
            |row| row.get::<_, String>(0),
        )?,
        incoming
    );
    Ok(())
}

#[test]
fn global_save_from_another_project_binds_the_shared_existing_route() -> anyhow::Result<()> {
    let _dir = ScopedTestDataDir::new("save-global-existing-route");
    let conn = db::open_db()?;
    conn.execute(
        "INSERT INTO memories
         (project, topic_key, title, content, memory_type, created_at_epoch,
          updated_at_epoch, status, scope, source_project, owner_scope, owner_key,
          context_class, source_trust_class)
         VALUES ('project-a', 'legacy-global-topic', 'Legacy global fact',
                 'A shared global fact.', 'discovery', 1, 1, 'active', 'global',
                 'project-a', 'user', 'user:default', 'startup_core', 'local_tool_output')",
        [],
    )?;
    let first_id = conn.last_insert_rowid();
    let request = SaveMemoryRequest {
        text: "A shared global fact.".to_string(),
        title: Some("Legacy global fact".to_string()),
        project: Some("project-b".to_string()),
        topic_key: Some("legacy-global-topic".to_string()),
        memory_type: Some("discovery".to_string()),
        scope: Some("global".to_string()),
        local_copy_enabled: Some(false),
        claim_enabled: Some(false),
        ..SaveMemoryRequest::default()
    };
    let second = save_memory(&conn, &request)?;

    assert_eq!(second.id, first_id);
    assert_eq!(
        conn.query_row(
            "SELECT project, source_project FROM memories WHERE id = ?1",
            [first_id],
            |row| Ok((row.get::<_, String>(0)?, row.get::<_, String>(1)?)),
        )?,
        ("project-a".to_string(), "project-a".to_string())
    );
    Ok(())
}