# Audit 04 - Agnosticismo runtime/provider: contro-analisi e stato

**Documento verificato:** [`20260923_audit_04_model_provider_agnosticism.md`](20260923_audit_04_model_provider_agnosticism.md)
**Baseline Git:** `0e2a91553a3bb782998dc109bc19dfeb8a8bedfe`
**Data verifica:** 2026-09-23
**Contratto risultante:** [`docs/architecture/provider-agnosticism.md`](../../architecture/provider-agnosticism.md)

Parte dell'audit e' stata assorbita dall'audit 03, completato prima di questo:

- model ID rimossi dal canonico;
- `execution_policy` con modello `inherit`;
- availability per runtime;
- routing dal catalogo;
- eccezione registrata per Graphify.

Questa fase copre il resto: capability, runtime registry, adapter, skill condivise ed enforcement.

## 1. Affermazioni verificate

| Finding | Affermazione | Esito | Evidenza |
|---|---|---|---|
| AGN-001 | Il canonico contiene modelli e campi host-specific | **Confermata, in parte gia' risolta** | I modelli sono stati rimossi nell'audit 03. Restava `runtime_permissions.codex_sandbox_mode` come rappresentazione universale dei permessi, usata anche per derivare `writePolicy` nel catalogo |
| AGN-002 | Non esiste un manifest unico dei runtime | **Confermata** | Liste runtime duplicate in `runtime-selection`, `state-manager` (target dei profili e snapshot skill), `mcp-startup-profile`, `project-mcp`, `install-user-runtime` (`RUNTIME_ROOTS`), `runtime-aggregation`, GUI `app.js`, `agent-catalog-runtime.mjs` e `hooks-generator-lib` |
| AGN-003 | Skill condivise chiamano primitive Codex | **Confermata** | 14 playbook impeccable citavano lo "structured user-input tool" di Codex. craft/shape richiedevano `image_gen`, critique `spawn_agent`. `ai-documents-validation-document-type` aveva wording Codex |
| AGN-004 | Catalogo hook misto canonico/host | **Confermata** | `HOOKS` conteneva insieme `matcher`, `antigravityMatcher` e `cursorEvent` |
| AGN-005 | Tool agenti hardcoded nel generatore | **Confermata** | `copilotToolsForRole`, `geminiToolsForRole` e `claudeToolsForRole` ramificavano sul `roleId` |
| AGN-006 | Availability diversa dalla capability | **Confermata, parzialmente gia' risolta** | La v2 per runtime e' stata introdotta nell'audit 03. Mancava un modello delle capability |
| AGN-007 | Aggiungere un client richiede molte modifiche | **Confermata** | Vedi AGN-002. I blocchi installer per runtime (path e merge dei formati) restano per natura specifici dell'host |
| AGN-008 | Graphify ha binding Gemini e spawn generico | **Confermata** | Gestito come eccezione registrata (opzione B) nell'audit 03. Ora copre anche le credenziali e `spawn_agent` |
| AGN-009 | Documentazione normativa non neutrale | **Confermata** | L'esempio `gpt-5.4` nel README era gia' rimosso nell'audit 03. La guida viva diceva ancora "progettata prima per agenti coding/Codex" |
| AGN-010 | Metadata analytics non aggiornati | **Confermata** | `analytics-node/package.json` citava solo Codex e VS Code Copilot. Nessuna ramificazione su modello o provider in query e aggregati (verificato con grep su `startsWith('gpt'`/`'claude'` e `provider ===`) |
| AGN-011 | Il confronto token usa un tokenizer OpenAI | **Confermata** | L'`o200k_base` e' dichiarato nel commento del generatore ma non nei tooltip della UI |
| AGN-012 | Le proiezioni devono restare one-way | **Nessuna violazione, enforcement assente** | Nessun import da `gpts/` nel codice |
| AGN-013 | Evaluator semantico futuro | **Non applicabile ora** | Non e' implementato. Il guardrail (protocollo OpenAI-compatible come adapter di trasporto, non come contratto) e' documentato nel contratto architetturale |
| AGN-014 | Manca un linter provider-agnostic | **Confermata, parzialmente** | L'audit dei contratti (audit 03) copriva model ID, `agent_type` e fork. Non copriva credenziali, tool host, campi modello host-specifici e import dalle proiezioni |
| AGN-015 | Manca conformance cross-runtime | **Confermata** | Nessun test di parita' tra liste runtime, hook e capability |

