Skip to content

fix(explore): surface camel-infix field definers on service-layer codebases (#1196)#1233

Open
umi008 wants to merge 1 commit into
colbymchenry:mainfrom
umi008:fix/1196-multi-word-field-queries
Open

fix(explore): surface camel-infix field definers on service-layer codebases (#1196)#1233
umi008 wants to merge 1 commit into
colbymchenry:mainfrom
umi008:fix/1196-multi-word-field-queries

Conversation

@umi008

@umi008 umi008 commented Jul 9, 2026

Copy link
Copy Markdown

Summary

Multi-word field-name queries (e.g. profileInfo isTrialEligible quotaInfo billingMethod) used to return 134 unrelated symbols and
bury the defining controller and service files under a dense neighbor.
Three compounding retrieval bugs were dead on JS/TS/Ruby/Python
service-layer codebases, where the camel-infix definer of a business
field is a method, not a class.

Root causes

  1. context builder 5b (CamelCase-boundary LIKE) used
    name.indexOf(titleCased) after titleCased.toLowerCase(), so
    a multi-hump token ("Profileinfo") could never indexOf into
    "getProfileInfoV2". The SQL layer matched case-insensitively; the
    JS boundary check silently re-tightened that and dropped the row.

  2. context builder 5b AND 5c restricted the LIKE batch to declaration
    kinds (class/interface/struct/trait/protocol/enum/type_alias), so on
    a method-centric codebase they contributed nothing. Single-word
    tokens like "search" → "Search" were unaffected because they
    don't go through the LIKE path the same way; this is why the bug
    wasn't caught during tuning.

  3. explore's named-symbol seeding was exact-name only. A field-name
    token (profileInfo) has no node of its own, so it contributed
    zero seeds: no +50 file score, no entryFiles protection, no
    named-file sort. The only surviving entry points were weak FTS
    sub-token hits (camelCase split gives quota, payment, …) and
    a depth-3 BFS from those dragged in a huge neighbor whose body
    filled the render budget.

FTS can't cover this case by design: camelCase identifiers are single
FTS tokens, so "profileinfo"* never matches an interior hump —
that's what 5b/5c were built for, and they were disabled by (1)+(2).

Fix

  • 5b: case-insensitive boundary check, with a guard that the
    boundary char itself is uppercase (so we still require a real hump).
  • 5b/5c: a separate LIKE batch for callable kinds
    (function/method/component), merged before the boundary
    filter. Per-batch 200-row cap so a hot single-word term can't crowd
    classes out of the length-ordered batch.
  • explore named-symbol seeding: new
    findCamelInfixCallables(cg, token) — a LIKE-based fallback that
    accepts prefix or camel-hump boundary matches on method/function/
    component kinds, case-insensitive. Fires only when the exact
    lookup yields no callable, so well-named queries are unaffected.
    Exposed CodeGraph.findNodesByNameSubstring publicly so this can
    be reached through the public API.

Validation

  • New test suite __tests__/context-multi-word-fields.test.ts
    builds a mini service-layer JS repo (controller/profileController.js
    with getProfileInfo/getProfileInfoV2, service/billing.js with
    _getCustomerBillingMethods) and asserts:
    • 5b recovers getProfileInfoV2 from a profileInfo token
    • callable kinds participate, so 5b surfaces _getCustomerBillingMethods
      for a billingMethod token
    • the multi-word field query from the issue surfaces BOTH defining
      methods in the same call
    • the camel-hump boundary check is precise: profileinfo matches
      getProfileInfoByName (true hump) but NOT reprofileinfoBogus
      (mid-word lowercase run)
  • All 4 new tests pass on Linux + macOS.
  • Existing context-ranking.test.ts (4), context.test.ts (17),
    explore-result-count.test.ts, explore-output-budget.test.ts,
    adaptive-explore-sizing.test.ts, explore-corroboration-ranking.test.ts,
    explore-blast-radius.test.ts — 63 tests — all still pass.

Reproduction

query: "profileInfo isTrialEligible quotaInfo billingMethod"

Before: 134 symbols across 26 files; defining files
controller/profileController.js and service/billing.js absent.
After: those two files rank at the top.

Closes #1196

…ebases (colbymchenry#1196)

Multi-word field-name queries (e.g. `profileInfo isTrialEligible
quotaInfo billingMethod`) used to return 134 unrelated symbols and
bury the defining controller and service files under a dense neighbor.
Three compounding retrieval bugs were dead on JS/TS/Ruby/Python
service-layer codebases (where the camel-infix definer is a method,
not a class):

1. context builder 5b (CamelCase-boundary LIKE) used
   `name.indexOf(titleCased)` after `titleCased.toLowerCase()`, so
   a multi-hump token ("Profileinfo") could never indexOf into
   "getProfileInfoV2". The SQL layer matched case-insensitively; the
   JS boundary check silently re-tightened that and dropped the row.
   Now case-insensitive, with a guard that the boundary char itself
   is uppercase so we still require a real hump.

2. context builder 5b AND 5c restricted the LIKE batch to declaration
   kinds (class/interface/struct/trait/protocol/enum/type_alias), so
   on a method-centric codebase they contributed nothing. Both now
   issue a separate LIKE batch for callable kinds (function/method/
   component) and merge before scoring, with a per-batch 200-row cap
   so a hot single-word term can't crowd classes out.

3. explore's named-symbol seeding was exact-name only. A field-name
   token (profileInfo) has no node of its own, so it contributed zero
   seeds: no +50 file score, no entryFiles protection, no named-file
   sort. Added findCamelInfixCallables: a LIKE-based fallback that
   accepts prefix or camel-hump boundary matches on method/function/
   component kinds, case-insensitive. Fires only when the exact
   lookup yields no callable (cands.length === 0), so well-named
   queries are unaffected. Exposed CodeGraph.findNodesByNameSubstring
   publicly so this can be reached through the public API.
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.

multi-word field-name queries never surface the defining files — 3 compounding retrieval bugs

1 participant