# 07 — Eval gap analysis

Fonte evidenze: `eval-inventory.raw.json` (subagente C) + sintesi main agent. Branch: `master` (il branch candidato aggiunge solo test di routing infra, v. `06-*.md`).

## Quadro generale (FACT)

- Tutte le 21 skill hanno esattamente un `evals/evals.json` → copertura **nominale** 100%.
- **Nessun eval di skill è eseguito automaticamente**: sono fixture documentali/manuali (confermato da `skills/svg/evals/README.md`); `scripts/check-skill-evals-json.js` valida solo la sintassi JSON, non è in npm scripts né in CI (solo step manuale in `docs/pr-checklist-mcp.md:13`).
- Gli unici test eseguibili e CI-gated riguardano l'**infrastruttura di routing** (`tests/routing-hooks.test.mjs` 25 casi, `scripts/test-routing-engine.mjs` 16 engineCases + ~70 assert inline, `smoke-codex-hooks.js`, `build-routing-catalog.mjs`) e i portable agents. I 16 smoke MCP (`tests/smoke/*.smoke.mjs`) sono eseguibili ma NON in CI.
- Categorie con copertura **zero** su tutto il repo: **efficienza** (0), **cross-model** (0), **ablation** (0). Regressione: quasi solo infra (1).

Conseguenza (INFERENCE): il sistema misura molto bene "il router sceglie come previsto dai fixture" e non misura affatto "la skill migliora l'outcome del task" — esattamente il gap che la domanda centrale dell'audit richiede di colmare. Gli eval documentali premiano l'aderenza alla procedura; nessuno confronta strategie alternative.

## Precisazione terminologica: outcome dichiarato vs outcome eseguito (correzione 2026-07-19)

La tabella per-skill sottostante e `eval-inventory.raw.json` attribuiscono la categoria "outcome" a diverse skill. Le due affermazioni ("alcune skill hanno outcome coverage" e "nessun eval misura l'outcome", SKAUD-013) sembrano contraddirsi; non lo sono, ma la terminologia originale era ambigua. Definizione corretta:

