fix(session-query): qualify persistence revisions by store

This commit is contained in:
Hypatia May
2026-07-15 12:32:18 +08:00
parent f88ca85ffd
commit 35edf2a825
13 changed files with 192 additions and 31 deletions

View File

@@ -926,4 +926,49 @@ describe('SQLite schema, cancellation, and real persistence integration', () =>
await expect(ctx.sessionPersistence.load(meta.id)).resolves.toMatchObject({ meta, events: [{ seq: 0 }] })
await persistence.dispose()
})
it('reconciles colliding local revisions when a derived index reopens against another SQLite store', async () => {
const persistencePathA = await temporaryPath('canonical-a.db')
const persistencePathB = await temporaryPath('canonical-b.db')
const searchPath = await temporaryPath('derived-collision.db')
const shared = header('same-id', 10)
const first = new Context()
await first.plugin(SessionStore)
const persistenceA = await first.plugin(SessionPersistenceSqlite, { path: persistencePathA })
await first.sessionPersistence.create(shared)
await first.sessionPersistence.append(shared.id, messageEvents('alpha source'))
const loadA = vi.spyOn(first.sessionPersistence, 'load')
const searchA = await first.plugin(SessionSearchSqlite, { path: searchPath })
await expect(first.sessionSearch.searchSessions({ query: 'alpha' }))
.resolves.toMatchObject({ items: [{ header: shared }] })
expect(loadA).toHaveBeenCalledTimes(1)
await searchA.dispose()
await persistenceA.dispose()
const reopened = new Context()
await reopened.plugin(SessionStore)
const persistenceAAgain = await reopened.plugin(SessionPersistenceSqlite, { path: persistencePathA })
const reopenedLoad = vi.spyOn(reopened.sessionPersistence, 'load')
const searchAAgain = await reopened.plugin(SessionSearchSqlite, { path: searchPath })
await expect(reopened.sessionSearch.searchSessions({ query: 'alpha' }))
.resolves.toMatchObject({ items: [{ header: shared }] })
expect(reopenedLoad).not.toHaveBeenCalled()
await searchAAgain.dispose()
await persistenceAAgain.dispose()
const second = new Context()
await second.plugin(SessionStore)
const persistenceB = await second.plugin(SessionPersistenceSqlite, { path: persistencePathB })
await second.sessionPersistence.create(shared)
await second.sessionPersistence.append(shared.id, messageEvents('bravo source'))
const loadB = vi.spyOn(second.sessionPersistence, 'load')
const searchB = await second.plugin(SessionSearchSqlite, { path: searchPath })
await expect(second.sessionSearch.searchSessions({ query: 'bravo' }))
.resolves.toMatchObject({ items: [{ header: shared }] })
await expect(second.sessionSearch.searchSessions({ query: 'alpha' })).resolves.toEqual({ items: [] })
expect(loadB).toHaveBeenCalledTimes(1)
await searchB.dispose()
await persistenceB.dispose()
})
})