From 4fcfa68e5854fe1652c9fe54fb35c6bd6189758f Mon Sep 17 00:00:00 2001 From: ualtinok <94532+ualtinok@users.noreply.github.com> Date: Mon, 26 Oct 2026 08:36:20 +0100 Subject: [PATCH 1/6] mason: add failing restricted-visibility cut attribution fixture (#971) Co-authored-by: alfonso-aft <289616620+alfonso-aft@users.noreply.github.com> --- .../list_envelope_conformance/support.rs | 36 +++++++++++++++++++ crates/aft/tests/list_envelope_drift_guard.rs | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/crates/aft/tests/list_envelope_conformance/support.rs b/crates/aft/tests/list_envelope_conformance/support.rs index 46401b2b9d..a1958505c5 100644 --- a/crates/aft/tests/list_envelope_conformance/support.rs +++ b/crates/aft/tests/list_envelope_conformance/support.rs @@ -2361,6 +2361,42 @@ fn enclosing_item(lines: &[&str], target: usize) -> String { .unwrap_or_else(|| "".to_string()) } +#[test] +fn qualified_visibility_cut_fixture_attribution() { + let source = r#" +fn plain() { + values.iter().take(1); +} +pub(super) fn restricted() { + values.iter().take(2); +} +pub(in crate::x) fn scoped() { + values.iter().take(3); +} +"#; + let lines = source.lines().collect::>(); + let cuts = lines + .iter() + .enumerate() + .filter(|(_, line)| line.contains(".take(")) + .map(|(index, _)| index) + .collect::>(); + let conformance = cuts + .iter() + .map(|&index| enclosing_item(&lines, index)) + .collect::>(); + let drift_guard = cuts + .iter() + .map(|&index| crate::list_envelope_drift_guard::find_enclosing_item(&lines, index)) + .collect::>(); + let expected = vec!["plain", "restricted", "scoped"]; + assert_eq!( + (conformance, drift_guard), + (expected.clone(), expected), + "both scanners must attribute each cut to its own function" + ); +} + pub fn discover_list_cutting_sites() -> Vec { let source_dir = aft_src_dir(); let mut paths = collect_rs_files(&source_dir.join("commands")); diff --git a/crates/aft/tests/list_envelope_drift_guard.rs b/crates/aft/tests/list_envelope_drift_guard.rs index 05e2c13cc8..c586cff2da 100644 --- a/crates/aft/tests/list_envelope_drift_guard.rs +++ b/crates/aft/tests/list_envelope_drift_guard.rs @@ -212,7 +212,7 @@ fn extract_item_name(line: &str) -> Option { None } -fn find_enclosing_item(lines: &[&str], target_idx: usize) -> String { +pub(crate) fn find_enclosing_item(lines: &[&str], target_idx: usize) -> String { for i in (0..=target_idx).rev() { if let Some(name) = extract_item_name(lines[i]) { return name; From 0a37ffd4535198bc823cdc2feecfba7afab74fa8 Mon Sep 17 00:00:00 2001 From: ualtinok <94532+ualtinok@users.noreply.github.com> Date: Mon, 26 Oct 2026 09:08:21 +0100 Subject: [PATCH 2/6] mason: type fixture expectations as owned item keys (#971) Co-authored-by: alfonso-aft <289616620+alfonso-aft@users.noreply.github.com> --- crates/aft/tests/list_envelope_conformance/support.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/aft/tests/list_envelope_conformance/support.rs b/crates/aft/tests/list_envelope_conformance/support.rs index a1958505c5..f8bc587d8b 100644 --- a/crates/aft/tests/list_envelope_conformance/support.rs +++ b/crates/aft/tests/list_envelope_conformance/support.rs @@ -2389,7 +2389,7 @@ pub(in crate::x) fn scoped() { .iter() .map(|&index| crate::list_envelope_drift_guard::find_enclosing_item(&lines, index)) .collect::>(); - let expected = vec!["plain", "restricted", "scoped"]; + let expected = ["plain", "restricted", "scoped"].map(String::from).to_vec(); assert_eq!( (conformance, drift_guard), (expected.clone(), expected), From 900c5c85aa37f4450240bdc7b4cb10570819f5f9 Mon Sep 17 00:00:00 2001 From: ualtinok <94532+ualtinok@users.noreply.github.com> Date: Mon, 26 Oct 2026 09:40:44 +0100 Subject: [PATCH 3/6] mason: share visibility-aware list-cut item discovery (#971) Parse parenthesized visibility and function qualifiers once for both scanners, retaining const/static/struct/enum names. Correct the sweep, reply and semantic_results registry keys without changing product code paths. The restricted-visibility fixture failed first with both scanners reporting plain for all three cuts. Move it out of support so the mutation matrix's second inclusion does not duplicate the regression test. Co-authored-by: alfonso-aft <289616620+alfonso-aft@users.noreply.github.com> --- crates/aft/src/list_surfaces.rs | 8 +- crates/aft/tests/helpers/list_cut_item.rs | 76 +++++++++++++++++++ crates/aft/tests/list_envelope/main.rs | 3 + .../conformance_test.rs | 36 +++++++++ .../list_envelope_conformance/support.rs | 71 +---------------- crates/aft/tests/list_envelope_drift_guard.rs | 65 +--------------- 6 files changed, 124 insertions(+), 135 deletions(-) create mode 100644 crates/aft/tests/helpers/list_cut_item.rs diff --git a/crates/aft/src/list_surfaces.rs b/crates/aft/src/list_surfaces.rs index a2fd135fb9..94c219b9be 100644 --- a/crates/aft/src/list_surfaces.rs +++ b/crates/aft/src/list_surfaces.rs @@ -196,7 +196,7 @@ pub static LIST_SURFACES: &[SurfaceEntry] = &[ ReasonEntry { reason: Reason::Cap, kind: ReasonKind::Selecting, - predicate_name: "SearchTrailer::shared_envelope_projection, StopState::S1MoreAtDepth, StopState::S2Exhausted, more_available, handle_external_semantic_or_hybrid_search, handle_external_grep_search, handle_semantic_or_hybrid_search, handle_grep_search, from_matches, run_engine_ranking, blast_radius_annotation_for_result, enrich_snippets_from_source_reference, enrich_snippets_from_source_with_context, read_bounded_snippet_line, truncate_chars, split_semantic_results, handle_split_search, rank_hits", + predicate_name: "SearchTrailer::shared_envelope_projection, StopState::S1MoreAtDepth, StopState::S2Exhausted, more_available, handle_external_semantic_or_hybrid_search, handle_external_grep_search, handle_semantic_or_hybrid_search, handle_grep_search, from_matches, run_engine_ranking, blast_radius_annotation_for_result, enrich_snippets_from_source_reference, enrich_snippets_from_source_with_context, read_bounded_snippet_line, truncate_chars, split_semantic_results, handle_split_search, rank_hits, external_exact::reply", }, ], }, @@ -1026,7 +1026,7 @@ pub static EXCLUSIONS: &[ExclusionEntry] = &[ // results page is the search surface's, registered under its cap reason. ExclusionEntry { file: "commands/semantic_search/external_exact.rs", - enclosing_item: "files_with_hits", + enclosing_item: "sweep", location_or_primitive: "commands::semantic_search::external_exact::sweep skipped_foreign_mounts", reason: "counts mount points of other filesystems that the walk does not enter; no list is cut here, and a walk the deadline stops is reported through the sweep's enumeration_stopped and the reply's coverage line", }, @@ -1044,9 +1044,9 @@ pub static EXCLUSIONS: &[ExclusionEntry] = &[ }, ExclusionEntry { file: "commands/semantic_search/external_pattern.rs", - enclosing_item: "semantic_results, semantic_index", + enclosing_item: "semantic_results", location_or_primitive: "commands::semantic_search::external_pattern::Corpus semantic enumeration", - reason: "enumerates at most SEMANTIC_ENUMERATION_LIMIT prose candidates before ranking, like the external query-only route; more_available reports the remaining candidates and the engine envelopes the results page. Discovery currently attributes the restricted-visibility method to its preceding semantic_index helper", + reason: "enumerates at most SEMANTIC_ENUMERATION_LIMIT prose candidates before ranking, like the external query-only route; more_available reports the remaining candidates and the engine envelopes the results page", }, ExclusionEntry { file: "commands/inspect.rs", diff --git a/crates/aft/tests/helpers/list_cut_item.rs b/crates/aft/tests/helpers/list_cut_item.rs new file mode 100644 index 0000000000..67c2275924 --- /dev/null +++ b/crates/aft/tests/helpers/list_cut_item.rs @@ -0,0 +1,76 @@ +pub(crate) fn extract_item_name(line: &str) -> Option { + let trimmed = line.trim(); + let declaration = if let Some(restricted) = trimmed.strip_prefix("pub(") { + restricted.split_once(')')?.1.trim_start() + } else { + trimmed.strip_prefix("pub ").unwrap_or(trimmed).trim_start() + }; + + // Strip function qualifiers separately so `const LIMIT` remains a const + // item, while `const unsafe extern "C" fn run` is named `run`, not `unsafe`. + let mut function = declaration; + while let Some(rest) = ["async ", "const ", "unsafe ", "extern \"C\" "] + .iter() + .find_map(|prefix| function.strip_prefix(prefix)) + { + function = rest.trim_start(); + } + let rest = function.strip_prefix("fn ").or_else(|| { + ["const ", "static ", "struct ", "enum "] + .iter() + .find_map(|prefix| declaration.strip_prefix(prefix)) + })?; + let name = rest + .trim_start() + .chars() + .take_while(|character| character.is_alphanumeric() || *character == '_') + .collect::(); + (!name.is_empty()).then_some(name) +} + +#[test] +fn visibility_and_qualifiers_preserve_item_names() { + for visibility in [ + "", + "pub ", + "pub(crate) ", + "pub(super) ", + "pub(self) ", + "pub(in crate::x) ", + ] { + for (declaration, expected) in [ + ("fn plain() {}", "plain"), + ("async fn asynchronous() {}", "asynchronous"), + ("const fn constant() {}", "constant"), + ("unsafe fn unchecked() {}", "unchecked"), + ("extern \"C\" fn foreign() {}", "foreign"), + ("async unsafe fn combined() {}", "combined"), + ("const unsafe extern \"C\" fn qualified() {}", "qualified"), + ("const LIMIT: usize = 1;", "LIMIT"), + ("static VALUES: &[usize] = &[];", "VALUES"), + ("struct Record {}", "Record"), + ("enum Choice {}", "Choice"), + ] { + let line = format!(" {visibility}{declaration}"); + assert_eq!( + extract_item_name(&line).as_deref(), + Some(expected), + "{line}" + ); + } + } +} + +#[test] +fn non_items_have_no_item_name() { + for line in [ + "", + "// pub(super) fn commented() {}", + "let item = 1;", + "impl Record {", + "pub(in crate::x fn unclosed() {}", + "pub(super) fn () {}", + ] { + assert_eq!(extract_item_name(line), None, "{line}"); + } +} diff --git a/crates/aft/tests/list_envelope/main.rs b/crates/aft/tests/list_envelope/main.rs index cd8080da26..c5bf74b32b 100644 --- a/crates/aft/tests/list_envelope/main.rs +++ b/crates/aft/tests/list_envelope/main.rs @@ -1,6 +1,9 @@ #[path = "../helpers/context_storage.rs"] mod context_storage; +#[path = "../helpers/list_cut_item.rs"] +mod list_cut_item; + #[path = "../list_envelope_bash.rs"] mod list_envelope_bash; #[path = "../list_envelope_callgraph.rs"] diff --git a/crates/aft/tests/list_envelope_conformance/conformance_test.rs b/crates/aft/tests/list_envelope_conformance/conformance_test.rs index 948c87c279..b6fab9b82b 100644 --- a/crates/aft/tests/list_envelope_conformance/conformance_test.rs +++ b/crates/aft/tests/list_envelope_conformance/conformance_test.rs @@ -344,6 +344,42 @@ fn renderer_and_measurement_callers_are_closed() { ); } +#[test] +fn qualified_visibility_cut_fixture_attribution() { + let source = r#" +fn plain() { + values.iter().take(1); +} +pub(super) fn restricted() { + values.iter().take(2); +} +pub(in crate::x) fn scoped() { + values.iter().take(3); +} +"#; + let lines = source.lines().collect::>(); + let cuts = lines + .iter() + .enumerate() + .filter(|(_, line)| line.contains(".take(")) + .map(|(index, _)| index) + .collect::>(); + let conformance = cuts + .iter() + .map(|&index| super::support::enclosing_item(&lines, index)) + .collect::>(); + let drift_guard = cuts + .iter() + .map(|&index| crate::list_envelope_drift_guard::find_enclosing_item(&lines, index)) + .collect::>(); + let expected = ["plain", "restricted", "scoped"].map(String::from).to_vec(); + assert_eq!( + (conformance, drift_guard), + (expected.clone(), expected), + "both scanners must attribute each cut to its own function" + ); +} + #[test] fn registry_free_discovery_resolves_every_cut() { let discovered = discover_list_cutting_sites(); diff --git a/crates/aft/tests/list_envelope_conformance/support.rs b/crates/aft/tests/list_envelope_conformance/support.rs index f8bc587d8b..901bf31ce0 100644 --- a/crates/aft/tests/list_envelope_conformance/support.rs +++ b/crates/aft/tests/list_envelope_conformance/support.rs @@ -31,6 +31,8 @@ use aft::protocol::Response; use aft::subc_format::{format_response_with_context, FormatContext, OutlineMode}; use serde_json::{json, Map, Value}; +use crate::list_cut_item::extract_item_name; + fn fixture_search_envelope( shown: usize, more_available: bool, @@ -2323,80 +2325,13 @@ pub struct DiscoveredCut { pub snippet: String, } -fn extract_item_name(line: &str) -> Option { - let trimmed = line.trim(); - let rest = [ - "pub(crate) fn ", - "pub fn ", - "fn ", - "async fn ", - "pub async fn ", - "pub(crate) async fn ", - "pub(crate) const ", - "pub const ", - "const ", - "pub(crate) static ", - "pub static ", - "static ", - "pub(crate) struct ", - "pub struct ", - "struct ", - "pub(crate) enum ", - "pub enum ", - "enum ", - ] - .iter() - .find_map(|prefix| trimmed.strip_prefix(prefix))?; - let name = rest - .chars() - .take_while(|character| character.is_alphanumeric() || *character == '_') - .collect::(); - (!name.is_empty()).then_some(name) -} - -fn enclosing_item(lines: &[&str], target: usize) -> String { +pub(super) fn enclosing_item(lines: &[&str], target: usize) -> String { (0..=target) .rev() .find_map(|index| extract_item_name(lines[index])) .unwrap_or_else(|| "".to_string()) } -#[test] -fn qualified_visibility_cut_fixture_attribution() { - let source = r#" -fn plain() { - values.iter().take(1); -} -pub(super) fn restricted() { - values.iter().take(2); -} -pub(in crate::x) fn scoped() { - values.iter().take(3); -} -"#; - let lines = source.lines().collect::>(); - let cuts = lines - .iter() - .enumerate() - .filter(|(_, line)| line.contains(".take(")) - .map(|(index, _)| index) - .collect::>(); - let conformance = cuts - .iter() - .map(|&index| enclosing_item(&lines, index)) - .collect::>(); - let drift_guard = cuts - .iter() - .map(|&index| crate::list_envelope_drift_guard::find_enclosing_item(&lines, index)) - .collect::>(); - let expected = ["plain", "restricted", "scoped"].map(String::from).to_vec(); - assert_eq!( - (conformance, drift_guard), - (expected.clone(), expected), - "both scanners must attribute each cut to its own function" - ); -} - pub fn discover_list_cutting_sites() -> Vec { let source_dir = aft_src_dir(); let mut paths = collect_rs_files(&source_dir.join("commands")); diff --git a/crates/aft/tests/list_envelope_drift_guard.rs b/crates/aft/tests/list_envelope_drift_guard.rs index c586cff2da..623a44eebc 100644 --- a/crates/aft/tests/list_envelope_drift_guard.rs +++ b/crates/aft/tests/list_envelope_drift_guard.rs @@ -5,6 +5,8 @@ use aft::list_envelope::{render_trailer, ListEnvelope, Reason, Total, Unit}; use aft::list_surfaces::{ExclusionEntry, EXCLUSIONS, LIST_SURFACES}; use serde_json::Value; +use crate::list_cut_item::extract_item_name; + /// Returns the path to `crates/aft/src`. fn aft_src_dir() -> PathBuf { Path::new(env!("CARGO_MANIFEST_DIR")).join("src") @@ -149,69 +151,6 @@ pub struct DiscoveredCut { pub snippet: String, } -fn extract_item_name(line: &str) -> Option { - let trimmed = line.trim(); - - // Check fn - if let Some(rest) = trimmed - .strip_prefix("pub(crate) fn ") - .or_else(|| trimmed.strip_prefix("pub fn ")) - .or_else(|| trimmed.strip_prefix("fn ")) - .or_else(|| trimmed.strip_prefix("async fn ")) - .or_else(|| trimmed.strip_prefix("pub async fn ")) - .or_else(|| trimmed.strip_prefix("pub(crate) async fn ")) - { - let name: String = rest - .chars() - .take_while(|c| c.is_alphanumeric() || *c == '_') - .collect(); - if !name.is_empty() { - return Some(name); - } - } - - // Check const / static - if let Some(rest) = trimmed - .strip_prefix("pub(crate) const ") - .or_else(|| trimmed.strip_prefix("pub const ")) - .or_else(|| trimmed.strip_prefix("const ")) - .or_else(|| { - trimmed - .strip_prefix("pub(crate) static ") - .or_else(|| trimmed.strip_prefix("pub static ")) - .or_else(|| trimmed.strip_prefix("static ")) - }) - { - let name: String = rest - .chars() - .take_while(|c| c.is_alphanumeric() || *c == '_') - .collect(); - if !name.is_empty() { - return Some(name); - } - } - - // Check struct / enum - if let Some(rest) = trimmed - .strip_prefix("pub(crate) struct ") - .or_else(|| trimmed.strip_prefix("pub struct ")) - .or_else(|| trimmed.strip_prefix("struct ")) - .or_else(|| trimmed.strip_prefix("pub(crate) enum ")) - .or_else(|| trimmed.strip_prefix("pub enum ")) - .or_else(|| trimmed.strip_prefix("enum ")) - { - let name: String = rest - .chars() - .take_while(|c| c.is_alphanumeric() || *c == '_') - .collect(); - if !name.is_empty() { - return Some(name); - } - } - - None -} - pub(crate) fn find_enclosing_item(lines: &[&str], target_idx: usize) -> String { for i in (0..=target_idx).rev() { if let Some(name) = extract_item_name(lines[i]) { From c14790e1481a610577af81bb2d1ed24d9e98b865 Mon Sep 17 00:00:00 2001 From: ualtinok <94532+ualtinok@users.noreply.github.com> Date: Mon, 26 Oct 2026 10:07:42 +0100 Subject: [PATCH 4/6] mason: remove obsolete rank_hits cut key (#971) The page cap belongs to external_exact::reply; rank_hits only sorts and has no list-cutting primitive. Co-authored-by: alfonso-aft <289616620+alfonso-aft@users.noreply.github.com> --- crates/aft/src/list_surfaces.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/aft/src/list_surfaces.rs b/crates/aft/src/list_surfaces.rs index 94c219b9be..4c3fd793f8 100644 --- a/crates/aft/src/list_surfaces.rs +++ b/crates/aft/src/list_surfaces.rs @@ -196,7 +196,7 @@ pub static LIST_SURFACES: &[SurfaceEntry] = &[ ReasonEntry { reason: Reason::Cap, kind: ReasonKind::Selecting, - predicate_name: "SearchTrailer::shared_envelope_projection, StopState::S1MoreAtDepth, StopState::S2Exhausted, more_available, handle_external_semantic_or_hybrid_search, handle_external_grep_search, handle_semantic_or_hybrid_search, handle_grep_search, from_matches, run_engine_ranking, blast_radius_annotation_for_result, enrich_snippets_from_source_reference, enrich_snippets_from_source_with_context, read_bounded_snippet_line, truncate_chars, split_semantic_results, handle_split_search, rank_hits, external_exact::reply", + predicate_name: "SearchTrailer::shared_envelope_projection, StopState::S1MoreAtDepth, StopState::S2Exhausted, more_available, handle_external_semantic_or_hybrid_search, handle_external_grep_search, handle_semantic_or_hybrid_search, handle_grep_search, from_matches, run_engine_ranking, blast_radius_annotation_for_result, enrich_snippets_from_source_reference, enrich_snippets_from_source_with_context, read_bounded_snippet_line, truncate_chars, split_semantic_results, handle_split_search, external_exact::reply", }, ], }, From 5dbbf030265e68b4b618a04b36f4e5baa2a7334a Mon Sep 17 00:00:00 2001 From: ualtinok <94532+ualtinok@users.noreply.github.com> Date: Mon, 26 Oct 2026 10:35:35 +0100 Subject: [PATCH 5/6] mason: register reply by its discovered bare item name (#971) The drift and conformance resolvers compare item names exactly, not qualified paths. The first post-fix list-envelope run found reply unresolved at external_exact.rs:583; use its bare name rather than external_exact::reply. Verification: the five touched list-envelope tests pass on linux,1c. The earlier fmt, cargo check, 187-test list-envelope target and prefix-control proof completed before the process change; no further broad gates or mutation checks were run after it. Co-authored-by: alfonso-aft <289616620+alfonso-aft@users.noreply.github.com> --- crates/aft/src/list_surfaces.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/aft/src/list_surfaces.rs b/crates/aft/src/list_surfaces.rs index 4c3fd793f8..d41af730d7 100644 --- a/crates/aft/src/list_surfaces.rs +++ b/crates/aft/src/list_surfaces.rs @@ -196,7 +196,7 @@ pub static LIST_SURFACES: &[SurfaceEntry] = &[ ReasonEntry { reason: Reason::Cap, kind: ReasonKind::Selecting, - predicate_name: "SearchTrailer::shared_envelope_projection, StopState::S1MoreAtDepth, StopState::S2Exhausted, more_available, handle_external_semantic_or_hybrid_search, handle_external_grep_search, handle_semantic_or_hybrid_search, handle_grep_search, from_matches, run_engine_ranking, blast_radius_annotation_for_result, enrich_snippets_from_source_reference, enrich_snippets_from_source_with_context, read_bounded_snippet_line, truncate_chars, split_semantic_results, handle_split_search, external_exact::reply", + predicate_name: "SearchTrailer::shared_envelope_projection, StopState::S1MoreAtDepth, StopState::S2Exhausted, more_available, handle_external_semantic_or_hybrid_search, handle_external_grep_search, handle_semantic_or_hybrid_search, handle_grep_search, from_matches, run_engine_ranking, blast_radius_annotation_for_result, enrich_snippets_from_source_reference, enrich_snippets_from_source_with_context, read_bounded_snippet_line, truncate_chars, split_semantic_results, handle_split_search, reply", }, ], }, From 6b798c879c7dfa3635830b7e4efb2fc5f763191a Mon Sep 17 00:00:00 2001 From: ualtinok <94532+ualtinok@users.noreply.github.com> Date: Mon, 26 Oct 2026 11:10:32 +0100 Subject: [PATCH 6/6] release notes and search-quality descriptor for list-envelope-item-names Co-authored-by: alfonso-aft <289616620+alfonso-aft@users.noreply.github.com> --- .../slice-descriptors/land-list-envelope-item-names.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 benchmarks/aft-search/slice-descriptors/land-list-envelope-item-names.json diff --git a/benchmarks/aft-search/slice-descriptors/land-list-envelope-item-names.json b/benchmarks/aft-search/slice-descriptors/land-list-envelope-item-names.json new file mode 100644 index 0000000000..ebd574711e --- /dev/null +++ b/benchmarks/aft-search/slice-descriptors/land-list-envelope-item-names.json @@ -0,0 +1,8 @@ +{ + "targeted_mechanism": "none", + "kind": "harness", + "slice_class": "non_ranking", + "fixtures": [ + "harness-goldens" + ] +}