Skip to main content

aft/
list_surfaces.rs

1use crate::list_envelope::{Reason, Unit};
2
3pub mod bash;
4pub mod call_tree;
5pub mod callers;
6pub mod glob;
7pub mod grep;
8pub mod impact;
9pub mod inspect;
10pub mod outline;
11pub mod search;
12pub mod trace_data;
13pub mod trace_to;
14
15/// Classification of a reason: whether the traversal stopped (`Bounding`)
16/// or a selector chose which of an enumerated set to retain (`Selecting`).
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18pub enum ReasonKind {
19    Bounding,
20    Selecting,
21}
22
23/// A registered reason on a surface with its kind and the name of the function or constant where the condition is evaluated.
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub struct ReasonEntry {
26    pub reason: Reason,
27    pub kind: ReasonKind,
28    pub predicate_name: &'static str,
29}
30
31/// Registry entry for a list-shaped surface.
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub struct SurfaceEntry {
34    pub command: &'static str,
35    pub mode: &'static str,
36    pub list_id: &'static str,
37    pub unit: Unit,
38    pub narrow: &'static [&'static str],
39    pub reasons: &'static [ReasonEntry],
40}
41
42/// Authoritative registry of every list-shaped surface in AFT.
43pub static LIST_SURFACES: &[SurfaceEntry] = &[
44    SurfaceEntry {
45        command: "callgraph",
46        mode: "impact",
47        list_id: "payload.sites",
48        unit: Unit::Sites,
49        narrow: &["depth", "includeTests"],
50        reasons: &[
51            ReasonEntry {
52                reason: Reason::Cap,
53                kind: ReasonKind::Selecting,
54                predicate_name: "HUB_SUMMARY_LIMIT, impact_result",
55            },
56            ReasonEntry {
57                reason: Reason::Depth,
58                kind: ReasonKind::Bounding,
59                predicate_name: "depth_cut_inside_requested, truncated",
60            },
61        ],
62    },
63    SurfaceEntry {
64        command: "callgraph",
65        mode: "callers",
66        list_id: "payload.callers",
67        unit: Unit::Items,
68        narrow: &["depth", "includeTests"],
69        reasons: &[
70            ReasonEntry {
71                reason: Reason::Cap,
72                kind: ReasonKind::Selecting,
73                predicate_name: "HUB_SUMMARY_LIMIT, callers_result, test_hidden_summary, included_summary",
74            },
75            ReasonEntry {
76                reason: Reason::Depth,
77                kind: ReasonKind::Bounding,
78                predicate_name: "depth_cut_inside_requested, truncated",
79            },
80        ],
81    },
82    SurfaceEntry {
83        command: "callgraph",
84        mode: "call_tree",
85        list_id: "payload.tree",
86        unit: Unit::Items,
87        narrow: &["depth", "includeTests"],
88        reasons: &[
89            ReasonEntry {
90                reason: Reason::Cap,
91                kind: ReasonKind::Selecting,
92                predicate_name: "HUB_SUMMARY_LIMIT",
93            },
94            ReasonEntry {
95                reason: Reason::Depth,
96                kind: ReasonKind::Bounding,
97                predicate_name: "depth_cut_inside_requested, truncated",
98            },
99        ],
100    },
101    // Note: `trace_to_symbol` was originally grouped with `trace_to` under `payload.paths`,
102    // but its reply is a single shortest path with no list semantics
103    // (`path: Option<Vec<...>>`), rather than a `paths` list. Truncation envelopes apply
104    // only to multi-path lists (`trace_to`).
105    SurfaceEntry {
106        command: "callgraph",
107        mode: "trace_to",
108        list_id: "payload.paths",
109        unit: Unit::Paths,
110        narrow: &["depth", "includeTests"],
111        reasons: &[
112            ReasonEntry {
113                reason: Reason::Depth,
114                kind: ReasonKind::Bounding,
115                predicate_name: "trace_to_result, max_depth_reached",
116            },
117            ReasonEntry {
118                reason: Reason::Budget,
119                kind: ReasonKind::Bounding,
120                predicate_name: "TRACE_TO_EXPANSION_BUDGET, trace_to_result_with_budget, lower_bound_trace_summary",
121            },
122            ReasonEntry {
123                reason: Reason::Cap,
124                kind: ReasonKind::Selecting,
125                predicate_name: "TRACE_TO_RETAINED_PATH_LIMIT, retain_trace_path, trace_to_symbol_result",
126            },
127        ],
128    },
129    SurfaceEntry {
130        command: "callgraph",
131        mode: "trace_data",
132        list_id: "payload.hops",
133        unit: Unit::Hops,
134        narrow: &["depth"],
135        reasons: &[ReasonEntry {
136            reason: Reason::Depth,
137            kind: ReasonKind::Bounding,
138            predicate_name: "depth_limited",
139        }],
140    },
141    SurfaceEntry {
142        command: "search",
143        mode: "",
144        list_id: "payload.results",
145        unit: Unit::Results,
146        narrow: &["offset", "topK", "path", "includeTests"],
147        reasons: &[
148            ReasonEntry {
149                reason: Reason::Walk,
150                kind: ReasonKind::Bounding,
151                predicate_name: "SearchTrailer::shared_envelope_projection, StopState::S2Exhausted",
152            },
153            ReasonEntry {
154                reason: Reason::Depth,
155                kind: ReasonKind::Bounding,
156                predicate_name: "SearchTrailer::shared_envelope_projection, StopState::S3DepthCap",
157            },
158            ReasonEntry {
159                reason: Reason::Budget,
160                kind: ReasonKind::Bounding,
161                predicate_name: "engine_capped",
162            },
163            ReasonEntry {
164                reason: Reason::Cap,
165                kind: ReasonKind::Selecting,
166                predicate_name: "SearchTrailer::shared_envelope_projection, StopState::S1MoreAtDepth, more_available, handle_external_semantic_or_hybrid_search, handle_external_grep_search, handle_semantic_or_hybrid_search, handle_grep_search, run_engine_ranking, view_semantic_search, blast_radius_annotation_for_result, enrich_snippets_from_source_reference, enrich_snippets_from_source_with_context, truncate_chars",
167            },
168        ],
169    },
170    SurfaceEntry {
171        command: "grep",
172        mode: "",
173        list_id: "payload.matches",
174        unit: Unit::Rows,
175        narrow: &["path", "include", "exclude"],
176        reasons: &[
177            ReasonEntry {
178                reason: Reason::Walk,
179                kind: ReasonKind::Bounding,
180                predicate_name: "handle_grep, grep_result, grep_result_bytes, walk_truncated, skipped_foreign_mounts",
181            },
182            ReasonEntry {
183                reason: Reason::Cap,
184                kind: ReasonKind::Selecting,
185                predicate_name: "DEFAULT_MAX_RESULTS, MAX_DISPLAY_MATCHES_PER_FILE, MAX_DISPLAY_MATCHES, handle_grep, format_grep_text, rendered_grep_match_count",
186            },
187        ],
188    },
189    SurfaceEntry {
190        command: "glob",
191        mode: "",
192        list_id: "payload.files",
193        unit: Unit::Files,
194        narrow: &["path"],
195        reasons: &[
196            ReasonEntry {
197                reason: Reason::Walk,
198                kind: ReasonKind::Bounding,
199                predicate_name: "GlobDiscovery, handle_glob, fallback_glob, glob_root, walk_truncated, skipped_foreign_mounts",
200            },
201            ReasonEntry {
202                reason: Reason::Cap,
203                kind: ReasonKind::Selecting,
204                predicate_name: "DEFAULT_MAX_RESULTS, MAX_DISPLAY_DIRECTORIES, MAX_DISPLAY_FILES_PER_DIRECTORY, handle_glob, format_glob_text, rendered_glob_file_count",
205            },
206        ],
207    },
208    SurfaceEntry {
209        command: "outline",
210        mode: "files",
211        list_id: "payload.files",
212        unit: Unit::Files,
213        narrow: &["path"],
214        reasons: &[
215            ReasonEntry {
216                reason: Reason::Budget,
217                kind: ReasonKind::Selecting,
218                predicate_name: "MAX_OUTPUT_BYTES, discover_outline_files, handle_outline_files_mode, budget_rollups_present",
219            },
220            ReasonEntry {
221                reason: Reason::Walk,
222                kind: ReasonKind::Bounding,
223                predicate_name: "OutlineFileDiscovery, discover_outline_files_with_options, collect_outline_files_with_device_lookup, collect_outline_files_breadth_first_with_device_lookup, outline_walk_skips_and_reports_injected_foreign_mount, ITERATIONS, collection_truncated, walk_truncated, skipped_foreign_mounts",
224            },
225        ],
226    },
227    SurfaceEntry {
228        command: "inspect",
229        mode: "",
230        list_id: "payload.details",
231        unit: Unit::Items,
232        narrow: &["topK", "scope", "sections"],
233        reasons: &[ReasonEntry {
234            reason: Reason::Cap,
235            kind: ReasonKind::Selecting,
236            predicate_name: "details_for, generated_details_for, test_only_details_for, topk_limiting",
237        }],
238    },
239    SurfaceEntry {
240        command: "bash",
241        mode: "",
242        list_id: "bash.output",
243        unit: Unit::Lines,
244        narrow: &[],
245        reasons: &[ReasonEntry {
246            reason: Reason::Cap,
247            kind: ReasonKind::Selecting,
248            predicate_name: "cap_lines, compress_json, finish, middle_truncate, append_hunk, cap_git_lines, compress_add, compress_blame, compress_diff, flush_status_entries, looks_like_golangci_json, finish_folded, first_error_lines, truncate_line, parse_tree, compress_tsc, frozen_compress_tsc, compressor_line_dropping",
249        }],
250    },
251];
252
253/// An entry in the discovery exclusions table with written justification.
254#[derive(Debug, Clone, Copy, PartialEq, Eq)]
255pub struct ExclusionEntry {
256    pub file: &'static str,
257    pub enclosing_item: &'static str,
258    pub location_or_primitive: &'static str,
259    pub reason: &'static str,
260}
261
262/// Exclusions from the registry-free discovery scan with non-empty written reasons.
263pub static EXCLUSIONS: &[ExclusionEntry] = &[
264    // The lexical lane's depth tiers are engine-internal cuts over a candidate
265    // pool (D_k = 200..3200); the agent never sees this list. The only cut an
266    // agent sees is the search surface's topK, which carries the envelope.
267    ExclusionEntry {
268        file: "commands/semantic_search/lexical_lane.rs",
269        enclosing_item: "from_scored_candidates",
270        location_or_primitive: "depth-tier truncate",
271        reason: "engine-internal lexical depth tier over the candidate pool; not an agent-visible list, the search surface attaches the envelope",
272    },
273    ExclusionEntry {
274        file: "commands/semantic_search/lexical_lane.rs",
275        enclosing_item: "enumerate_to_depth",
276        location_or_primitive: "depth-tier take",
277        reason: "engine-internal lexical depth tier over the candidate pool; not an agent-visible list, the search surface attaches the envelope",
278    },
279    ExclusionEntry {
280        file: "commands/semantic_search/lexical_lane.rs",
281        enclosing_item: "score_complete_selected_pool",
282        location_or_primitive: "depth-tier take",
283        reason: "engine-internal lexical depth tier over the candidate pool; not an agent-visible list, the search surface attaches the envelope",
284    },
285    // The block builder's page cut and the depth-tier observation are engine
286    // cuts inside the search engine; the page the agent sees is the search
287    // surface's, which attaches the envelope and the paging trailer.
288    ExclusionEntry {
289        file: "commands/semantic_search/blocks.rs",
290        enclosing_item: "build",
291        location_or_primitive: "page take",
292        reason: "engine-internal page cut over the frozen block list; the search surface attaches the envelope and paging trailer",
293    },
294    ExclusionEntry {
295        file: "commands/semantic_search/blocks.rs",
296        enclosing_item: "observe_through_depth",
297        location_or_primitive: "depth-tier take",
298        reason: "engine-internal depth-tier observation over lane candidates; not an agent-visible list",
299    },
300    ExclusionEntry {
301        file: "commands/semantic_search/paging.rs",
302        enclosing_item: "build_l",
303        location_or_primitive: "interval take",
304        reason: "engine-internal interval cut when building L over frozen blocks; the served page's envelope and paging trailer are the search surface's",
305    },
306    ExclusionEntry {
307        file: "commands/bash_status.rs",
308        enclosing_item: "handle",
309        location_or_primitive: "bash_status / bash live-tail",
310        reason: "bash live-tail (bash_status polling) output is shown raw by design and carries no truncation envelope",
311    },
312    ExclusionEntry {
313        file: "commands/status.rs",
314        enclosing_item: "handle",
315        location_or_primitive: "summary count arrays",
316        reason: "summary counts and census count arrays are totals by construction and carry no truncation envelope",
317    },
318    ExclusionEntry {
319        file: "commands/delete_file.rs",
320        enclosing_item: "MAX_PATHS",
321        location_or_primitive: "commands::delete_file::MAX_PATHS",
322        reason: "error message preview of offending non-regular file paths is diagnostic formatting, not a returned list payload",
323    },
324    ExclusionEntry {
325        file: "commands/read.rs",
326        enclosing_item: "handle_directory",
327        location_or_primitive: "commands::read::MAX_DIRECTORY_ENTRIES",
328        reason: "raw directory entry read mode limits directory listing entries to MAX_DIRECTORY_ENTRIES",
329    },
330    ExclusionEntry {
331        file: "commands/lsp_diagnostics.rs",
332        enclosing_item: "build_response, compute_unchecked_files, handle_directory_mode",
333        location_or_primitive: "commands::lsp_diagnostics::DIRECTORY_FILE_CAP",
334        reason: "internal diagnostics scanner file resolution cap is an engine boundary, not a returned list",
335    },
336    ExclusionEntry {
337        file: "commands/bash_orchestrate.rs",
338        enclosing_item: "format_seconds",
339        location_or_primitive: "commands::bash_orchestrate::seconds.truncate",
340        reason: "string manipulation trimming timestamp representation, not a list truncation",
341    },
342    ExclusionEntry {
343        file: "commands/zoom.rs",
344        enclosing_item: "suggest_close_symbols",
345        location_or_primitive: "commands::zoom::resolve_zoom_symbol candidate suggestion",
346        reason: "did-you-mean candidate suggestion trimming for invalid symbol error messages",
347    },
348    ExclusionEntry {
349        file: "commands/grep.rs",
350        enclosing_item: "truncate_line_text",
351        location_or_primitive: "commands::grep::truncate_line_text",
352        reason: "line text preview truncation, not a list truncation",
353    },
354    ExclusionEntry {
355        file: "commands/semantic_search/mod.rs",
356        enclosing_item: "collect_degraded_grep_files, empty_degraded_grep_fallback_names_missing_semantic_coverage, execute_degraded_grep_fallback, handle_external_bounded_lexical_fallback, semantic_unavailable_grep_fallback_response",
357        location_or_primitive: "commands::semantic_search degraded grep fallback status",
358        reason: "internal fallback search status notes and degraded grep walk markers",
359    },
360    ExclusionEntry {
361        file: "subc_format.rs",
362        enclosing_item: "unresolved_summary_text",
363        location_or_primitive: "subc_format::UNRESOLVED_SUMMARY_NAME_LIMIT",
364        reason: "unresolved call site summary line preview names formatting",
365    },
366    ExclusionEntry {
367        file: "subc_format.rs",
368        enclosing_item: "format_outline_files_text",
369        location_or_primitive: "subc_format::MAX_UNCHECKED_FILES_IN_FOOTER",
370        reason: "legacy unchecked files list in outline text footer",
371    },
372    ExclusionEntry {
373        file: "subc_format.rs",
374        enclosing_item: "directory_outline_preserves_walk_truncation_footer, files_outline_uses_the_counting_walk_limit_in_partial_footer",
375        location_or_primitive: "subc_format walk truncation footer tests",
376        reason: "test assertions verifying legacy walk truncation footer",
377    },
378    ExclusionEntry {
379        file: "commands/trace_to_symbol.rs",
380        enclosing_item: "handle_trace_to_symbol",
381        location_or_primitive: "commands::trace_to_symbol::handle_trace_to_symbol",
382        reason: "trace_to_symbol reply is a single shortest path (path: Option<Vec<...>>) with no list semantics, so it carries no truncation envelope",
383    },
384];
385
386/// Look up a surface by command, mode, and list id.
387pub fn find_surface(command: &str, mode: &str, list_id: &str) -> Option<&'static SurfaceEntry> {
388    LIST_SURFACES.iter().find(|s| {
389        s.command == command
390            && (s.mode == mode || s.mode.is_empty() || mode.is_empty())
391            && s.list_id == list_id
392    })
393}