/**
 * pipeline/chronic-failures.ts
 *
 * Aggregates error data across recent reports to identify tasks that
 * consistently fail (>threshold error rate). This catches structurally
 * broken tasks — wrong model config, tasks too complex for the provider,
 * persistent API incompatibility — that would otherwise be invisible.
 *
 * @see docs/exec-plans/eval-pipeline-timeout-resilience.md — Phase 5
 */
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
/**
 * Query recent reports and identify tasks with chronic failures.
 *
 * @param reportStore - The report store to query
 * @param options - Lookback window and threshold
 * @returns Chronic failure report, or null if no reports found
 */
export async function detectChronicFailures(reportStore, options = {}) {
    const lookback = options.lookback ?? 10;
    const threshold = options.threshold ?? 0.5;
    const reports = await reportStore.queryRecentErrors(lookback);
    if (reports.length === 0) {
        return { lookback, threshold, failures: [], reportsFound: 0 };
    }
    // Aggregate errors by task
    const taskErrors = new Map();
    for (const report of reports) {
        for (const error of report.errors) {
            let entry = taskErrors.get(error.task);
            if (!entry) {
                entry = {
                    runsWith: new Set(),
                    modelErrors: new Map(),
                    errors: [],
                };
                taskErrors.set(error.task, entry);
            }
            entry.runsWith.add(report.reportId);
            entry.modelErrors.set(error.model, (entry.modelErrors.get(error.model) ?? 0) + 1);
            entry.errors.push(error.error);
        }
    }
    // Identify chronic failures (error rate > threshold)
    const failures = [];
    const totalRuns = reports.length;
    for (const [task, data] of taskErrors) {
        const errorRate = data.runsWith.size / totalRuns;
        if (errorRate >= threshold) {
            // Find the most common error message
            const errorCounts = new Map();
            for (const err of data.errors) {
                const truncated = err.slice(0, 200);
                errorCounts.set(truncated, (errorCounts.get(truncated) ?? 0) + 1);
            }
            const commonError = [...errorCounts.entries()].sort((a, b) => b[1] - a[1])[0]?.[0] ??
                "unknown";
            const modelBreakdown = [...data.modelErrors.entries()]
                .map(([model, errorCount]) => ({ model, errorCount }))
                .sort((a, b) => b.errorCount - a.errorCount);
            failures.push({
                task,
                errorRate,
                errorCount: data.runsWith.size,
                totalRuns,
                modelBreakdown,
                commonError,
            });
        }
    }
    // Sort by error rate descending
    failures.sort((a, b) => b.errorRate - a.errorRate);
    return { lookback, threshold, failures, reportsFound: reports.length };
}
// ---------------------------------------------------------------------------
// Formatting
// ---------------------------------------------------------------------------
/**
 * Format a chronic failure report for console output.
 */
export function formatChronicFailuresConsole(report) {
    const lines = [];
    lines.push(`Chronic Failure Report (last ${report.reportsFound} runs)`);
    lines.push("━".repeat(50));
    lines.push("");
    if (report.failures.length === 0) {
        lines.push("  ✅ No chronic failures detected (all tasks below " +
            `${(report.threshold * 100).toFixed(0)}% error threshold)`);
        lines.push("");
        return lines.join("\n");
    }
    lines.push(`  ⚠ ${report.failures.length} task(s) with chronic failures ` +
        `(>${(report.threshold * 100).toFixed(0)}% error rate):`);
    lines.push("");
    for (const f of report.failures) {
        lines.push(`  ${f.task}`);
        lines.push(`    Error rate: ${f.errorCount}/${f.totalRuns} runs ` +
            `(${(f.errorRate * 100).toFixed(0)}%)`);
        const models = f.modelBreakdown
            .map((m) => `${m.model} (${m.errorCount})`)
            .join(", ");
        lines.push(`    Models affected: ${models}`);
        lines.push(`    Common error: "${f.commonError}"`);
        lines.push("    Suggested action: Increase timeoutMs for affected models or simplify task");
        lines.push("");
    }
    return lines.join("\n");
}
