Repository navigation
fix(code_index): one embeddings call per batch, fail on the first error - #6975
Conversation
… error With the embedding backend down or the model name wrong, indexing retried every batch with sleeps, then re-sent each chunk on its own with a 60 s timeout, and dropped the chunks that failed with only a log line. A failed call or a short batch now raises at once with the model name and how to load it, as RAG already does. The one wait kept is RAG's: a batch that comes back with no vectors while the model is still loading gets two more tries. The C++ parity plan, which said to port the old retry and fallback, now describes this behavior. Closes amd#4832
|
Verdict: Approve with suggestions When Lemonade is down or the embedding model name is wrong, code indexing now fails on its first call and says how to fix it. Before, it spent minutes retrying and re-sending chunks one at a time, then quietly dropped the ones that still failed. The logic is correct and the tests cover the new behaviour well. RAG already fails this way, and this change matches it.
Real-world evidenceN/A: the evidence harness wrote no bundle for this PR. The PR description has the author's own run: a 60-file repo indexed against a closed port made 1 embedding call and 0 sleeps on this branch, against 69 calls, 60 single-chunk calls and 6 sleeps on 🔍 Technical detailsIssues 🟡 Stale doc claim ( 🟢 Code that can no longer run:
Leaving it costs nothing at runtime, but a reader will assume partial indexes still happen. Either remove 🟢 Checks run
Strengths
|
…rrent From review. The wrapped error no longer doubles a period when the cause ends in one, the batch loop has no unreachable sentinel, and the MCP doc's rebuild_index row no longer promises a dropped-chunks warning that can't happen. The dropped-chunk block is now marked as a guard.
Summary
With Lemonade down or the embedding model name wrong, code indexing now fails on its first call and says what to do. Before, it retried every batch with sleeps, then re-sent every chunk on its own, so a large repo took many minutes to report anything, and chunks that failed one at a time were dropped with only a log line.
Why
CLAUDE.mdallows a retry only when the caller asks for one, and RAG already fails this way (its twin issue was #4798). Code indexing kept the old path: three tries per batch with 2 s sleeps, then one 60 s call per chunk, for every batch of 25.Linked issue
Closes #4832
Changes
RuntimeErrorthat names the model and how to load it, and a batch with any missing or empty vector raises instead of being partly kept.search()goes through the same path, so it also fails at once instead of after retries.rebuild_indexrow promised a warning listing chunks that failed to embed. That can't happen anymore, so it now says the rebuild fails with the embedding error (found in review).Decisions to check
chunks_dropped. The un-hashing of incomplete files and thechunks_droppedfield stay as a guard, with a comment saying so, so the agent tool's and MCP server's results keep their shape. Removingchunks_droppedend to end changes the MCP response, so I'd rather do that in its own PR if you want it.Test plan
Run in a
python:3.12-slimcontainer with.[ui]and the test tools installed:tests/unit/test_code_index*.py,test_flagship_code_index_scope.py): 215 passed, 1 skipped.python util/lint.py --all: passes, with the existing mypy warning count.pytest tests/unit -n 3: 34,763 passed and 35 failed under load. Rerun on their own, 19 still fail, and the same 19 fail withmain'ssdk.pyin my container. None fail only with this change.Two tests asserted the old fallback and drop. They now assert the new behavior, and three tests are new. With the source change reverted, all five fail:
The last one only renames the method it patches.
Evidence
A 60-file repo indexed with a real
LemonadeClientpointed at a closed port (127.0.0.1:9), sleeps counted rather than waited:mainA refused connection fails fast, so both runs took under a second here. Against a backend that hangs instead, the same calls on
mainadd up to about 87 minutes for these 60 files (9 × 180 s + 60 × 60 s + 12 s), against at most 180 s with this PR. That figure comes from the timeouts, not from a run.Checklist
Closes #N/Fixes #N/Refs #N).python util/lint.py --all,pytest tests/unit/). The code-index tests above, and the fulltests/unitrun below.