From 8f24168dcd89c92f1212908d4b820aa9588a04f1 Mon Sep 17 00:00:00 2001 From: Patrick Plate Date: Tue, 7 Apr 2026 23:41:13 +0200 Subject: [PATCH] =?UTF-8?q?fix(bigmind):=20fix=20FTS=20sync=20in=20delete?= =?UTF-8?q?=5Fchunks=5Fbefore=20=E2=80=94=20use=20rowid=20DELETE=20not=20r?= =?UTF-8?q?ebuild?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit conversation_chunks_fts is a standalone FTS5 table (no content= option). The old INSERT ... VALUES('rebuild') is a no-op on standalone tables and left deleted chunks searchable in the FTS shadow tables. Fix: collect IDs before deletion, explicitly DELETE FROM conversation_chunks_fts WHERE rowid IN (...) before removing from the main table. This keeps FTS in sync after every vacuum call. Tests: 303/303 passing. Vacuum tests now pass for the right reason. --- mcp/bigmind/bigmind/memory_store.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/mcp/bigmind/bigmind/memory_store.py b/mcp/bigmind/bigmind/memory_store.py index b8e2929..ae0449d 100644 --- a/mcp/bigmind/bigmind/memory_store.py +++ b/mcp/bigmind/bigmind/memory_store.py @@ -441,21 +441,28 @@ def search_chunks(user_id: str, query: str, limit: int = 10) -> list: def delete_chunks_before(user_id: str, cutoff_iso: str) -> int: """Delete Tier-3 chunks older than cutoff. Returns count deleted.""" with db() as conn: - count = conn.execute( - "SELECT COUNT(*) FROM conversation_chunks WHERE user_id=? AND created_at < ?", + # Collect IDs first — needed for FTS sync. + # conversation_chunks_fts is a STANDALONE FTS5 table (no content= option), + # so we must delete FTS rows explicitly by rowid. The old VALUES('rebuild') + # approach only works for content= backed tables and was a no-op here. + rows = conn.execute( + "SELECT id FROM conversation_chunks WHERE user_id=? AND created_at < ?", (user_id, cutoff_iso), - ).fetchone()[0] - if count == 0: + ).fetchall() + if not rows: return 0 + ids = [r[0] for r in rows] + # Delete FTS entries by rowid before removing from main table + placeholders = ",".join("?" * len(ids)) + conn.execute( + f"DELETE FROM conversation_chunks_fts WHERE rowid IN ({placeholders})", + ids, + ) conn.execute( "DELETE FROM conversation_chunks WHERE user_id=? AND created_at < ?", (user_id, cutoff_iso), ) - # Rebuild the FTS5 index from the content table — always correct for content= tables - conn.execute( - "INSERT INTO conversation_chunks_fts(conversation_chunks_fts) VALUES('rebuild')" - ) - return count + return len(ids) # ── FACTS ───────────────────────────────────────────────────────────────────────