remem-ai 0.6.81

Local-first coding agent memory for Claude Code and OpenAI Codex
Documentation
use crate::adapter::{EventSummary, ParsedHookEvent};
use crate::db::{self, test_support::ScopedTestDataDir};

use super::super::spill::{spill_capture_event, SPILL_REASON_CAPTURE_PERSISTENCE_FAILED};
use super::observe_input;

#[tokio::test]
async fn observe_spills_projection_failure_and_replays_capture_once() -> anyhow::Result<()> {
    let _test_dir = ScopedTestDataDir::new("observe-persist-failure-spill");
    let failing_input = serde_json::json!({
        "session_id": "sess-persist-fail",
        "cwd": "/tmp/remem",
        "tool_name": "Edit",
        "tool_input": {"file_path": "src/lib.rs"},
        "tool_response": {"content": "edited"}
    })
    .to_string();

    let conn = db::open_db()?;
    conn.execute_batch(
        "CREATE TRIGGER fail_events_insert
         BEFORE INSERT ON events
         BEGIN
             SELECT RAISE(FAIL, 'events blocked');
         END;",
    )?;
    drop(conn);

    let err = observe_input(&failing_input, Some("claude-code"))
        .await
        .expect_err("event insert failure should spill");
    assert!(err.to_string().contains("events blocked"), "{err}");
    assert!(crate::db::data_dir().join("capture-spill.jsonl").exists());

    let conn = db::open_db()?;
    let partial_captures: i64 = conn.query_row(
        "SELECT COUNT(*) FROM captured_events WHERE session_id = 'sess-persist-fail'",
        [],
        |row| row.get(0),
    )?;
    let partial_events: i64 = conn.query_row(
        "SELECT COUNT(*) FROM events WHERE session_id = 'sess-persist-fail'",
        [],
        |row| row.get(0),
    )?;
    let partial_tasks: i64 = conn.query_row(
        "SELECT COUNT(*) FROM extraction_tasks WHERE session_row_id IN (
             SELECT id FROM sessions WHERE session_id = 'sess-persist-fail'
         )",
        [],
        |row| row.get(0),
    )?;
    assert_eq!(partial_captures, 0);
    assert_eq!(partial_events, 0);
    assert_eq!(partial_tasks, 0);
    let partial_drop: (i64, i64) = conn.query_row(
        "SELECT COUNT(*), COUNT(recovered_event_id)
         FROM capture_drop_events
         WHERE session_id = 'sess-persist-fail'
           AND reason = 'capture_persistence_failed'",
        [],
        |row| Ok((row.get(0)?, row.get(1)?)),
    )?;
    let partial_stats = db::query_system_stats(&conn)?;
    assert_eq!(partial_drop, (1, 0));
    assert_eq!(partial_stats.actionable_capture_drops, 1);
    assert_eq!(partial_stats.unrecovered_capture_spills, 1);
    conn.execute_batch("DROP TRIGGER fail_events_insert;")?;
    drop(conn);

    let replay_trigger = serde_json::json!({
        "session_id": "sess-replay-trigger",
        "cwd": "/tmp/remem",
        "tool_name": "Edit",
        "tool_input": {"file_path": "src/other.rs"},
        "tool_response": {"content": "edited"}
    })
    .to_string();
    observe_input(&replay_trigger, Some("claude-code")).await?;

    let conn = db::open_db()?;
    let replayed_captures: i64 = conn.query_row(
        "SELECT COUNT(*) FROM captured_events WHERE session_id = 'sess-persist-fail'",
        [],
        |row| row.get(0),
    )?;
    let replayed_events: i64 = conn.query_row(
        "SELECT COUNT(*) FROM events WHERE session_id = 'sess-persist-fail'",
        [],
        |row| row.get(0),
    )?;
    assert_eq!(replayed_captures, 1);
    assert_eq!(replayed_events, 1);
    let linked_event_id: i64 = conn.query_row(
        "SELECT captured_event_id FROM events WHERE session_id = 'sess-persist-fail'",
        [],
        |row| row.get(0),
    )?;
    assert!(linked_event_id > 0);
    let replayed_drop: (String, Option<i64>) = conn.query_row(
        "SELECT reason, recovered_event_id
         FROM capture_drop_events
         WHERE session_id = 'sess-persist-fail'",
        [],
        |row| Ok((row.get(0)?, row.get(1)?)),
    )?;
    let replayed_stats = db::query_system_stats(&conn)?;
    assert_eq!(replayed_drop.0, SPILL_REASON_CAPTURE_PERSISTENCE_FAILED);
    assert!(replayed_drop.1.is_some());
    assert_eq!(replayed_stats.actionable_capture_drops, 0);
    assert_eq!(replayed_stats.unrecovered_capture_spills, 0);
    assert!(!crate::db::data_dir().join("capture-spill.jsonl").exists());

    let replayed_event_id: String = conn.query_row(
        "SELECT event_id FROM captured_events WHERE session_id = 'sess-persist-fail'",
        [],
        |row| row.get(0),
    )?;
    let replayed_summary = conn.query_row(
        "SELECT event_type, summary, detail, files, exit_code
         FROM events
         WHERE session_id = 'sess-persist-fail'",
        [],
        |row| {
            Ok(EventSummary {
                event_type: row.get(0)?,
                summary: row.get(1)?,
                detail: row.get(2)?,
                files_json: row.get(3)?,
                exit_code: row.get(4)?,
            })
        },
    )?;
    drop(conn);

    let replayed_event = ParsedHookEvent {
        session_id: "sess-persist-fail".to_string(),
        cwd: Some("/tmp/remem".to_string()),
        project: "/tmp/remem".to_string(),
        reference_time_epoch: None,
        tool_name: "Edit".to_string(),
        tool_input: Some(serde_json::json!({"file_path": "src/lib.rs"})),
        tool_response: Some(serde_json::json!({"content": "edited"})),
    };
    spill_capture_event(
        "claude-code",
        &replayed_event_id,
        &replayed_event,
        &replayed_summary,
        SPILL_REASON_CAPTURE_PERSISTENCE_FAILED,
        &anyhow::anyhow!("retry same partial capture"),
    )?;
    observe_input(&replay_trigger, Some("claude-code")).await?;

    let conn = db::open_db()?;
    let retry_replayed_events: i64 = conn.query_row(
        "SELECT COUNT(*) FROM events WHERE session_id = 'sess-persist-fail'",
        [],
        |row| row.get(0),
    )?;
    assert_eq!(retry_replayed_events, 1);
    Ok(())
}