/**
 * Phase 4: recall ranking utilities — Reciprocal Rank Fusion (RRF)
 * + similarity-threshold gating.
 *
 * The engine returns lessons (text-match similarity) and memories
 * (semantic-vector similarity) on different score scales — they're
 * not directly comparable. RRF sidesteps that: it ignores absolute
 * scores and uses ranks-within-list only. Items appearing in BOTH
 * lists get a strong combined boost — "the text matched AND the
 * embedding is close" is the most reliable signal.
 *
 * The similarity threshold filters PER-SOURCE before merging so a
 * weak hit in one list can't poison the merged ranking. When all
 * results are filtered out, recall returns an empty merged array —
 * "no relevant context" is decision-makable; "top hit at sim=0.31"
 * is noise.
 */
/** Conventional RRF damping constant — survives well across domains. */
export declare const RRF_K = 60;
/** Default minimum similarity to consider a result relevant. */
export declare const DEFAULT_MIN_SIMILARITY = 0.5;
export interface LessonHit {
    kind: "lesson";
    id: string;
    description: string;
    status: string;
    body_preview: string;
    similarity: number;
    applied_count: number;
}
export interface MemoryHit {
    kind: "memory";
    id: string;
    description: string;
    body_preview: string;
    similarity: number;
    /** v0.5: present when the engine's `memory.search` ran in hybrid
     * (or text-only) mode. `"both"` means the hit surfaced from both
     * the semantic neighborhood AND the text-match scan — strongest
     * signal. Surfaced through to the MCP response for diagnostics. */
    source?: "semantic" | "text" | "both";
}
export type RecallHit = LessonHit | MemoryHit;
export interface MergedHit {
    kind: "lesson" | "memory";
    id: string;
    description: string;
    body_preview: string;
    /** Original per-source similarity (lesson text-match or memory semantic). */
    similarity: number;
    /** RRF score — higher is better. Not directly comparable to similarity. */
    rrf_score: number;
    /** 1-based rank in the lesson list (undefined if not a lesson hit). */
    lesson_rank?: number;
    /** 1-based rank in the memory list (undefined if not a memory hit). */
    memory_rank?: number;
    /** v0.5: when this hit came from a memory and the engine produced
     * the memory in hybrid (or text-only) mode, this carries the
     * sub-source attribution: `"semantic"`, `"text"`, or `"both"`.
     * Lesson hits leave this undefined (engine.recall doesn't expose
     * a sub-source). */
    source?: "semantic" | "text" | "both";
}
/**
 * Filter a hit list to those with similarity at or above `threshold`.
 * Stable: preserves the input order (which is engine-side rank).
 */
export declare function filterBySimilarity<T extends {
    similarity: number;
}>(hits: T[], threshold: number): T[];
/**
 * Reciprocal Rank Fusion across two ranked lists. The RRF score for
 * an item is `sum over each source list: 1 / (RRF_K + rank_in_that_list)`,
 * where rank is 1-based. Items appearing in both lists accumulate
 * contributions and naturally rank above single-source items.
 *
 * Returns merged hits ordered by descending `rrf_score`. Identity is
 * by `id` — a lesson and a memory with the same id (engine never
 * collides these in practice) would merge; we treat that as harmless.
 */
export declare function mergeRrf(lessons: LessonHit[], memories: MemoryHit[]): MergedHit[];
//# sourceMappingURL=recall.d.ts.map