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
+19
View File
@@ -49,6 +49,7 @@ import { Mutex, FileLock } from './utils';
import { FileWatcher, WatchOptions, PendingFile, LockUnavailableError } from './sync';
import { EXTRACTION_VERSION } from './extraction/extraction-version';
import { getCodeGraphDir } from './directory';
import { deriveProjectNameTokens } from './search/query-utils';
import { CodeGraphPackageVersion } from './mcp/version';
// Re-export types for consumers
@@ -154,6 +155,13 @@ export class CodeGraph {
this.db = db;
this.queries = queries;
this.projectRoot = projectRoot;
// Down-weight the project name as a query term in search ranking — it names
// the whole repo, not a symbol, so it has no discriminative value (#720).
try {
this.queries.setProjectNameTokens(deriveProjectNameTokens(projectRoot));
} catch {
// Best-effort: ranking still works without it.
}
this.fileLock = new FileLock(
path.join(getCodeGraphDir(projectRoot), 'codegraph.lock')
);
@@ -747,6 +755,17 @@ export class CodeGraph {
return this.queries.searchNodes(query, options);
}
/**
* Normalized project-name tokens (go.mod / package.json / repo dir) used to
* down-weight the non-discriminative project name in search ranking (#720).
* Exposed so explore can exclude it from the PascalCase type-disambiguation
* bias, which would otherwise pull overloaded tokens toward whichever stack
* embeds the project name.
*/
getProjectNameTokens(): Set<string> {
return this.queries.getProjectNameTokens();
}
/**
* Find the project's "primary route file" — the file with the densest
* concentration of framework-emitted `route` nodes (≥3 routes, ≥30%