remem-ai 0.6.79

Local-first coding agent memory for Claude Code and OpenAI Codex
Documentation
//! Reference-integrity queries used by the focused CurrentTruth diagnostic.

use std::collections::BTreeSet;

use anyhow::Result;
use rusqlite::{params, Connection};

use super::{ReferenceIssue, TruthDoctorOptions};

pub(super) fn collect_unreconstructable_historical_refs(
    _conn: &Connection,
    opts: &TruthDoctorOptions,
    reference_epoch: i64,
    out: &mut BTreeSet<ReferenceIssue>,
) -> Result<()> {
    if opts.as_of_epoch.is_none() {
        return Ok(());
    }
    out.insert(ReferenceIssue {
        relation_ref: format!("historical_cutoff:{reference_epoch}"),
        claim_ref: format!("truth_scope:{}", opts.project),
        problem: "unreconstructable_historical_truth",
        stored_status: None,
    });
    Ok(())
}

pub(super) fn collect_dangling_memory_edge_refs(
    conn: &Connection,
    opts: &TruthDoctorOptions,
    reference_epoch: i64,
    out: &mut BTreeSet<ReferenceIssue>,
) -> Result<()> {
    let mut stmt = conn.prepare(
        "SELECT 'memory_edge:' || me.id,
                CASE WHEN me.from_memory_id IS NULL
                     THEN 'memory_edge:' || me.id || ':from_memory_id:null'
                     ELSE 'memory:' || me.from_memory_id END
         FROM memory_edges me
         LEFT JOIN memories fm ON fm.id = me.from_memory_id
         JOIN memories tm ON tm.id = me.to_memory_id
         LEFT JOIN memory_candidates mc ON mc.id = me.source_candidate_id
         WHERE (me.from_memory_id IS NULL OR fm.id IS NULL)
           AND NOT (me.edge_type = 'derived_from'
                    AND me.from_memory_id IS NULL
                    AND mc.id IS NOT NULL)
           AND tm.project = ?1
           AND (?2 IS NULL OR tm.branch IS NULL OR tm.branch = ?2)
           AND (?4 IS NULL OR tm.topic_key = ?4)
           AND me.created_at_epoch <= ?3
         UNION ALL
         SELECT 'memory_edge:' || me.id,
                CASE WHEN me.to_memory_id IS NULL
                     THEN 'memory_edge:' || me.id || ':to_memory_id:null'
                     ELSE 'memory:' || me.to_memory_id END
         FROM memory_edges me
         JOIN memories fm ON fm.id = me.from_memory_id
         LEFT JOIN memories tm ON tm.id = me.to_memory_id
         WHERE (me.to_memory_id IS NULL OR tm.id IS NULL)
           AND fm.project = ?1
           AND (?2 IS NULL OR fm.branch IS NULL OR fm.branch = ?2)
           AND (?4 IS NULL OR fm.topic_key = ?4)
           AND me.created_at_epoch <= ?3",
    )?;
    let rows = stmt.query_map(
        params![opts.project, opts.branch, reference_epoch, opts.subject],
        |row| {
            Ok(ReferenceIssue {
                relation_ref: row.get(0)?,
                claim_ref: row.get(1)?,
                problem: "dangling_claim_reference",
                stored_status: None,
            })
        },
    )?;
    for row in rows {
        out.insert(row?);
    }
    Ok(())
}

pub(super) fn collect_self_referential_memory_edge_refs(
    conn: &Connection,
    opts: &TruthDoctorOptions,
    reference_epoch: i64,
    out: &mut BTreeSet<ReferenceIssue>,
) -> Result<()> {
    let mut stmt = conn.prepare(
        "SELECT 'memory_edge:' || me.id, 'memory:' || memory.id, memory.status
         FROM memory_edges me
         JOIN memories memory ON memory.id = me.from_memory_id
         WHERE me.from_memory_id = me.to_memory_id
           AND memory.project = ?1
           AND (?2 IS NULL OR memory.branch IS NULL OR memory.branch = ?2)
           AND (?4 IS NULL OR memory.topic_key = ?4)
           AND me.created_at_epoch <= ?3",
    )?;
    let rows = stmt.query_map(
        params![opts.project, opts.branch, reference_epoch, opts.subject],
        |row| {
            Ok(ReferenceIssue {
                relation_ref: row.get(0)?,
                claim_ref: row.get(1)?,
                problem: "self_referential_relation",
                stored_status: Some(row.get(2)?),
            })
        },
    )?;
    for row in rows {
        out.insert(row?);
    }
    Ok(())
}

pub(super) fn collect_invalid_user_claim_replacement_refs(
    conn: &Connection,
    opts: &TruthDoctorOptions,
    reference_epoch: i64,
    out: &mut BTreeSet<ReferenceIssue>,
) -> Result<()> {
    let mut stmt = conn.prepare(
        "SELECT 'user_claim_supersedes:' || current.id,
                'user_claim:' || current.supersedes_claim_id,
                CASE WHEN old.id IS NULL THEN 'dangling_claim_reference'
                     WHEN current.supersedes_claim_id = current.id
                     THEN 'self_referential_relation'
                     ELSE 'replacement_scope_mismatch' END,
                CASE WHEN old.id IS NULL THEN NULL ELSE old.status END
         FROM user_context_claims current
         LEFT JOIN user_context_claims old ON old.id = current.supersedes_claim_id
         WHERE current.owner_scope = 'repo' AND current.owner_key = ?1
           AND current.supersedes_claim_id IS NOT NULL
           AND (old.id IS NULL
             OR current.supersedes_claim_id = current.id
             OR old.owner_scope != current.owner_scope
             OR old.owner_key != current.owner_key)
           AND current.created_at_epoch <= ?2
           AND (?3 IS NULL
                OR current.claim_key = ?3
                OR current.claim_type || ':' || current.claim_key = ?3)",
    )?;
    let rows = stmt.query_map(
        params![opts.project, reference_epoch, opts.subject],
        |row| {
            let problem = match row.get::<_, String>(2)?.as_str() {
                "dangling_claim_reference" => "dangling_claim_reference",
                "self_referential_relation" => "self_referential_relation",
                _ => "replacement_scope_mismatch",
            };
            Ok(ReferenceIssue {
                relation_ref: row.get(0)?,
                claim_ref: row.get(1)?,
                problem,
                stored_status: row.get(3)?,
            })
        },
    )?;
    for row in rows {
        out.insert(row?);
    }
    Ok(())
}