fix(MULTIVERSION-0001): fix version isolation, 404 on unknown version, commit-hash lookup, and searchModeUsed
Bug 1: Thread version tag from run() into crawl() via getVersionTag() helper so
LocalCrawler and GithubCrawler receive the correct ref when indexing a named
version instead of always crawling HEAD.
Bug 2: Return HTTP 404 with code VERSION_NOT_FOUND when a requested version tag
is not found in repository_versions, instead of silently falling back to a
cross-version mixed result set.
Bug 4: Before returning 404, attempt a commit_hash prefix match (min 7 chars)
so callers can request a version by full or short SHA.
Bug 3: Change HybridSearchService.search() to return
{ results, searchModeUsed } and propagate searchModeUsed through
ContextResponseMetadata and ContextJsonResponseDto so callers can see which
strategy (keyword / semantic / hybrid / keyword_fallback) was actually used.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -395,7 +395,7 @@ describe('HybridSearchService', () => {
|
||||
seedSnippet(client, { repositoryId: repoId, documentId: docId, content: 'hello world' });
|
||||
|
||||
const svc = new HybridSearchService(client, searchService, null);
|
||||
const results = await svc.search('hello', { repositoryId: repoId });
|
||||
const { results } = await svc.search('hello', { repositoryId: repoId });
|
||||
|
||||
expect(results.length).toBeGreaterThan(0);
|
||||
expect(results[0].snippet.content).toBe('hello world');
|
||||
@@ -406,14 +406,14 @@ describe('HybridSearchService', () => {
|
||||
|
||||
const provider = makeMockProvider([[1, 0]]);
|
||||
const svc = new HybridSearchService(client, searchService, provider);
|
||||
const results = await svc.search('alpha zero', { repositoryId: repoId, alpha: 0 });
|
||||
const { results } = await svc.search('alpha zero', { repositoryId: repoId, alpha: 0 });
|
||||
|
||||
expect(results.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it('returns empty array when FTS5 query is blank and no provider', async () => {
|
||||
const svc = new HybridSearchService(client, searchService, null);
|
||||
const results = await svc.search(' ', { repositoryId: repoId });
|
||||
const { results } = await svc.search(' ', { repositoryId: repoId });
|
||||
expect(results).toHaveLength(0);
|
||||
});
|
||||
|
||||
@@ -425,7 +425,7 @@ describe('HybridSearchService', () => {
|
||||
});
|
||||
|
||||
const svc = new HybridSearchService(client, searchService, makeNoopProvider());
|
||||
const results = await svc.search('noop fallback', { repositoryId: repoId });
|
||||
const { results } = await svc.search('noop fallback', { repositoryId: repoId });
|
||||
|
||||
expect(results.length).toBeGreaterThan(0);
|
||||
});
|
||||
@@ -445,7 +445,7 @@ describe('HybridSearchService', () => {
|
||||
const provider = makeMockProvider([[1, 0, 0, 0]]);
|
||||
const svc = new HybridSearchService(client, searchService, provider);
|
||||
|
||||
const results = await svc.search('hybrid search', {
|
||||
const { results } = await svc.search('hybrid search', {
|
||||
repositoryId: repoId,
|
||||
alpha: 0.5
|
||||
});
|
||||
@@ -464,7 +464,7 @@ describe('HybridSearchService', () => {
|
||||
const provider = makeMockProvider([[1, 0]]);
|
||||
const svc = new HybridSearchService(client, searchService, provider);
|
||||
|
||||
const results = await svc.search('deduplicate snippet', {
|
||||
const { results } = await svc.search('deduplicate snippet', {
|
||||
repositoryId: repoId,
|
||||
alpha: 0.5
|
||||
});
|
||||
@@ -487,7 +487,7 @@ describe('HybridSearchService', () => {
|
||||
const provider = makeMockProvider([[1, 0]]);
|
||||
const svc = new HybridSearchService(client, searchService, provider);
|
||||
|
||||
const results = await svc.search('pagination test', {
|
||||
const { results } = await svc.search('pagination test', {
|
||||
repositoryId: repoId,
|
||||
limit: 3,
|
||||
alpha: 0.5
|
||||
@@ -519,7 +519,7 @@ describe('HybridSearchService', () => {
|
||||
const provider = makeMockProvider([[1, 0]]);
|
||||
const svc = new HybridSearchService(client, searchService, provider);
|
||||
|
||||
const results = await svc.search('anything', {
|
||||
const { results } = await svc.search('anything', {
|
||||
repositoryId: repoId,
|
||||
alpha: 1
|
||||
});
|
||||
@@ -543,7 +543,7 @@ describe('HybridSearchService', () => {
|
||||
const provider = makeMockProvider([[1, 0]]);
|
||||
const svc = new HybridSearchService(client, searchService, provider);
|
||||
|
||||
const results = await svc.search('metadata check', {
|
||||
const { results } = await svc.search('metadata check', {
|
||||
repositoryId: repoId,
|
||||
alpha: 0.5
|
||||
});
|
||||
@@ -580,7 +580,7 @@ describe('HybridSearchService', () => {
|
||||
const provider = makeMockProvider([[1, 0]]);
|
||||
const svc = new HybridSearchService(client, searchService, provider);
|
||||
|
||||
const results = await svc.search('repository keyword', {
|
||||
const { results } = await svc.search('repository keyword', {
|
||||
repositoryId: repoId,
|
||||
alpha: 0.5
|
||||
});
|
||||
@@ -607,7 +607,7 @@ describe('HybridSearchService', () => {
|
||||
const provider = makeMockProvider([[1, 0]]);
|
||||
const svc = new HybridSearchService(client, searchService, provider);
|
||||
|
||||
const codeResults = await svc.search('function example', {
|
||||
const { results: codeResults } = await svc.search('function example', {
|
||||
repositoryId: repoId,
|
||||
type: 'code',
|
||||
alpha: 0.5
|
||||
@@ -632,7 +632,7 @@ describe('HybridSearchService', () => {
|
||||
const svc = new HybridSearchService(client, searchService, provider);
|
||||
|
||||
// Should not throw and should return results.
|
||||
const results = await svc.search('default alpha hybrid', { repositoryId: repoId });
|
||||
const { results } = await svc.search('default alpha hybrid', { repositoryId: repoId });
|
||||
expect(Array.isArray(results)).toBe(true);
|
||||
});
|
||||
|
||||
@@ -761,7 +761,7 @@ describe('HybridSearchService', () => {
|
||||
const searchService = new SearchService(client);
|
||||
const hybridService = new HybridSearchService(client, searchService, mockProvider);
|
||||
|
||||
const results = await hybridService.search('keyword', {
|
||||
const { results } = await hybridService.search('keyword', {
|
||||
repositoryId: repoId,
|
||||
searchMode: 'keyword'
|
||||
});
|
||||
@@ -820,7 +820,7 @@ describe('HybridSearchService', () => {
|
||||
const searchService = new SearchService(client);
|
||||
const hybridService = new HybridSearchService(client, searchService, mockProvider);
|
||||
|
||||
const results = await hybridService.search('semantic', {
|
||||
const { results } = await hybridService.search('semantic', {
|
||||
repositoryId: repoId,
|
||||
searchMode: 'semantic',
|
||||
profileId: 'test-profile'
|
||||
@@ -848,7 +848,7 @@ describe('HybridSearchService', () => {
|
||||
const searchService = new SearchService(client);
|
||||
const hybridService = new HybridSearchService(client, searchService, null);
|
||||
|
||||
const results = await hybridService.search('test query', {
|
||||
const { results } = await hybridService.search('test query', {
|
||||
repositoryId: repoId,
|
||||
searchMode: 'semantic'
|
||||
});
|
||||
@@ -867,7 +867,7 @@ describe('HybridSearchService', () => {
|
||||
const searchService = new SearchService(client);
|
||||
const hybridService = new HybridSearchService(client, searchService, mockProvider);
|
||||
|
||||
const results = await hybridService.search(' ', {
|
||||
const { results } = await hybridService.search(' ', {
|
||||
repositoryId: repoId,
|
||||
searchMode: 'semantic'
|
||||
});
|
||||
@@ -885,7 +885,7 @@ describe('HybridSearchService', () => {
|
||||
const searchService = new SearchService(client);
|
||||
const hybridService = new HybridSearchService(client, searchService, noopProvider);
|
||||
|
||||
const results = await hybridService.search('test query', {
|
||||
const { results } = await hybridService.search('test query', {
|
||||
repositoryId: repoId,
|
||||
searchMode: 'semantic'
|
||||
});
|
||||
@@ -951,7 +951,7 @@ describe('HybridSearchService', () => {
|
||||
const hybridService = new HybridSearchService(client, searchService, mockProvider);
|
||||
|
||||
// Query with heavy punctuation that preprocesses to nothing.
|
||||
const results = await hybridService.search('!!!@@@###', {
|
||||
const { results } = await hybridService.search('!!!@@@###', {
|
||||
repositoryId: repoId,
|
||||
searchMode: 'auto',
|
||||
profileId: 'test-profile'
|
||||
@@ -978,7 +978,7 @@ describe('HybridSearchService', () => {
|
||||
const searchService = new SearchService(client);
|
||||
const hybridService = new HybridSearchService(client, searchService, mockProvider);
|
||||
|
||||
const results = await hybridService.search('hello', {
|
||||
const { results } = await hybridService.search('hello', {
|
||||
repositoryId: repoId,
|
||||
searchMode: 'auto'
|
||||
});
|
||||
@@ -1038,7 +1038,7 @@ describe('HybridSearchService', () => {
|
||||
const hybridService = new HybridSearchService(client, searchService, mockProvider);
|
||||
|
||||
// Query that won't match through FTS after punctuation normalization.
|
||||
const results = await hybridService.search('%%%vector%%%', {
|
||||
const { results } = await hybridService.search('%%%vector%%%', {
|
||||
repositoryId: repoId,
|
||||
searchMode: 'hybrid',
|
||||
alpha: 0.5,
|
||||
@@ -1064,7 +1064,7 @@ describe('HybridSearchService', () => {
|
||||
const searchService = new SearchService(client);
|
||||
const hybridService = new HybridSearchService(client, searchService, null);
|
||||
|
||||
const results = await hybridService.search('!!!@@@###$$$', {
|
||||
const { results } = await hybridService.search('!!!@@@###$$$', {
|
||||
repositoryId: repoId
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user