- Watermark stamping fans out at flush: all three projections stamped
with the committed generation before their flushes persist.
- waitForIndexed(path?, {generation, timeoutMs}) — the one honest read
barrier for write-then-recall consumers; typed timeout error carries
the pending count and names the gauge; getIndexStatus() gains
per-projection gauges. awaitPendingEmbeds() unchanged underneath.
- adoptLogAuthority() self-backfills curable divergences (pre-log
records, witness drift) by identity re-commit before flipping — a
fresh brain flips clean; log-ahead divergences still refuse loudly.
- The verification oracle gains VERB legs (all four divergence classes;
unwired = honest verbsChecked: 0, never a scope claim).
- find({where: {}}) match-all serves (was silent-empty, warm AND cold;
same fix in count/streaming/subgraph seeding); removeMany({where:{}})
refuses typed — a match-all bulk delete must be explicit.
- Aggregation native envelope stamped via noteSourceGeneration before
serializeState; the native-blob restore gates through the same
adoption verdict as caller-side state (the unconditional adopt dies).
- LC8 pinned: a wholesale directory move opens and serves identically
across all three intelligences, with history traveling.
Gates: unit 2031/2031 (156 files) · integration 812 (91 files) ·
conformance 27/27.
184 lines
7.9 KiB
TypeScript
184 lines
7.9 KiB
TypeScript
/**
|
|
* @module tests/integration/find-matchall-cold
|
|
* @description THE MATCH-ALL SILENT-EMPTY PIN: `find({ where: {} })` is a
|
|
* match-all query — zero predicates constrain nothing — yet it used to route
|
|
* through the index-filter branch, where `getIdsForFilter({})` answers `[]`
|
|
* by contract. Result: 0 rows while storage held rows (worst on a freshly
|
|
* reopened brain, where it masqueraded as data loss), the forbidden answer
|
|
* class — a silent empty instead of served-or-refused. These tests pin the
|
|
* law: an empty `where` routes exactly like an absent `where`, serving from
|
|
* truth-complete sources (a storage page bounded to the offset+limit window,
|
|
* or the column store's top-K sort under orderBy) — warm AND cold, on the
|
|
* live brain, the Db pin path, pagination.count, streaming.entities, and the
|
|
* semantic path (`{ query, where: {} }` must not short-circuit to `[]`).
|
|
* The one deliberate refusal: `removeMany({ where: {} })` throws — a
|
|
* match-all BULK DELETE must be asked for explicitly, never inherited.
|
|
*/
|
|
import { describe, it, expect, afterEach } from 'vitest'
|
|
import { mkdtempSync, rmSync } from 'node:fs'
|
|
import { tmpdir } from 'node:os'
|
|
import { join } from 'node:path'
|
|
import { Brainy } from '../../src/index.js'
|
|
import { NounType } from '../../src/types/graphTypes.js'
|
|
|
|
const dirs: string[] = []
|
|
const brains: Brainy[] = []
|
|
|
|
afterEach(async () => {
|
|
for (const b of brains.splice(0)) await b.close().catch(() => {})
|
|
for (const d of dirs.splice(0)) rmSync(d, { recursive: true, force: true })
|
|
})
|
|
|
|
async function open(dir: string): Promise<Brainy> {
|
|
const b = new Brainy({ storage: { type: 'filesystem', path: dir }, requireSubtype: false })
|
|
await b.init()
|
|
brains.push(b)
|
|
return b
|
|
}
|
|
|
|
/** Seed three plain documents with a sortable numeric field. */
|
|
async function seed(brain: Brainy): Promise<string[]> {
|
|
const ids: string[] = []
|
|
ids.push(await brain.add({ data: 'alpha row', type: NounType.Document, metadata: { n: 1 } }))
|
|
ids.push(await brain.add({ data: 'beta row', type: NounType.Document, metadata: { n: 2 } }))
|
|
ids.push(await brain.add({ data: 'gamma row', type: NounType.Document, metadata: { n: 3 } }))
|
|
await brain.flush()
|
|
return ids
|
|
}
|
|
|
|
describe('find({ where: {} }) — match-all serves, warm and cold', () => {
|
|
it('the repro: a freshly reopened filesystem brain serves match-all (not a silent 0)', async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-cold-'))
|
|
dirs.push(dir)
|
|
const brain = await open(dir)
|
|
await seed(brain)
|
|
await brain.close()
|
|
brains.pop()
|
|
|
|
const reopened = await open(dir)
|
|
const rows = await reopened.find({ where: {}, limit: 10 })
|
|
expect(rows.length, 'match-all serves every stored row on the cold brain').toBe(3)
|
|
|
|
// The predicate paths that always worked cold stay working — same brain.
|
|
expect((await reopened.find({ where: { n: 1 }, limit: 10 })).length).toBe(1)
|
|
expect((await reopened.find({ where: { 'system.type': 'document' }, limit: 10 })).length).toBe(3)
|
|
}, 120000)
|
|
|
|
it('match-all + orderBy on a metadata field serves sorted after reopen', async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-order-'))
|
|
dirs.push(dir)
|
|
const brain = await open(dir)
|
|
await seed(brain)
|
|
await brain.close()
|
|
brains.pop()
|
|
|
|
const reopened = await open(dir)
|
|
const rows = await reopened.find({ where: {}, orderBy: 'n', order: 'desc', limit: 10 })
|
|
expect(rows.length, 'sorted match-all serves every stored row cold').toBe(3)
|
|
expect(
|
|
rows.map((r) => (r.metadata as { n: number }).n),
|
|
'orderBy is honored on the cold match-all page'
|
|
).toEqual([3, 2, 1])
|
|
}, 120000)
|
|
|
|
it('warm brain unchanged: match-all, sorted match-all, and predicates all serve in-session', async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-warm-'))
|
|
dirs.push(dir)
|
|
const brain = await open(dir)
|
|
await seed(brain)
|
|
|
|
expect((await brain.find({ where: {}, limit: 10 })).length).toBe(3)
|
|
const sorted = await brain.find({ where: {}, orderBy: 'n', order: 'asc', limit: 2 })
|
|
expect(sorted.map((r) => (r.metadata as { n: number }).n)).toEqual([1, 2])
|
|
expect((await brain.find({ where: { n: 2 }, limit: 10 })).length).toBe(1)
|
|
// Pagination window respected: match-all never over-serves the page.
|
|
expect((await brain.find({ where: {}, limit: 2, offset: 2 })).length).toBe(1)
|
|
}, 120000)
|
|
|
|
it('the semantic path: find({ query, where: {} }) must not short-circuit to []', async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-query-'))
|
|
dirs.push(dir)
|
|
const brain = await open(dir)
|
|
await seed(brain)
|
|
await brain.close()
|
|
brains.pop()
|
|
|
|
const reopened = await open(dir)
|
|
// Before the fix, the pre-resolved empty filter matched nothing and the
|
|
// vector search was skipped entirely — a silent [] for every such query.
|
|
const rows = await reopened.find({ query: 'alpha row', where: {}, limit: 10 })
|
|
expect(rows.length, 'an unconstraining where must not empty a semantic query').toBeGreaterThan(0)
|
|
}, 120000)
|
|
|
|
it('the Db pin path: asOf(g).find({ where: {} }) serves at the pinned generation after reopen', async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-asof-'))
|
|
dirs.push(dir)
|
|
const brain = await open(dir)
|
|
await brain.add({ data: 'first', type: NounType.Document, metadata: { n: 1 } })
|
|
await brain.add({ data: 'second', type: NounType.Document, metadata: { n: 2 } })
|
|
await brain.flush()
|
|
const gTwo = brain.generation()
|
|
await brain.add({ data: 'third', type: NounType.Document, metadata: { n: 3 } })
|
|
await brain.flush()
|
|
await brain.close()
|
|
brains.pop()
|
|
|
|
const reopened = await open(dir)
|
|
// Current-generation pin (delegates to the live find fast path).
|
|
const now = reopened.now()
|
|
expect((await now.find({ where: {}, limit: 10 })).length).toBe(3)
|
|
|
|
// Historical pin: the record-overlay path must serve match-all too.
|
|
const past = await reopened.asOf(gTwo)
|
|
try {
|
|
const rows = await past.find({ where: {}, limit: 10 })
|
|
expect(rows.length, 'match-all at the pinned generation sees exactly the rows of that generation').toBe(2)
|
|
} finally {
|
|
await past.release()
|
|
}
|
|
}, 120000)
|
|
|
|
it('pagination.count({ where: {} }) counts every row instead of a silent 0', async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-count-'))
|
|
dirs.push(dir)
|
|
const brain = await open(dir)
|
|
await seed(brain)
|
|
await brain.close()
|
|
brains.pop()
|
|
|
|
const reopened = await open(dir)
|
|
// The law: an empty where counts exactly like an absent where (the
|
|
// unfiltered total — which by long-standing count semantics includes
|
|
// system entities such as the VFS root, hence >= the 3 user rows).
|
|
const emptyWhere = await reopened.pagination.count({ where: {} })
|
|
expect(emptyWhere).toBe(await reopened.pagination.count({}))
|
|
expect(emptyWhere).toBeGreaterThanOrEqual(3)
|
|
}, 120000)
|
|
|
|
it('streaming.entities({ where: {} }) streams every row instead of nothing', async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-stream-'))
|
|
dirs.push(dir)
|
|
const brain = await open(dir)
|
|
await seed(brain)
|
|
await brain.close()
|
|
brains.pop()
|
|
|
|
const reopened = await open(dir)
|
|
const streamed: string[] = []
|
|
for await (const entity of reopened.streaming.entities({ where: {} })) {
|
|
streamed.push(entity.id)
|
|
}
|
|
expect(streamed.length, 'an unconstraining where streams the full store').toBeGreaterThanOrEqual(3)
|
|
}, 120000)
|
|
|
|
it('removeMany({ where: {} }) refuses loudly — match-all bulk delete is never implicit', async () => {
|
|
const dir = mkdtempSync(join(tmpdir(), 'brainy-matchall-remove-'))
|
|
dirs.push(dir)
|
|
const brain = await open(dir)
|
|
await seed(brain)
|
|
|
|
await expect(brain.removeMany({ where: {} })).rejects.toThrow(/matches EVERYTHING/)
|
|
// Nothing was deleted by the refused call.
|
|
expect((await brain.find({ where: {}, limit: 10 })).length).toBe(3)
|
|
}, 120000)
|
|
})
|