Skip to content

Commit 9435d51

Browse files
committed
fix(knowledge): refuse a projection backfill page size that is not a positive integer
The page size is interpolated into the page statement and a page of nothing would report the projection filled, so a payload that asks for either is refused before the first page rather than quietly reshaped. Claude-Session: https://claude.ai/code/session_01XU6c7pKRpa5CMoMHKDdqxX
1 parent 526f659 commit 9435d51

2 files changed

Lines changed: 38 additions & 0 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* @vitest-environment node
3+
*/
4+
import { backfillProjectionSourceAcl } from '@sim/db/script-migrations/0021_embedding_search_connector'
5+
import type { Sql } from 'postgres'
6+
import { describe, expect, it, vi } from 'vitest'
7+
8+
/** A session that must never be reached: every case below is refused before the first page. */
9+
const untouched = { begin: vi.fn() } as unknown as Sql
10+
11+
describe('backfillProjectionSourceAcl', () => {
12+
it.each([0, -1, 1.5, Number.NaN, Number.POSITIVE_INFINITY])(
13+
'refuses a page size of %s instead of reporting the projection filled',
14+
async (pageSize) => {
15+
await expect(
16+
backfillProjectionSourceAcl(untouched, 'embedding_search', { pageSize })
17+
).rejects.toThrow('page size must be a positive integer')
18+
expect(untouched.begin).not.toHaveBeenCalled()
19+
}
20+
)
21+
22+
it.each([-1, Number.NaN])('refuses a pause of %s', async (pauseMs) => {
23+
await expect(
24+
backfillProjectionSourceAcl(untouched, 'embedding_search', { pauseMs })
25+
).rejects.toThrow('pause must be a non-negative number')
26+
expect(untouched.begin).not.toHaveBeenCalled()
27+
})
28+
})

‎packages/db/script-migrations/0021_embedding_search_connector.ts‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,16 @@ export async function backfillProjectionSourceAcl(
121121
): Promise<ProjectionSourceAclBackfillProgress> {
122122
const pageSize = options.pageSize ?? PROJECTION_SOURCE_ACL_PAGE_SIZE
123123
const pauseMs = options.pauseMs ?? PROJECTION_SOURCE_ACL_PAGE_PAUSE_MS
124+
/**
125+
* The page size is interpolated into the statement and a page of nothing would report the
126+
* projection filled; a payload that asks for either is refused rather than quietly reshaped.
127+
*/
128+
if (!Number.isSafeInteger(pageSize) || pageSize < 1) {
129+
throw new Error(`Projection backfill page size must be a positive integer, got ${pageSize}`)
130+
}
131+
if (!Number.isFinite(pauseMs) || pauseMs < 0) {
132+
throw new Error(`Projection backfill pause must be a non-negative number, got ${pauseMs}`)
133+
}
124134
const startedAt = Date.now()
125135
const deadline =
126136
options.budgetMs === undefined ? Number.POSITIVE_INFINITY : startedAt + options.budgetMs

0 commit comments

Comments
 (0)