fix(8.0): never serve a silent [] from find({connected}) on a cold-loaded graph

8.0 shipped with no cold-graph guard (the 7.33.4 fix was never ported), so on a
cold open of a large brain where the native adjacency reports membership but its
source->target edges did not load, find({connected})/neighbors()/related() could
silently return [] for persisted edges.

Add the converged isReady() contract: GraphIndexProvider.isReady?(): boolean is
the honest cold-load readiness signal (true ONLY when edges are loaded), so brainy
gates on it instead of the lying membership-size() proxy. verifyGraphAdjacencyLive()
checks it — Strategy 1: false -> hydrate the id-mapper, rebuild from storage, re-check,
throw GraphIndexNotReadyError if still not ready; providers without isReady() fall
back to a global known-edge-sample probe (Strategy 2, not the queried anchor, so a
genuinely edgeless node still returns []). rebuildIndexesIfNeeded gates the graph
rebuild on it too, with the id-mapper hydrated before the adjacency rebuild on the
lazy cold-open path (the CTX-BR-RESTORE-REBUILD ordering, shared with restore()).
executeGraphSearch re-verifies before trusting an empty connected result and
re-collects on a heal. 6-case integration test + 1718 unit green.
This commit is contained in:
David Snelling 2026-06-30 09:30:11 -07:00
parent 93f61dbc79
commit 229b0679fc
4 changed files with 542 additions and 98 deletions

View file

@ -250,6 +250,20 @@ export interface GraphIndexProvider {
*/
readonly isInitialized: boolean
/**
* @description Returns true ONLY when the sourcetarget EDGES are loaded (NOT
* membership/manifest count) the honest cold-load readiness signal. brainy
* gates the graph rebuild + the connected read-time guard on it: a `false`
* forces a rebuild from storage, and a still-`false` after that rebuild raises
* a loud {@link import('./errors/brainyError.js').GraphIndexNotReadyError}
* rather than serving an empty traversal as truth. cortex >= 2.7.8 (2.x) / 3.0
* exposes it; ABSENT on older providers, where brainy falls back to a
* known-edge-sample probe.
* @returns `true` when the persisted adjacency is loaded and traversals are
* trustworthy; `false` when only the count/manifest loaded (cold-open).
*/
isReady?(): boolean
/**
* @description Entity ints reachable from `id` (1 hop), deduped.
* @param id - The entity's interned int (from the shared idMapper).