#!/usr/bin/env node
/**
 * judge-evaluator (D31, §9.4) — оценщик ПОСТФАКТУМ. Отдельный (не сам судья):
 * сверяет прошлые вердикты судьи И роутера с тем, что вылезло НИЖЕ (на Гейте-3 / у
 * владельца). Промах = проблема, которую пропустил GO-вердикт. Систематическую халтуру
 * ловит по СЛЕДУ (частота промахов), а не по одному вердикту. Чистая функция над данными;
 * источник (лог вердиктов J8 + всплывшие проблемы) подаётся снаружи (4-G/живой прогон).
 */
const DEFAULT_THRESHOLD = 0.2;

function rate(misses, totalGo) {
  return totalGo > 0 ? misses / totalGo : 0;
}

/**
 * @param {object} a
 * @param {Array<{verdict_id,decision,source?}>} a.verdicts - прошлые вердикты (GO/NO-GO)
 * @param {Array<{missed_by,where?}>} a.surfaced - проблемы, вылезшие ниже (missed_by → id вердикта)
 * @param {number} [a.threshold]
 */
export function evaluatePostfactum({ verdicts = [], surfaced = [], threshold = DEFAULT_THRESHOLD } = {}) {
  const goById = new Map();
  for (const v of verdicts) {
    if (v && v.decision === 'GO') goById.set(v.verdict_id, v.source || 'unknown');
  }
  // Промах = всплывшая проблема, пропущенная GO-вердиктом (NO-GO-вердикт её «поймал» — не промах).
  const missList = (surfaced || []).filter((s) => s && goById.has(s.missed_by));
  const totalGo = goById.size;
  const misses = missList.length;

  const bySource = {};
  const sources = new Set([...goById.values()]);
  for (const src of sources) {
    const srcGo = [...goById.values()].filter((x) => x === src).length;
    const srcMiss = missList.filter((s) => goById.get(s.missed_by) === src).length;
    bySource[src] = { totalGo: srcGo, misses: srcMiss, missRate: rate(srcMiss, srcGo) };
  }

  const missRate = rate(misses, totalGo);
  return { totalGo, misses, missRate, flag: totalGo > 0 && missRate > threshold, bySource };
}
