use lantern::memory::{
AddMemoryOptions, ListMemoryOptions, MemoryKind, MemoryStatus, add_memory, archive_memory,
list_memories,
};
use lantern::store::Store;
use tempfile::tempdir;
fn new_store() -> (tempfile::TempDir, Store) {
let root = tempdir().unwrap();
let store = Store::initialize(&root.path().join("store")).unwrap();
(root, store)
}
#[test]
fn add_memory_persists_defaults_and_returns_record() {
let (_root, store) = new_store();
let record = add_memory(
&store,
AddMemoryOptions {
kind: MemoryKind::Preference,
scope: "user:raphael".into(),
content: "Raphael prefers separate branches on his repos.".into(),
priority: None,
urgency: None,
confidence: None,
source_refs: Vec::new(),
},
)
.unwrap();
assert_eq!(record.kind, MemoryKind::Preference);
assert_eq!(record.scope, "user:raphael");
assert_eq!(
record.content,
"Raphael prefers separate branches on his repos."
);
assert_eq!(record.priority, 50);
assert_eq!(record.urgency, 0);
assert_eq!(record.confidence, 1.0);
assert_eq!(record.status, MemoryStatus::Active);
assert!(record.created_at > 0);
assert_eq!(record.updated_at, record.created_at);
let listed = list_memories(&store, ListMemoryOptions::default()).unwrap();
assert_eq!(listed.records.len(), 1);
assert_eq!(listed.records[0].id, record.id);
}
#[test]
fn list_memories_filters_and_orders_active_records_by_policy_fields() {
let (_root, store) = new_store();
let low = add_memory(
&store,
AddMemoryOptions {
kind: MemoryKind::Fact,
scope: "project:lantern".into(),
content: "Low priority fact.".into(),
priority: Some(10),
urgency: Some(0),
confidence: Some(0.7),
source_refs: Vec::new(),
},
)
.unwrap();
let urgent = add_memory(
&store,
AddMemoryOptions {
kind: MemoryKind::Goal,
scope: "project:lantern".into(),
content: "Urgent goal.".into(),
priority: Some(90),
urgency: Some(80),
confidence: Some(1.0),
source_refs: Vec::new(),
},
)
.unwrap();
let high = add_memory(
&store,
AddMemoryOptions {
kind: MemoryKind::Constraint,
scope: "project:lantern".into(),
content: "High priority constraint.".into(),
priority: Some(90),
urgency: Some(20),
confidence: Some(1.0),
source_refs: Vec::new(),
},
)
.unwrap();
let other_scope = add_memory(
&store,
AddMemoryOptions {
kind: MemoryKind::Fact,
scope: "user:raphael".into(),
content: "Other scope.".into(),
priority: Some(100),
urgency: Some(100),
confidence: Some(1.0),
source_refs: Vec::new(),
},
)
.unwrap();
archive_memory(&store, &low.id).unwrap();
let listed = list_memories(
&store,
ListMemoryOptions {
scope: Some("project:lantern".into()),
status: Some(MemoryStatus::Active),
kind: None,
limit: Some(10),
},
)
.unwrap();
let ids: Vec<_> = listed.records.iter().map(|r| r.id.as_str()).collect();
assert_eq!(ids, vec![urgent.id.as_str(), high.id.as_str()]);
assert!(!ids.contains(&low.id.as_str()));
assert!(!ids.contains(&other_scope.id.as_str()));
}
#[test]
fn archive_memory_marks_record_without_deleting_it() {
let (_root, store) = new_store();
let record = add_memory(
&store,
AddMemoryOptions {
kind: MemoryKind::Observation,
scope: "global".into(),
content: "Temporary observation.".into(),
priority: Some(40),
urgency: Some(5),
confidence: Some(0.6),
source_refs: vec!["session://abc#turn-1".into()],
},
)
.unwrap();
let archived = archive_memory(&store, &record.id).unwrap();
assert_eq!(archived.id, record.id);
assert_eq!(archived.status, MemoryStatus::Archived);
assert!(archived.updated_at >= archived.created_at);
assert_eq!(
archived.source_refs,
vec!["session://abc#turn-1".to_string()]
);
let active = list_memories(
&store,
ListMemoryOptions {
status: Some(MemoryStatus::Active),
..Default::default()
},
)
.unwrap();
assert!(active.records.is_empty());
let archived_records = list_memories(
&store,
ListMemoryOptions {
status: Some(MemoryStatus::Archived),
..Default::default()
},
)
.unwrap();
assert_eq!(archived_records.records.len(), 1);
assert_eq!(archived_records.records[0].id, record.id);
}