Skip to content

fix(stdio): short-circuit semantic_search when index is being rebuilt#163

Merged
aeneasr merged 1 commit into
mainfrom
fix-hanging
May 20, 2026
Merged

fix(stdio): short-circuit semantic_search when index is being rebuilt#163
aeneasr merged 1 commit into
mainfrom
fix-hanging

Conversation

@aeneasr

@aeneasr aeneasr commented May 20, 2026

Copy link
Copy Markdown
Member

Summary

  • When a background indexer holds the index flock, `ensureIndexed` sets `out.StaleWarning` and returns, but `handleSemanticSearch` still called `embedQuery`. On a single-instance embedding backend (e.g. LM Studio) saturated by the indexer's 32-chunk batches, the query embed queues behind those batches and the MCP call hangs well past Claude Code's timeout.
  • Fix: short-circuit `handleSemanticSearch` when `StaleWarning` is set, returning the warning text immediately. The warning already instructs the caller to use standard tools for the next 10 tool calls before retrying, so doing the embed work would be pure waste — and on a busy backend, it hangs.
  • Covers all four `StaleWarning`-setting paths in `ensureIndexed`: flock held by another process, in-process goroutine already running, background goroutine couldn't acquire the flock, and the 15s timeout firing.

Reproduction

Two parallel `semantic_search` MCP calls into different subdirectories of a monorepo (`/cloud/kratos` and `/cloud/keto`) while a background `lumen index /cloud` holds the shared-effective-root flock.

Before fix After fix
Parallel kratos+keto `tools/call` timed out at 100s, no responses id:2 at 1.375s, id:3 at 1.389s
Regression unit test n/a PASS in ~0.7s
Sanity revert of fix n/a unit test FAILs in 3.67s

Test plan

  • `go test ./cmd -run TestHandleSemanticSearch_StaleWarningShortCircuits` passes
  • Revert the short-circuit and confirm the regression test fails (catches the bug)
  • End-to-end repro with parallel MCP `tools/call` against a held-flock monorepo returns both responses in <2s instead of hanging
  • `go vet ./...` clean
  • `golangci-lint run` clean

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Search query handling improved during index rebuilding. When the index is being rebuilt by background processes, searches now immediately return a stale-data warning instead of attempting to process the query, preventing unnecessary processing overhead and resource usage during this maintenance window.

Review Change Stack

When a background indexer holds the index flock, ensureIndexed sets
out.StaleWarning and returns immediately, but handleSemanticSearch then
proceeded to call embedQuery. On a single-instance embedding backend
(e.g. LM Studio) saturated by the indexer's 32-chunk batches, the query
embed queues behind those batches and the MCP call hangs well past
Claude Code's timeout — the user sees an infinite "loading" state and
never receives the warning text telling them to use standard tools for
the next 10 calls.

Reproduced reliably with two parallel semantic_search calls into
different subdirectories of a monorepo while a background lumen index of
the monorepo root holds the flock. After the fix both responses return
in ~0.4s with the StaleWarning text instead of timing out at 100s.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented May 20, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4b214827-6cd0-41fe-ada0-953931c80f24

📥 Commits

Reviewing files that changed from the base of the PR and between e310ed0 and d24beed.

📒 Files selected for processing (2)
  • cmd/stdio.go
  • cmd/stdio_concurrency_test.go

📝 Walkthrough

Walkthrough

This PR adds a short-circuit optimization to handleSemanticSearch that returns early with a formatted warning when the search index is stale (being rebuilt), avoiding unnecessary query embedding and search execution. A concurrency regression test validates this behavior under lock contention scenarios.

Changes

Stale Warning Short-Circuit

Layer / File(s) Summary
handleSemanticSearch stale-warning short-circuit
cmd/stdio.go
When out.StaleWarning is set, handleSemanticSearch returns immediately with formatted results and the warning text instead of embedding the query and executing the search.
Regression test for stale-warning short-circuit
cmd/stdio_concurrency_test.go
New imports and TestHandleSemanticSearch_StaleWarningShortCircuits verify the handler returns quickly with the stale-warning message when the index lock is held externally, and that the embedder is never called.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding short-circuit logic to semantic_search when the index is being rebuilt, which directly addresses the core fix implemented in the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-hanging

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@aeneasr aeneasr enabled auto-merge (squash) May 20, 2026 11:06
@aeneasr aeneasr merged commit 89555d0 into main May 20, 2026
10 checks passed
@aeneasr aeneasr deleted the fix-hanging branch May 20, 2026 11:20
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