use rusqlite::Connection;
use crate::context::load_session_start_candidates;
use crate::context_bundle::{
compile_session_start_bundle, AgentRole, ChannelKind, ContextRequest, DegradedMode, ProjectRef,
RiskClass, TrustClass, CONTEXT_BUNDLE_SCHEMA_VERSION,
};
use super::{insert_memory, setup_context_schema};
const PROJECT: &str = "demo/project";
const EPOCH: i64 = 1_710_000_000;
fn conn_with_schema() -> Connection {
let conn = Connection::open_in_memory().expect("in-memory connection");
setup_context_schema(&conn);
conn
}
fn request() -> ContextRequest {
ContextRequest {
schema_version: CONTEXT_BUNDLE_SCHEMA_VERSION,
task: "resume the migration work".to_string(),
project: ProjectRef {
key: PROJECT.to_string(),
},
branch: None,
worktree: None,
role: AgentRole::Coder,
as_of_epoch: EPOCH,
token_budget: 3_000,
risk: RiskClass::Low,
include_superseded: false,
}
}
#[test]
fn candidates_route_memories_to_their_sections() {
let conn = conn_with_schema();
insert_memory(
&conn,
1,
PROJECT,
None,
"decision",
"Chose sqlite",
"Body",
EPOCH,
);
insert_memory(
&conn,
2,
PROJECT,
None,
"preference",
"Always run fmt",
"Body",
EPOCH,
);
insert_memory(
&conn,
3,
PROJECT,
None,
"session_activity",
"Ran the suite",
"Body",
EPOCH,
);
let candidates = load_session_start_candidates(&conn, PROJECT, "/tmp/remem-bundle-test", None)
.expect("load");
let channel_of = |key: &str| {
candidates
.iter()
.find(|item| item.stable_key == key)
.unwrap_or_else(|| panic!("missing candidate {key}"))
.channel
};
assert_eq!(channel_of("memory:1"), ChannelKind::Core);
assert_eq!(channel_of("memory:2"), ChannelKind::Preferences);
assert_eq!(channel_of("memory:3"), ChannelKind::MemoryIndex);
}
#[test]
fn candidates_carry_canonical_attribution_and_project_scope() {
let conn = conn_with_schema();
insert_memory(
&conn,
1,
PROJECT,
None,
"decision",
"Chose sqlite",
"Body",
EPOCH,
);
let candidates = load_session_start_candidates(&conn, PROJECT, "/tmp/remem-bundle-test", None)
.expect("load");
let item = candidates
.iter()
.find(|item| item.stable_key == "memory:1")
.expect("candidate");
assert_eq!(item.canonical_ref.as_deref(), Some("memory:1"));
assert_eq!(item.projection_ref, None);
assert_eq!(item.project.as_deref(), Some(PROJECT));
assert_eq!(item.trust, TrustClass::Standard);
}
#[test]
fn canonical_load_failure_is_an_error_not_a_shorter_list() {
let conn = conn_with_schema();
conn.execute("DROP TABLE memories", []).expect("drop");
let error = load_session_start_candidates(&conn, PROJECT, "/tmp/remem-bundle-test", None)
.expect_err("a failed canonical load must not return candidates");
assert!(
error.to_string().contains("canonical context load failed"),
"unexpected error: {error}"
);
}
#[test]
fn canonical_load_failure_produces_a_blocked_bundle() {
let conn = conn_with_schema();
conn.execute("DROP TABLE memories", []).expect("drop");
let bundle =
compile_session_start_bundle(&conn, &request(), "/tmp/remem-bundle-test", None, true)
.expect("compile");
assert_eq!(bundle.degraded_mode, DegradedMode::Blocked);
assert_eq!(bundle.audit.degraded_mode, DegradedMode::Blocked);
assert_eq!(
bundle.audit.truncation_reason.as_deref(),
Some("canonical_load_failed")
);
assert!(bundle.current_truth.is_empty());
assert!(bundle.memory_index.is_empty());
assert_eq!(bundle.audit.selected_count, 0);
}
#[test]
fn healthy_load_compiles_a_full_bundle_from_the_database() {
let conn = conn_with_schema();
insert_memory(
&conn,
1,
PROJECT,
None,
"decision",
"Chose sqlite",
"Body",
EPOCH,
);
let bundle =
compile_session_start_bundle(&conn, &request(), "/tmp/remem-bundle-test", None, true)
.expect("compile");
assert_eq!(bundle.degraded_mode, DegradedMode::Full);
assert!(bundle.audit.truncation_reason.is_none());
assert_eq!(
bundle
.current_truth
.iter()
.map(|item| item.stable_key.as_str())
.collect::<Vec<_>>(),
vec!["memory:1"]
);
assert!(!bundle.audit.plan_hash.is_empty());
}
#[test]
fn missing_enrichment_degrades_to_canonical_only() {
let conn = conn_with_schema();
insert_memory(
&conn,
1,
PROJECT,
None,
"decision",
"Chose sqlite",
"Body",
EPOCH,
);
let bundle =
compile_session_start_bundle(&conn, &request(), "/tmp/remem-bundle-test", None, false)
.expect("compile");
assert_eq!(bundle.degraded_mode, DegradedMode::CanonicalOnly);
assert_eq!(bundle.current_truth.len(), 1);
}