397777089e
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
42 lines
2.2 KiB
JavaScript
42 lines
2.2 KiB
JavaScript
#!/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 };
|
|
}
|