Spaces:
Sleeping
Sleeping
| /** | |
| * actionClaimDetector.ts — GAP-TRUTH: rileva affermazioni di azioni completate | |
| * nel testo finale e le confronta con proofLedger. | |
| * | |
| * Problema risolto: il finalOutputGate decideva "richiede prova?" guardando | |
| * `steps` (i tool effettivamente chiamati) — ma un LLM può scrivere | |
| * "Ho fatto il commit e il deploy" SENZA aver chiamato git_push/deploy_trigger | |
| * affatto. In quel caso `steps` non contiene alcun CRIT_TOOL → il gate | |
| * (versione precedente) passava SEMPRE, perché `requiresProof` derivava | |
| * solo dai tool call, non dal TESTO. | |
| * | |
| * Questo modulo chiude il cerchio: legge il TESTO (cosa l'LLM dichiara di | |
| * aver fatto) e lo incrocia con proofLedger (cosa è stato VERAMENTE | |
| * verificato), indipendentemente da `steps`. | |
| * | |
| * Design: | |
| * - Solo pattern in PRIMA PERSONA + TEMPO COMPLETATO ("ho fatto", "I've done", | |
| * "completato", "successfully") — evita falsi positivi su spiegazioni | |
| * generiche ("quando fai il commit...", "per pushare devi..."). | |
| * - Pure, sync. Unico import: type-only da proofLedger (zero costo runtime). | |
| * - Best-effort: in caso di eccezione interna, ritorna "nessuna claim" | |
| * (mai bloccante — il blocco fail-closed vero è in finalOutputGate | |
| * per garbage/empty, non qui). | |
| * | |
| * @module actionClaimDetector | |
| */ | |
| import type { Proof } from "./proofLedger"; | |
| // GAP-TRUTH-3: ClaimCategory, CATEGORY_LABELS, CATEGORY_TO_LEDGER_ACTIONS → single source of truth | |
| import { | |
| type ClaimCategory, | |
| CATEGORY_LABELS, | |
| CATEGORY_TO_LEDGER_ACTIONS, | |
| } from "./proofToolRegistry"; | |
| // Re-export per backward compat dei consumer esistenti (emitFinalText.ts, bench-truth-gate.mjs) | |
| export type { ClaimCategory }; | |
| export { CATEGORY_LABELS, CATEGORY_TO_LEDGER_ACTIONS }; | |
| // ClaimCategory, CATEGORY_LABELS, CATEGORY_TO_LEDGER_ACTIONS → vedi proofToolRegistry.ts (re-exportati sopra) | |
| // ─── Pattern: prima persona + completamento (IT + EN) ───────────────────────── | |
| // Tutti richiedono "ho/I've/I have/è stato/has been/successfully" + verbo al | |
| // participio passato — NON matchano imperativi, futuro, o spiegazioni generiche. | |
| const _CLAIM_PATTERNS: Record<ClaimCategory, RegExp[]> = { | |
| git_push: [ | |
| /\b(ho|abbiamo)\s+(già\s+)?(fatto\s+(il\s+)?)?(commit(t?ato)?|push(at[oi])?|spint[oi])\b/i, | |
| /\b(commit|push)\s+(e\s+(commit|push)\s+)?(è\s+stat[oi]\s+|sono\s+stat[ei]\s+)?(effettuat[oi]|complet[ao]t[oi]|fatt[oi]|riuscit[oi])\b/i, | |
| /\bho\s+(già\s+)?(caricat[oi]|invi?at[oi])\s+(le\s+)?modifiche/i, | |
| /\bmodifiche\s+(caricate|pushate|inviate|già\s+su)\s+(su\s+)?(git(hub)?|repo)/i, | |
| /\bI(?:'ve| have)\s+(already\s+)?(committed|pushed|push(ed)?\s+(the\s+)?changes)\b/i, | |
| /\b(commit|push)(ing)?\s+(is\s+)?(done|completed|successful)\b/i, | |
| /\bsuccessfully\s+(pushed|committed)\b/i, | |
| /\bchanges\s+(have\s+been|are)\s+(pushed|committed)\b/i, | |
| ], | |
| deploy: [ | |
| /\b(ho|abbiamo)\s+(già\s+)?(fatto\s+(il\s+)?)?deploy(at[oi])?\b/i, | |
| /\bdeploy\s+(è\s+stat[oi]\s+|sono\s+stat[ei]\s+)?(effettuat[oi]|complet[ao]t[oi]|riuscit[oi])\b/i, | |
| /\b(il\s+)?sito\s+(è\s+|risulta\s+)?(ora\s+)?(online|pubblicat[oi]|live|aggiornat[oi])\b/i, | |
| /\bI(?:'ve| have)\s+(already\s+)?deployed\b/i, | |
| /\bdeploy(ment)?\s+(is\s+)?(done|completed|successful|live)\b/i, | |
| /\bsuccessfully\s+deployed\b/i, | |
| /\b(the\s+)?site\s+is\s+(now\s+)?(live|online|updated)\b/i, | |
| ], | |
| file_write: [ | |
| /\b(ho|abbiamo)\s+(già\s+)?(creat[oi]|salvat[oi]|scritt[oi]|aggiornat[oi]|modificat[oi]|sovrascritt[oi])\s+(il\s+)?file/i, | |
| /\bfile\s+(è\s+stat[oi]\s+|sono\s+stat[ei]\s+)?(creat[oi]|salvat[oi]|aggiornat[oi]|scritt[oi]|modificat[oi])\b/i, | |
| /\bI(?:'ve| have)\s+(already\s+)?(created|saved|written|updated|overwritten)\s+(the\s+)?file/i, | |
| /\b(the\s+)?file\s+(has\s+been|is\s+now)\s+(created|saved|updated|written)\b/i, | |
| ], | |
| code_exec: [ | |
| /\b(ho|abbiamo)\s+(già\s+)?eseguit[oi]\s+(il\s+)?codice/i, | |
| /\bcodice\s+(è\s+stat[oi]\s+)?eseguit[oi]\s+(con\s+successo)?/i, | |
| /\bI(?:'ve| have)\s+(already\s+)?(run|executed)\s+(the\s+)?code/i, | |
| /\bcode\s+(has\s+)?(ran|executed|run)\s+successfully\b/i, | |
| ], | |
| }; | |
| /** | |
| * Rileva quali categorie di azione il TESTO dichiara come completate. | |
| * Scansiona tutte le categorie; ritorna l'insieme di quelle con almeno | |
| * un pattern match in prima persona + completamento. | |
| */ | |
| export function detectClaimedCategories(text: string): Set<ClaimCategory> { | |
| const out = new Set<ClaimCategory>(); | |
| if (!text || text.length < 8) return out; | |
| try { | |
| // Limita la scansione ai primi 4000 char — i claim di completamento | |
| // stanno tipicamente in apertura/chiusura della risposta, non nel mezzo | |
| // di blocchi di codice lunghi. | |
| const sample = text.length > 4000 ? text.slice(0, 2000) + text.slice(-2000) : text; | |
| for (const cat of Object.keys(_CLAIM_PATTERNS) as ClaimCategory[]) { | |
| if (_CLAIM_PATTERNS[cat].some(re => re.test(sample))) out.add(cat); | |
| } | |
| } catch { /* best-effort — mai bloccante */ } | |
| return out; | |
| } | |
| /** | |
| * Per ogni categoria dichiarata, verifica se proofLedger ha almeno una prova | |
| * VERIFICATA per i tool corrispondenti. | |
| * | |
| * @returns lista di etichette leggibili per le categorie PROBLEMATICHE | |
| * (claim presente, ma nessuna prova verificata) — vuota se tutto ok. | |
| */ | |
| export function checkClaimsAgainstLedger( | |
| claimed: Set<ClaimCategory>, | |
| snapshot: readonly Proof[], | |
| ): string[] { | |
| const problems: string[] = []; | |
| try { | |
| for (const cat of claimed) { | |
| const actions = CATEGORY_TO_LEDGER_ACTIONS[cat]; | |
| const entries = snapshot.filter(p => actions.includes(p.action)); | |
| if (entries.length === 0) { | |
| problems.push(`${CATEGORY_LABELS[cat]} (nessuna azione registrata)`); | |
| } else if (!entries.some(e => e.verified)) { | |
| problems.push(`${CATEGORY_LABELS[cat]} (eseguito ma non verificato)`); | |
| } | |
| // entries.some(verified) → almeno una prova verificata per questa categoria → OK | |
| } | |
| } catch { /* best-effort — mai bloccante */ } | |
| return problems; | |
| } | |