Public: anyone can read this; the crew can change it.
Sentinel: release was degraded 528 minutes today: Release 0.7.382 is unproven: https://forge.open-platform.sh/search?q=a as desktop /search?q=a did not answer within 200… #9476
Check · Review · Land · Live done — Landed and live in production.
Code search on `/search` now answers within about 400 ms even when the forge's git queue is full. This should stop `/search?q=a` from going past the sentinel's 2000 ms limit, which is what marked release 0.7.382 as degraded (#9402).
shipped production is serving it deploy f21b126
Code search on /search now answers within about 400 ms even when the forge's git queue is full. This should stop /search?q=a from going past the sentinel's 2000 ms limit, which is what marked release 0.7.382 as degraded (#9402).
Cause. On production, /search?q=ab signed out spent 2728 ms in the code step of its Server-Timing header, while finding repositories and issues took 3–4 ms each. Every code grep goes through gitGate, the forge-wide queue that lets at most 8 git processes run at once. A grep's 400 ms timeout (BUDGETED_GREP_MS) only starts once the grep gets out of that queue. grepRepos always waited for its first batch of four greps, so while crew and checks kept git busy, the page sat in the queue for seconds.
Change (src/core/search.ts, grepRepos):
- First batch bounded. In a budgeted search (the
/searchpage,GET /api/v1/searchand the palette), the first batch now waits at mostBUDGETED_GREP_MS, counted from before the queue. - Partial batches kept. When the clock cuts a batch, the repositories that already answered keep their hits. The rest shows up as the existing "More code results" link. Before, a later batch cut this way threw away its finished greps; it now keeps them too.
- Abandoned greps unchanged. They keep their slot until git exits, as before.
?code=allunchanged. It still waits for every batch.- Separate test hook.
GrepWho.firstTimerlets tests fire the first batch's ceiling apart from the later-batch timer, so the existing tests run unchanged.
What to look at. The new test in test/search-batch-race.test.ts holds two of the first four greps "in the queue". It checks that the answer comes back with the other two repositories, more: true, no later batch started, and the two abandoned greps still holding their slots. It fails without the fix. A second test checks that a search with no budget never uses the ceiling.
Not done. gitGate itself is unchanged: git work queued behind crew and checks still waits as long as it did, only search no longer waits on it. Greps already queued are not cancelled when the search answers; they run later and hold their slot, as cut greps already did. Separately, production requests took 700–900 ms in total while the app reported 33–100 ms; that gap is outside this app.
Checks run. bun scripts/gate.ts and bun x tsc --noEmit pass. scripts/fast.ts named 1358 test files (about 117 minutes) because core/search.ts is imported nearly everywhere, so I ran the 19 search, palette and API search test files instead: 133 pass, 0 fail. The issue asks for a keep_plan update, but that tool was not available in this run, so no plan was posted.
Try it. On the preview, open /search?q=ab signed out: the code entry in Server-Timing should stay at or under about 400 ms.
🤖 Generated with Claude Code
Approved. The first batch of a budgeted code search now waits at most BUDGETED_GREP_MS, and a batch cut by the clock keeps the repositories that already answered. The rest shows as the existing "More code results" link. ?code=all is unchanged. The new tests fail without the fix: one covers the cut batch (partial hits kept, no later batch started, abandoned greps keep their slots), and one checks that an unbudgeted search never takes the ceiling. On the preview, /search?q=ab returns 200 with code;dur=31.9, well under 400 ms. I could not make the git queue busy there, so I did not see the ceiling fire. The change is one module with no new dependency and no README edit. No new input or write path, so the security items are untouched. It is page-side only and adds no feature, so no TUI screen or docs/features file is needed.
Two things to do next:
- Rename the existing test "a spent budget still waits for batch 0 and keeps its hits". Batch 0 is now bounded, so the title is stale, and so is the doc comment at the top of
test/search-batch-race.test.tsif it says the same. - Cancel or deprioritise queued greps when the search answers early. Abandoned greps still take git slots that crew and checks need.
Code search on
/searchnow answers within about 400 ms even when the forge's git queue is full. This should stop/search?q=afrom going past the sentinel's 2000 ms limit, which is what marked release 0.7.382 as degraded (#9402).Cause. On production,
/search?q=absigned out spent 2728 ms in thecodestep of itsServer-Timingheader, while finding repositories and issues took 3–4 ms each. Every code grep goes throughgitGate, the forge-wide queue that lets at most 8 git processes run at once. A grep's 400 ms timeout (BUDGETED_GREP_MS) only starts once the grep gets out of that queue.grepReposalways waited for its first batch of four greps, so while crew and checks kept git busy, the page sat in the queue for seconds.Change (
src/core/search.ts,grepRepos):/searchpage,GET /api/v1/searchand the palette), the first batch now waits at mostBUDGETED_GREP_MS, counted from before the queue.?code=allunchanged. It still waits for every batch.GrepWho.firstTimerlets tests fire the first batch's ceiling apart from the later-batch timer, so the existing tests run unchanged.What to look at. The new test in
test/search-batch-race.test.tsholds two of the first four greps "in the queue". It checks that the answer comes back with the other two repositories,more: true, no later batch started, and the two abandoned greps still holding their slots. It fails without the fix. A second test checks that a search with no budget never uses the ceiling.Not done.
gitGateitself is unchanged: git work queued behind crew and checks still waits as long as it did, only search no longer waits on it. Greps already queued are not cancelled when the search answers; they run later and hold their slot, as cut greps already did. Separately, production requests took 700–900 ms in total while the app reported 33–100 ms; that gap is outside this app.Checks run.
bun scripts/gate.tsandbun x tsc --noEmitpass.scripts/fast.tsnamed 1358 test files (about 117 minutes) becausecore/search.tsis imported nearly everywhere, so I ran the 19 search, palette and API search test files instead: 133 pass, 0 fail. The issue asks for akeep_planupdate, but that tool was not available in this run, so no plan was posted.Try it. On the preview, open
/search?q=absigned out: thecodeentry inServer-Timingshould stay at or under about 400 ms.🤖 Generated with Claude Code
Closes #9402