@@ -61,6 +61,11 @@ describe('workspace file search dispatch PostgreSQL deadlines', () => {
6161 workspace_id text PRIMARY KEY, enqueued_at timestamp NOT NULL,
6262 updated_at timestamp NOT NULL, last_dispatched_at timestamp
6363 )`
64+ await connection `CREATE INDEX ON workspace_file_search_index
65+ (workspace_id, updated_at, file_id, source_content_updated_at)
66+ WHERE status = 'pending' AND dispatched_at IS NULL`
67+ await connection `CREATE INDEX ON workspace_file_search_index (workspace_id, dispatched_at)
68+ WHERE status = 'pending' AND dispatched_at IS NOT NULL`
6469 await connection `INSERT INTO workspace_file_search_backfill (id, updated_at)
6570 VALUES ('workspace-file-search-v1', '2026-09-16 00:00:00')`
6671 database . current = drizzle ( connection )
@@ -92,6 +97,71 @@ describe('workspace file search dispatch PostgreSQL deadlines', () => {
9297 } )
9398 }
9499
100+ async function seedQueue ( workspaceId : string , queued : number , active = 0 ) {
101+ await connection `UPDATE workspace_file_search_backfill SET completed_at = now()`
102+ await connection `INSERT INTO workspace_files (id, workspace_id, context, content_updated_at)
103+ SELECT ${ workspaceId } || '-' || lpad(n::text, 6, '0'), ${ workspaceId } , 'workspace', '2026-09-16'
104+ FROM generate_series(1, ${ queued + active } ) n`
105+ await connection `INSERT INTO workspace_file_search_index
106+ (file_id, workspace_id, source_content_updated_at, status, updated_at, dispatched_at)
107+ SELECT id, workspace_id, content_updated_at, 'pending', '2026-09-16',
108+ CASE WHEN row_number() OVER (ORDER BY id DESC) <= ${ active } THEN now() ELSE NULL END
109+ FROM workspace_files WHERE workspace_id = ${ workspaceId } `
110+ await connection `INSERT INTO workspace_file_search_dispatch_queue
111+ (workspace_id, enqueued_at, updated_at) VALUES (${ workspaceId } , now(), now())`
112+ }
113+
114+ it ( 'skips a locked candidate without losing it or exceeding workspace capacity' , async ( ) => {
115+ await seedQueue ( 'workspace-1' , 3 , 1 )
116+ await connection . begin ( async ( tx ) => {
117+ await tx `SELECT file_id FROM workspace_file_search_index
118+ WHERE file_id = 'workspace-1-000001' FOR UPDATE`
119+ const results = await Promise . all ( [
120+ prepareWorkspaceFileSearchDispatch ( ) ,
121+ prepareWorkspaceFileSearchDispatch ( ) ,
122+ ] )
123+ expect ( results . flatMap ( ( result ) => result . payloads ) . map ( ( payload ) => payload . fileId ) ) . toEqual (
124+ [ 'workspace-1-000002' ]
125+ )
126+ const [ locked ] = await tx `SELECT dispatched_at FROM workspace_file_search_index
127+ WHERE file_id = 'workspace-1-000001'`
128+ expect ( locked . dispatched_at ) . toBeNull ( )
129+ } )
130+ expect ( ( await prepareWorkspaceFileSearchDispatch ( ) ) . payloads ) . toEqual ( [ ] )
131+ await connection `UPDATE workspace_file_search_index SET status = 'ready'
132+ WHERE file_id = 'workspace-1-000002'`
133+ const retry = await prepareWorkspaceFileSearchDispatch ( )
134+ expect ( retry . payloads . map ( ( payload ) => payload . fileId ) ) . toEqual ( [ 'workspace-1-000001' ] )
135+ } )
136+
137+ it ( 'claims only available slots from a large backlog and preserves current-file eligibility' , async ( ) => {
138+ await seedQueue ( 'workspace-1' , 10_000 , 1 )
139+ await seedQueue ( 'workspace-2' , 3 )
140+ await connection `UPDATE workspace_files SET deleted_at = now() WHERE id = 'workspace-1-000001'`
141+ await connection `UPDATE workspace_files SET content_updated_at = '2026-09-17'
142+ WHERE id = 'workspace-1-000002'`
143+ await connection `UPDATE workspace_files SET context = 'execution' WHERE id = 'workspace-1-000003'`
144+ const result = await prepareWorkspaceFileSearchDispatch ( )
145+ expect ( result . payloads . map ( ( payload ) => payload . fileId ) . sort ( ) ) . toEqual ( [
146+ 'workspace-1-000004' ,
147+ 'workspace-2-000001' ,
148+ 'workspace-2-000002' ,
149+ ] )
150+ expect ( ( await prepareWorkspaceFileSearchDispatch ( ) ) . payloads ) . toEqual ( [ ] )
151+ } )
152+
153+ it ( 'honors the remaining global capacity across workspace probes' , async ( ) => {
154+ await seedQueue ( 'workspace-1' , 3 )
155+ await seedQueue ( 'workspace-2' , 3 )
156+ await seedQueue ( 'workspace-active' , 0 , 99 )
157+ const result = await prepareWorkspaceFileSearchDispatch ( )
158+ expect ( result . payloads ) . toHaveLength ( 1 )
159+ expect ( ( await prepareWorkspaceFileSearchDispatch ( ) ) . payloads ) . toEqual ( [ ] )
160+ const [ row ] = await connection `SELECT count(*)::int AS active FROM workspace_file_search_index
161+ WHERE status = 'pending' AND dispatched_at IS NOT NULL`
162+ expect ( row . active ) . toBe ( 100 )
163+ } )
164+
95165 it ( 'fails on a locked backfill row and releases the dispatcher lock' , async ( ) => {
96166 let release = ( ) => { }
97167 let locked = ( ) => { }
0 commit comments