Merge remote-tracking branches 'origin/fix/planner-provider-door' and 'origin/fix/containment-batching' into rel/10.4.10-candidate
This commit is contained in:
commit
34f1886f7c
6 changed files with 367 additions and 3 deletions
|
|
@ -7346,6 +7346,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