/** * @module tests/unit/storage/getVerbs-totalCount * @description Verb-side mirror of getNouns-totalCount (the b2005ff fix). The * verb type-scan pagination (`BaseStorage.getVerbsWithPagination`) early-terminates * at `offset + limit + 1` (it peeks one extra item to compute `hasMore`), then * returned `collectedVerbs.length` as `totalCount` — i.e. the PAGE size, never the * dataset total. So `getVerbs({ pagination: { limit: 1 } }).totalCount` reported 1 * (or 2) for any non-empty brain on the unfiltered path. `totalCount` must be the * authoritative O(1) verb counter (`totalVerbCount`, isNew-gated + * visibility-filtered, rehydrated from `counts.json` on init). */ import { describe, it, expect } from 'vitest' import { mkdtempSync, rmSync } from 'fs' import { tmpdir } from 'os' import { join } from 'path' import { FileSystemStorage } from '../../../src/storage/adapters/fileSystemStorage.js' import type { VerbMetadata, HNSWVerb } from '../../../src/coreTypes.js' import { VerbType } from '../../../src/types/graphTypes.js' const DIM = 8 /** A deterministic non-zero vector so the verb record is well-formed. */ function vec(seed: number): number[] { return Array.from({ length: DIM }, (_, i) => ((seed + i) % 7) / 7 - 0.5) } /** Storage shards by UUID, so ids must be 32 hex chars. */ function uuid(i: number, salt = 0): string { return (i + salt).toString(16).padStart(32, '0') } /** * Seed `n` unique verbs. Metadata is saved BEFORE the verb record: it is where * the O(1) verb counter is incremented (isNew-gated), mirroring the real * relate() path. */ async function seed(storage: FileSystemStorage, n: number): Promise { for (let i = 0; i < n; i++) { const id = uuid(i, 0x1000) const sourceId = uuid(i, 0x4000) const targetId = uuid(i, 0x8000) await storage.saveVerbMetadata(id, { verb: VerbType.RelatedTo, sourceId, targetId, createdAt: Date.now(), updatedAt: Date.now() } as VerbMetadata) await storage.saveVerb({ id, vector: vec(i), connections: new Map(), verb: VerbType.RelatedTo, sourceId, targetId } as HNSWVerb) } } describe('FileSystemStorage.getVerbs totalCount (verb mirror of b2005ff)', () => { it('reports the TRUE total, not the page size, for a 1-item page', async () => { const dir = mkdtempSync(join(tmpdir(), 'brainy-verbtotal-')) try { const storage = new FileSystemStorage(dir) await storage.init() await seed(storage, 25) const onePage = await storage.getVerbs({ pagination: { limit: 1 } }) expect(onePage.items.length).toBe(1) // Before the fix this was the peeked page size (limit + 1 == 2). expect(onePage.totalCount).toBe(25) expect(onePage.hasMore).toBe(true) } finally { rmSync(dir, { recursive: true, force: true }) } }) it('still reports the true total after a cold reopen (counts rehydrate)', async () => { const dir = mkdtempSync(join(tmpdir(), 'brainy-verbtotal-reopen-')) try { const first = new FileSystemStorage(dir) await first.init() await seed(first, 25) await (first as unknown as { persistCounts(): Promise }).persistCounts() const reopened = new FileSystemStorage(dir) await reopened.init() const page = await reopened.getVerbs({ pagination: { limit: 1 } }) expect(page.totalCount).toBe(25) } finally { rmSync(dir, { recursive: true, force: true }) } }) })