fix(bigmind): fix FTS sync in delete_chunks_before — use rowid DELETE not rebuild

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.
This commit is contained in:
Patrick Plate
2026-04-07 23:41:13 +02:00
parent cda8946c75
commit 8f24168dcd
+16 -9
View File
@@ -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 ───────────────────────────────────────────────────────────────────────