This repository has been archived on 2026-09-03. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
open-brainy/tests/unit/storage/pagination-parallel-hydration.test.ts
David Snelling de79d6b5a4 test(hygiene): close every brain the unit suite creates
Each file opened one or more Brainy instances (beforeEach, or a small
per-test helper like migration-gate-family-scoped's module-level seed())
and never closed them. migration-gate-family-scoped.test.ts now tracks
every brain seed() hands back in a describe-scoped array drained by
afterEach, since the helper itself lives outside the describe block.
2026-09-03 09:06:10 -07:00

98 lines
4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @module tests/unit/storage/pagination-parallel-hydration
* @description The canonical enumeration walk (getNounsWithPagination) hydrated
* each item's vector + metadata ONE-AT-A-TIME — N×per-op-latency serially, the
* dominant term in an index heal (cortex heal-cost decomposition). It now
* hydrates 16-way, and a new getNounIdsWithPagination returns ids WITHOUT
* hydration (zero per-entity reads when unfiltered). Both must preserve the exact
* pagination contract: same order, cursor continuation, filters, totalCount.
*/
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { Brainy, NounType } from '../../../src/index.js'
describe('paginated enumeration — parallel hydration + id-only (cortex heal-cost)', () => {
let brain: any
let storage: any
const N = 30
beforeEach(async () => {
process.env.BRAINY_DETERMINISTIC_EMBEDDINGS = 'true'
brain = new Brainy({ requireSubtype: false, storage: { type: 'memory' }, dimensions: 384 })
await brain.init()
for (let i = 0; i < N; i++) {
await brain.add({
data: `n${i}`,
type: i % 3 === 0 ? NounType.Task : NounType.Concept,
metadata: { i }
})
}
await brain.flush()
storage = brain.storage
})
afterEach(async () => {
await brain.close()
})
/** Page the whole dataset through a small limit via cursor and collect ordered ids. */
const pageAll = async (fn: (opts: any) => Promise<any>, key: 'items' | 'ids') => {
const out: string[] = []
let cursor: string | undefined
for (let guard = 0; guard < 1000; guard++) {
const page = await fn({ limit: 4, cursor })
const batch = key === 'items' ? page.items.map((n: any) => n.id) : page.ids
out.push(...batch)
if (!page.hasMore) break
cursor = page.nextCursor
}
return out
}
it('parallel hydration yields the SAME ordered pages as one big page', async () => {
const big = await storage.getNounsWithPagination({ limit: 1000, offset: 0 })
const bigIds = big.items.map((n: any) => n.id)
// At least the N we added (a brain also has its VFS root entity).
expect(bigIds.length).toBeGreaterThanOrEqual(N)
expect(big.totalCount).toBe(bigIds.length)
const paged = await pageAll((o) => storage.getNounsWithPagination(o), 'items')
expect(paged).toEqual(bigIds) // identical order, no dupes, no gaps across pages
})
it('getNounIdsWithPagination returns exactly the same ids, in the same order', async () => {
const idsPaged = await pageAll((o) => storage.getNounIdsWithPagination(o), 'ids')
const itemsPaged = await pageAll((o) => storage.getNounsWithPagination(o), 'items')
expect(idsPaged).toEqual(itemsPaged)
expect(new Set(idsPaged).size).toBe(idsPaged.length) // every id exactly once
expect(idsPaged.length).toBeGreaterThanOrEqual(N)
})
it('id-only enumeration does ZERO per-entity hydration reads when unfiltered', async () => {
const readSpy = vi.spyOn(storage as any, 'readCanonicalObject')
await storage.getNounIdsWithPagination({ limit: 1000, offset: 0 })
expect(readSpy).not.toHaveBeenCalled()
readSpy.mockRestore()
// The hydrating walk, by contrast, DOES read each entity.
const readSpy2 = vi.spyOn(storage as any, 'readCanonicalObject')
await storage.getNounsWithPagination({ limit: 1000, offset: 0 })
expect(readSpy2.mock.calls.length).toBeGreaterThan(0)
readSpy2.mockRestore()
})
it('a type filter matches between the hydrating and id-only walks', async () => {
const taskItems = await storage.getNounsWithPagination({
limit: 1000,
offset: 0,
filter: { nounType: NounType.Task }
})
const taskIds = await storage.getNounIdsWithPagination({
limit: 1000,
offset: 0,
filter: { nounType: NounType.Task }
})
const expected = Math.ceil(N / 3) // every 3rd is a Task
expect(taskItems.items.length).toBe(expected)
expect(new Set(taskIds.ids)).toEqual(new Set(taskItems.items.map((n: any) => n.id)))
})
})