ms-ai-architect/scripts/kb-eval/lib/gold-consistency.mjs

62 lines
2.6 KiB
JavaScript

// lib/gold-consistency.mjs — G3 (programdok §8): deterministisk gull-intern-
// konsistens-vakt. Fanger FP1-klassen (Spor 2b): et claim med verdict=correct
// hvis egen `notes` innrømmer at den påståtte verdien ikke er bekreftet mot
// kilden («uverifisert / illustrativ / ikke i kilden»). Verdikten sier «matcher
// kilden»; noten sier det motsatte — en selvmotsigende annotasjon.
//
// Tripwire-design: brede markører for recall, presisjon via en eksplisitt
// `consistency_waiver`-escape-hatch (menneske-i-loop §4c). Linten klassifiserer
// ikke — den surfacer kandidater et menneske enten relabel-er eller waiver-er
// med begrunnelse. Ren funksjon, ingen I/O; testet i tests/kb-eval/.
// Markører som — i en note festet til et verdict=correct-claim — innrømmer at
// den påståtte verdien IKKE er bekreftet mot den siterte kilden. Holdt brede med
// vilje (recall); falske positive absorberes av waiver-hatchen, ikke av en
// perfekt regex. Hver er en delstreng matchet case-insensitivt.
export const CONTRADICTION_MARKERS = [
'uverifisert',
'ikke verifiser', // ikke verifisert / ikke verifiserbar
'kan ikke verifiser',
'illustrativ', // illustrativt / illustrative
'ikke i kilden',
'ikke nevnt i kild',
'kilden oppgir ikke',
'ikke bekreftet',
'ubekreftet',
'source_silent',
'plassholder',
'placeholder',
'eksempel-tall',
'eksempeltall',
];
// Verdikter som hevder samsvar med dagens kilde. Kun disse kan motsi en
// «ikke bekreftet»-note: outdated/wrong/unsourced anerkjenner allerede ikke-match.
const ASSERTS_SOURCE_MATCH = new Set(['correct']);
export function findContradictionMarkers(notes) {
if (!notes || typeof notes !== 'string') return [];
const lc = notes.toLowerCase();
return CONTRADICTION_MARKERS.filter((m) => lc.includes(m));
}
function hasWaiver(claim) {
return typeof claim.consistency_waiver === 'string' && claim.consistency_waiver.trim().length > 0;
}
// Returnerer { ok, flagged: [{ id, verdict, notes, markers }] }.
// Et claim flagges når: verdikten hevder kilde-samsvar, noten bærer en
// motsigelses-markør, og det ikke finnes et ikke-tomt consistency_waiver.
export function lintGoldConsistency(goldSet) {
const claims = (goldSet && goldSet.claims) || [];
const flagged = [];
for (const c of claims) {
if (!ASSERTS_SOURCE_MATCH.has(c.verdict)) continue;
if (hasWaiver(c)) continue;
const markers = findContradictionMarkers(c.notes);
if (markers.length) {
flagged.push({ id: c.id, verdict: c.verdict, notes: c.notes, markers });
}
}
return { ok: flagged.length === 0, flagged };
}