pub trait SemanticFallback: Send + Sync {
// Required method
fn search<'life0, 'life1, 'async_trait>(
&'life0 self,
query: &'life1 str,
limit: usize,
) -> Pin<Box<dyn Future<Output = Result<Vec<MemoryId>, MemoryError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
// Provided method
fn reconcile<'life0, 'life1, 'async_trait>(
&'life0 self,
_active: &'life1 [(MemoryId, String)],
_revision: u64,
) -> Pin<Box<dyn Future<Output = Result<(), MemoryError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
}Expand description
An optional paraphrase-tolerant backend.
Reached only when lexical search finds too little — an indirect question, a pronoun-heavy reference, or a fact the user is describing rather than naming.
Required Methods§
Provided Methods§
Sourcefn reconcile<'life0, 'life1, 'async_trait>(
&'life0 self,
_active: &'life1 [(MemoryId, String)],
_revision: u64,
) -> Pin<Box<dyn Future<Output = Result<(), MemoryError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn reconcile<'life0, 'life1, 'async_trait>(
&'life0 self,
_active: &'life1 [(MemoryId, String)],
_revision: u64,
) -> Pin<Box<dyn Future<Output = Result<(), MemoryError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Bring the backend in line with the active corpus.
Called after the canonical index is recompiled — that is, after a
session seals and reconciliation has decided what is true. active is
the entire desired state: every active record paired with the text
it should be findable by, from
embedding_text.
Passing the whole set rather than a diff is deliberate. A diff has to be right, and the cost of getting it wrong is a vector store that quietly disagrees with the corpus — which is the failure this method exists to prevent, reintroduced by the fix for it. A backend given the full set can reconcile idempotently and embed only what it does not already hold.
Default is a no-op, so an existing implementation keeps compiling and
keeps its current behaviour: an index that never learns about
corrections. That is the safe failure — semantic_ranking resolves
every returned id against the canonical index and drops what is no
longer retrievable, so a stale backend loses facts rather than serving
wrong ones — but it is still a failure, and it lands hardest on
corrected facts, which are the ones a user has shown they care about.
§revision orders concurrent callers
One engine hands the same backend to every session it opens, so two
sessions sealing at the same moment both call this — each with a corpus
snapshot taken before it started. Because active is a whole desired
state rather than a diff, the call that finishes last wins, and if
that is the one that started first it silently removes every record
the other added, vectors and all.
Serialising the calls does not fix that: the loser’s snapshot is stale
whenever it is applied, not only when it interleaves. So callers pass
the canonical index revision the snapshot was taken from — monotonic per
engine — and an implementation must ignore a revision it has already
passed. Pass 0 if there is nothing meaningful to order by; that
disables the check rather than breaking it.