Symptom
mcp_suite mcp_handler_test::graph_query_test::test_ast_grep_search_respects_public_path_glob failed once on 061cd6267d in a focused run under lane load (hauler ticket cc-5457, unsealed_graph status_behavior_test graph_query_test: 50/51). The panic is not in the ast-grep assertion. It is in the shared fixture warm-up, support.rs:373:
assertion `left == right` failed: {... "freshness":{"indexing":{"latest_generation":"generation.v1.7c902c39.00000001.cf86…","rebuild_in_flight":false,"served_generation":"generation.v1.7c902c39.00000001.cf86…","staleness_state":"verifying","summary":"state=verifying rebuild_in_flight=false … progress=ready 3/3 files"},"state":"possibly_stale"} …}
left: Object {"indexing": …, "state": String("possibly_stale")}
right: Object {"state": String("fresh")}
Cause (test race)
wait_for_code_index_generation waits for tracedecay_status wait_for: ready and then asserts that the next tracedecay_search is fresh. ready means a complete generation serves. By the freshness ladder (CodeIndexFreshnessLadderV1::project, pinned by verifying_is_not_a_rebuild), a ready generation with a queued or running verification pass and no source change reads verifying. wait_for_readiness(Ready) requires the worker's pass to be finished (#2365), but a wake that is already queued is not part of that check. Under load the queued pass is still pending or running when the search reads freshness. The product reports this state truthfully. The helper waits for one state and asserts a different one.
The same gap is deterministic when the source changed without a hint: the ready wait returns right away, and the next search answers fresh from the old generation without the edit.
Repro
- The flake itself: 1 failure in the focused run above. 128 focused runs (16 parallel processes, test binary evicted from page cache before each round) did not reproduce it.
- Deterministic: write
src/warm_probe.rs after the fixture warmed, call warm_code_index_search(&server, "warm_probe_marker"), then search warm_probe_marker. On master the search is fresh on generation …00000001 with no result for the new file (6/6 runs).
Fix
The warm-up waits for fresh, the state it asserts. That wait sweeps the source and requires a settled fresh ladder.
Symptom
mcp_suitemcp_handler_test::graph_query_test::test_ast_grep_search_respects_public_path_globfailed once on061cd6267din a focused run under lane load (hauler ticket cc-5457,unsealed_graph status_behavior_test graph_query_test: 50/51). The panic is not in the ast-grep assertion. It is in the shared fixture warm-up,support.rs:373:Cause (test race)
wait_for_code_index_generationwaits fortracedecay_statuswait_for: readyand then asserts that the nexttracedecay_searchisfresh.readymeans a complete generation serves. By the freshness ladder (CodeIndexFreshnessLadderV1::project, pinned byverifying_is_not_a_rebuild), a ready generation with a queued or running verification pass and no source change readsverifying.wait_for_readiness(Ready)requires the worker's pass to be finished (#2365), but a wake that is already queued is not part of that check. Under load the queued pass is still pending or running when the search reads freshness. The product reports this state truthfully. The helper waits for one state and asserts a different one.The same gap is deterministic when the source changed without a hint: the
readywait returns right away, and the next search answersfreshfrom the old generation without the edit.Repro
src/warm_probe.rsafter the fixture warmed, callwarm_code_index_search(&server, "warm_probe_marker"), then searchwarm_probe_marker. On master the search isfreshon generation…00000001with no result for the new file (6/6 runs).Fix
The warm-up waits for
fresh, the state it asserts. That wait sweeps the source and requires a settled fresh ladder.