mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
fix(session-query): preserve typed query failures (round 5)
This commit is contained in:
@@ -53,6 +53,16 @@ function expectCode(code: SessionQueryErrorCode): Error {
|
||||
return expect.objectContaining({ code }) as Error
|
||||
}
|
||||
|
||||
function replaceCursorOffset(
|
||||
cursor: ReturnType<typeof SessionSearchCursor>,
|
||||
offset: number,
|
||||
): ReturnType<typeof SessionSearchCursor> {
|
||||
const payload = JSON.parse(
|
||||
Buffer.from(cursor, 'base64url').toString('utf8'),
|
||||
) as Record<string, unknown>
|
||||
return SessionSearchCursor(Buffer.from(JSON.stringify({ ...payload, offset }), 'utf8').toString('base64url'))
|
||||
}
|
||||
|
||||
class TestPersistence extends SessionPersistence {
|
||||
static entries = new Map<SessionIdType, { meta: SessionHeader; events: SessionEvent[] }>()
|
||||
static revisions = new Map<SessionIdType, number>()
|
||||
@@ -276,6 +286,14 @@ describe('SQLite session search', () => {
|
||||
expect(sessionPage.nextCursor).toEqual(expect.any(String))
|
||||
if (eventPage.nextCursor === undefined || sessionPage.nextCursor === undefined) throw new Error('expected cursors')
|
||||
|
||||
const unsafeOffsetCursor = replaceCursorOffset(eventPage.nextCursor, 1e100)
|
||||
await expect(ctx.sessionSearch.searchEvents({
|
||||
sessionId: target.id,
|
||||
query: 'needle',
|
||||
limit: 1,
|
||||
cursor: unsafeOffsetCursor,
|
||||
})).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_CURSOR'))
|
||||
|
||||
const eventKeys = eventPage.items.map(item => `${item.sessionId}:${item.seq}`)
|
||||
let eventCursor: ReturnType<typeof SessionSearchCursor> | undefined = eventPage.nextCursor
|
||||
while (eventCursor !== undefined) {
|
||||
@@ -399,6 +417,34 @@ describe('SQLite session search', () => {
|
||||
.toThrow(expectCode('SESSION_QUERY_INVALID_CONFIG'))
|
||||
}
|
||||
})
|
||||
|
||||
it('rejects aggregate filter bindings above SQLite\'s portable variable limit', async () => {
|
||||
const ctx = await liveContext()
|
||||
const session = ctx.sessions.create(SessionId('binding-limit'), { seed: messageEvents('needle') })
|
||||
// Each clause is below the ceiling; combined with its sibling and fixed
|
||||
// query bindings, the complete statement is not portable.
|
||||
const halfPortableLimit = 16_383
|
||||
const ids = Array.from(
|
||||
{ length: halfPortableLimit },
|
||||
(_, index) => SessionId(`binding-${index}`),
|
||||
)
|
||||
const types = Array.from({ length: halfPortableLimit }, () => 'user/message' as const)
|
||||
const surfaces = Array.from({ length: halfPortableLimit }, () => 'current' as const)
|
||||
|
||||
await expect(ctx.sessionSearch.searchSessions({
|
||||
query: 'needle',
|
||||
sessionFilters: [{ kind: 'id', values: ids }],
|
||||
eventFilters: [{ kind: 'type', values: types }],
|
||||
})).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER'))
|
||||
await expect(ctx.sessionSearch.searchEvents({
|
||||
sessionId: session.id,
|
||||
query: 'needle',
|
||||
filters: [
|
||||
{ kind: 'type', values: types },
|
||||
{ kind: 'surface', values: surfaces },
|
||||
],
|
||||
})).rejects.toThrow(expectCode('SESSION_QUERY_INVALID_FILTER'))
|
||||
})
|
||||
})
|
||||
|
||||
describe('SQLite reconciliation and source lifecycle', () => {
|
||||
|
||||
Reference in New Issue
Block a user