/** * Retrieval metrics for the Second Brain scoreboard. * * Definitions are spelled out in full because every number this org reports is * judged against them. Nothing here rounds: callers format for display, never * for the JSON payload. * * @module v1/cli/knowledge/eval/metrics */ /** A ranked retrieval result, already reduced to one entry per document. */ export interface RankedDoc { /** Repo-relative document path — the unit of relevance judgement. */ docId: string; /** Best score seen for this document across its chunks. */ score: number; /** Which chunk produced the best score (for debugging misses). */ chunkIndex: number; } export interface QueryOutcome { queryId: string; query: string; relevant: string[]; ranked: RankedDoc[]; /** 1-based rank of the first relevant doc within the top 10, else null. */ firstRelevantRank: number | null; recallAt: Record; hitAt: Record; reciprocalRank: number; latencyMs: number; /** IDF-weighted lexical overlap between query and its gold document(s). */ overlap: number; overlapTercile?: 'low' | 'mid' | 'high'; } export interface Scoreboard { queries: number; /** Macro-averaged. Standard definition: |top-k INTERSECT R| / |R|. */ recallAt1: number; recallAt5: number; recallAt10: number; /** Fraction of queries with >= 1 relevant doc in top-k. Equals recall when |R| = 1. */ hitRateAt1: number; hitRateAt5: number; hitRateAt10: number; /** Mean reciprocal rank, cutoff 10. Queries with no hit contribute 0. */ mrrAt10: number; /** Queries where no relevant doc appeared anywhere in the top 10. */ totalMisses: number; latencyMsP50: number; latencyMsP95: number; /** 95% Wald half-width on hitRateAt5 — how large a delta must be to be signal. */ hitRateAt5Ci95: number; } export declare const K_VALUES: readonly [1, 5, 10]; /** * Reduce chunk-level hits to a ranked list of unique documents. A document's * rank is the rank of its best-scoring chunk; further chunks of an * already-seen document are dropped rather than pushing other documents down. */ export declare function dedupeByDoc(hits: Array<{ docId: string; score: number; chunkIndex: number; }>, cutoff: number): RankedDoc[]; export declare function scoreQuery(args: { queryId: string; query: string; relevant: string[]; ranked: RankedDoc[]; latencyMs: number; overlap?: number; }): QueryOutcome; export declare function aggregate(outcomes: QueryOutcome[]): Scoreboard; import { contentTokens, STOPWORDS } from '../../memory/text-tokens.js'; export { contentTokens, STOPWORDS }; export interface TrivialityReport { /** Fraction of the query's content tokens appearing anywhere in the doc. */ overlapRatio: number; /** Longest run of consecutive query tokens appearing consecutively in the doc. */ maxContiguousRun: number; trivial: boolean; reason?: string; } /** * @param query the golden-set query string * @param docText the FULL text of the target document */ export declare function assessTriviality(query: string, docText: string): TrivialityReport; export interface IdfModel { idf: Map; docCount: number; } export declare function buildIdf(docs: string[]): IdfModel; /** * IDF-weighted overlap in [0,1]: the share of the query's total information * mass that is literally present in the gold document. */ export declare function idfOverlap(model: IdfModel, query: string, docText: string): number; /** Split outcomes into terciles by overlap and aggregate each independently. */ export declare function terciles(outcomes: QueryOutcome[]): { cutLow: number; cutHigh: number; low: Scoreboard; mid: Scoreboard; high: Scoreboard; }; export interface PairedComparison { a: string; b: string; /** Queries where A hit at k and B missed. */ aWins: number; /** Queries where B hit at k and A missed. */ bWins: number; ties: number; /** Two-sided McNemar p, exact binomial on the discordant pairs. */ p: number; significant: boolean; note: string; } export declare function pairedCompare(aName: string, aOutcomes: QueryOutcome[], bName: string, bOutcomes: QueryOutcome[], k?: 1 | 5 | 10): PairedComparison; //# sourceMappingURL=metrics.d.ts.map