/**
 * Hybrid retrieval orchestrator — Step A.3 of v4.15.
 *
 * Glues the three retrievers (FTS via SQLite FTS5, vector via embeddings,
 * graph via `graphRankFromQuery`) into a single ranking by feeding their
 * rank lists into Reciprocal Rank Fusion (`reciprocalRankFusion`), then
 * applying the existing per-memory boosts (recency, category, link, tag,
 * activation, contradiction) as **multiplicative tweaks on top of the
 * RRF score** rather than additive components in a fixed-weight sum.
 *
 *   finalScore = rrfScore
 *     × (1 + 0.05 × priority)                // priority: 0–1
 *     × (1 + recencyBoost)                   // 0 / 0.05 / 0.1
 *     × (1 + 0.1 × categoryMatch)            // 0 or 1
 *     × (1 + linkBoost)                      // 0–0.15
 *     × (1 + tagBoost)                       // 0–0.1
 *     × (1 + activationBoost)                // 0–?
 *     × (1 - contradictionPenalty)           // 0–0.12
 *
 * Why multiplicative on top of RRF rather than additive:
 *   - RRF is rank-based, so its raw score scale is small and consistent.
 *   - Multiplicative boosts preserve the *relative* RRF order while
 *     letting context modulate it — they don't drown out the underlying
 *     retrieval signal the way fixed additive weights do.
 *   - Contradiction penalty is multiplicative (`1 - p`) so it shrinks
 *     score proportionally rather than potentially flipping sign.
 *
 * The module is split intentionally: `runHybridRanker` is pure-ish (it
 * accepts already-loaded rank lists + a memory map) so it can be unit
 * tested without standing up the embedding model or the FTS pipeline.
 * Step A.4 will add the DB-backed `hybridSearch` wrapper that builds
 * those inputs from a `SearchOptions`.
 */
import type Database from 'better-sqlite3';
import { type RankList } from './rrf.js';
import type { Memory, MemoryConfig, SearchResult } from '../types.js';
export interface HybridRankerWeights {
    fts: number;
    vector: number;
    graph: number;
}
export declare const DEFAULT_HYBRID_WEIGHTS: HybridRankerWeights;
/** Cormack et al. (2009) recommended RRF smoothing constant. */
export declare const DEFAULT_RRF_K = 60;
export interface HybridRankerInput {
    /** Rank lists from FTS, vector, graph. Any subset is allowed. */
    rankLists: readonly RankList[];
    /** Memory id → Memory record. The caller pre-loads these. */
    memories: Map<number, Memory>;
    /** Memory id → cosine similarity (used only for explanation breakdowns). */
    vectorSimilarities?: Map<number, number>;
    /** Memory id → normalised FTS score (used only for explanation breakdowns). */
    ftsScores?: Map<number, number>;
    /** Original user query — drives category detection and tag extraction. */
    query: string;
    /** SQLite handle — used for memory_links lookups. */
    db: Database.Database;
    /** Memory config. `salienceThreshold` gates the includeDecayed filter. */
    config: MemoryConfig;
    /** Override RRF k constant. Default 60. */
    rrfK?: number;
    /** Attach a `SearchExplanation` to each `SearchResult`. */
    includeExplanation?: boolean;
    /** Skip the decay-threshold filter. */
    includeDecayed?: boolean;
    /** Cap result count. Default 20. */
    limit?: number;
    /**
     * Override the activation-boost lookup. Defaults to the module-level
     * cache in `../activation.js`. Tests inject a stub.
     */
    activationBoostFn?: (memoryId: number) => number;
}
export declare function runHybridRanker(input: HybridRankerInput): SearchResult[];
