Repository navigation
feat: agentic-search incorporation — blast-radius files, Stage 2-4 surfaces, and slice locate - #17
Conversation
Stage 1 of the agentic-search incorporation plan: make the reverse/transitive dependency blast radius return actionable collaborator FILES, not just slice ids, so an agent can read them directly instead of falling back to brute-force grep (closes ContextBench FINDINGS failure mode #2: blast-radius went unused because the index held the relationship but surfaced only abstract slice ids). - `deps … --files`: lists the concrete files of the dependency slices, file-level (the "candidate file discovery" hop; file:line stays at the read via grep --symbols, per the layered-provenance invariant). Nearest dependents first, deduped across the transitive set, no cap (never hides gold). New CollaboratorFile type; DepsOutput.files is conditionally serialized (skip_serializing_if) so default JSON is byte-identical for existing consumers. - `context <file>`: adds a one-line factual `blast-radius:` summary to human output (the affordance that advertises the radius so the agent pulls it in); JSON contract unchanged. - docs: navigating.md + agent-workflows.md document the new flag and affordance. Tests: collaborator_files scoping unit test + 2 CLI tests (listing/dedup/order, empty radius → exit 0, additive JSON, human affordance present + JSON unchanged, singular/plural grammar). fmt + clippy -D warnings clean; 48 lib + 58 CLI tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Stage 1 context affordance advertised only the REVERSE direction (blast-radius: who depends on this slice). But retrieval and change-impact pull opposite ways: for finding distributed gold, the relevant direction is usually FORWARD — the code this slice relies on. The xarray-2905 confound made this concrete: the gold's cross-slice file was a forward dependency of the located slice, so a reverse-only affordance could never surface it, and an agent declining the reverse hop was behaving correctly. `slice deps --files` was already bidirectional (it resolves whichever set the --reverse/--transitive flags compute). Only the context affordance was one-directional. Now context emits both factual lines when non-empty: depends-on: N files in M slices this relies on — slice deps <id> --transitive --files blast-radius: N files in M reverse-dep slices — slice deps <id> --reverse --transitive --files Forward listed first (the retrieval-relevant direction). JSON contract unchanged. Test extended to cover both directions across the chain fixture: root (reverse-only), tip (forward-only), middle (both, singular grammar). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…declared coverage `slice outline <file>` enumerates a file's definitions (name + file:line span); `slice symbols <slice>` aggregates them across a slice's files. Both reuse the existing reject-on-ambiguity heuristic via a new `enumerate_symbols` in symbols.rs — no new deps, same point-query spanners walked over every def line. The mandatory honesty constraint (plan §5): every surface declares its coverage — `coverage: N/M definitions spanned`, where M is detected def/class/fn lines and N the ones confidently spanned. Decorators, multi-line signatures, nested functions and tab indent are skipped, not guessed, so a low ratio is a real signal (on xarray: utils.py 82/98, core-utils 114/133). Per the plan, if declared coverage is too low to trust on real repos, that is itself the evidence that would gate an AST backend (Stage 3) — Stage 2's quality ceiling is a Stage 3 trigger. Gate note: the canonical re-baseline showed the binding constraint is read PRECISION, not the AUC nav-tax this stage targets, and that Stage 2's trigger is not cleanly met (nav-tax is negative on deepseek but positive on gpt-5.5). Built at the user's direction with that contradiction on the record; its benchmark value will be measured, not assumed. 52 lib + 60 CLI tests pass; fmt + clippy clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…oggle Swap a Tree-sitter backend in behind symbols.rs's three span operations (enclosing_span, definition_span, enumerate_symbols) — the precision upgrade the module header always anticipated. The heuristic is reject-on-ambiguity (decorators, multi-line signatures, nested functions, tab indent all return None); a real parser has none of those blind spots. Two-layer toggle so the dependency cost is opt-in (keeps invariant #4 — zero heavy deps — intact for the default artifact): - compile-time `ast` Cargo feature: default builds pull zero tree-sitter deps (grammar crates are optional → present in Cargo.lock, never compiled in); `--features ast` compiles the backend. - runtime `SLICE_SYMBOLS=heuristic`: inside an ast build, forces the old path — A/B both backends from one binary, safe field rollback. New src/symbols_ast.rs (Python only — the whole benchmark surface, and where the heuristic's reject cases are densest) dispatches in front of the heuristic inside symbols.rs's public functions. Unsupported languages fall through to the heuristic, so the backend only ever upgrades precision, never regresses. Verified live on examples/mock-repo/src/api/handlers.py: heuristic outline reports 1/3 (skips two decorated route handlers), AST reports 3/3. CLI tests that assert heuristic-specific coverage are feature-gated so both builds stay green and the ast variants double as integration proof of the upgrade. 58 lib (+6) + 60 CLI tests green on both feature configs; fmt + clippy clean with and without --features ast. Built ahead of the §6 gate by explicit direction; the toggle is what makes that safe — OFF by default it costs nothing. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…its (`semantic` feature) First commit of the Stage 4 semantic/hybrid lens: build + persist a staleness-tracked vector index. Query path (find --semantic) lands next. - `Embedder` trait with an `OpenRouterEmbedder` backend (OpenAI-compatible /v1/embeddings, key from OPENROUTER_API_KEY, header-only — never logged). Pluggable so a local/offline backend drops in behind the same interface later (plan §7: ships local-able). - Behind a `semantic` Cargo feature (pulls `ureq`); OFF by default so the shipped binary stays zero-heavy-deps (invariant #4), same toggle pattern as `ast`. - Embeds only slice-ANCHORED units — slice description + each abstraction — never anonymous source chunks (§7 guardrail). Each unit stores its owning slice's content fingerprint (same machinery as DOCS.yaml staleness) so the query path can flag a stale hit rather than silently return it. - `slice semantic-index` builds slices/SEMANTIC.json (provider/model/dims + units). Regenerable artifact → gitignored. Verified live on examples/mock-repo: 11 units across 3 slices, 512-dim vectors via openai/text-embedding-3-small. 55 lib tests (+3); fmt + clippy clean on default, semantic, and ast+semantic. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…k + freshness
The query half of the semantic lens. `slice find <q> --semantic` (feature-gated
flag on find): embed the query with the index's own model, generate candidates
by cosine, then re-rank deterministically and emit anchored hits.
Honors the §7 guardrails exactly:
- Vector score is a CANDIDATE GENERATOR only. Final order is owned by
determinism: fresh-before-stale, then match breadth, then reverse-dep
centrality, with cosine as a tiebreak only (never outranks a deterministic
signal), slice_id for stability.
- Every hit returns slice_id + files (anchor) + freshness + a reason (matched
unit's kind/text + sim score).
- Freshness is real: each hit's owning-slice fingerprint is recomputed and
compared to the value stored at build; a drifted slice is flagged `stale`
and demoted, not silently returned at top.
Verified on examples/mock-repo: an NL query that names no symbol ("how do
users log in and keep a session") surfaces auth-service at #1 (sim 0.68);
after touching an auth file, auth-service is flagged `stale` and drops below
the fresh slices despite still having the highest cosine.
58 lib tests (+3: cosine, rank_cmp ordering, snippet); fmt + clippy clean on
default, semantic, and ast+semantic.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Gemini embeddings top MTEB and are the more current/popular OpenRouter choice; OpenRouter exposes the model OpenAI-compatibly and it honours dimensions:512 identically. Pure default swap — the provider stays pluggable (--model) and any model still works. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Real repos produce many units (xarray: 298) — the old 128-chunk exceeded gemini-embedding's 100-input batch cap and failed the whole index build with a 400. 96 stays under it; OpenAI models allow far more, so it's safe for both. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds the source-code embedding ablation the card-level findings point to: embeddings had only ever been tested on the card surface (where lexical already ties them); the untested arm is the code surface, where keyword (grep) collapses. New `--units` switch on `semantic-index` and `find --semantic`: - cards (default, unchanged): card description + abstractions. - code: one symbol-body chunk per definition (reuses enumerate_symbols), anchored to slice_id + file:line. - code-sliceaug: the SAME chunks, prepended with owning-slice context (slice_id + description + matching abstraction + runtime-flow lines) before embedding. Identical chunking across code/code-sliceaug — only the embedded input text differs — so the A/B isolates the augmentation. Each mode writes its own index file (SEMANTIC[-code|-code-sliceaug].json) so they coexist for comparison. Query aggregates to files for code modes, slices for cards; deterministic rerank + freshness unchanged. Provenance records unit_mode + task_type (null — OpenRouter's Gemini passthrough ignores task_type, verified DOCUMENT==QUERY==none, so all arms are symmetric). Guardrail held: every code unit carries slice_id + file:line, never an anonymous chunk. Behind the `semantic` feature, no new deps. 62 lib tests (+5); fmt + clippy clean on default, semantic, ast+semantic. Verified on examples/mock-repo. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…cument semantic search Code-mode hits now carry the matched symbol's `file:line` anchor in --json (the definition site), so a consumer can read the exact span instead of the file from the top. Cards mode stays slice-level (anchor null). Document `find --semantic` (cards|code units, deterministic rerank, freshness) in docs/navigating.md as the opt-in `semantic`-feature capability it is. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e flow diagram Tracks the three analysis deliverables (force-added past the design/ gitignore; the scratch incorporation-plan stays local): - slice-cli-feature-map.md — every command/feature/flag, grouped by job, with status + FINDINGS line refs; plus the feature-overlap analysis. - idealised-paths.md — not a playbook; the force diagram of what detracts the agent from the ideal path (7 detractors, all pushing toward locate->read->done and away from EXPAND-to-collaborators), with the gradient-flip implications. - idealised-paths-flow.png — the agent path vs the forces: coverage is won/lost at one gate (commit-to-EXPAND); forces push to the early exit, two affordances push to full coverage. These ground the next experiment: flip the two gate affordances (completeness signal + inline collaborators) and re-run the agent A/B before any consolidation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ance test The gate-test (inline collaborators into slice_context) predicted xarray recovers; it went 0.90 -> 0.70 instead. Falsifying fact: base already reads the gold collaborator utils.py 4/5 seeds — never invisible. Banner added so the doc reads as a record of the reasoning, not a live model. Detractors 4/5 (advisory handoffs, overlap) survive; detractor 2 (invisibility) does not. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR expands slice-cli’s navigation surfaces to be more “actionable for agents”: it can now resolve dependency blast radius into concrete files (deps --files), advertises dependency context in context’s human output, and introduces additional opt-in retrieval/structure features (Tree-sitter symbol spans via ast, and embedding-based semantic search via semantic).
Changes:
- Add
deps --filesto emit dependency slices’ collaborator files (and conditionally serialize them in JSON). - Add symbol-orientation commands (
outline,symbols) with declared coverage; introduce an opt-in Tree-sitter AST backend (ast) to improve span precision. - Add opt-in semantic indexing/query (
semantic-index,find --semantic) plus supporting docs/design updates.
Reviewed changes
Copilot reviewed 14 out of 17 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| rust/slice-rs/tests/cli.rs | Adds/updates CLI tests covering deps --files, context affordances, and symbol surfaces (incl. feature-gated AST behavior). |
| rust/slice-rs/src/symbols.rs | Adds AST dispatch + symbol enumeration API while preserving heuristic fallback behavior. |
| rust/slice-rs/src/symbols_ast.rs | Introduces Tree-sitter backend for Python symbol spans under ast feature. |
| rust/slice-rs/src/semantic.rs | Adds semantic indexing + querying implementation under semantic feature. |
| rust/slice-rs/src/models.rs | Extends JSON models (DepsOutput.files) and adds symbol-output structs. |
| rust/slice-rs/src/lib.rs | Wires new feature-gated modules (semantic, symbols_ast). |
| rust/slice-rs/src/error.rs | Adds Embedding error variant under semantic feature. |
| rust/slice-rs/src/commands.rs | Implements deps --files, outline, symbols, and new context human affordance lines. |
| rust/slice-rs/src/cli.rs | Adds new CLI commands/flags and feature-gated semantic options. |
| rust/slice-rs/Cargo.toml | Introduces ast + semantic features and optional deps (tree-sitter*, ureq). |
| rust/slice-rs/Cargo.lock | Locks new optional dependency graph for ast/semantic. |
| docs/navigating.md | Documents deps --files and semantic search usage. |
| docs/agent-workflows.md | Documents context affordance behavior for agent workflows. |
| design/slice-cli-feature-map.md | Adds feature map snapshot describing current surfaces and feature gating. |
| design/idealised-paths.md | Adds analysis doc on “ideal paths” and routing detractors (snapshot). |
| .gitignore | Attempts to ignore generated semantic index artifacts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Greptile SummaryThis PR incorporates Stages 1–4 of the agentic-search plan into
Confidence Score: 5/5Safe to merge — all new surfaces are behind opt-in feature flags or additive to existing commands, and the default binary is unchanged. All new functionality is gated behind the No files require special attention for merge safety. Important Files Changed
Sequence DiagramsequenceDiagram
participant Agent
participant CLI as slice CLI
participant Semantic as semantic.rs
participant Commands as commands.rs
participant Index as SEMANTIC.json
participant OR as OpenRouter API
participant Slices as slices/*.md
Note over Agent,Slices: slice locate (composite discovery path)
Agent->>CLI: slice locate "how does auth work"
CLI->>Semantic: locate(ctx, needle, json, styles, top)
Semantic->>Index: "load_index(Code) -> SemanticIndex"
Semantic->>OR: "embed_query(needle) -> qvec"
Semantic->>Slices: load_slice_docs() [inside ranked_hits]
Semantic->>Semantic: "cosine candidates -> deterministic re-rank"
Semantic->>Slices: load_slice_docs() [again for card_match]
Semantic->>Semantic: "card_match(docs, needle) -> disagreement check"
Semantic-->>Agent: file:line anchors + optional CHECK warning
Note over Agent,Slices: slice deps --files (blast-radius discovery)
Agent->>CLI: slice deps auth --reverse --transitive --files
CLI->>Commands: "deps(ctx, auth, reverse=true, transitive=true, files=true)"
Commands->>Slices: load_slice_docs_meta()
Commands->>Commands: "transitive_reverse_deps() -> dep ids (BFS order)"
Commands->>Commands: "collaborator_files() -> expand globs, dedup, attribute"
Commands-->>Agent: file TAB slice_id rows (nearest collaborator first)
Note over Agent,Slices: slice outline / symbols (orientation surface)
Agent->>CLI: slice outline src/auth.py
CLI->>Commands: outline(ctx, file)
Commands->>Commands: enumerate_symbols() [AST or heuristic]
Commands-->>Agent: file:start-end TAB name + coverage N/M
Reviews (7): Last reviewed commit: "fix: expand glob files: entries in deps ..." | Re-trigger Greptile |
Eng-review + Codex outside-voice pass over the agent-facing tool-surface consolidation, plus two follow-up rounds folding in measurement and implementation-fidelity findings. Supersedes the pre-review draft. Key decisions: Phase 1 is output-preserving consolidation only (net-new behaviour deferred to a gated Phase 1b); a Phase 0.5 trajectory-confusion gate must pass before any build; Phase 3 runs a v1+grep control arm with pre-registered stats; V2_RETRIEVAL_TOOLS (no freshness) registers in the A/B. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The benchmark-validated path (semantic top hits as read-ready file:line anchors + read-now framing + card-description disagreement CHECK) baked into the binary, so agent guidance shrinks to one line. Behind the semantic feature; falls back to the code-sliceaug index; --top/--json. The CHECK is disagreement-based, not a score threshold — measured: embedding misses carry top-of-board similarities, so the card match (which catches them at rank 1) is the only deterministic detector. Shares the candidate->rank pipeline with find --semantic (extracted ranked_hits). Docs: navigating.md locate section; setup.md agent-guidance one-liner. CLAUDE.md: fix the stale design/ description (committed, not gitignored), add symbols/semantic module-map rows, drop the Python-history note (git history carries it). 64 lib + 52 CLI tests pass; fmt + clippy -D warnings clean; live-smoked on the flask checkout (correct top-1 anchors; CHECK fires advisorily). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
README: feature-flag install paths (semantic / ast) with their runtime needs; core-commands table gains grep --symbols, outline/symbols, locate, semantic-index, deps --files. setup.md: feature flags in the install section; semantic-index build step (with the rebuild-after-reslicing note) in repo setup. agent-workflows.md: search table covers the scoped-grep and locate paths with the read-anchors-first guidance. Complements the earlier navigating.md/setup-block locate additions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tep to both flows Slice cards carry per-slice fingerprints into SEMANTIC*.json units; regenerating or diff-updating cards makes locate/find --semantic flag every hit stale. Both the full generation and diff-update flows now end with the rebuild (or a tell-the-user note when the binary lacks the semantic feature). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@greptile review |
…/ as local scratch Greptile flagged that .gitignore ignored design/ while four files were force-tracked there and CLAUDE.md described it as committed — so any new file dropped into design/ would be silently ignored. Move the four published records (feature map, idealised-paths + flow png, consolidation-plan v2) to the tracked docs/design/, depth-correcting their relative links. design/ stays gitignored for local planning scratch, and the ignore is now root-anchored (/design/) so nested design dirs aren't swept up. CLAUDE.md updated to match. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@greptile review |
Address Copilot review on PR #17: - collaborator_files iterated doc.files verbatim, so a slice whose files: is a glob leaked the raw pattern through `deps --files` and miscounted the depends-on:/blast-radius: affordance. Thread ctx and expand each entry via expand_literal_or_existing so output stays file-level; non-glob entries pass through unchanged. Adds a CLI regression test for glob expansion. - navigating.md: semantic re-rank uses reverse-dependency count (fan-in), not "distance" — corrected. - agent-workflows.md: document the depends-on: affordance line alongside blast-radius: (context prints both directions). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@greptile review |
Stages 1-4 of the agentic-search incorporation plan plus the productized outcome of the
benchmark campaign (evidence trail: slice-cli-benchmark
stage1-bench-and-index, FINDINGS.md).deps --filescollaborator-file discovery + bidirectionaldepends-on:/blast-radius:context affordances.outline/symbolsorientation surfaces (the one addition the loop A/Bs validated).--features ast(correctness upgrade; off by default).find --semanticbehind--features semantic, code/cards/code-sliceaug unit modes.slice locate: the benchmark-validated composite discovery path as one command — semantic top hits as read-readyfile:lineanchors + a deterministic card-match disagreement CHECK (embedding misses are confidently wrong, never low-scored). Cross-model validated: 100% adoption at call 1 on three model families.Tests: 64 lib + 52 CLI pass; fmt + clippy -D warnings clean on both feature sets.
🤖 Generated with Claude Code