## 2. Finding nuovi

- **N1 - L'installer non aggiornava mai le copie fisiche dei profili agente.** Con il fallback a copia, un file esistente veniva segnalato come "already exists" e restava invariato. I profili nella home erano quindi fermi ai modelli dell'incidente (`gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`) anche dopo aver rilanciato l'installer. I 4 `explorer` legacy non venivano rimossi. Corretto nel commit `64996d0e`.
- **N2 - La prima correzione di N1 poteva sovrascrivere modifiche dell'utente.** Il commit `64996d0e` considerava "gestita" qualunque copia con lo stesso nome di ruolo, e per `explorer` anche la stessa descrizione. Un profilo personalizzato dall'utente sarebbe stato sostituito. Lo ha rilevato lo smoke esistente sulla migrazione di `explorer`. Il criterio attuale e' piu' stretto: una copia e' gestita solo se coincide byte per byte (a meno dei CRLF) con una versione **committata** dello stesso file. Le versioni vengono lette con un `git log` per directory e un `git cat-file --batch`, senza costo misurabile sul planning. Senza git sono accettate solo le corrispondenze esatte. Sulla home reale il piano sostituisce 30 profili obsoleti e rimuove i 4 `explorer` legacy: tutti coincidono con una versione storica del repository.
- **N3 - Uno smoke dell'audit 01 dipendeva dalla configurazione reale dell'utente.** Su Windows il path MCP di VS Code deriva da `APPDATA`, e il test non lo isolava. Dopo la reinstallazione il `mcp.json` reale conteneva `office-mcp-server` e il test falliva. Ora `APPDATA` punta alla home di test.
- **N4 - Il ruolo `docs_writer` su Copilot non aveva il tool `search`,** nonostante la capability `repo.search`. Derivando i tool dagli adapter il profilo generato lo acquisisce: e' l'unica differenza nei profili rigenerati.

## 3. Implementazione

