Files
codebase-memory-mcp/src/store
LynxBay eef798bff7 fix(store): distinguish transient SQLITE_BUSY from corruption before quarantine (#1206, #1037)
The quarantine path in resolve_store_internal() used the shallow
cbm_store_check_integrity() to decide whether to rename a project DB
to .corrupt and rebuild it. That check has two flaws that together
cause healthy databases to be destroyed under concurrent access:

1. It treats ANY sqlite3_prepare_v2 failure as corruption. Under
   concurrent MCP instances (#1206), a writer lock held by another
   instance makes the schema lookup return SQLITE_BUSY/LOCKED — a
   transient condition, not damage. The losing instance quarantines
   a perfectly healthy DB and rebuilds a sparse replacement.

2. It never runs PRAGMA quick_check, so it cannot catch real
   page-level corruption either. A DB with a torn node/edge btree
   but an intact projects table passes the check and keeps being
   served (#1037) — the inverse failure.

This change introduces cbm_store_check_integrity_verdict(), which
returns a tri-state (OK / CORRUPT / TRANSIENT) and runs the shallow
check plus PRAGMA quick_check, classifying BUSY/LOCKED/IO-lock codes
as TRANSIENT. The quarantine decision in mcp.c now quarantines ONLY
on a confirmed CORRUPT verdict; TRANSIENT releases the mutation lease
and retries on the next resolve, never touching the DB file.

The existing cbm_store_check_integrity() and _deep() are unchanged,
so all other call sites (hot opens, artifact import, maintenance)
keep their current behavior.

Verified: builds clean with -Wall -Wextra -Werror; cli list_projects
and index_status run correctly against the patched binary.

Signed-off-by: LynxBay <187708458+LynxBay@users.noreply.github.com>
2026-08-11 21:23:14 +08:00
..