feat(query): address dotted symbol targets through an indexed tail lookup - #942
merlincat11 wants to merge 1 commit into
Conversation
…okup A dotted target such as Details.QueryHandler.Handle, Handler.Process or pkg.Handler.Process could not be resolved by short name. _looks_like_java_method_fqn is a purely lexical test, so every dotted target looks Java-shaped whatever language defines it, and _java_fqn_candidates then withheld the match from Go, Python, Kotlin, TypeScript and C# alike. Resolve dotted targets against an exact qualified-tail match, consulted only when no Java candidate exists. A Java-shaped target with real Java matches still resolves against Java, so the established anti-mislink contract is unchanged; an exact match on the whole symbol path is not the fuzzy globally-unique-name fallback that guard was written to block. The lookup is backed by an indexed nodes.symbol column holding the portion of qualified_name after the first "::". Matching with substr(qualified_name, -n) instead planned as SCAN nodes on every dotted lookup, with a second scan for the ambiguity count. symbol is stored rather than reconstructed from parent_name and name because qualified_name is built from identity_name or name, so the reconstruction would miss C++ overload identities. Migration v10 backfills and indexes the column. The index is created there rather than in the schema script: _init_schema runs before run_migrations and CREATE TABLE IF NOT EXISTS cannot add a column to an existing table, so indexing symbol from the script would fail to open every pre-v10 database. candidate_count now counts the population candidates were drawn from, so more than _MAX_DOTTED_TARGET_CANDIDATES matches no longer report the capped slice with candidates_truncated false.
code-review-graph reviewOverall risk: 0.85 (CRITICAL) — 18 changed function(s)/class(es), 24 affected flow(s), 7 test gap(s) Risk-scored changes
Affected execution flows
Test gaps
Token savings: this graph-backed report used ~33,190 fewer tokens (~64%) than reading every changed file in full (estimated, chars/4 approximation). Powered by code-review-graph — local-first analysis; no code leaves the CI runner. |
|
Integrated on |
|
Merged into |
…s through an indexed tail lookup Port the reviewed token-efficiency implementation with targeted regression coverage. Source-PR: tirth8205#942 Maintainer corrections and scope extraction applied where needed.
Summary
A dotted symbol target could not be addressed by short name.
Details.QueryHandler.Handle,Handler.Processandpkg.Handler.Processall returnednot_found.The cause is that
_looks_like_java_method_fqn()is a purely lexical test, so everydotted target looks Java-FQN-shaped regardless of which language defines it.
_java_fqn_candidates()then withheld the match from Go, Python, Kotlin, TypeScript andC# alike. That guard exists to stop a globally unique method name in another language
being selected for a Java FQN, but it was over-blocking far beyond Java.
nodes.symbolcolumn instead of a table scanSplit out of #937, which is the C# nested-type identity fix (#934). This is the
query-resolution half; the two are independent and this branch is cut from
main.Java precedence is unchanged
The tail lookup is consulted only when no Java candidate exists. A Java-shaped target
with real Java matches still resolves against Java:
maincom.example.Handler.processprocessHandler.processHandler.Process/pkg.Handler.ProcessHandler.processDetails.QueryHandler.HandleEvery Java row is identical to
main. The only behavior change is that a dotted targetwith an exact qualified-path match now resolves where
mainreturnednot_found. Anexact match on the entire symbol path is different in kind from the fuzzy
globally-unique-name fallback the guard was written to block, and cannot mislink.
Indexed lookup
Matching with
substr(qualified_name, -n) = ?cannot use any B-tree index; SQLite plannedit as
SCAN nodeson every dotted lookup, plus a second scan for the ambiguity count.Nodes now carry an indexed
symbolcolumn holding the portion ofqualified_nameafterthe first
::.symbolis stored rather than reconstructed fromparent_name || '.' || namebecause
qualified_nameis built fromidentity_name or name, so the reconstruction wouldmiss C++ overload identities.
Migration v10 backfills and indexes the column. The index is created in the migration,
not the schema script:
_init_schemaruns beforerun_migrations, andCREATE TABLE IF NOT EXISTScannot add a column to an existing table, so indexingsymbolfrom the script raised
no such column: symboland every pre-v10 database failed to open.SUPPORTED_SCHEMA_VERSIONin the VS Code backend moves to 10 to match.Bounded-result honesty
candidate_countusedlen(candidates)for Java-shaped targets, so 101 exact matchesreported
matches 100 node(s)withcandidates_truncated: false— both wrong, on fieldsthat exist for agent-facing transparency. It now counts the population candidates were
drawn from.
Testing
uv run pytest tests/ --tb=short -q(2996 passed, 9 skipped, 2 xpassed)_MAX_DOTTED_TARGET_CANDIDATES + 1symbolcolumn stripped, reproducing a genuine pre-v10 graphEXPLAIN QUERY PLANasserts indexedSEARCHfor both lookupsuv run ruff check code_review_graph/uv run mypy code_review_graph/ --ignore-missing-imports --no-strict-optional