| Fase audit | Stato | Note |
|---|---|---|
| PR1 - Contratto architetturale | **Fatto** | `docs/architecture/provider-agnosticism.md` e §2.2.1 della guida viva |
| PR2 - Runtime registry | **Fatto** | `scripts/runtime/runtime-registry.js` contiene: <ul><li>`AI_RUNTIMES`: `supports`, `agentProfile`, `mcpConfig` e capability con stato `available`/`unavailable`/`unknown`;</li><li>`CAPABILITIES`, `RUNTIME_IDS`, `capabilityStatus`;</li><li>`validateRuntimeRegistry`, che rifiuta i campi provider o modello.</li></ul> Derivano dal registry `runtime-selection`, `state-manager` (target dei profili, `unsupported` e snapshot skill), `mcp-startup-profile` (`CLIENT_MCP_CAPABILITIES`), `project-mcp` (runtime con scope di progetto verificato) e `install-user-runtime` (`RUNTIME_ROOTS`) |
| PR3 - Pulizia del canonico | **Fatto** | `runtime_permissions` e' sostituito da `tool_capabilities` per ruolo. `writePolicyFor(role)` produce la write policy del catalogo e il sandbox Codex. Il campo legacy e' ancora letto, deve essere coerente con le capability ed emette un warning di migrazione |
| PR4 - Capability per agenti e hook | **Fatto** | `RUNTIME_TOOL_ADAPTERS` mappa le capability sui tool Copilot, Gemini e Claude (`toolsForRuntime`), senza branch sui ruoli. `CANONICAL_HOOKS` separa evento e script da `HOST_HOOK_MAPPINGS` (`nested`/`antigravity`/`cursor`, dove `null` e' un N/A esplicito). La vista `HOOKS` e' identica alla precedente |
| PR5 - Skill condivise | **Fatto** | Tutte le skill condivise usano ora `user.question.structured`, con domanda in chat come fallback. craft e shape usano `image.generate` e dichiarano il fallback `capability_unavailable:image.generate`. critique usa un gate `subagent.spawn`. `impeccable-codex.md` e' etichettato come note host ed e' registrato come eccezione. Il wording Codex in `ai-documents-validation-document-type` e' neutralizzato |
| PR6 - Analytics e UI | **Fatto** | La descrizione del package elenca tutti i runtime. I tooltip dei token dichiarano il tokenizer `o200k_base` come unita' di riferimento, distinta dai token contati dal provider |
| PR7 - Enforcement e conformance | **Fatto, con deviazioni** | L'audit dei contratti rileva: <ul><li>credenziali provider;</li><li>tool host senza capability gate sulla stessa riga;</li><li>campi modello host-specifici;</li><li>import da `gpts/` nel codice core (area `core-code`, solo questa regola).</li></ul> Il nuovo blocco `Test 0-provider-agnostic` copre: <ul><li>validazione del registry;</li><li>completezza delle capability;</li><li>parita' delle liste runtime (GUI, UMD, hook, catalogo);</li><li>mapping hook espliciti per host;</li><li>violazioni sintetiche per ogni tipo;</li><li>righe con capability gate che passano.</li></ul> |

KPI dopo l'intervento: `agent-contract-audit --strict` riporta **0 errori, 0 warning, 21 eccezioni registrate**.

- KPI 1-3 (model ID, credenziali, tool host non gated nel core): **0**.
- KPI 4: un'unica fonte, piu' liste locali vincolate da test di parita'.
- KPI 7: nessuna sostituzione silenziosa nelle skill modificate.

## 4. Deviazioni motivate

- **Registry in `scripts/runtime/`, non in `config/`.** Il planner di `test:affected` non mappa una nuova directory `config/`: il gate `--strict` la considererebbe area scoperta.
- **Nessuno script npm `test:provider-agnostic`.** L'audit strict gira gia' in `test:routing`, e i test di parita' negli smoke runtime, entrambi in CI. Un nuovo script avrebbe richiesto di modificare `package.json` e il registry delle suite senza aggiungere copertura.
- **I moduli portabili mantengono liste locali.** Gli hook `.mjs` vengono copiati in directory temporanee dagli smoke Codex, e `runtime-aggregation` e `app.js` girano nel browser: non possono importare il registry Node. La coerenza e' garantita dai test di parita', non da un import.
- **Blocchi installer per runtime non unificati.** Path e merge dei formati (TOML Codex, JSON VS Code/Claude/Cursor, adapter Antigravity) sono adapter per natura. Unificarli era fuori scope (AGENTS.md: niente refactor estesi); le liste derivabili sono state derivate.
- **Nessuna suite `tests/runtime-portability.test.mjs` separata con fixture JSON per capability.** Le capability sono dati del registry, gia' coperti dai test di parita' e di validazione. Fixture duplicate sarebbero un'altra fonte da mantenere.
- **Capability quasi tutte `unknown`.** Sono marcate solo quelle verificate (spawn e hook Codex e Claude, domanda strutturata Claude, MCP client, N/A di Cursor). Per il vincolo 33.4 dell'audit, `unknown` non viene mai promosso ad `available`.

## 5. Azioni per l'utente

- Rilanciare `node scripts/install-user-runtime.js --all`. Il nuovo criterio sostituisce i 30 profili agente obsoleti ancora installati e rimuove i 4 `explorer` legacy. I profili modificati a mano restano intatti e compaiono come WARNING.
- Riavviare Codex, Claude Code e gli altri client, oltre al server MCP analytics (il `package.json` e' cambiato: solo la descrizione, nessuna dipendenza).
