Agents still need shell fallbacks to finish code investigation and review #555

Open
opened 2026-11-09 12:29:10 +01:00 by buildagent · 3 comments
Member

Scope (consolidated 2026-11-12)

An agent should be able to investigate indexed code and review a change without switching to shell source inspection. Wrong answers, unavailable workflows, reply cost and lifecycle delays can each force that switch. This ticket owns the goal and its measurements; implementation belongs to the linked canonical tickets. Every remaining fallback must have a recorded tool call, cost and filed gap.

Priority: High · Risk: wrong answer · Size: L
Merged into this ticket: #556 (Fallback metric and task benchmark)

Done

  • Root routing and daemon lifetime have regression tests: worktree_git_file_beats_outer_config in crates/indexer/src/project.rs and daemon_survives_spawning_client_group_signal in crates/mcp-server/tests/mcp_smoke.rs.
  • Bounded handshake and rollback controls are in twenty_clients_attach_with_every_read_connection_held, crates/daemon/tests/handshake_saturation_e2e.rs, and failed_commit_rolls_back_and_the_connection_can_commit_durably, crates/indexer/tests/owned_transaction.rs.
  • The transcript classifier in crates/indexer/tests/fallback_rate.rs uses production coverage and separates foreign/non-code/ambiguous calls; its git-log control is at line 643 (e5467bfb/be13b777).
  • Session-envelope and historical-read/hunk mechanisms exist in crates/mcp-server/tests/tool_ux_e3_e2e.rs and mcp_smoke.rs; their remaining workflow acceptance is in #521.

Remaining

