You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Query matching is lexical, and a miss never says so. A query is tokenized and every token is OR-prefix-matched against symbol name / qualified name / signature / docstring (bm25(nodes_fts, 0, 20, 5, 1, 2), src/db/queries.ts), with a LIKE-substring pass, a bounded-edit-distance name pass, and a word→identifier-segment lookup (name_segment_vocab) on top. A natural-language question therefore works exactly as far as its words overlap text the index holds — and when none of them do, the whole response is:
No relevant code found for "<query>"
The caller cannot distinguish this codebase has no such concept from your words differ from the code's words, and it is handed no vocabulary to retry with. The next move is Read/Grep — the fallback this tool exists to prevent.
$ codegraph explore "how do we stop users signing up too fast"
No relevant code found for"how do we stop users signing up too fast"
$ codegraph query "signup throttle"
ℹ No results found for"signup throttle"# the same shape works whenever the words DO overlap identifiers:
$ codegraph query "how do we register a new user account"
method create_account
src/users.py:3
# one literal token rescues an otherwise-synonym query:
$ codegraph explore "throttle signup limit"
→ 2 symbols, matched on the word `limit`in`check_limit`
Nothing is graded or labeled. An exact identifier scores 94.6, a synonym query's lone file-node hit 17.6, and both render as plain positive results.
Proposal — reuse the response shape the tool already has
Report which query tokens occur anywhere in the index (name / signature / docstring / segment vocab) and which do not — e.g. signup, throttle: absent; limit: 1 symbol name.
When at least one token exists, return up to ~8 candidate names for those tokens (segment vocab + searchNodes + fuzzy fallback), labeled as candidates, not answers.
When no token exists, say that in those words — "none of these words appear in any indexed name, signature, comment, or path" — and name the likely cause. Optionally list the project's most central indexed symbols so the caller can orient.
State the contract in one line: names, file names and code terms match; prose matches where it is a leading comment or docstring.
Precedent for the shape: a missing symbol name already answers with > **Note:** no symbol named "X". Did you mean: A, B? (src/graph/named-symbol-flow.ts), and the CLI prints Symbol "X" not found — did you mean: …?. This is the same treatment one level up, at the query. Success-shaped response, no isError, no instruction/description text.
Relationship to existing reports
This closes none of them — the root causes are different, verified: #1642 is an index shortfall (the default build/ ignore hides Java package paths), #1372 is the ASCII-only query splitter dropping pure-CJK terms (PR #1377), #1830 is the false-positive path (a path-shaped token treated as free text), and #1831/#1836 is a different surface (node's file-not-indexed message). They are all one family though: a miss and a real absence are byte-identical, and no response names its own cause. This is the query-level half of that family.
Concept
Query matching is lexical, and a miss never says so. A query is tokenized and every token is OR-prefix-matched against symbol name / qualified name / signature / docstring (
bm25(nodes_fts, 0, 20, 5, 1, 2),src/db/queries.ts), with a LIKE-substring pass, a bounded-edit-distance name pass, and a word→identifier-segment lookup (name_segment_vocab) on top. A natural-language question therefore works exactly as far as its words overlap text the index holds — and when none of them do, the whole response is:The caller cannot distinguish this codebase has no such concept from your words differ from the code's words, and it is handed no vocabulary to retry with. The next move is Read/Grep — the fallback this tool exists to prevent.
Repro (1.6.0; one temp project, 5 symbols)
src/users.py:RegistrationService.create_account,RateLimiter.check_limit—src/orders.py:OrderStateMachine.transition,cancel_orderWhy the miss has exactly this shape
"state"*,"machine"*,"pressure"*,"backpressure"*match nothing, even whereOrderStateMachine/applyBackpressureare indexed andname_segment_vocabholds those very segments. (See FTS retrieval quality: camelCase sub-word recall, column-weighted bm25, path filtering, dedupe #1520; PR feat(search): surface camelCase symbols via segment vocab (#1520) #1530 extends that path.)"i"*alone matches 3 nodes, viaorder_idandin. (Bears on Prioritize precise matching over fuzzy matching or prefix matching #1455.)Proposal — reuse the response shape the tool already has
signup,throttle: absent;limit: 1 symbol name.searchNodes+ fuzzy fallback), labeled as candidates, not answers.Precedent for the shape: a missing symbol name already answers with
> **Note:** no symbol named "X". Did you mean: A, B?(src/graph/named-symbol-flow.ts), and the CLI printsSymbol "X" not found — did you mean: …?. This is the same treatment one level up, at the query. Success-shaped response, noisError, no instruction/description text.Relationship to existing reports
This closes none of them — the root causes are different, verified: #1642 is an index shortfall (the default
build/ignore hides Java package paths), #1372 is the ASCII-only query splitter dropping pure-CJK terms (PR #1377), #1830 is the false-positive path (a path-shaped token treated as free text), and #1831/#1836 is a different surface (node's file-not-indexed message). They are all one family though: a miss and a real absence are byte-identical, and no response names its own cause. This is the query-level half of that family.