Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .alfonso/release-notes/next/paused-notice-building.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- `aft_search` now keeps the approved paused-embedding notice visible while the keyword index is still building.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"targeted_mechanism": "none",
"kind": "harness",
"slice_class": "engine_unwired",
"fixtures": [
"crates/aft/tests/integration/tool_call_parity_test.rs"
],
"fenced_files": [
"crates/aft/src/commands/semantic_search/mod.rs"
],
"note": "- Ranking and routing are unchanged; benchmark rows must remain byte-identical."
}
46 changes: 46 additions & 0 deletions crates/aft/src/commands/semantic_search/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1799,6 +1799,14 @@ impl SearchLaneStatus {
[("trigram", &self.trigram), ("semantic", &self.semantic)]
.into_iter()
.map(|(name, lane)| {
if name == "semantic" && !lane.is_ready() && lane.effective != IndexEffective::Off {
let backend = ctx.semantic_backend_health_snapshot();
if !backend.available && backend.paused_until_ms.is_some() {
// A scheduled pause is not an ordinary unavailable-index
// state, even when no lane is ready to run this request.
return PAUSED_EMBEDDING_DETAIL.to_string();
}
}
let state = match lane.effective {
IndexEffective::Unavailable
if lane.unavailable_reason.as_deref()
Expand Down Expand Up @@ -8872,6 +8880,44 @@ mod tests {
});
}

#[test]
fn lane_paused_trigram_building_search_shows_approved_sentence() {
use crate::synapse_embed::pause_test_support::*;
crate::semantic_index::with_lane_pause_clock(START, |_clock| {
let project = tempfile::tempdir().unwrap();
let ctx = test_context(project.path());
ctx.set_canonical_cache_root(project.path().to_path_buf());
*ctx.semantic_index_status().write().unwrap() = SemanticIndexStatus::Building {
stage: "embedding".to_string(),
files: None,
entries_done: None,
entries_total: None,
};
let (publish, receiver) = crossbeam_channel::unbounded::<SearchIndex>();
ctx.install_search_index_rx(receiver, ctx.configure_generation());
record_pause_for_root(project.path());

// Keeping the publication sender alive holds the trigram lane in its
// building state while the search reply is rendered.
let response =
with_first_search_index_load_wait_budget_for_test(Duration::ZERO, || {
handle_semantic_search(
&semantic_request("where remix panel mounted option switching handled", 5),
&ctx,
)
});
let text = crate::subc_format::format_response("search", &response, false);
assert!(text.lines().any(|line| {
line == "Semantic search unavailable: the embedding model is paused; using keyword search only."
}), "{text}");
assert!(
text.lines().any(|line| line == "trigram: building"),
"{text}"
);
drop(publish);
});
}

#[test]
fn blocked_local_query_times_out_falls_back_and_late_result_populates_cache() {
let project = tempfile::tempdir().expect("create project dir");
Expand Down
Loading