- **Outcome dichiarato (documentale)** — il caso eval descrive un risultato atteso (`expected_output`/`expectations`) in prosa dentro un fixture JSON che nessun harness esegue o giudica automaticamente. È ciò che la tabella chiama "outcome": presente in 15 file eval. Valore: rubrica manuale/LLM-judge *potenziale*, zero verifica effettiva.
- **Outcome eseguito e verificato** — un runner esegue il prompt contro un modello, valuta il risultato contro criteri machine-checkable e produce pass/fail riproducibile. Copertura attuale: **0 su tutto il repo** (FACT, evidenza F-048; unica eccezione parziale: gli smoke deterministici della skill svg, che però testano i tool, non l'outcome del task con modello).

SKAUD-013 va quindi letto così: non "mancano casi outcome" (ne esistono 15 file in forma dichiarata), ma "manca l'infrastruttura che trasformi l'outcome dichiarato in outcome verificato". Per questo il task è stato riformulato (v. backlog rivisto): **prima** schema eval v2 (campo `success_criteria` machine-checkable, retro-compatibile) + **runner eseguibile**, e **solo dopo** l'aggiunta di nuovi casi. Aggiungere casi allo stato attuale aumenterebbe solo la documentazione, non la misura.

## Copertura per skill (categorie presenti → mancanti principali)

| Skill | Casi | Coperte | Mancanti critiche |
| --- | --- | --- | --- |
| mcp-master-orchestrator | 11 | routing, trigger, anti-trigger | outcome, efficienza (costo coordinamento), ablation |
| mcp-technical-analyst | 14 | procedura, outcome, routing, safety | efficienza, robustness, ablation |
| mcp-code-reviewer | 12 | outcome, routing, procedura | safety (falsi positivi), cross-model |
| mcp-mantis-ticket-writer | 15 | procedura, outcome, routing | robustness (input incompleti) |
| svg | 17 | routing, procedura, outcome, robustness | ablation; eval 11/15/16 troppo accoppiati (v. sotto) |
| mcp-frontend-performance-debugger | 10 | routing, procedura, outcome, robustness | efficienza |
| mcp-coldfusion-developer | 8 | procedura, routing, safety | outcome reale su migrazione |
| ai-documents-validation-document-type | 8 | routing, procedura, outcome | portabilità (path E:\ hardcoded) |
| mcp-git-mantis-workflow | 7 | procedura, outcome, safety | anti-trigger vs orchestrator |
| mcp-handoff-pack | 7 | outcome, anti-trigger, procedura | — (adeguata al ruolo) |
| mcp-memory-operator | 6 | safety, procedura, routing | outcome (recall utile?) |
| mcp-skill-miner | 6 | trigger, anti-trigger, procedura | outcome |
| mcp-analytics-operator | 5 | outcome, safety, procedura | anti-trigger vs skill-miner |
| mcp-browser-automation | 5 | procedura, trigger, anti-trigger | outcome |
| mcp-database-expert | 5 | procedura, outcome, safety, anti-trigger | — |
| mcp-grid-ui-debugger | 5 | trigger, routing, procedura | mismatch: 7 eval_focus per 5 casi (FACT) |
| mcp-mantis-test-writer | 5 | anti-trigger, safety, procedura | **schema divergente** (v. sotto) |
| mcp-sophia-yii-developer | 5 | routing, procedura, outcome | robustness |
| mcp-runtime-integrator | 5 | procedura, anti-trigger, robustness | outcome |
| mcp-office-expert | 3 | procedura, outcome | set più piccolo del repo per 3 formati (Word/Excel/PDF) |
| mcp-docs-navigator | 9 | routing, procedura, outcome | efficienza (verbosità ricerca) |

## Problemi puntuali (FACT, con evidenza)

1. **Schema divergente**: `skills/mcp-mantis-test-writer/evals/evals.json` usa `{version:1, cases[], expect[]}` invece dello schema comune `{skill_name, eval_focus, evals[]}`; un reader generico legge `cases_count: 0` silenziosamente (riprodotto dal subagente C).
2. **Accoppiamento all'implementazione**:
   - `ai-documents-validation-document-type` id 1 (riga 12): path assoluto `E:\ai-documents-validation`;
   - `svg` id 11/15 (righe 132-183): policy hardcoded "inkscape primary / mai rsvg-convert su Windows"; id 16 (riga 192): path tool hardcoded;
   - `scripts/test-routing-engine.mjs:37-54,169-234`: assert accoppiati ai nomi di campo interni (`positiveLocks`, `catalogStatus` ecc.) — un refactor del return shape rompe decine di assert insieme.
3. **Doppio binario non collegato**: gli 11 casi routing dell'orchestrator (documentali) e i fixture eseguibili `fixtures/hooks/legacy-modernization-routing.json` coprono gli stessi concetti senza fonte comune → possono driftare (FACT, nota C).
4. **`check-skill-evals-json.js` non wired** in npm/CI: la validazione anche solo sintattica dipende dalla disciplina manuale (FACT).

## Eval proposti (RECOMMENDATION)

**Eval schema v2 + runner (priorità 1, prerequisito)** — SKAUD-013 riformulato: (a) schema v2 retro-compatibile con `success_criteria[]` machine-checkable (check deterministici o `judge_prompt` per LLM-judge) e `schema_version`; (b) runner eseguibile (`scripts/run-skill-evals.mjs`) che esegue i casi v2 contro un modello configurabile e produce pass/fail JSONL, con giudizio **blind** per i criteri LLM-judge (stesso protocollo di `08-ablation-test-plan.md` §Blind judging: identificatori anonimi, nessun metadata di variante/modello/costo prima del giudizio); (c) solo dopo, migrazione dei casi outcome-dichiarato esistenti di orchestrator/technical-analyst/code-reviewer al formato verificabile. Senza (a)+(b), nuovi casi restano documentazione.

**Ablation eval (priorità 1)** — vedi `08-ablation-test-plan.md`: 13 task eseguiti sulle varianti pertinenti A/B/C/D/E1/E2 (confronti canonici B-A, C-B, D-B, E1-D, E2-D); senza questi non è possibile classificare con confidenza le istruzioni MODEL_COMPENSATION.

**Cross-model eval (priorità 2)** — eseguire il set di routing eval documentali dell'orchestrator con un modello economico e uno frontier e confrontare la skill scelta: misura se i trigger dipendono dalla capacità del modello.

**Efficienza (priorità 2)** — budget di tool-call/handoff per i 3 workflow compositi dell'orchestrator; oggi nessun eval penalizza il lavoro superfluo.

**Fix meccanici (priorità 1, modello economico)** — riallineare lo schema di mantis-test-writer; rimuovere i path hardcoded; wiring di `check-skill-evals-json.js` in `npm test`; riconciliare i 7 eval_focus/5 casi del grid-ui-debugger. Task atomici in `10-prioritized-backlog.json` (SKAUD-010..-014).
