find_callers returns a first page of pure noise on high-ref names, and the filter its own description prescribes does not exist #141

Closed
opened 2026-09-05 12:52:54 +02:00 by buildagent · 0 comments
Member

Found by a production-readiness review against the live v0.26.1 daemon on this repo. This is on the most-used tool, needs no upgrade, no large repo and no unusual environment.

Measured, live

find_callers on ReadPool::get (crates/daemon/src/read_pool.rs:77), default limit: 50, exclude_tests: true:

total: 823, total_resolved: 360
page_rows: 50, page_resolved: 0, page_name_fallback: 50

All 50 rows are EXTRACT_DIAGNOSTICS.get(i), SYMBOL_KINDS.get(..), cols.get(&end). Not one is a call to the symbol asked about. The 360 real callers live in crates/daemon/ and sort after crates/abi/ and crates/cli/ because the query is ORDER BY f.path, r.start_line (crates/daemon/src/local_index.rs:3039) — resolution-blind ordering.

The interface gap

The shipped description (crates/mcp-server/src/server.rs:9101) says:

filter on resolution == "resolved" for high-confidence hits.

FindCallersArgs (server.rs:3066) has symbol_id, exclude_tests, limit, cursor, project, response_format. There is no such parameter. find_references has none either. The server computes page_resolved at server.rs:7406 — it knows the page is useless — and offers no way to ask for the useful rows.

This is the #138 shape at the API level: the description names an action the interface cannot perform.

Why it is worse than it looks

Three of the ten symbols project_overview puts in top_referenced_symbols are in this class (get 388, len 255, path 211). The orientation tool actively steers agents into it. It costs ~2,400 tokens to return zero information, which inverts the product's core claim — rg 'pool\.get(' is strictly better here. And an agent under budget pressure reads snippets, not resolution fields.

Calibration — the tool is not broadly broken

On distinctive names it is clean: tool_body 233 refs / 0 fallback; classify_walked 6/6 resolved with a correct in_test split. The defect is scoped to short stdlib-colliding names — which is precisely the set with the highest ref counts, i.e. the ones people ask about.

Two things to fix, and they are separable

  1. The missing parameter. Either add the resolution filter the description promises, or change the description. Adding it is right — page_resolved is already computed.
  2. The ordering. ORDER BY f.path is resolution-blind. Resolved rows should not sort after name-fallback noise on the first page. Whatever is chosen must keep the cursor stable (see #127).

Do not fix this by dropping name_fallback rows — they are honest and some are wanted. The defect is that the caller cannot express which set they want.

  • #120 (the "10x less context" claim) — this is a concrete case where the tool costs more than ripgrep and returns less.
  • #111 (startup payload categories).
  • #127 (cursor epochs) — any ordering change interacts with cursor stability.

🤖 Generated with Claude Code

https://claude.ai/code/session_01K1zj5VcFJvJt3pQxe9259K

Found by a production-readiness review against the live v0.26.1 daemon on this repo. This is on the most-used tool, needs no upgrade, no large repo and no unusual environment. ## Measured, live `find_callers` on `ReadPool::get` (`crates/daemon/src/read_pool.rs:77`), default `limit: 50`, `exclude_tests: true`: ``` total: 823, total_resolved: 360 page_rows: 50, page_resolved: 0, page_name_fallback: 50 ``` All 50 rows are `EXTRACT_DIAGNOSTICS.get(i)`, `SYMBOL_KINDS.get(..)`, `cols.get(&end)`. Not one is a call to the symbol asked about. The 360 real callers live in `crates/daemon/` and sort after `crates/abi/` and `crates/cli/` because the query is `ORDER BY f.path, r.start_line` (`crates/daemon/src/local_index.rs:3039`) — **resolution-blind ordering**. ## The interface gap The shipped description (`crates/mcp-server/src/server.rs:9101`) says: > filter on `resolution == "resolved"` for high-confidence hits. `FindCallersArgs` (`server.rs:3066`) has `symbol_id`, `exclude_tests`, `limit`, `cursor`, `project`, `response_format`. **There is no such parameter.** `find_references` has none either. The server computes `page_resolved` at `server.rs:7406` — it knows the page is useless — and offers no way to ask for the useful rows. This is the #138 shape at the API level: the description names an action the interface cannot perform. ## Why it is worse than it looks Three of the ten symbols `project_overview` puts in `top_referenced_symbols` are in this class (`get` 388, `len` 255, `path` 211). **The orientation tool actively steers agents into it.** It costs ~2,400 tokens to return zero information, which inverts the product's core claim — `rg 'pool\.get('` is strictly better here. And an agent under budget pressure reads snippets, not `resolution` fields. ## Calibration — the tool is not broadly broken On distinctive names it is clean: `tool_body` 233 refs / 0 fallback; `classify_walked` 6/6 resolved with a correct `in_test` split. The defect is scoped to short stdlib-colliding names — **which is precisely the set with the highest ref counts**, i.e. the ones people ask about. ## Two things to fix, and they are separable 1. **The missing parameter.** Either add the `resolution` filter the description promises, or change the description. Adding it is right — `page_resolved` is already computed. 2. **The ordering.** `ORDER BY f.path` is resolution-blind. Resolved rows should not sort after name-fallback noise on the first page. Whatever is chosen must keep the cursor stable (see #127). Do not fix this by dropping `name_fallback` rows — they are honest and some are wanted. The defect is that the caller cannot express which set they want. ## Related - #120 (the "10x less context" claim) — this is a concrete case where the tool costs more than ripgrep and returns less. - #111 (startup payload categories). - #127 (cursor epochs) — any ordering change interacts with cursor stability. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01K1zj5VcFJvJt3pQxe9259K
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.

Dependencies

No dependencies set

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