use anyhow::Result;
use rusqlite::{params, Connection};
pub(crate) fn seed_current_memory_proof(conn: &Connection, memory_id: i64) -> Result<()> {
seed_current_memory_proof_inner(conn, memory_id, true)
}
pub(crate) fn seed_current_memory_direct_evidence_proof(
conn: &Connection,
memory_id: i64,
) -> Result<()> {
seed_current_memory_proof_inner(conn, memory_id, false)
}
fn seed_current_memory_proof_inner(
conn: &Connection,
memory_id: i64,
with_candidate: bool,
) -> Result<()> {
let (project, topic_key, content, memory_type, created_at, status, owner_scope, owner_key): (
String,
Option<String>,
String,
String,
i64,
String,
Option<String>,
Option<String>,
) = conn.query_row(
"SELECT project, topic_key, content, memory_type, created_at_epoch, status,
owner_scope, owner_key
FROM memories WHERE id = ?1",
[memory_id],
|row| {
Ok((
row.get(0)?,
row.get(1)?,
row.get(2)?,
row.get(3)?,
row.get(4)?,
row.get(5)?,
row.get(6)?,
row.get(7)?,
))
},
)?;
let topic_key = topic_key.unwrap_or_else(|| format!("g2-fixture-{memory_id}"));
let event_id_override = format!("g2-fixture-event-{memory_id}");
let session_id = format!("g2-fixture-session-{memory_id}");
let event = crate::db::record_captured_event_with_id_and_created_at(
conn,
&crate::db::CaptureEventInput {
host: "codex-cli",
session_id: &session_id,
project: &project,
cwd: None,
event_type: "message",
role: Some("assistant"),
tool_name: None,
content: &content,
task_kind: None,
},
Some(&event_id_override),
created_at,
)?;
let canonical_project =
crate::project_alias::resolve_project_identity(conn, &project)?.canonical_path;
let owner_scope = owner_scope.unwrap_or_else(|| "repo".to_string());
let mut owner_key = owner_key.unwrap_or_else(|| canonical_project.clone());
if owner_scope == "repo" {
owner_key =
crate::project_alias::resolve_project_identity(conn, &owner_key)?.canonical_path;
}
let evidence_event_ids = serde_json::to_string(&[event.event_row_id])?;
let candidate_id = if with_candidate {
let project_id: i64 = conn.query_row(
"SELECT id FROM projects WHERE project_path = ?1 ORDER BY id DESC LIMIT 1",
[&canonical_project],
|row| row.get(0),
)?;
conn.execute(
"INSERT INTO memory_candidates
(project_id, scope, memory_type, topic_key, text, evidence_event_ids,
confidence, risk_class, review_status, created_at_epoch, updated_at_epoch)
VALUES (?1, 'project', ?2, ?3, ?4, ?5, 0.95, 'low', 'accepted', ?6, ?6)",
params![
project_id,
memory_type,
topic_key,
content,
evidence_event_ids,
created_at
],
)?;
Some(conn.last_insert_rowid())
} else {
None
};
let state_key_id = if matches!(
memory_type.as_str(),
"decision" | "architecture" | "preference"
) {
conn.execute(
"INSERT INTO memory_state_keys
(owner_scope, owner_key, memory_type, state_key, current_memory_id,
created_at_epoch, updated_at_epoch)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?6)",
params![
owner_scope,
owner_key,
memory_type,
format!("g2-fixture-state-{memory_id}"),
memory_id,
created_at
],
)?;
Some(conn.last_insert_rowid())
} else {
None
};
conn.execute(
"UPDATE memories
SET source_candidate_id = ?1, evidence_event_ids = ?2,
confidence = 0.95, valid_from_epoch = ?3, state_key_id = ?4,
source_project = COALESCE(source_project, ?5),
target_project = COALESCE(target_project, ?5),
owner_scope = COALESCE(owner_scope, 'repo'),
owner_key = COALESCE(owner_key, ?5),
context_class = COALESCE(context_class, 'startup_core')
WHERE id = ?6",
params![
candidate_id,
evidence_event_ids,
created_at,
state_key_id,
canonical_project,
memory_id
],
)?;
let updated = conn.changes();
anyhow::ensure!(updated == 1, "fixture memory {memory_id} was not updated");
let visibility = crate::truth::classify_memory(
conn,
memory_id,
chrono::Utc::now().timestamp().max(created_at),
)?;
if status == "active" {
anyhow::ensure!(
visibility.current_context_eligible,
"fixture memory {memory_id} proof classified as {:?}/{:?}",
visibility.classification,
visibility.reason
);
}
Ok(())
}