Summary
mmr_enabled = true has no effect when vector_backend = "sqlite". The MMR code path gated on if let Some(qdrant) = &self.qdrant — when self.qdrant is None (SQLite-only config), MMR is silently skipped and results are plain-truncated.
Root Cause
crates/zeph-memory/src/semantic.rs, line 753–780:
if self.mmr_enabled && !vector_results.is_empty() {
if let Some(qdrant) = &self.qdrant {
// MMR applied only here
ranked = apply_mmr(&ranked, &vec_map, self.mmr_lambda, limit);
} else {
ranked.truncate(limit); // always taken with SQLite backend
}
}
The apply_mmr() function itself uses pre-fetched vectors (vec_map: HashMap<MessageId, Vec<f32>>) which are fetched via qdrant.get_vectors(). SQLite-backed vector search (recall_vectors_sqlite()) returns scored results but does not expose raw vectors for post-hoc MMR computation.
Expected Behavior
Option A: Implement MMR for SQLite backend by returning raw vectors from recall_vectors_sqlite() alongside scores.
Option B: Log a WARN at startup when mmr_enabled = true but vector_backend = "sqlite" so the operator knows MMR is inactive.
Option B is a quick fix; Option A is the correct fix.
Impact
Any deployment using vector_backend = "sqlite" (the default in testing and many production configs) gets no diversity re-ranking regardless of mmr_enabled = true.
Steps to Reproduce
- Set
vector_backend = "sqlite", mmr_enabled = true in config
- Send queries with semantically similar results in memory
- Run with
RUST_LOG=zeph_memory::semantic=debug
- Observe
recall: final results without any preceding recall: mmr re-ranked log entry
Severity: High
Default test config uses SQLite backend. MMR was believed to be active but was not.
Summary
mmr_enabled = truehas no effect whenvector_backend = "sqlite". The MMR code path gated onif let Some(qdrant) = &self.qdrant— whenself.qdrantisNone(SQLite-only config), MMR is silently skipped and results are plain-truncated.Root Cause
crates/zeph-memory/src/semantic.rs, line 753–780:The
apply_mmr()function itself uses pre-fetched vectors (vec_map: HashMap<MessageId, Vec<f32>>) which are fetched viaqdrant.get_vectors(). SQLite-backed vector search (recall_vectors_sqlite()) returns scored results but does not expose raw vectors for post-hoc MMR computation.Expected Behavior
Option A: Implement MMR for SQLite backend by returning raw vectors from
recall_vectors_sqlite()alongside scores.Option B: Log a
WARNat startup whenmmr_enabled = truebutvector_backend = "sqlite"so the operator knows MMR is inactive.Option B is a quick fix; Option A is the correct fix.
Impact
Any deployment using
vector_backend = "sqlite"(the default in testing and many production configs) gets no diversity re-ranking regardless ofmmr_enabled = true.Steps to Reproduce
vector_backend = "sqlite",mmr_enabled = truein configRUST_LOG=zeph_memory::semantic=debugrecall: final resultswithout any precedingrecall: mmr re-rankedlog entrySeverity: High
Default test config uses SQLite backend. MMR was believed to be active but was not.