/**
 * Candidate Judge
 *
 * Tie-breaks exploration candidates whose objective (gate) scores are equal.
 * Objective verification always outranks judgment — the judge is consulted
 * only among candidates tied at the top of the ladder ranking.
 */
const CANDIDATE_OUTPUT_CHARS = 2_000;
function buildJudgePrompt(task, candidates) {
    const sections = [
        'You are a strict senior code reviewer judging competing solutions to the same task.',
        'Rate on: correctness, completeness, simplicity, and how well gate feedback was addressed.',
        '',
        `TASK: ${task}`,
        '',
    ];
    for (const c of candidates) {
        sections.push(`=== CANDIDATE ${c.id} (strategy: ${c.strategy}, gate score: ${Math.round(c.score * 100)}%) ===`);
        sections.push(c.output.slice(0, CANDIDATE_OUTPUT_CHARS));
        if (c.ladderFeedback) {
            sections.push(`Gate feedback: ${c.ladderFeedback.slice(0, 500)}`);
        }
        sections.push('');
    }
    sections.push(`Respond with ONLY a JSON object: {"winner": "<candidate id>", "rationale": "<one sentence>"}`);
    return sections.join('\n');
}
/** Extract the first JSON object from model output (tolerates prose/fences). */
export function extractJson(text) {
    const match = text.match(/\{[\s\S]*?\}/);
    if (!match)
        return null;
    try {
        return JSON.parse(match[0]);
    }
    catch {
        return null;
    }
}
/**
 * Model-backed judge. Falls back to the first candidate (caller's ranking
 * order) when the verdict is unparseable or names an unknown candidate.
 */
export function createModelJudge(executor) {
    return async (task, candidates) => {
        const fallback = {
            winnerId: candidates[0].id,
            rationale: 'judge fallback: kept objective ranking',
        };
        if (candidates.length < 2)
            return fallback;
        let raw;
        try {
            raw = await executor(buildJudgePrompt(task, candidates));
        }
        catch {
            return fallback;
        }
        const parsed = extractJson(raw);
        const winner = typeof parsed?.winner === 'string' ? parsed.winner : undefined;
        if (!winner || !candidates.some((c) => c.id === winner)) {
            return fallback;
        }
        return {
            winnerId: winner,
            rationale: typeof parsed?.rationale === 'string' ? parsed.rationale : '',
        };
    };
}
//# sourceMappingURL=judge.js.map