Fallback measurement

  • Reduce ambiguous transcript cases and qualify the full archived calibration, preserving indexed/foreign/non-code boundaries. (#556)

Workflow benchmark

  • Add review-a-diff, value-use caller, foreign-checkout bind verification and concept-location tasks with calls/tokens/correctness versus shell and recorded ceilings. (#556)
  • Prove ≤5% indexed-code fallback and tokens ≤shell; file every residual class rather than infer success from delivered mechanisms. (#555)

Linked delivery and trust

  • Track wrong-target and missing-use work in #531/#536/#540, reply/discovery/review gaps in #521, foreign read-only attach in #559 and optional adoption hook in #571; retain not-ready-versus-absent settlement evidence. (#555)

Acceptance

  • On the agent task benchmark, indexed-code fallback rate is ≤5%, tokens per completed task are ≤ the shell baseline, and every remaining fallback class has a filed issue.
  • Archived-session calibration reproduces hand-labelled fallback cases; git-log and foreign-class mutations fail. Publish per-task calls, tokens, correctness and enforced code-index call ceilings.

Suggested order

  1. Finish classifier calibration and benchmark coverage first; no package release or bind account needed.
  2. Use the measurements to qualify trust/capability work in #531/#536/#540/#521/#559; those tickets specify package releases and bind accounts.
  3. Measure adoption channels under #571 only after the operator chooses scope; host experiment, no bind change intended.

Original report

Epic: zero fallback. No agent should want to switch back from code-index to the shell

Goal: an agent working on code reaches for code-index first and never needs grep/rg/sed/cat/git show on indexed code. Where it still does, that fallback is a measured, filed gap, not a habit.

Why now: on 2026-11-09, five implementation sessions (Claude lead + Codex workers) dogfooded code-index on this repo and logged every friction (/tmp/claude-1000/dogfood-triage.md, summarised in #521 comments). Even the lead, who required code-index from every worker, fell back to the shell for diff review and corpus reads. Asked why, the answers were product gaps, not preferences.

Why agents switch back (four causes, all observed 2026-11-09)

Cause Evidence Result
1. Trust broken once #553 wrong tree served silently; symbol_not_found/path_not_indexed/never during reconcile (#546); std flush bound into another test crate (#531) one silent wrong answer, and the agent verifies everything by grep for the rest of the session
2. Cannot answer no before/after hunk view; no ad-hoc directory; OR queries lose the line census; no path-glob list; no outline name filter (#521) the shell is the only route, and the habit sticks
3. Too expensive every reply repeats long semantics strings, evidence_gaps and answer_provenance for every linked tree (roughly 1 KB fixed per reply with 6 trees, observed); ~15k-token tools/list (#521); grep -n gives line+text in one call, search_text only with line_text=true the shell is cheaper per answer, so switching is rational
4. Too slow or unstable daemon SIGTERMed with its spawner → respawn + full reconcile (#554, 3× in one day); cold query --root 5–60 s waiting costs more than grep

Plan (order matters)

  1. Measure first: the fallback-rate metric (sub-issue). Without it nothing below can be shown to work.
  2. Trust: #553 (fixed on integration-1109), #554 (in progress), #531, #546's "not ready ≠ absent" item.
  3. Reply diet: cause 3 (sub-issue). Expected to be the biggest lever.
  4. Capability gaps: before/after hunks (sub-issue); ad-hoc attach (sub-issue); the #521 friction list.
  5. Catch the habit: a shell interception hook (sub-issue).

Acceptance for the epic

On the agent task benchmark (sub-issue 1), the fallback rate on indexed code is ≤ 5% of code lookups, and every remaining fallback class has a filed issue. Tokens per completed task are ≤ the shell baseline.

Rule for every agent working in this repo

Use code-index first for anything about code. When you fall back to the shell, log the exact call, why, and what code-index should have done, and link it here or in #521. A fallback without a log entry is the only wrong move.

## Scope (consolidated 2026-11-12) An agent should be able to investigate indexed code and review a change without switching to shell source inspection. Wrong answers, unavailable workflows, reply cost and lifecycle delays can each force that switch. This ticket owns the goal and its measurements; implementation belongs to the linked canonical tickets. Every remaining fallback must have a recorded tool call, cost and filed gap. **Priority:** High · **Risk:** wrong answer · **Size:** L **Merged into this ticket:** #556 (Fallback metric and task benchmark) ## Done - Root routing and daemon lifetime have regression tests: `worktree_git_file_beats_outer_config` in `crates/indexer/src/project.rs` and `daemon_survives_spawning_client_group_signal` in `crates/mcp-server/tests/mcp_smoke.rs`. - Bounded handshake and rollback controls are in `twenty_clients_attach_with_every_read_connection_held`, `crates/daemon/tests/handshake_saturation_e2e.rs`, and `failed_commit_rolls_back_and_the_connection_can_commit_durably`, `crates/indexer/tests/owned_transaction.rs`. - The transcript classifier in `crates/indexer/tests/fallback_rate.rs` uses production coverage and separates foreign/non-code/ambiguous calls; its git-log control is at line 643 (e5467bfb/be13b777). - Session-envelope and historical-read/hunk mechanisms exist in `crates/mcp-server/tests/tool_ux_e3_e2e.rs` and `mcp_smoke.rs`; their remaining workflow acceptance is in #521. ## Remaining ### Fallback measurement - Reduce ambiguous transcript cases and qualify the full archived calibration, preserving indexed/foreign/non-code boundaries. (#556) ### Workflow benchmark - Add review-a-diff, value-use caller, foreign-checkout bind verification and concept-location tasks with calls/tokens/correctness versus shell and recorded ceilings. (#556) - Prove ≤5% indexed-code fallback and tokens ≤shell; file every residual class rather than infer success from delivered mechanisms. (#555) ### Linked delivery and trust - Track wrong-target and missing-use work in #531/#536/#540, reply/discovery/review gaps in #521, foreign read-only attach in #559 and optional adoption hook in #571; retain not-ready-versus-absent settlement evidence. (#555) ## Acceptance - On the agent task benchmark, indexed-code fallback rate is ≤5%, tokens per completed task are ≤ the shell baseline, and every remaining fallback class has a filed issue. - Archived-session calibration reproduces hand-labelled fallback cases; git-log and foreign-class mutations fail. Publish per-task calls, tokens, correctness and enforced code-index call ceilings. ## Suggested order 1. Finish classifier calibration and benchmark coverage first; no package release or bind account needed. 2. Use the measurements to qualify trust/capability work in #531/#536/#540/#521/#559; those tickets specify package releases and bind accounts. 3. Measure adoption channels under #571 only after the operator chooses scope; host experiment, no bind change intended. ## Original report # Epic: zero fallback. No agent should want to switch back from code-index to the shell **Goal:** an agent working on code reaches for code-index first and never needs `grep`/`rg`/`sed`/`cat`/`git show` on indexed code. Where it still does, that fallback is a measured, filed gap, not a habit. **Why now:** on 2026-11-09, five implementation sessions (Claude lead + Codex workers) dogfooded code-index on this repo and logged every friction (`/tmp/claude-1000/dogfood-triage.md`, summarised in #521 comments). Even the lead, who required code-index from every worker, fell back to the shell for diff review and corpus reads. Asked why, the answers were product gaps, not preferences. ## Why agents switch back (four causes, all observed 2026-11-09) | Cause | Evidence | Result | |---|---|---| | **1. Trust broken once** | #553 wrong tree served silently; `symbol_not_found`/`path_not_indexed`/`never` during reconcile (#546); std `flush` bound into another test crate (#531) | one silent wrong answer, and the agent verifies everything by grep for the rest of the session | | **2. Cannot answer** | no before/after hunk view; no ad-hoc directory; OR queries lose the line census; no path-glob list; no outline name filter (#521) | the shell is the only route, and the habit sticks | | **3. Too expensive** | every reply repeats long `semantics` strings, `evidence_gaps` and `answer_provenance` for every linked tree (roughly 1 KB fixed per reply with 6 trees, observed); ~15k-token tools/list (#521); `grep -n` gives line+text in one call, `search_text` only with `line_text=true` | the shell is cheaper per answer, so switching is rational | | **4. Too slow or unstable** | daemon SIGTERMed with its spawner → respawn + full reconcile (#554, 3× in one day); cold `query --root` 5–60 s | waiting costs more than grep | ## Plan (order matters) 1. **Measure first:** the fallback-rate metric (sub-issue). Without it nothing below can be shown to work. 2. **Trust:** #553 (fixed on `integration-1109`), #554 (in progress), #531, #546's "not ready ≠ absent" item. 3. **Reply diet:** cause 3 (sub-issue). Expected to be the biggest lever. 4. **Capability gaps:** before/after hunks (sub-issue); ad-hoc attach (sub-issue); the #521 friction list. 5. **Catch the habit:** a shell interception hook (sub-issue). ## Acceptance for the epic On the agent task benchmark (sub-issue 1), the fallback rate on indexed code is ≤ 5% of code lookups, and every remaining fallback class has a filed issue. Tokens per completed task are ≤ the shell baseline. ## Rule for every agent working in this repo Use code-index first for anything about code. When you fall back to the shell, log the exact call, why, and what code-index should have done, and link it here or in #521. **A fallback without a log entry is the only wrong move.**
Author
Member

Tracking (filed 2026-11-09)

  • #556 fallback-rate metric + agent task benchmark (first)
  • #553 wrong tree served silently (fixed on integration-1109)
  • #554 daemon dies with its spawner (in progress)
  • #531 wrong binds (incl. the tier3_import_boost cross-crate field case)
  • #546 "not ready" must not read as "absent"
  • #557 reply diet
  • #558 before/after hunks, read_code rev=
  • #559 ad-hoc project attach
  • #560 shell interception hook
  • #521 friction list (worktree gaps 3–5, OR-query census, path_glob list, outline filter, find_callers value-use hint)
## Tracking (filed 2026-11-09) - [ ] #556 fallback-rate metric + agent task benchmark (**first**) - [ ] #553 wrong tree served silently (fixed on `integration-1109`) - [ ] #554 daemon dies with its spawner (in progress) - [ ] #531 wrong binds (incl. the tier3_import_boost cross-crate field case) - [ ] #546 "not ready" must not read as "absent" - [ ] #557 reply diet - [ ] #558 before/after hunks, `read_code rev=` - [ ] #559 ad-hoc project attach - [ ] #560 shell interception hook - [ ] #521 friction list (worktree gaps 3–5, OR-query census, path_glob list, outline filter, find_callers value-use hint)
Author
Member

Baseline measured (#556 part 1, details there): lead session 30.6% fallback rate on indexed code, top shapes sed -n/grep -n/git show/git diff. Workers on the wrong tree (#553): up to 66.7%. Workers after the --root fix: 0–4.2%. So trust/routing and the reviewer workflow (#558, #559) are the levers. #553, #554 and #512 B are now fixed on integration-1109.

Baseline measured (#556 part 1, details there): lead session **30.6%** fallback rate on indexed code, top shapes `sed -n`/`grep -n`/`git show`/`git diff`. Workers on the wrong tree (#553): up to 66.7%. Workers after the `--root` fix: **0–4.2%**. So trust/routing and the reviewer workflow (#558, #559) are the levers. #553, #554 and #512 B are now fixed on `integration-1109`.
Author
Member

Dogfood from the C# recorded-base regression investigation in codex-base (integration snapshot e142099484f0). Full per-call findings below; corpus fallbacks reproduce known ad-hoc-root gap #559.

D1 Setup provenance does not name the root

  • call: index_coverage({"path":"crates/indexer/tests/corpus_bind_diff.rs"})
  • expected: answer_provenance.indexed_trees.primary names this worktree
  • got: primary has head e142099484 and sibling_worktrees 3, no path; tool description names the correct codex-base root
  • cost: extra project_overview call, same omission
  • suggestion: include absolute root in setup provenance

D2 Read refused during reconcile

  • call: read_code({"target":"crates/indexer/tests/corpus_bind_diff.rs:1-160","envelope":"minimal"})
  • expected: source range
  • got: path_not_indexed while index_coverage said pending/index_reconciling
  • cost: retried successfully, no shell fallback
  • suggestion: wait briefly for pending eligible file before refusing

D3 Corpus source outside roots (#559)

  • call: read_code({"target":["/tmp/claude-1000/codex-acct/cs-dapper/source/Dapper/SqlMapper.Identity.cs:1-105","/tmp/claude-1000/codex-acct/cs-dapper/source/Dapper.Rainbow/SqlCompactDatabase.cs:1-55"],"envelope":"minimal"})
  • expected: audit source ranges in staged corpus
  • got: path_outside_known_roots for both
  • cost: shell range reads required
  • suggestion: support explicit read-only ad-hoc corpus roots; linked to #555 and #559

D4 Short-term search is not searched

  • call: search_text({"query":["expect_resolved","::"],"path_glob":"crates/daemon/tests/precision_gate.rs","limit":2,"max_lines_per_file":10,"envelope":"minimal","response_format":"concise"})
  • expected: caller selector format
  • got: text_scan.reliable=false, total_basis=not_searched for ::
  • cost: no fallback; used longer terms and source range instead
  • suggestion: reject short-only queries before executing with a direct actionable error

D5 + Exact regression path located cheaply

  • call: search_text({"query":["proven","supertype"],"path_glob":"crates/indexer/src/index/*","limit":20,"envelope":"minimal","response_format":"concise"})
  • expected: the member lookup base proof code
  • got: inherited_members.rs and member_lookup.rs with matching line lists
  • cost: one batched search followed by bounded read_code ranges, no shell
  • suggestion: retain per-file line lists in concise mode

D6 Corpus bind audit requires ad-hoc reads (#559)

  • call: read_code({"target":["/tmp/claude-1000/codex-base/after-cs-dapper/source/Dapper.Rainbow/Database.cs:30-52","/tmp/claude-1000/codex-base/after-cs-dapper/source/Dapper.Rainbow/Database.cs:112-140"],"envelope":"minimal"})
  • expected: target declarations for all three added binds
  • got: path_outside_known_roots
  • cost: shell bounded source reads; two extra ranges
  • suggestion: explicit ad-hoc read root; linked to #555 and #559

D7 Corpus containing types outside roots (#559)

  • call: read_code({"target":"/tmp/claude-1000/codex-base/after-cs-dapper/source/Dapper.Rainbow/Database.cs:1-30","envelope":"minimal"})
  • expected: containing type chain for bind audit
  • got: path_outside_known_roots
  • cost: shell read of first 30 lines
  • suggestion: explicit ad-hoc read root; linked to #555 and #559

D8 Guessed metadata paths cost extra calls

  • call: read_code({"target":["crates/indexer/src/index/inherited_members.rs:290-520","crates/indexer/tests/corpus/shipped.rs:1-100","crates/indexer/tests/corpus.rs:1-10"],"envelope":"minimal"}); read_code({"target":["crates/indexer/src/index/inherited_members.rs:111-159","crates/indexer/tests/corpus.toml:1-30"],"envelope":"minimal"})
  • expected: corpus support and manifest
  • got: file_not_readable for guessed paths; actual paths were corpus/mod.rs and tests/corpus/corpus.toml
  • cost: extra calls, no fallback
  • suggestion: offer closest indexed path candidates in file_not_readable

D9 Struct/impl name ambiguous in impact

  • call: change_impact({"symbol_ids":["BaseLookup"],"limit":0,"max_depth":1,"envelope":"minimal","response_format":"concise"})
  • expected: impact of the new lookup implementation
  • got: ambiguous_symbol with struct and impl candidates
  • cost: one retry using the supplied path_line
  • suggestion: offer an explicit same-file declaration-group seed option
Dogfood from the C# recorded-base regression investigation in `codex-base` (integration snapshot `e142099484f0`). Full per-call findings below; corpus fallbacks reproduce known ad-hoc-root gap #559. ## D1 Setup provenance does not name the root - call: index_coverage({"path":"crates/indexer/tests/corpus_bind_diff.rs"}) - expected: answer_provenance.indexed_trees.primary names this worktree - got: primary has head e142099484f0 and sibling_worktrees 3, no path; tool description names the correct codex-base root - cost: extra project_overview call, same omission - suggestion: include absolute root in setup provenance ## D2 Read refused during reconcile - call: read_code({"target":"crates/indexer/tests/corpus_bind_diff.rs:1-160","envelope":"minimal"}) - expected: source range - got: path_not_indexed while index_coverage said pending/index_reconciling - cost: retried successfully, no shell fallback - suggestion: wait briefly for pending eligible file before refusing ## D3 Corpus source outside roots (#559) - call: read_code({"target":["/tmp/claude-1000/codex-acct/cs-dapper/source/Dapper/SqlMapper.Identity.cs:1-105","/tmp/claude-1000/codex-acct/cs-dapper/source/Dapper.Rainbow/SqlCompactDatabase.cs:1-55"],"envelope":"minimal"}) - expected: audit source ranges in staged corpus - got: path_outside_known_roots for both - cost: shell range reads required - suggestion: support explicit read-only ad-hoc corpus roots; linked to https://git.h-dv.de/h-dv/code-index/issues/555 and #559 ## D4 Short-term search is not searched - call: search_text({"query":["expect_resolved","::"],"path_glob":"crates/daemon/tests/precision_gate.rs","limit":2,"max_lines_per_file":10,"envelope":"minimal","response_format":"concise"}) - expected: caller selector format - got: text_scan.reliable=false, total_basis=not_searched for :: - cost: no fallback; used longer terms and source range instead - suggestion: reject short-only queries before executing with a direct actionable error ## D5 + Exact regression path located cheaply - call: search_text({"query":["proven","supertype"],"path_glob":"crates/indexer/src/index/*","limit":20,"envelope":"minimal","response_format":"concise"}) - expected: the member lookup base proof code - got: inherited_members.rs and member_lookup.rs with matching line lists - cost: one batched search followed by bounded read_code ranges, no shell - suggestion: retain per-file line lists in concise mode ## D6 Corpus bind audit requires ad-hoc reads (#559) - call: read_code({"target":["/tmp/claude-1000/codex-base/after-cs-dapper/source/Dapper.Rainbow/Database.cs:30-52","/tmp/claude-1000/codex-base/after-cs-dapper/source/Dapper.Rainbow/Database.cs:112-140"],"envelope":"minimal"}) - expected: target declarations for all three added binds - got: path_outside_known_roots - cost: shell bounded source reads; two extra ranges - suggestion: explicit ad-hoc read root; linked to https://git.h-dv.de/h-dv/code-index/issues/555 and #559 ## D7 Corpus containing types outside roots (#559) - call: read_code({"target":"/tmp/claude-1000/codex-base/after-cs-dapper/source/Dapper.Rainbow/Database.cs:1-30","envelope":"minimal"}) - expected: containing type chain for bind audit - got: path_outside_known_roots - cost: shell read of first 30 lines - suggestion: explicit ad-hoc read root; linked to https://git.h-dv.de/h-dv/code-index/issues/555 and #559 ## D8 Guessed metadata paths cost extra calls - call: read_code({"target":["crates/indexer/src/index/inherited_members.rs:290-520","crates/indexer/tests/corpus/shipped.rs:1-100","crates/indexer/tests/corpus.rs:1-10"],"envelope":"minimal"}); read_code({"target":["crates/indexer/src/index/inherited_members.rs:111-159","crates/indexer/tests/corpus.toml:1-30"],"envelope":"minimal"}) - expected: corpus support and manifest - got: file_not_readable for guessed paths; actual paths were corpus/mod.rs and tests/corpus/corpus.toml - cost: extra calls, no fallback - suggestion: offer closest indexed path candidates in file_not_readable ## D9 Struct/impl name ambiguous in impact - call: change_impact({"symbol_ids":["BaseLookup"],"limit":0,"max_depth":1,"envelope":"minimal","response_format":"concise"}) - expected: impact of the new lookup implementation - got: ambiguous_symbol with struct and impl candidates - cost: one retry using the supplied path_line - suggestion: offer an explicit same-file declaration-group seed option
buildagent changed title from Epic: zero fallback — no agent should want to switch back from code-index to the shell to Agents still need shell fallbacks to finish code investigation and review 2026-11-12 22:22:53 +01:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
h-dv/code-index#555
No description provided.