Skip to content
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"slice_class": "engine_unwired",
"targeted_mechanism": "none",
"kind": "harness",
"fixtures": [
"crates/aft/tests/integration/tool_call_parity_test.rs",
"crates/aft/src/search_index.rs",
"crates/aft/src/commands/semantic_search/mod.rs",
"crates/aft/src/commands/semantic_search/exact_lane.rs"
],
"slices": [
"views-f-lexical-routing"
],
"note": "Views-on lexical acquisition projects verified v3 payloads into the existing read-only query engine. Views are default-off, so the benchmark runs the views-off path, whose acquisition, scoring, fusion, admission and paging are unchanged; ranked rows must remain byte-identical to the committed reference."
}
466 changes: 454 additions & 12 deletions crates/aft/src/commands/configure.rs

Large diffs are not rendered by default.

11 changes: 10 additions & 1 deletion crates/aft/src/commands/glob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const MAX_DIRECTORY_SECTIONS: usize = 8;
const MAX_DISPLAY_DIRECTORIES: usize = 6;

pub fn handle_glob(req: &RawRequest, ctx: &AppContext) -> Response {
let config = ctx.config();
let _pin = config.views.enabled.then(|| ctx.pin_config_to(config));
ctx.with_read_policy_snapshot(&req.id, || {
crate::context::confinement::with_floor_disclosure(|| {
crate::bounded_io::command(req, ctx, handle_glob_inner)
Expand Down Expand Up @@ -590,7 +592,14 @@ fn glob_root(
}
let search_root_text = search_root.to_string_lossy();
let search_scope = resolve_search_scope(project_root, Some(search_root_text.as_ref()));
let indexed_snapshot = {
let view_snapshot = (search_scope.use_index && !ignored_target)
.then(|| ctx.lexical_view_snapshot("glob"))
.flatten();
let indexed_snapshot = if let Some(snapshot) = view_snapshot {
// Failed view acquisition uses the bounded current-tree walk, never a
// borrowed legacy snapshot that may describe another checkout.
snapshot.ok()
} else {
let search_index = ctx
.search_index()
.read()
Expand Down
2 changes: 2 additions & 0 deletions crates/aft/src/commands/grep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ pub(crate) mod work_probe {
}

pub fn handle_grep(req: &RawRequest, ctx: &AppContext) -> Response {
let config = ctx.config();
let _pin = config.views.enabled.then(|| ctx.pin_config_to(config));
ctx.with_read_policy_snapshot(&req.id, || {
crate::context::confinement::with_floor_disclosure(|| {
crate::bounded_io::command(req, ctx, handle_grep_inner)
Expand Down
34 changes: 31 additions & 3 deletions crates/aft/src/commands/semantic_search/exact_lane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,36 @@ impl ExactLane {
fallback_options: Option<&FallbackExactOptions>,
scope: &ExactEvidenceScope,
) -> Result<ServeOutcome, MemoError> {
let is_ready = index.is_some_and(SearchIndex::is_ready);
let snapshot = index
.filter(|index| index.is_ready())
.map(SearchIndex::snapshot);
self.search_scoped_snapshot(
snapshot.as_ref(),
project_root,
snapshot_generation,
query,
include_tests,
offset,
top_k,
fallback_options,
scope,
)
}

/// Accepts an optional SearchIndexSnapshot without requiring a mutable index.
pub(crate) fn search_scoped_snapshot(
&self,
snapshot: Option<&crate::search_index::SearchIndexSnapshot>,
project_root: &Path,
snapshot_generation: GenerationToken,
query: &str,
include_tests: bool,
offset: usize,
top_k: usize,
fallback_options: Option<&FallbackExactOptions>,
scope: &ExactEvidenceScope,
) -> Result<ServeOutcome, MemoError> {
let is_ready = snapshot.is_some();
// Index loading can finish without changing snapshot_generation. Give
// fallback results a separate memo key so they cannot be reused once
// the full index is ready.
Expand All @@ -538,9 +567,8 @@ impl ExactLane {

self.memo.get_or_verify(&key, offset, top_k, || {
if is_ready {
let snapshot = index.unwrap().snapshot();
Ok(self.execute_ready_mode_scoped(
&snapshot,
snapshot.unwrap(),
project_root,
query,
include_tests,
Expand Down
159 changes: 100 additions & 59 deletions crates/aft/src/commands/semantic_search/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,7 +581,22 @@ impl extensions::ReadinessSource for RuntimeReadinessSource<'_> {
},
};

let trigram =
let trigram = if let Some(snapshot) = self.ctx.lexical_view_snapshot("aft_search") {
match snapshot {
Ok(snapshot) => TrigramReadiness {
status: IndexStatus::Ready,
snapshot: Some(Arc::new(snapshot)),
evicted: false,
lock_contended: false,
},
Err(_) => TrigramReadiness {
status: IndexStatus::Fallback,
snapshot: None,
evicted: false,
lock_contended: false,
},
}
} else {
match try_read_with_budget(self.ctx.search_index(), INTERACTIVE_ARTIFACT_READ_BUDGET) {
Some(index) if index.as_ref().is_some_and(SearchIndex::is_ready) => {
TrigramReadiness {
Expand Down Expand Up @@ -629,7 +644,8 @@ impl extensions::ReadinessSource for RuntimeReadinessSource<'_> {
evicted: false,
lock_contended: true,
},
};
}
};

let symbol_cache = self.ctx.symbol_cache();
let symbol = match try_read_with_budget(&symbol_cache, INTERACTIVE_ARTIFACT_READ_BUDGET) {
Expand Down Expand Up @@ -661,6 +677,9 @@ impl extensions::ReadinessSource for RuntimeReadinessSource<'_> {
}

fn bounded_first_search_wait(&self) -> extensions::ReadinessWait {
if self.ctx.lexical_views_enabled() {
return extensions::ReadinessWait::Completed;
}
// A writer-held pointer cannot be advanced by the loader drain below;
// preserve the interactive contention bound instead of sleeping 2.5s.
if matches!(
Expand Down Expand Up @@ -791,6 +810,8 @@ fn handle_semantic_search_with_disk_fallback(
ctx: &AppContext,
allow_disk_fallback: bool,
) -> Response {
let config = ctx.config();
let _pin = config.views.enabled.then(|| ctx.pin_config_to(config));
use extensions::{RawQuery, Root, Token};

let page_request = match paging::parse_public_page_request(&req.params) {
Expand Down Expand Up @@ -926,6 +947,11 @@ fn handle_semantic_search_with_disk_fallback(
// The extensions come from the search_b2 install point: A-side defaults
// until campaign B2 installs its router, plans, variants and readiness.
let extensions = crate::search_b2::install_defaults();
if external_root.is_none() {
if let Some(Err(error)) = ctx.lexical_view_snapshot("aft_search") {
return Response::error(&req.id, "internal_error", error);
}
}
if let Some((pattern_text, compiled)) = pattern {
return handle_pattern_request(
req,
Expand Down Expand Up @@ -3994,7 +4020,12 @@ fn regex_route_collection(
compiled: &pattern_compile::CompiledPattern,
include_tests: bool,
) -> Option<std::io::Result<crate::search_index::GrepFileCollection>> {
let snapshot = {
let snapshot = if let Some(snapshot) = ctx.lexical_view_snapshot("aft_search") {
match snapshot {
Ok(snapshot) => snapshot,
Err(error) => return Some(Err(std::io::Error::other(error))),
}
} else {
#[cfg(test)]
regex_route_lock_hook(false);
let Some(guard) =
Expand Down Expand Up @@ -4836,8 +4867,12 @@ fn run_engine_ranking(
return Err("request_cancelled".to_string());
}
}
let context_index = borrowed_index
.is_none()
let view_snapshot = if borrowed_index.is_none() {
ctx.lexical_view_snapshot("aft_search").transpose()?
} else {
None
};
let context_index = (borrowed_index.is_none() && view_snapshot.is_none())
.then(|| try_read_with_budget(ctx.search_index(), INTERACTIVE_ARTIFACT_READ_BUDGET));
let empty_index = SearchIndex::new();
let index = borrowed_index
Expand All @@ -4849,16 +4884,19 @@ fn run_engine_ranking(
.and_then(|guard| guard.as_ref())
})
.unwrap_or(&empty_index);
let generation = borrowed_index
.map(|(_, generation)| generation.clone())
let generation = view_snapshot
.as_ref()
.map(|snapshot| GenerationToken::new_with_str(&snapshot.content_generation()))
.or_else(|| borrowed_index.map(|(_, generation)| generation.clone()))
.unwrap_or_else(|| {
GenerationToken::new_with_str(&format!(
"{}:{}",
ctx.search_index_rx_generation(),
ctx.semantic_index_rx_generation()
))
});
let snapshot = index.snapshot();
let index_ready = view_snapshot.is_some() || index.is_ready();
let snapshot = view_snapshot.unwrap_or_else(|| index.snapshot());
let content_tokens = query_shape::extract_content_tokens(query);
let token_refs = content_tokens
.iter()
Expand Down Expand Up @@ -4944,8 +4982,8 @@ fn run_engine_ranking(
let mut exact_candidates =
if plan.contains(SearchLaneKind::Exact) || plan.shape == SearchShape::Identifier {
let outcome = exact_lane::ExactLane::with_memo(ctx.search_exact_memo())
.search_scoped(
Some(&index),
.search_scoped_snapshot(
index_ready.then_some(&snapshot),
project_root,
generation.clone(),
exact_input,
Expand Down Expand Up @@ -5012,8 +5050,8 @@ fn run_engine_ranking(
for (fact_input, exact_form) in fact_inputs {
// Only phrase evidence is kept from these passes.
let outcome = lane
.search_scoped(
Some(&index),
.search_scoped_snapshot(
index_ready.then_some(&snapshot),
project_root,
generation.clone(),
&fact_input,
Expand Down Expand Up @@ -5082,35 +5120,35 @@ fn run_engine_ranking(
&& exact_candidates.is_empty()
&& exact_disclosures.is_empty()
&& index_disclosures.is_empty()
&& index.is_ready())
.then(|| nearest_names::looked_up_identifiers(exact_input))
.flatten()
.filter(|identifiers| {
// Absence is checked over every indexed file, tests included: a name
// that only a test uses still exists, and the ordinary ranking says
// more about it than a not-found answer would.
identifiers.iter().all(|identifier| {
snapshot
.whole_corpus_exact_pass(identifier, project_root, None)
.map(|matches| matches.is_empty())
.unwrap_or_else(|error| {
index_disclosures.push(error.to_string());
false
})
&& index_ready)
.then(|| nearest_names::looked_up_identifiers(exact_input))
.flatten()
.filter(|identifiers| {
// Absence is checked over every indexed file, tests included: a name
// that only a test uses still exists, and the ordinary ranking says
// more about it than a not-found answer would.
identifiers.iter().all(|identifier| {
snapshot
.whole_corpus_exact_pass(identifier, project_root, None)
.map(|matches| matches.is_empty())
.unwrap_or_else(|error| {
index_disclosures.push(error.to_string());
false
})
})
})
})
.map(|identifiers| {
let target = identifiers.last().expect("at least one identifier");
nearest_names::NotFoundAnswer {
query: exact_lane::exact_phrase(exact_input).to_string(),
names: nearest_names::nearest_names(
target,
lexical_candidates
.iter()
.map(|candidate| candidate.path.as_path()),
),
}
});
.map(|identifiers| {
let target = identifiers.last().expect("at least one identifier");
nearest_names::NotFoundAnswer {
query: exact_lane::exact_phrase(exact_input).to_string(),
names: nearest_names::nearest_names(
target,
lexical_candidates
.iter()
.map(|candidate| candidate.path.as_path()),
),
}
});
// A code literal that no indexed file contains (tests included) gets the
// same kind of answer: the reply says so first, and the files that only
// share its words are labelled similar rather than presented as matches.
Expand All @@ -5125,26 +5163,26 @@ fn run_engine_ranking(
let literal_absent = (not_found.is_none()
&& plan.shape == SearchShape::CodeLiteral
&& exact_disclosures.is_empty()
&& index.is_ready())
.then(|| exact_lane::exact_phrase(exact_input))
.filter(|phrase| phrase.len() >= 3)
.filter(|phrase| {
match literal_presence(
ctx,
&snapshot,
project_root,
&generation,
phrase,
&exact_candidates,
) {
Ok(presence) => presence == memo::LiteralPresence::Absent,
Err(error) => {
index_disclosures.push(error.to_string());
false
&& index_ready)
.then(|| exact_lane::exact_phrase(exact_input))
.filter(|phrase| phrase.len() >= 3)
.filter(|phrase| {
match literal_presence(
ctx,
&snapshot,
project_root,
&generation,
phrase,
&exact_candidates,
) {
Ok(presence) => presence == memo::LiteralPresence::Absent,
Err(error) => {
index_disclosures.push(error.to_string());
false
}
}
}
})
.map(str::to_string);
})
.map(str::to_string);

let path_lookup_candidates = if plan.contains(SearchLaneKind::PathLookup) {
let query_path_tokens = query
Expand Down Expand Up @@ -7377,6 +7415,9 @@ fn search_index_ready_with_budget(
ctx: &AppContext,
wait_budget: Duration,
) -> Result<bool, SearchIndexWaitError> {
if let Some(snapshot) = ctx.lexical_view_snapshot("aft_search") {
return Ok(snapshot.is_ok());
}
let deadline = Instant::now() + wait_budget;
loop {
if search_cancellation_requested() {
Expand Down
Loading
Loading