feat(plugin): an optional planFindPage door — an index that can plan a find answers it in one call
Some checks failed
CI / Node 22 (push) Successful in 12m34s
CI / Node 24 (push) Successful in 12m21s
CI / Integration + conformance (Node 22) (push) Failing after 17m4s
CI / Bun (latest) (push) Successful in 12m19s
Some checks failed
CI / Node 22 (push) Successful in 12m34s
CI / Node 24 (push) Successful in 12m21s
CI / Integration + conformance (Node 22) (push) Failing after 17m4s
CI / Bun (latest) (push) Successful in 12m19s
The provider's read doors each serve one stage, so a find that consults three of them crosses into the index three times and marshals a result set at every crossing: a filter matching a hundred thousand rows builds a hundred thousand id strings to return a page of twenty-five. An index able to decide the stage order itself can answer the page in one call and build ids only for the page. planFindPage is optional and additive, in the shape filterIdsWithin and getIdSetForFilter already set. The hook sits above the branch selection, because the branches are what decide stage order per call site and an index that plans has to be asked before that choice is made. Absent — as it is on this engine's own index — every find is served by the stage doors exactly as before, which is what keeps this engine the ordering oracle for any index that implements one. The contract the door must keep, written where an implementer will read it: identical rows in identical order to what the stage doors would produce; the graph-first law (neighbours are the candidate universe, the filter runs over those ids, orderBy sorts the whole set, the page is cut last); null returned BEFORE any work rather than instead of an answer; and emptyAt naming the stage that produced an empty page, so the serving law is applied to the right index — an empty graph answer is re-verified against the adjacency before it is believed, and a filter-empty is not. Pinned in tests/integration/find-planner-door.test.ts: absent changes nothing; present it is asked first with normalized params, the hidden ids and the graph provider; its page is used and hydrated in its order; a declining door leaves the result identical to the no-door path; and the two emptyAt branches verify the adjacency, or correctly do not.
This commit is contained in:
parent
d5147ed608
commit
4d5f823f47
4 changed files with 226 additions and 2 deletions
|
|
@ -7344,6 +7344,47 @@ export class Brainy<T = any> implements BrainyInterface<T> {
|
|||
await this.verifyMetadataLive()
|
||||
}
|
||||
|
||||
// PLANNED FIND (optional provider door, `MetadataIndexProvider.planFindPage`).
|
||||
//
|
||||
// The stage doors below each serve one stage, so a find that consults
|
||||
// three of them crosses into the index three times and marshals a result
|
||||
// set at every crossing — a filter matching a hundred thousand rows
|
||||
// builds a hundred thousand id strings to return a page of twenty-five.
|
||||
// An index that can decide the stage order itself answers the page in one
|
||||
// call and materializes ids only for the page.
|
||||
//
|
||||
// The hook sits ABOVE the branch selection because the branches are what
|
||||
// decide stage order per call site; an index that plans has to be asked
|
||||
// before that choice is made, not inside one of its arms.
|
||||
//
|
||||
// Optional and additive: a provider without the door, and any shape the
|
||||
// door hands back, take exactly the path they always took. `null` is a
|
||||
// routing decision the door must make BEFORE doing any work — never a
|
||||
// partial answer. Every guard above still ran (readiness, the migration
|
||||
// gate, the where-clause validation, the metadata cold-read guard), and
|
||||
// the serving law is applied here on the way out: an empty answer is
|
||||
// re-verified against the index that produced it before it is believed.
|
||||
const planningIndex = this.metadataIndex as unknown as MetadataIndexProvider
|
||||
if (typeof planningIndex.planFindPage === 'function') {
|
||||
const planned = await planningIndex.planFindPage(params, [...hiddenIds], this.graphIndex)
|
||||
if (planned !== null && planned !== undefined) {
|
||||
if (planned.ids.length === 0) {
|
||||
// A cold adjacency can report a size yet hold no edges, so an empty
|
||||
// graph answer is not truth until the adjacency verifies live. A
|
||||
// genuinely edgeless anchor verifies and the empty result stands.
|
||||
if (planned.emptyAt === 'graph') await this.verifyGraphAdjacencyLive()
|
||||
return []
|
||||
}
|
||||
const plannedEntities = await this.batchGet(planned.ids)
|
||||
const plannedResults: Result<T>[] = []
|
||||
for (const id of planned.ids) {
|
||||
const entity = plannedEntities.get(id)
|
||||
if (entity) plannedResults.push(this.createResult(id, 1.0, entity))
|
||||
}
|
||||
return plannedResults
|
||||
}
|
||||
}
|
||||
|
||||
// Handle metadata-only queries (no vector search needed)
|
||||
if (!hasVectorSearchCriteria && !hasGraphCriteria && hasFilterCriteria) {
|
||||
// Build filter for metadata index
|
||||
|
|
|
|||
Reference in a new issue