brainy/tests/unit/graph/graph-fastpath-honest-readiness.test.ts

96 lines
4.2 KiB
TypeScript
Raw Normal View History

2026-07-13 13:08:52 -07:00
/**
* @module tests/unit/graph/graph-fastpath-honest-readiness
* @description Pattern-A / Finding 2: getVerbsBySource/ByTarget gated the graph
* fast path on `graphIndex.isInitialized` (a proxy that reads true once the
* manifest/count loaded even if the sourcetarget adjacency did NOT the fast
* path then returned a silent []). The honest gate skips the fast path when the
* provider reports isReady()===false, falling to the correct canonical shard
* scan; and a one-shot probe self-heals a no-isReady provider whose adjacency
* did not cold-load.
*/
import { describe, it, expect, beforeEach } from 'vitest'
import { Brainy, NounType, VerbType } from '../../../src/index.js'
describe('graph fast-path honest readiness (Finding 2)', () => {
let brain: any
let storage: any
let a: string
let b: string
let c: string
beforeEach(async () => {
process.env.BRAINY_DETERMINISTIC_EMBEDDINGS = 'true'
brain = new Brainy({ requireSubtype: false, storage: { type: 'memory' }, dimensions: 384 })
await brain.init()
a = await brain.add({ data: 'a', type: NounType.Concept })
b = await brain.add({ data: 'b', type: NounType.Concept })
c = await brain.add({ data: 'c', type: NounType.Concept })
await brain.relate({ from: a, to: b, type: VerbType.Contains })
await brain.relate({ from: a, to: c, type: VerbType.Contains })
await brain.flush()
storage = brain.storage
// Warm + wire the storage graph index (lazy) so we can stub it.
await storage.getVerbsBySource(a)
})
it('not-ready provider → shard scan returns the REAL edges, not a silent []', async () => {
const gi = storage.graphIndex
// Simulate a cold native provider: count/manifest loaded (isInitialized) but
// the source→target adjacency is NOT (isReady false; fast-path lookup empty).
gi.isReady = () => false
const origBySource = gi.getVerbIdsBySource.bind(gi)
gi.getVerbIdsBySource = async () => [] // cold adjacency — old fast path trusted this
storage._graphFastPathProbed = true // isolate the GATE (probe skips isReady-capable anyway)
try {
const verbs = await storage.getVerbsBySource(a)
// Honest gate skipped the cold fast path → canonical shard scan → real edges.
expect(verbs.length).toBe(2)
} finally {
delete gi.isReady
gi.getVerbIdsBySource = origBySource
}
})
it('ready provider → fast path is used and an empty result is trusted', async () => {
const gi = storage.graphIndex
gi.isReady = () => true
let fastPathCalls = 0
const origBySource = gi.getVerbIdsBySource.bind(gi)
gi.getVerbIdsBySource = async (...args: any[]) => { fastPathCalls++; return origBySource(...args) }
storage._graphFastPathProbed = true
try {
// `c` has no OUTGOING edges — a genuinely empty result via the fast path.
const verbs = await storage.getVerbsBySource(c)
expect(verbs).toEqual([])
expect(fastPathCalls).toBeGreaterThan(0) // fast path was taken, not a shard scan
} finally {
delete gi.isReady
gi.getVerbIdsBySource = origBySource
}
})
it('no-isReady provider whose adjacency did not cold-load → probe rebuilds once', async () => {
const gi = storage.graphIndex
if ('isReady' in gi) delete gi.isReady // force the "unknown" (no honest signal) path
// Force the probe to see a cold adjacency: a known edge resolves to no ints.
const origBySource = gi.getVerbIdsBySource.bind(gi)
let cold = true
gi.getVerbIdsBySource = async (...args: any[]) => (cold ? [] : origBySource(...args))
let rebuilds = 0
const origRebuild = gi.rebuild.bind(gi)
gi.rebuild = async (...args: any[]) => { rebuilds++; cold = false; return origRebuild(...args) }
storage._graphFastPathProbed = false // re-arm the one-shot probe
try {
await storage.getVerbsBySource(a)
expect(rebuilds).toBe(1) // probe detected cold adjacency + rebuilt once
expect(storage._graphFastPathProbed).toBe(true) // latched — no second rebuild
rebuilds = 0
await storage.getVerbsByTarget(b)
expect(rebuilds).toBe(0) // probe does not re-run
} finally {
gi.getVerbIdsBySource = origBySource
gi.rebuild = origRebuild
}
})
})