88 credentialGroup ,
99 document ,
1010 embedding ,
11+ embeddingSearch ,
1112 knowledgeBase ,
1213 knowledgeConnector ,
1314 knowledgeConnectorMember ,
@@ -19,7 +20,7 @@ import {
1920} from '@sim/db/schema'
2021import { createLogger , Logger } from '@sim/logger'
2122import { generateId } from '@sim/utils/id'
22- import { and , eq , inArray , sql } from 'drizzle-orm'
23+ import { and , eq , inArray , type SQL , sql } from 'drizzle-orm'
2324import { NextRequest } from 'next/server'
2425import { afterAll , beforeAll , describe , expect , it , type MockInstance , vi } from 'vitest'
2526import { z } from 'zod'
@@ -41,13 +42,15 @@ import {
4142 seedKnowledgeMemberFixture ,
4243} from '@/lib/knowledge/__integration__/seed-source-access-fixture'
4344import { type KnowledgeSearchTagFilter , searchKnowledge } from '@/lib/knowledge/application/search'
45+ import type { KbEmbeddingDimensions } from '@/lib/knowledge/embedding-models'
4446import {
4547 SearchBudget ,
4648 SearchDeadlineError ,
4749 type SearchExecutor ,
4850} from '@/lib/knowledge/search/budget'
4951import type { SearchStage } from '@/lib/knowledge/search/diagnostics'
5052import type { WorkspaceSearchFilters } from '@/lib/knowledge/search/filters'
53+ import { embeddingCandidateDistance } from '@/lib/knowledge/vector-columns'
5154import { POST as searchRoute } from '@/app/api/knowledge/search/route'
5255import { ResolvedSecretTraceRegistry } from '@/executor/utils/resolved-secret-trace-registry'
5356
@@ -120,6 +123,25 @@ function topicVector(topic = 0) {
120123 return vector . map ( ( value ) => value / magnitude )
121124}
122125const queryVector = topicVector ( )
126+
127+ /**
128+ * The exact nearest chunks on the projection's stored halfvec, which is what the page's order
129+ * is measured against: the walk ranks on that column, and nothing rescores it.
130+ */
131+ async function exactProjectionNeighbors ( vector : number [ ] , limit : number , readerClause ?: SQL ) {
132+ const distance = embeddingCandidateDistance (
133+ dimensions as KbEmbeddingDimensions ,
134+ JSON . stringify ( vector ) ,
135+ 'text-embedding-3-small'
136+ )
137+ /** Unaliased: the distance expression qualifies its column with the table's own name. */
138+ return db . execute < { id : string } > ( sql `SELECT ${ embeddingSearch . id } AS id FROM ${ embeddingSearch }
139+ INNER JOIN document d ON d.id = ${ embeddingSearch . documentId }
140+ WHERE ${ embeddingSearch . knowledgeBaseId } = ${ ids . knowledgeBaseId }
141+ AND ${ embeddingSearch . enabled } ${ readerClause ?? sql `` }
142+ ORDER BY (${ distance } ) + 0, ${ embeddingSearch . id }
143+ LIMIT ${ limit } ` )
144+ }
123145const captured : CapturedQuery [ ] = [ ]
124146const report : Record < string , unknown > = {
125147 fixture : ids ,
@@ -213,6 +235,10 @@ function explainNodes(node: ExplainNode): ExplainNode[] {
213235 * aliases its own lateral `scoped_chunk`, so this cannot match it, and matching on the rendered
214236 * clause casing would silently stop these assertions from running at all.
215237 */
238+ /** The vector page reads a pool slice's identities from the projection and its documents. */
239+ const VECTOR_PAGE_JOIN =
240+ 'INNER JOIN "document" ON "document"."id" = "embedding_search"."document_id"'
241+
216242function isVectorCandidateQuery ( statement : string ) {
217243 return statement . toLowerCase ( ) . includes ( ') as visible' )
218244}
@@ -476,12 +502,12 @@ async function sample(
476502 item . query . includes ( 'limit' ) ||
477503 item . query . includes ( 'CROSS JOIN LATERAL' ) ||
478504 isVectorCandidateQuery ( item . query ) ||
479- item . query . includes ( 'WITH scored_search_candidates' ) ||
505+ item . query . includes ( VECTOR_PAGE_JOIN ) ||
480506 item . query . includes ( 'WITH matched_keyword_chunks' ) )
481507 )
482508 const plans : Array <
483509 CapturedQuery & {
484- kind : 'keyword' | 'vector' | 'rerank ' | 'probe'
510+ kind : 'keyword' | 'vector' | 'page ' | 'probe'
485511 plan : z . infer < typeof explainSchema >
486512 }
487513 > = [ ]
@@ -516,9 +542,8 @@ async function sample(
516542 ? 'keyword'
517543 : isVectorCandidateQuery ( query . query )
518544 ? 'vector'
519- : query . query . includes ( 'order by' ) ||
520- query . query . includes ( 'WITH scored_search_candidates' )
521- ? 'rerank'
545+ : query . query . includes ( 'order by' ) || query . query . includes ( VECTOR_PAGE_JOIN )
546+ ? 'page'
522547 : 'probe' ,
523548 query : query . query ,
524549 parameters : query . parameters ,
@@ -1004,13 +1029,10 @@ describe.skipIf(!enabled)('Knowledge search latency on a realistic indexed corpu
10041029 expect ( vectorPlans ) . toHaveLength ( 1 )
10051030 expect ( vectorPlans [ 0 ] . plan [ 0 ] . Plan [ 'Actual Rows' ] ) . toBeGreaterThan ( 0 )
10061031 assertCompactCandidates ( vectorPlans [ 0 ] . plan [ 0 ] . Plan )
1007- expect ( plans . some ( ( plan ) => plan . kind === 'rerank' ) ) . toBe ( true )
1008- const rerank = plans . find ( ( plan ) => plan . kind === 'rerank' ) !
1009- const actual = await db . $client . unsafe ( rerank . query , rerank . parameters ) . values ( )
1010- const expected = await db . execute < { id : string } > ( sql `SELECT id FROM embedding
1011- WHERE knowledge_base_id = ${ ids . knowledgeBaseId } AND enabled
1012- ORDER BY (embedding <=> ${ JSON . stringify ( queryVector ) } ::vector) + 0, id
1013- LIMIT ${ actual . length } ` )
1032+ expect ( plans . some ( ( plan ) => plan . kind === 'page' ) ) . toBe ( true )
1033+ const page = plans . find ( ( plan ) => plan . kind === 'page' ) !
1034+ const actual = await db . $client . unsafe ( page . query , page . parameters ) . values ( )
1035+ const expected = await exactProjectionNeighbors ( queryVector , actual . length )
10141036 const expectedIds = new Set ( expected . map ( ( { id } ) => id ) )
10151037 const recall = actual . filter ( ( [ id ] ) => expectedIds . has ( id ) ) . length / expected . length
10161038 expect ( recall ) . toBeGreaterThanOrEqual ( 0.95 )
@@ -1028,12 +1050,9 @@ describe.skipIf(!enabled)('Knowledge search latency on a realistic indexed corpu
10281050 expectCompleteVectorSearch ( diagnostics )
10291051 const candidates = plans . find ( ( plan ) => plan . kind === 'vector' ) !
10301052 assertCompactCandidates ( candidates . plan [ 0 ] . Plan )
1031- const rerank = plans . find ( ( plan ) => plan . kind === 'rerank' ) !
1032- const actual = await db . $client . unsafe ( rerank . query , rerank . parameters ) . values ( )
1033- const expected = await db . execute < { id : string } > ( sql `SELECT id FROM embedding
1034- WHERE knowledge_base_id = ${ ids . knowledgeBaseId } AND enabled
1035- ORDER BY (embedding <=> ${ JSON . stringify ( topicVector ( topic ) ) } ::vector) + 0, id
1036- LIMIT ${ actual . length } ` )
1053+ const page = plans . find ( ( plan ) => plan . kind === 'page' ) !
1054+ const actual = await db . $client . unsafe ( page . query , page . parameters ) . values ( )
1055+ const expected = await exactProjectionNeighbors ( topicVector ( topic ) , actual . length )
10371056 const expectedIds = new Set ( expected . map ( ( { id } ) => id ) )
10381057 const recall = actual . filter ( ( [ id ] ) => expectedIds . has ( id ) ) . length / expected . length
10391058 expect ( recall ) . toBeGreaterThanOrEqual ( 0.95 )
@@ -1082,15 +1101,14 @@ describe.skipIf(!enabled)('Knowledge search latency on a realistic indexed corpu
10821101 )
10831102 expectCompleteVectorSearch ( diagnostics )
10841103 expect ( result . data . results ) . toHaveLength ( 15 )
1085- const rerank = plans . find ( ( plan ) => plan . kind === 'rerank' ) !
1086- expect ( rerank ) . toBeDefined ( )
1087- const actual = await db . $client . unsafe ( rerank . query , rerank . parameters ) . values ( )
1088- const expected = await db . execute < { id : string } > ( sql `SELECT e.id FROM embedding e
1089- INNER JOIN document d ON d.id = e.document_id
1090- WHERE e.knowledge_base_id = ${ ids . knowledgeBaseId } AND e.enabled
1091- AND d.acl @> ARRAY[${ reader } ]::text[]
1092- ORDER BY (e.embedding <=> ${ JSON . stringify ( queryVector ) } ::vector) + 0, e.id
1093- LIMIT ${ actual . length } ` )
1104+ const page = plans . find ( ( plan ) => plan . kind === 'page' ) !
1105+ expect ( page ) . toBeDefined ( )
1106+ const actual = await db . $client . unsafe ( page . query , page . parameters ) . values ( )
1107+ const expected = await exactProjectionNeighbors (
1108+ queryVector ,
1109+ actual . length ,
1110+ sql `AND d.acl @> ARRAY[${ reader } ]::text[]`
1111+ )
10941112 expect ( expected . length ) . toBeGreaterThan ( 0 )
10951113 const expectedIds = new Set ( expected . map ( ( { id } ) => id ) )
10961114 const recall = actual . filter ( ( [ id ] ) => expectedIds . has ( id ) ) . length / expected . length
@@ -1128,9 +1146,10 @@ describe.skipIf(!enabled)('Knowledge search latency on a realistic indexed corpu
11281146 expect ( probe [ 0 ] . query ) . not . toContain ( '<=>' )
11291147 expect ( probe [ 0 ] . plan [ 0 ] . Plan [ 'Actual Rows' ] ) . toBe ( 12 )
11301148 expect ( assertIndexedChunkProbe ( probe [ 0 ] . plan [ 0 ] . Plan ) ) . toBe ( documentIds . length )
1131- const vector = plans . filter ( ( plan ) => plan . kind === 'rerank' )
1132- expect ( vector ) . toHaveLength ( 1 )
1133- expect ( vector [ 0 ] . query ) . toContain ( '"embedding"."id" in' )
1149+ /** The page reads the bounded ranking's identities from the projection, never the original vectors. */
1150+ const page = plans . filter ( ( plan ) => plan . kind === 'page' )
1151+ expect ( page ) . toHaveLength ( 1 )
1152+ expect ( page [ 0 ] . query ) . not . toContain ( '"embedding"."embedding"' )
11341153 }
11351154 } finally {
11361155 await db
@@ -1175,16 +1194,16 @@ describe.skipIf(!enabled)('Knowledge search latency on a realistic indexed corpu
11751194 count < HYBRID_CANDIDATE_LIMIT ? 0 : 1
11761195 )
11771196 if ( count > HYBRID_CANDIDATE_LIMIT ) {
1178- const rerank = plans . find ( ( plan ) => plan . kind === 'rerank ' ) !
1179- const actual = await db . $client . unsafe ( rerank . query , rerank . parameters ) . values ( )
1180- const expected = await db . execute < { id : string } > ( sql `SELECT id FROM embedding
1181- WHERE knowledge_base_id = ${ ids . knowledgeBaseId } AND enabled
1182- AND document_id IN ( ${ sql . join (
1183- documentIds . map ( ( id ) => sql ` ${ id } ` ) ,
1184- sql `, `
1185- ) } )
1186- ORDER BY (embedding <=> ${ JSON . stringify ( queryVector ) } ::vector) + 0, id
1187- LIMIT ${ actual . length } ` )
1197+ const page = plans . find ( ( plan ) => plan . kind === 'page ' ) !
1198+ const actual = await db . $client . unsafe ( page . query , page . parameters ) . values ( )
1199+ const expected = await exactProjectionNeighbors (
1200+ queryVector ,
1201+ actual . length ,
1202+ sql `AND ${ embeddingSearch . documentId } IN ( ${ sql . join (
1203+ documentIds . map ( ( id ) => sql `${ id } ` ) ,
1204+ sql `, `
1205+ ) } )`
1206+ )
11881207 const expectedIds = new Set ( expected . map ( ( { id } ) => id ) )
11891208 const recall = actual . filter ( ( [ id ] ) => expectedIds . has ( id ) ) . length / expected . length
11901209 expect ( recall ) . toBeGreaterThanOrEqual ( 0.95 )
@@ -1352,7 +1371,7 @@ describe.skipIf(!enabled)('Knowledge search latency on a realistic indexed corpu
13521371 )
13531372 expectCompleteVectorSearch ( diagnostics )
13541373 expect ( diagnostics . accessScopeKind ) . toBe ( 'workspace' )
1355- expect ( diagnostics . vectorRanking ) . toBe ( 'candidate-rerank ' )
1374+ expect ( diagnostics . vectorRanking ) . toBe ( 'projection-walk ' )
13561375 expect ( result . data . results ) . toHaveLength ( 15 )
13571376 expect ( plans . some ( ( plan ) => plan . kind === 'vector' ) ) . toBe ( true )
13581377 for ( const row of result . data . results ) {
@@ -1441,7 +1460,7 @@ describe.skipIf(!enabled)('Knowledge search latency on a realistic indexed corpu
14411460 } )
14421461 )
14431462 expectCompleteVectorSearch ( tagged . diagnostics )
1444- expect ( tagged . diagnostics . vectorRanking ) . toBe ( 'candidate-rerank ' )
1463+ expect ( tagged . diagnostics . vectorRanking ) . toBe ( 'projection-walk ' )
14451464 expect ( tagged . result . data . results ) . toHaveLength ( 15 )
14461465 for ( const row of tagged . result . data . results ) {
14471466 const ordinal = Number ( row . documentId . split ( '-doc-' ) [ 1 ] )
0 commit comments