/**
 * benchmark-grading.ts
 *
 * STANDING BENCHMARK RULE — "best_valid_number" grading policy
 * ──────────────────────────────────────────────────────────────
 *
 * This is the centralized, canonical grading utility for all Rainmaker
 * forecast performance measurement. Every graded forecast — Recently
 * Graded, By League, By Confidence Tier, and all derived metrics —
 * MUST use this module as the single source of truth.
 *
 * POLICY: Forecasts are graded using the most advantageous valid number
 * available between the original forecast and the closing market line.
 * Both values are ALWAYS compared — neither source is preferred by default.
 * If the original forecast is better, use the original.
 * If the closing market is better, use the closing.
 * If both are the same, use that shared value.
 * This is intentional. This is not accidental. This is the benchmark
 * rule moving forward unless explicitly changed.
 *
 * WHY benchmark_source is tracked:
 *   - Identifies whether 'original' or 'closing' was selected as the benchmark
 *   - Enables audit of which source provided the grading advantage
 *   - Values: 'original', 'closing', 'equal', 'only_original', 'only_closing'
 *
 * WHY original_forecast is preserved:
 *   - Audit trail: we can always reference what was originally posted
 *   - CLV analysis: comparing original vs close is a separate concern
 *   - Historical integrity: the raw data is never lost
 *
 * WHY benchmark_forecast may differ from original_forecast:
 *   - The benchmark represents the strongest defensible grading position
 *   - If either the original or the close is more favorable, we grade from that number
 *   - The displayed forecast MUST match the benchmark forecast
 *
 * HOW Push is determined:
 *   - If the final result lands exactly on the benchmark forecast number,
 *     the result is a Push (P). Not W, not L.
 *   - Push applies to spreads and totals where integer lines exist.
 *   - Half-point lines eliminate push possibility.
 *
 * DO NOT simplify, remove, or consolidate this logic without explicit
 * authorization. The separation of original/benchmark/closing is load-bearing.
 */
export type BenchmarkGrade = 'W' | 'L' | 'P';
export type ForecastType = 'spread' | 'total' | 'moneyline';
/**
 * Identifies which number was selected as the benchmark.
 *   'original' — the model's originally published forecast was more advantageous
 *   'closing'  — the closing market number was more advantageous
 *   'equal'    — both values were identical
 *   'only_original' — closing was missing, original was used by default
 *   'only_closing'  — original was missing, closing was used by default
 */
export type BenchmarkSource = 'original' | 'closing' | 'equal' | 'only_original' | 'only_closing';
export interface BenchmarkGradingInput {
    forecastType: ForecastType;
    /** For spread: the side selected (home or away). For total: 'over' or 'under'. */
    side: 'home' | 'away' | 'over' | 'under';
    /** The model's originally published forecast number (spread line or total). */
    originalForecast: number | null;
    /** The closing market number (spread line or total). */
    closingMarket: number | null;
    /** For spread: actual margin from the forecast side's perspective (positive = side won by that many). */
    actualMargin?: number | null;
    /** For total: actual combined score. */
    actualTotal?: number | null;
    /** Home score */
    homeScore: number;
    /** Away score */
    awayScore: number;
    /** Is the forecast side the home team? (spread only) */
    isHome?: boolean;
    /** Optional league context for market sanitization. */
    league?: string | null;
}
export interface BenchmarkGradingResult {
    /** The benchmark forecast number actually used for grading. */
    benchmarkForecast: number | null;
    /** The original forecast as published. */
    originalForecast: number | null;
    /** The closing market line. */
    closingMarket: number | null;
    /** Which source was selected as the benchmark ('original', 'closing', 'equal', etc). */
    benchmarkSource: BenchmarkSource;
    /** Final grade: W, L, or P. */
    grade: BenchmarkGrade;
    /** Named grading policy used. */
    gradingPolicy: 'best_valid_number';
    /** The forecast type graded. */
    forecastType: ForecastType;
    /** Debug explanation of how grade was determined. */
    explanation: string;
}
/**
 * Select the most advantageous valid number between original and closing.
 *
 * POLICY: Compare both values and use whichever is more favorable for grading.
 *   - If the original forecast is better, use the original forecast.
 *   - If the closing market is better, use the closing market.
 *   - If both are the same, use that shared value.
 *   - Do NOT default to one source just because it is newer.
 *
 * For spreads:
 *   - The LARGER number is always more favorable for the forecast side.
 *   - Favorite -5 vs close -7: max(-5, -7) = -5 (original, less points to lay)
 *   - Favorite -7 vs close -5: max(-7, -5) = -5 (closing, less points to lay)
 *   - Underdog +5 vs close +3: max(5, 3) = +5 (original, more cushion)
 *   - Underdog +3 vs close +5: max(3, 5) = +5 (closing, more cushion)
 *
 * For totals:
 *   - Over: LOWER total is more favorable (easier to go over) -> min(orig, close)
 *   - Under: HIGHER total is more favorable (easier to stay under) -> max(orig, close)
 */
export declare function selectBenchmarkForecast(forecastType: ForecastType, side: string, originalForecast: number | null, closingMarket: number | null): {
    value: number | null;
    source: BenchmarkSource;
};
export declare function sanitizeClosingSpreadForLeague(league: string | null | undefined, closingSpread: number | null | undefined): number | null;
/**
 * Grade a forecast using the benchmark-rule policy.
 *
 * This is the SINGLE SOURCE OF TRUTH for grading outcomes.
 * All performance views, summaries, and metrics must use this function.
 */
export declare function gradeForecast(input: BenchmarkGradingInput): BenchmarkGradingResult;
/**
 * Extract spread grading inputs from forecast_data and odds_data JSON blobs.
 * This is the bridge between the raw DB data and the grading engine.
 */
export declare function gradeFromForecastData(forecastData: any, oddsData: any, homeTeam: string, awayTeam: string, homeScore: number, awayScore: number, league?: string | null): BenchmarkGradingResult | null;
/**
 * Compute win rate from W-L-P counts.
 * Pushes are excluded from the denominator (W / (W + L)).
 */
export declare function computeWinRate(wins: number, losses: number): number | null;
/**
 * Format W-L-P record string.
 */
export declare function formatWLP(wins: number, losses: number, pushes: number): string;
//# sourceMappingURL=benchmark-grading.d.ts.map