/** * L1 — graph-retrieval ranked-list stream for RRF fusion * (docs/plans/2026-06-02-l1-graph-rrf-stream.md). * * READ-ONLY consumer of the E3 graph substrate (entities/relations built by E3.1, * guarded by E3.3). Produces a ranked list of `entries[]` indices ordered by graph * proximity to the strong lexical seeds, for use as a 3rd fusion input to `rrfFuse` * beside BM25 + dense (src/search.ts hybridSearch, scoring:'rrf'). * * DISTINCT from graph-recall.ts: that INJECTS out-of-pool neighbours post-hoc; this * RE-RANKS within the already-filtered candidate pool. It only assigns ranks to * entries that are (a) graph-reached from a seed AND (b) present in `entries[]`. Seeds * themselves are never scored (they already rank via BM25/dense; scoring them would * double-count and dilute the orthogonal graph signal). * * Reuses the E3.2 BFS traversal shape from graph-recall.ts (loadEntitiesByMemoryId * seeds -> loadNeighborRelations BFS both directions, per-hop fanout cap, visited set * -> loadEntitiesByIds to resolve reached -> memoryId). Expands across the local AND * global stores. Pure reads (SELECTs only via graph.ts helpers), so the E3.3 * check-graph-writes lint permits this module living outside graph.ts. * * The graph stream's score scale (1/lexRank seed strength x decay^hops) only sets the * WITHIN-graph-stream ORDERING; RRF then re-ranks the list by 1/(k + graphRank), so the * absolute magnitude is washed out by fusion. Do not tune the scale expecting a * fused-score effect — only the induced order matters. */ import type { MemoryEntry } from './memory.js'; /** Default hops expanded from each seed (MVP; hard cap MAX_HOPS=3 reused from graph-recall). */ export declare const DEFAULT_GRAPH_HOPS = 2; /** Default per-hop multiplicative decay applied to the seed strength. */ export declare const DEFAULT_GRAPH_DECAY = 0.5; /** Default number of top lexical seeds expanded from. */ export declare const DEFAULT_GRAPH_SEED_COUNT = 10; /** Recommended RRF weight for the graph stream — a CLI-only convenience default. The * library `graphStream.weight` option stays REQUIRED (opt-in is explicit). */ export declare const DEFAULT_GRAPH_STREAM_WEIGHT = 0.5; /** A lexical seed to expand the graph from: a candidate index + its lexical strength. */ export interface GraphSeed { /** Index into the caller's `entries[]`. */ index: number; /** Lexical strength (1/lexRank); higher = stronger seed. Propagated x decay^hops. */ strength: number; } export interface GraphStreamOpts { hippoRoot: string; tenantId: string; /** The global store root, when distinct + initialized (where global seeds' graph lives). */ globalRoot?: string; /** Hops to expand from each seed. Clamped to [1, MAX_HOPS]. Default DEFAULT_GRAPH_HOPS. */ hops?: number; /** Per-hop multiplicative decay on the seed strength. Default DEFAULT_GRAPH_DECAY. */ decay?: number; /** Per-hop fanout cap. Default DEFAULT_MAX_NEIGHBORS. */ maxNeighbors?: number; } /** * Pick the top `seedCount` candidates by best lexical rank (lowest position across the * BM25 and dense ranked lists), with strength = 1/(bestRank + 1). Pure; exported for * direct unit testing. A candidate present in either ranked list is eligible. */ export declare function selectGraphSeeds(bm25Ranked: ReadonlyArray, cosineRanked: ReadonlyArray, seedCount: number): GraphSeed[]; /** * Produce the graph-retrieval ranked list: `entries[]` indices ordered by graph * proximity (desc) to the lexical `seeds`. Only graph-reached, in-pool, non-seed * indices appear; the rest are absent (-> rrfFuse absentRank). Pure reads. * * Returns `[]` when there are no seeds/entries, the graph is empty, no seed maps to an * entity, or nothing reached is in-pool — the caller then skips the 3rd fusion list. */ export declare function graphRankStream(entries: ReadonlyArray, seeds: ReadonlyArray, opts: GraphStreamOpts): number[]; //# sourceMappingURL=graph-stream.d.ts.map