Skip to content

fix: exact-name symbol lookup silently fails on snake_case names#15

Merged
saldestechnology merged 1 commit into
mainfrom
worktree-fix-like-escape
Jul 10, 2026
Merged

fix: exact-name symbol lookup silently fails on snake_case names#15
saldestechnology merged 1 commit into
mainfrom
worktree-fix-like-escape

Conversation

@saldestechnology

Copy link
Copy Markdown
Collaborator

Problem

query find, query callers, query deps, query impact, explain, and source return "not found" for any symbol whose name contains an underscore — i.e. most snake_case identifiers in Rust/Go/Python/C codebases.

$ ctx query find get            # ✅ found
$ ctx query find run_sql        # ⛔ "No symbols found"
$ ctx query find discover_files # ⛔ "No symbols found"
$ ctx query impact run_audit    # ⚠️ "No impact detected"  ← silently wrong

The symbols are indexed — ctx sql, search, and semantic all find them. Only the LIKE-based exact-name path fails.

Root cause

find_symbols_filtered (src/db/schema.rs) escapes LIKE metacharacters (%, _, \) with a backslash (escape_like_pattern, and glob_to_like_pattern for the file filter), but none of the LIKE clauses declared ESCAPE '\'. In SQLite the backslash is not the escape character unless declared, so the escaped \_ was matched literally as "backslash + any char" — which never matches a name like run_sql. Substrings without underscores matched fine, which is why the bug hid in plain sight.

The impact variant is the most dangerous: it returns "No impact detected" rather than an error, which a caller (human or agent) reads as "safe to change."

Fix

Add ESCAPE '\' to all three affected LIKE clauses:

  • name / qualified_name substring match
  • the file_path glob filter
  • the starts_with prefix match in the ORDER BY

Why the tests missed it

The existing find_symbols_filtered tests only used underscore-free names (new, main, targetfn). This PR adds test_find_symbols_with_underscore_name, which looks up a snake_case name by exact match and asserts the underscore is treated literally (does not wildcard-match runsql) and that exact match still ranks ahead of the longer prefix match.

Verification

  • New regression test fails before the fix, passes after.
  • Full suite green: 379 tests, 0 failures; cargo fmt --check and cargo clippy --all-targets -D warnings clean.
  • End-to-end against a real index: query find run_sql, explain open_sql_sandbox, and query impact find_symbols_filtered all now resolve correctly.

find_symbols_filtered escapes LIKE metacharacters (`%`, `_`, `\`) with a
backslash via escape_like_pattern / glob_to_like_pattern, but none of the
LIKE clauses declared `ESCAPE '\'`. In SQLite the backslash is not the
escape character unless declared, so an escaped `\_` was matched literally
as "backslash followed by any character" — meaning any symbol whose name
contains an underscore (`run_sql`, `discover_files`, `open_sql_sandbox`)
never matched an exact-name query and returned zero rows.

Because snake_case is the dominant identifier style in Rust/Go/Python/C,
this silently broke the primary lookup path for most real symbols across
`query find`, `query callers`, `query deps`, `query impact`, `explain`,
and `source`. The `impact` case was the most dangerous: it reported
"No impact detected" instead of an error, reading as "safe to change".

Add `ESCAPE '\'` to all three LIKE clauses (name/qualified_name, the
file_path glob filter, and the starts_with prefix match in ORDER BY).

The existing tests never caught this because they only exercised
underscore-free names (`new`, `main`, `targetfn`); add a regression test
that looks up a snake_case name by exact match and asserts the underscore
is treated literally (does not wildcard-match `runsql`).
@saldestechnology
saldestechnology merged commit ce217d7 into main Jul 10, 2026
5 checks passed
@saldestechnology
saldestechnology deleted the worktree-fix-like-escape branch July 11, 2026 13:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant