fix(index): drop and recreate on a schema bump instead of deleting rows - #211
Conversation
`_wipe` cleared the index with DELETE FROM — rows only. But `_SCHEMA` is entirely CREATE TABLE IF NOT EXISTS and `_connect` runs it *before* wiping, so on an existing index file the old column shape survived the wipe. v6.6.0 added `confidence`/`conflicts_with` to `notes` and bumped SCHEMA_VERSION 4 -> 5. On any existing install every ingest INSERT then failed with "no such column: confidence" — a sqlite3.Error, which refresh() catches and returns None for. Permanently: refresh() None, search() None, 0 notes indexed, repairable only by a manual `omind reindex --rebuild`. It was quiet because invariant 2 held. Retrieval fell back to the pre-index substring scan, so nothing errored; recall just silently collapsed. Measured on the live 784-note vault: recall@1 0% wedged -> 60% rebuilt, MRR 0.00 -> 0.64. Latent since SCHEMA_VERSION was introduced — earlier bumps were shape compatible, so nothing tripped it. The counter promised a migration it never performed, and every test built a fresh index rather than upgrading an old one. `test_a_schema_bump_that_adds_a_column_rebuilds_the_index` now walks the real upgrade path: build, strip the columns back to the previous shape, reopen. Closes #210. Co-Authored-By: Claude Opus 5 <[email protected]>
|
Warning Review limit reached
Next review available in: 43 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Closes #210. Part of the v7.0.0 batch.
This is already shipped
Anyone upgrading an existing install to v6.6.0 has a dead search index until they run
omind reindex --rebuildby hand. Found while setting up the #193 evaluation gate:omind bench --qualityagainst the live vault returned recall@1 = 0%.Mechanism
_SCHEMAis entirelyCREATE TABLE IF NOT EXISTS, and_connectruns it before_wipe. So on an existing file the tables are never recreated and the old column shape survives the wipe.v6.6.0 (#195) added
confidence+conflicts_withand bumpedSCHEMA_VERSION4 → 5. Every ingest INSERT then fails withno such column: confidence— asqlite3.Error, whichrefresh()catches and converts toNone. Permanently:Reproduced on the live 784-note vault and in a fixture.
Why nobody would notice
Invariant 2 did exactly what it promises — retrieval fell back to the pre-index substring scan. So there is no error, no crash, no traceback. Literal-substring queries keep returning something. The failure is silently much worse recall, which is the hardest kind to spot.
Measured on the live vault, wedged vs. rebuilt:
omind doctorwas the one honest signal (784 stale note(s); run 'omind reindex --rebuild') — worth remembering that it was right and nothing else was.Fix
_wipedrops the tables and re-runs_SCHEMA. A wipe already means every row is disposable, so there is nothing to preserve by being gentle.The general lesson
This is latent since
SCHEMA_VERSIONwas introduced — I didn't add it, #195 was just the first bump to change a table's shape rather than only its contents.SCHEMA_VERSIONpromised a migration it never actually performed, and every existing test built a fresh index.test_a_schema_bump_that_adds_a_column_rebuilds_the_indexwalks the real upgrade path: build at the current schema, strip the two columns back to the previous shape, set the old version, reopen. That test would have caught this, and will catch the next one.Gates
ruff check .·mypy src(strict) ·pytest(869 passed) ·pip-audit— green locally.🤖 Generated with Claude Code