From 7bec2dc2d042816ed0aff81fdb582f458ce5ec91 Mon Sep 17 00:00:00 2001 From: Mikael Hugo Date: Sat, 2 May 2026 22:38:24 +0200 Subject: [PATCH] fix(sf): invalidate stale embedding when memory content is updated MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updateMemoryContent rewrote the row but left the existing memory_embeddings vector in place — that vector was computed against the old content, so the next cosine query would score the memory by what it used to say, not what it says now. Now drop the embedding row on update; the next runEmbeddingBackfill (agent_end hook) re-embeds. Best-effort: a missing embedding is the silent-fallback case the ranker already handles. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/resources/extensions/sf/memory-store.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/resources/extensions/sf/memory-store.ts b/src/resources/extensions/sf/memory-store.ts index 2be41d872..db2217217 100644 --- a/src/resources/extensions/sf/memory-store.ts +++ b/src/resources/extensions/sf/memory-store.ts @@ -6,6 +6,7 @@ import { _getAdapter, decayMemoriesBefore, + deleteMemoryEmbedding, incrementMemoryHitCount, insertMemoryRow, isDbAvailable, @@ -270,6 +271,12 @@ export function createMemory(fields: { /** * Update a memory's content and optionally its confidence. + * + * Invalidates the existing embedding row (if any): the stored vector was + * computed against the old content and would otherwise rank incorrectly + * on the next cosine query. The next runEmbeddingBackfill sweep will + * re-embed the new content. This is best-effort — a missing embedding + * row is the silent-fallback case the ranker already handles. */ export function updateMemoryContent( id: string, @@ -280,6 +287,12 @@ export function updateMemoryContent( try { updateMemoryContentRow(id, content, confidence, new Date().toISOString()); + try { + deleteMemoryEmbedding(id); + } catch { + // Stale-vector window is brief (until next backfill); never fail + // the content update because the embedding cleanup raised. + } return true; } catch { return false;