fix(search): down-weight the project name in ranking — completes #720 (#748)

The per-word path fix (#745) brought the backend to parity but not above:
the project name still gave the lexically-matching stack a residual dir
match + an FTS class-name match, so a backend query that included the
project name still ranked the frontend at/above the backend.

Derive the project name from go.mod module / package.json name / repo dir,
and treat a query word matching it as non-discriminative: drop it from path
relevance and from codegraph_explore's PascalCase type-disambiguation bias
(reporter's suggestions #1/#2) — unless it's the only query word, so a bare
project-name search still scores.

Narrow by construction: the down-weighting fires ONLY when a query word
matches the derived project name (≥5 chars), so every query that doesn't
name the project is byte-identical. On the reporter's repro the backend
controllers now top a backend question that includes the project name;
queries without it, bare project-name queries, and normal symbol queries
are unchanged. Query-time only (no re-index).

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-06-08 22:43:54 -04:00
committed by GitHub
co-authored by Claude Opus 4.8
parent afec1282e1
commit 75ae1e8bd9
6 changed files with 154 additions and 10 deletions
+9 -3
View File
@@ -21,7 +21,7 @@ import {
} from '../sync/worktree';
import type { PendingFile } from '../sync';
import type { Node, Edge, SearchResult, Subgraph, NodeKind } from '../types';
import { isTestFile } from '../search/query-utils';
import { isTestFile, normalizeNameToken } from '../search/query-utils';
import {
existsSync,
readFileSync,
@@ -1661,8 +1661,14 @@ export class ToolHandler {
// agent writes "DataRequest task validate", the `task`/`validate` it wants
// are DataRequest's, NOT the same-named overloads in Validation.swift /
// Concurrency.swift / the abstract base. Used below to bias overloaded
// names toward the file/class the query also names.
const typeTokens = tokens.filter((o) => /^[A-Z][A-Za-z0-9]{3,}/.test(o));
// names toward the file/class the query also names. EXCLUDE the project
// name (a PascalCase token a user naturally includes) — it names the whole
// repo, so biasing toward it just pulls overloads to whichever stack
// embeds it, re-burying the rest (#720).
const projectNameTokens = cg.getProjectNameTokens();
const typeTokens = tokens.filter(
(o) => /^[A-Z][A-Za-z0-9]{3,}/.test(o) && !projectNameTokens.has(normalizeNameToken(o)),
);
const inNamedContext = (n: Node) =>
typeTokens.some((ct) => {
const lc = ct.toLowerCase();