mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-11 03:38:07 +00:00
fix(augment): recover symbols missed by FTS file ranking
This commit is contained in:
parent
acb65b95b6
commit
4f520ea18d
2 changed files with 34 additions and 17 deletions
|
|
@ -129,7 +129,7 @@ export async function augment(pattern: string, cwd?: string): Promise<string> {
|
|||
}
|
||||
|
||||
// Step 1: BM25 search (fast, no embeddings)
|
||||
const { results: bm25Results, ftsAvailable } = await searchFTSFromLbug(pattern, 10, repoId);
|
||||
const { results: bm25Results } = await searchFTSFromLbug(pattern, 10, repoId);
|
||||
|
||||
// Step 2: Map BM25 file results to symbols
|
||||
const symbolMatches: Array<{
|
||||
|
|
@ -167,16 +167,18 @@ export async function augment(pattern: string, cwd?: string): Promise<string> {
|
|||
}
|
||||
}
|
||||
|
||||
// When FTS indexes are unavailable (read-only DB, first run before indexes are built),
|
||||
// fall back to a direct name CONTAINS query so enrichment still works.
|
||||
if (symbolMatches.length === 0 && !ftsAvailable) {
|
||||
// FTS ranks files by mentions, so a widely referenced symbol's definition
|
||||
// may not be present in the top file results. Fall back to graph names
|
||||
// whenever those files produce no symbol match, regardless of FTS health.
|
||||
if (symbolMatches.length === 0) {
|
||||
const fallbackRows = await executeQuery(
|
||||
repoId,
|
||||
`
|
||||
MATCH (n)
|
||||
WHERE n.name CONTAINS '${patternFirstWord}'
|
||||
RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath
|
||||
ORDER BY id
|
||||
RETURN n.id AS id, n.name AS name, labels(n)[0] AS type, n.filePath AS filePath,
|
||||
CASE WHEN n.name = '${patternFirstWord}' THEN 0 ELSE 1 END AS exactRank
|
||||
ORDER BY exactRank, id
|
||||
LIMIT 5
|
||||
`,
|
||||
).catch(() => []);
|
||||
|
|
|
|||
|
|
@ -130,23 +130,38 @@ withTestLbugDB(
|
|||
expect(result).toBe('');
|
||||
});
|
||||
|
||||
// ─── Negative-safety: fallback must stay gated on !ftsAvailable ───
|
||||
//
|
||||
// When FTS is available but happens to return zero BM25 hits, the
|
||||
// CONTAINS fallback must NOT fire — preserving the original early-return
|
||||
// semantics. If anyone later loosens the gate to `symbolMatches.length
|
||||
// === 0` alone, this test fails.
|
||||
|
||||
it('does NOT fire CONTAINS fallback when FTS is available but BM25 returns empty', async () => {
|
||||
it('falls back to graph names when FTS is available but BM25 returns empty', async () => {
|
||||
const bm25 = await import('../../src/core/search/bm25-index.js');
|
||||
const spy = vi
|
||||
.spyOn(bm25, 'searchFTSFromLbug')
|
||||
.mockResolvedValue({ results: [], ftsAvailable: true });
|
||||
try {
|
||||
// 'login' WOULD match a graph node via CONTAINS, but FTS is available
|
||||
// and empty → fallback gate must hold → result must be ''.
|
||||
// FTS health does not imply its top file results contain the symbol's
|
||||
// definition. The graph-name fallback must recover the exact node.
|
||||
const result = await augment('login', handle.dbPath);
|
||||
expect(result).toBe('');
|
||||
expect(result).toContain('[GitNexus]');
|
||||
expect(result).toContain('login');
|
||||
} finally {
|
||||
spy.mockRestore();
|
||||
}
|
||||
});
|
||||
|
||||
it('finds an exact-name symbol when FTS ranks only mentioning files', async () => {
|
||||
const bm25 = await import('../../src/core/search/bm25-index.js');
|
||||
const spy = vi.spyOn(bm25, 'searchFTSFromLbug').mockResolvedValue({
|
||||
results: Array.from({ length: 5 }, (_, i) => ({
|
||||
filePath: `src/caller-${i}.ts`,
|
||||
score: 100 - i,
|
||||
nodeIds: [`file:caller-${i}`],
|
||||
})),
|
||||
ftsAvailable: true,
|
||||
});
|
||||
try {
|
||||
// The graph contains func:login in src/auth.ts, but none of the
|
||||
// FTS-ranked files defines it. Exact-name lookup must still recover it.
|
||||
const result = await augment('login', handle.dbPath);
|
||||
expect(result).toContain('[GitNexus]');
|
||||
expect(result).toContain('login');
|
||||
} finally {
|
||||
spy.mockRestore();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue