export type UrlShapeReason = 'homepage' | 'serp' | 'social-promo'; export type ContentGateReason = 'low-content' | 'low-overlap'; export type ScoreFloorReason = 'negative-score'; export interface UrlShapeVerdict { reject: boolean; reason?: UrlShapeReason; } export interface ContentGateVerdict { reject: boolean; reason?: ContentGateReason; } export interface ScoreFloorVerdict { reject: boolean; reason?: ScoreFloorReason; } export declare const SCORE_FLOOR = 0; /** * Classify a candidate research source by its (post-rerank) relevance score. * Rejects strictly-negative scores — the cross-encoder's "not relevant" * verdict. Positive scores (the keyless passthrough path's engine/RRF values, * or a relevant cross-encoder logit) always survive, so this is a no-op when * no cross-encoder ran. The caller is responsible for never emptying the pool * (it keeps the single best source as a floor of last resort). * * `withinBreadthKeep` marks the top-N best-ranked candidates (by the reranker's * own ordering) and disables the negative-score reject for them entirely. The * cross-encoder's ABSOLUTE logits are miscalibrated per-query: on a niche query * it damps the WHOLE pool below zero — including genuinely canonical, on-topic * pages (live C1: sqlite.org/fts5.html, the sqlite-vec author's post, dev.to / * deepwiki / kentcdodds explainers all scored below even -0.35), which collapses * standard depth to ~1 source. Its RELATIVE ordering stays meaningful, so inside * the keep window the quality bar is rank position + the upstream url-shape and * content gates, NOT an absolute cutoff. Outside the window the strict `< 0` * rule applies unchanged, so a genuinely off-topic page that ranks past the pool * (it sorts below the on-topic survivors) is still rejected — that is what keeps * junk out of the long tail while the window stays wide. */ export declare function classifyScoreFloor(relevanceScore: number, withinBreadthKeep?: boolean): ScoreFloorVerdict; /** * Classify a candidate URL by shape alone (no fetch). A bare-root homepage or a * search-engine results page is junk for research synthesis. `includeDomains` * roots are exempt — if the caller scoped research to a domain, its root is an * intentional target. */ export declare function classifyUrlShape(url: string, includeDomains?: string[]): UrlShapeVerdict; /** * Distinct, stop-word-stripped content terms from the research question. Used * by the content gate to measure query overlap. */ export declare function queryContentTerms(question: string): string[]; /** * Gate fetched (or snippet) content. Rejects only when the page is BOTH thin * AND off-topic — a short on-topic doc survives (high overlap) and a long page * survives (high word count). Fails open when there are no query terms. */ export declare function gateContent(markdown: string, queryTerms: string[]): ContentGateVerdict; //# sourceMappingURL=source-validation.d.ts.map