Skip to content

fix(code-intel): serve code tools from the last committed index during a reindex - #27

Merged
wongk merged 2 commits into
mainfrom
fix/search-reads-during-reindex
Sep 19, 2026
Merged

wongk merged 2 commits into
mainfrom
fix/search-reads-during-reindex

Conversation

@wongk

@wongk wongk commented Sep 19, 2026

Copy link
Copy Markdown

Problem

Every code tool refused to answer while any reindex held the index-write lock. index_state mapped "lock held" to rebuilding, so code_search, relations and code_query failed for the whole length of every reindex. On a large repo that was most of the time.

Why reading is safe

A reindex writes in one transaction, a full rebuild included, and the databases run in WAL mode. Until the writer commits, a reader in another process sees the last committed index, whole.

test_reads_during_reindex.py proves this with the real engine. It pauses an indexer in a subprocess after its deletes and before its inserts, for both a full rebuild and an incremental run. The reader still sees every symbol and line of the previous index, then sees the new content once the writer commits.

Change

  • A held lock on a populated index is now ready with refreshing=True. It stays rebuilding only where there is nothing committed to read: a first build with no files yet. The torn-index checks are unchanged (missing tables, symbols without files).
  • take_refreshing() reports whether this thread read a refreshing index since it was last called.
  • The MCP dispatcher clears that mark before each tool call and takes it after. It then sets index_state: "refreshing" and appends a note to the response text, the same way the repeat-call note is added: "note: the code index is refreshing; results come from the last completed index and may not reflect the newest edits".

Trade-off

During a reindex, answers may be missing the edits that reindex is picking up.

WAL commits each attached database separately, so one read that spans the commit could see code_context and fts out of step for a few milliseconds.

Tests

The real-engine premise test above, plus:

  • Unit tests for the new states, and for the mark on both fresh and throttled probes.
  • A dispatcher test calling code_search (engine-cache path) and code_query (require_ready path) with the lock held. Each answers, carries the note, and the note does not leak into the next call.

The tests fail on three separate breakages:

  • a held lock blocking readers again
  • a first build answering from an empty index
  • the dispatcher dropping the note

Related

One of three independent fixes for code search failing on symphony-alpha: fix/code-engine-autosync-leak, fix/incremental-reindex-batched-deletes, fix/search-reads-during-reindex. Each is based on main, and all three merge cleanly in any order (checked with git merge-tree, and their new tests pass together on an octopus merge).

wongk and others added 2 commits September 18, 2026 16:30
…g a reindex

A held index-write lock made every code tool refuse to answer for the length
of every reindex. A reindex commits in one transaction and the databases run
in WAL mode, so readers see the last committed index whole until it commits.
Answer from it and append a note that results may lag the newest edits; a
first build with nothing committed still refuses.

Co-Authored-By: lemoncrow <302591943+lemoncrow-agent[bot]@users.noreply.github.com>
LemonCrow-Session: s1
@wongk
wongk merged commit c1cf006 into main Sep 19, 2026
9 checks passed
@wongk
wongk deleted the fix/search-reads-during-reindex branch September 19, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant