use std::sync::Arc;
use mnemo_core::embedding::DeterministicEmbedding;
use mnemo_core::error::Error;
use mnemo_core::query::MnemoEngine;
use mnemo_core::query::recall::RecallRequest;
use mnemo_core::query::remember::RememberRequest;
use mnemo_core::storage::duckdb::DuckDbStorage;
use mnemo_postgres::PgVectorIndex;
const DIM: usize = 8;
const AGENT: &str = "pg-fail-loud";
async fn engine_with_poolless_pgvector() -> (Arc<MnemoEngine>, uuid::Uuid) {
let storage = Arc::new(DuckDbStorage::open_in_memory().expect("in-memory duckdb"));
let index = Arc::new(PgVectorIndex::new());
let engine = Arc::new(MnemoEngine::new(
storage,
index,
Arc::new(DeterministicEmbedding::new(DIM)),
AGENT.to_string(),
None,
));
let id = engine
.remember(RememberRequest::new(
"a record that definitely exists".to_string(),
))
.await
.expect("remember must succeed — only the ANN read path is unsupported")
.id;
(engine, id)
}
fn assert_backend_unsupported(strategy: &str, result: Result<impl std::fmt::Debug, Error>) {
match result {
Ok(v) => panic!(
"strategy=`{strategy}` returned Ok({v:?}) on a backend that cannot do ANN. \
This is the silent-empty regression: the caller cannot tell \"no matches\" \
from \"not implemented\", and will record the empty answer as a fact. \
The recall path must propagate the index error (`.await?`), never \
`.unwrap_or_default()` it."
),
Err(Error::BackendUnsupported {
backend,
capability,
detail,
}) => {
assert_eq!(
backend, "postgres",
"strategy=`{strategy}`: the error must name the backend so a caller \
knows which one is unsupported"
);
assert_eq!(
capability, "semantic_recall",
"strategy=`{strategy}`: the error must name the unsupported operation"
);
assert!(
!detail.is_empty(),
"strategy=`{strategy}`: the error must carry actionable detail"
);
}
Err(other) => panic!(
"strategy=`{strategy}`: expected the structured BackendUnsupported variant \
(callers match on backend/capability rather than sniffing strings); got: {other}"
),
}
}
#[tokio::test]
async fn semantic_recall_strategies_error_and_never_return_empty() {
let (engine, _id) = engine_with_poolless_pgvector().await;
for strategy in ["semantic", "auto", "graph", "domain_scoped"] {
let mut req = RecallRequest::new("a record that definitely exists".to_string());
req.strategy = Some(strategy.to_string());
let result = engine.recall(req).await.map(|r| r.memories.len());
assert_backend_unsupported(strategy, result);
}
}
#[tokio::test(flavor = "current_thread")]
async fn semantic_recall_fails_loud_on_current_thread_runtime() {
let (engine, _id) = engine_with_poolless_pgvector().await;
let mut req = RecallRequest::new("a record that definitely exists".to_string());
req.strategy = Some("semantic".to_string());
let result = engine.recall(req).await.map(|r| r.memories.len());
assert_backend_unsupported("semantic", result);
}
#[tokio::test]
async fn control_the_fixture_store_is_not_empty() {
let (engine, id) = engine_with_poolless_pgvector().await;
let record = engine
.storage
.get_memory(id)
.await
.expect("storage read must succeed");
assert!(
record.is_some(),
"control failed: the fixture store has no record at {id}, so the \
BackendUnsupported assertions above prove nothing about silent-empty"
);
}