Both shapes confirmed with cor for the lockstep (cor builds the native side
against these; the JS index is a no-op / unchanged):
- probeConsistency?(): Promise<boolean> — OPTIONAL O(1) cold-open consistency
sampler on MetadataIndexProvider. brainy calls it ONCE per brain on the first
read; on `false` it self-heals via detectAndRepairCorruption() — the metadata
counterpart of the 7.33.2 graph cold-load guard, completing the phantom triad's
detect-and-repair-on-open. Best-effort: a probe failure never breaks a read
(the one-shot guard resets so a transient failure retries). The JS index omits
the method, so it is simply never probed.
- getIdsForFilter(filter, opts?: { limit?; offset? }) — brainy passes a page
bound on the UNSORTED find({ type, where, limit }) path so a native provider can
early-stop and return only the [0, limit) prefix, killing the O(N) FFI marshal
at billion scale (pairs with cor #75). brainy passes offset:0 and ALWAYS
re-windows the result itself (visibility filter + slice); the JS index ignores
opts and returns all matches (behaviour unchanged).
New unit tests cover brainy's call behaviour for both (probe→repair on false,
healthy→no-repair, failure-is-best-effort, once-per-brain; opts passed with
offset 0 on the unsorted path). Full gate green: unit 1718, integration 607.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
90 lines
3.9 KiB
TypeScript
90 lines
3.9 KiB
TypeScript
/**
|
|
* @module tests/unit/brainy/metadata-provider-contract
|
|
* @description Brainy-side wiring of the two metadata-provider contract additions
|
|
* confirmed with cor for the lockstep:
|
|
*
|
|
* 1. `probeConsistency()` — an OPTIONAL O(1) cold-open consistency sampler. On the
|
|
* first read, brainy calls it once; on `false` it self-heals via
|
|
* `detectAndRepairCorruption()` (the metadata counterpart of the graph cold-load
|
|
* guard). The native provider implements it; the JS index omits it (no-op).
|
|
* 2. `getIdsForFilter(filter, opts?)` — brainy passes a page bound on the UNSORTED
|
|
* `find({ type, where, limit })` path so a native provider can early-stop. The JS
|
|
* index ignores `opts`.
|
|
*
|
|
* These are unit tests of brainy's CALL behaviour (the real end-to-end honoring is
|
|
* exercised by cor's combined matrix); they inject probe/spy hooks onto the live JS
|
|
* metadata index, which has neither method by default.
|
|
*/
|
|
import { describe, it, expect, beforeEach } from 'vitest'
|
|
import { Brainy } from '../../../src/brainy'
|
|
import { NounType } from '../../../src/types/graphTypes'
|
|
|
|
describe('metadata-provider contract wiring (probeConsistency + getIdsForFilter opts)', () => {
|
|
let brain: Brainy<any>
|
|
let mi: any
|
|
|
|
beforeEach(async () => {
|
|
brain = new Brainy({ requireSubtype: false, storage: { type: 'memory' }, silent: true })
|
|
await brain.init()
|
|
await brain.add({ data: 'a', type: NounType.Thing, metadata: { kind: 'x' } })
|
|
await brain.add({ data: 'b', type: NounType.Thing, metadata: { kind: 'y' } })
|
|
mi = (brain as any).metadataIndex
|
|
;(brain as any)._metadataConsistencyProbed = false // reset the one-shot guard
|
|
})
|
|
|
|
it('calls probeConsistency once on cold open and self-heals via detectAndRepairCorruption on false', async () => {
|
|
let probes = 0
|
|
let repairs = 0
|
|
mi.probeConsistency = async () => { probes++; return false } // corrupt → must repair
|
|
const origRepair = mi.detectAndRepairCorruption.bind(mi)
|
|
mi.detectAndRepairCorruption = async () => { repairs++; return origRepair() }
|
|
|
|
await brain.find({ where: { kind: 'x' } })
|
|
expect(probes).toBe(1)
|
|
expect(repairs).toBe(1)
|
|
|
|
// Second read must NOT re-probe (once per brain).
|
|
await brain.find({ where: { kind: 'y' } })
|
|
expect(probes).toBe(1)
|
|
expect(repairs).toBe(1)
|
|
})
|
|
|
|
it('does NOT repair when the probe reports healthy', async () => {
|
|
let repairs = 0
|
|
mi.probeConsistency = async () => true // clean
|
|
const origRepair = mi.detectAndRepairCorruption.bind(mi)
|
|
mi.detectAndRepairCorruption = async () => { repairs++; return origRepair() }
|
|
|
|
await brain.find({ where: { kind: 'x' } })
|
|
expect(repairs).toBe(0)
|
|
})
|
|
|
|
it('a probe failure never breaks the read (best-effort, retried next time)', async () => {
|
|
let probes = 0
|
|
mi.probeConsistency = async () => { probes++; throw new Error('probe boom') }
|
|
|
|
// The read still succeeds despite the throwing probe.
|
|
const rows = await brain.find({ where: { kind: 'x' } })
|
|
expect(rows.length).toBe(1)
|
|
expect(probes).toBe(1)
|
|
// Guard reset on failure → the next read retries the probe.
|
|
await brain.find({ where: { kind: 'y' } })
|
|
expect(probes).toBe(2)
|
|
})
|
|
|
|
it('passes a page bound to getIdsForFilter on the unsorted find path (offset 0, brainy re-windows)', async () => {
|
|
let seenOpts: { limit?: number; offset?: number } | undefined
|
|
const orig = mi.getIdsForFilter.bind(mi)
|
|
mi.getIdsForFilter = async (filter: any, opts?: { limit?: number; offset?: number }) => {
|
|
seenOpts = opts
|
|
return orig(filter, opts)
|
|
}
|
|
|
|
const rows = await brain.find({ where: { kind: 'x' }, limit: 5 })
|
|
expect(rows.length).toBe(1) // result correctness preserved (JS ignores opts)
|
|
expect(seenOpts).toBeDefined()
|
|
expect(typeof seenOpts!.limit).toBe('number')
|
|
expect(seenOpts!.limit).toBeGreaterThanOrEqual(5)
|
|
expect(seenOpts!.offset).toBe(0) // brainy applies offset itself via slice
|
|
})
|
|
})
|