# 20260923 - Audit agent model, routing e binding runtime

**File:** `20260923_audit_agent_model_routing.md`  
**Data:** 2026-09-23  
**Repository target:** `sophiadeveloper/mcp-servers`  
**Snapshot analizzato:** commit `c6f09d9c253a12b710c4a61bd0dc519585dc98e3` (`master` al momento dell'analisi)  
**Documento collegato:** `20260923_audit_subagent_usage.md`  
**Tipo documento:** piano implementativo per agenti  
**Priorità:** alta  
**Stato:** pronto per implementazione incrementale

---

## 1. Obiettivo

Completare l'audit sui subagenti affrontando un problema distinto dal solo fan-out:

1. eliminare la dipendenza strutturale da nomi di modello concreti e soggetti a churn;
2. rendere il catalogo degli agenti realmente canonico, evitando liste ruolo duplicate o incomplete;
3. rendere deterministica la relazione tra:
   - ruolo Sophia selezionato;
   - profilo custom installato sul runtime corrente;
   - subagente effettivamente avviato dall'host;
4. impedire fallback silenziosi verso agenti generici o "equivalenti" quando era stato selezionato un ruolo custom preciso;
5. distinguere nettamente:
   - identità logica del ruolo;
   - nickname/display name;
   - modello;
   - runtime;
   - meccanismo concreto di spawn;
6. introdurre telemetria privacy-safe per confrontare **agente raccomandato** e **agente effettivamente eseguito**.

Questo documento estende `20260923_audit_subagent_usage.md`.

Non sostituisce le decisioni già prese lì su:

- subagenti opt-in;
- fan-out massimo;
- contesto bounded;
- divieto di full-history fork come default;
- controllo di profondità;
- separazione dei `guardian_review`;
- misurazione token/costo;
- stop alla delegazione ricorsiva.

Il nuovo focus è:

```text
selection
    -> exact logical role
    -> runtime capability
    -> runtime profile
    -> exact dispatch
    -> observed execution
```

anziché l'attuale modello prevalentemente advisory:

```text
selection
    -> textual hint
    -> host/model decides what to do
    -> maybe custom agent
    -> maybe generic/equivalent agent
    -> no authoritative reconciliation
```

---

## 2. Chiarimento sui modelli "deprecati"

Nel repository sono presenti riferimenti a modelli vecchi rispetto alla baseline corrente, incluso `gpt-5.4` e `gpt-5.4-mini`.

È però importante non trasformare il problema in una semplice ricerca/sostituzione.

Alla data del 2026-09-23:

- `gpt-5.4` risulta ancora documentato come modello disponibile nell'API OpenAI;
- la pagina ufficiale delle deprecazioni OpenAI non dichiara genericamente deprecato `gpt-5.4`;
- esistono invece varianti/snapshot specifici deprecati e, soprattutto, la disponibilità di un modello può differire tra API, Codex, piano ChatGPT e runtime host;
- nell'incidente documentato in `20260923_audit_subagent_usage.md`, `gpt-5.4` e `gpt-5.4-mini` erano **non supportati dal runtime Codex collegato a quell'account**, causando spawn falliti.

Quindi la root cause non è:

```text
gpt-5.4 è sempre deprecato
```

ma:

```text
un ruolo Sophia contiene un model ID concreto
        +
quel model ID viene proiettato nel runtime
        +
la disponibilità reale cambia per host/account/versione
        =
profilo fragile e spawn potenzialmente fallito
```

Riferimenti correnti:

- OpenAI model page GPT-5.4: https://developers.openai.com/api/docs/models/gpt-5.4
- OpenAI deprecations: https://developers.openai.com/api/docs/deprecations
- GitHub Copilot custom agents: https://docs.github.com/en/copilot/reference/custom-agents-configuration
- GitHub Copilot CLI custom agents/subagents: https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-command-reference

La correzione deve quindi essere **model-agnostic by default**, non "aggiorna i nomi modello a quelli più recenti".

---

# 3. Evidenze nel repository

## 3.1 Fonte canonica degli agenti

La fonte dichiarata come canonica è:

```text
docs/agents/canonical-subagents.yaml
```

I ruoli attuali sono:

```text
scout
implementer
technical_analyst
code_reviewer
test_writer
docs_writer
ui_ux_engineer
```

La fonte contiene correttamente:

- `purpose`;
- `semantic_summary`;
- `routing_role`;
- `task_phases`;
- `capabilities`;
- `not_for`;
- `skill_affinities`;
- `prioritize`;
- `avoid`;
- `output`;
- `escalate_when`;
- `nickname_candidates`;
- `runtime_permissions`.

Contiene però anche:

```yaml
recommended_model_profile:
  default_model: ...
  codex_model: ...
  copilot_model: ...
  copilot_multiplier: ...
  reasoning_effort: ...
```

Questa parte lega la definizione semantica del ruolo a dettagli volatili del provider/runtime.

### Problema

Il ruolo:

```text
technical_analyst
```

deve significare:

```text
analisi tecnica read-only, multi-sorgente, evidence-based
```

non:

```text
usa necessariamente il model ID X sul provider Y
```

L'identità del ruolo deve sopravvivere al cambio di:

- generazione modello;
- piano utente;
- provider;
- policy runtime;
- disponibilità regionale;
- naming del modello;
- modello selezionato dal parent.

---

## 3.2 `portable-agents-lib.js` rende obbligatorio un modello concreto

File:

```text
scripts/portable-agents-lib.js
```

Il parser canonico inizializza:

```javascript
recommended_model_profile: {
  default_model: null,
  codex_model: null,
  copilot_model: null,
  copilot_multiplier: null,
  reasoning_effort: null,
}
```

e la validazione richiede almeno:

```javascript
if (!role.recommended_model_profile.default_model) {
  errors.push(...)
}
```

Per Codex:

```javascript
const codexModel =
  role.recommended_model_profile.codex_model
  || role.recommended_model_profile.default_model;

...
model = "${codexModel}"
```

Per Copilot:

```javascript
const copilotModel =
  role.recommended_model_profile.copilot_model
  || role.recommended_model_profile.default_model;

...
model: "${copilotModel}"
```

Quindi oggi un ruolo non può essere veramente model-agnostic.

---

## 3.3 Claude e Gemini sono già più agnostici

Lo stesso generatore usa invece:

```yaml
model: inherit
```

per:

- Claude Code;
- Gemini / Antigravity.

Questo dimostra che nel repository esistono già due strategie incompatibili:

```text
Codex/Copilot
    -> pin modello

Claude/Gemini
    -> inherit
```

Il target deve convergere verso:

```text
inherit/default host
```

come default comune, lasciando eventuali override concreti fuori dall'identità canonica del ruolo.

Per GitHub Copilot questo è anche coerente con il contratto corrente del client: il campo `model` è opzionale e, se omesso, il custom agent eredita il modello di default/sessione.

---

## 3.4 Riferimenti `gpt-5.4*` ancora presenti

La ricerca nel repository mostra riferimenti in almeno:

```text
README.md
docs/analisi-tecniche/analisi-codex-sandbox-mode-agenti.md
docs/analisi-tecniche/analisi-tecnica-agenti-code-reviewer-test-writer.md
docs/analisi-tecniche/analisi-tecnica-analytics-mcp-server.md
tests/fixtures/codex/codex-session.fixture.jsonl
tests/smoke/analytics-node.smoke.mjs
```

Non vanno trattati tutti allo stesso modo.

### Classificazione obbligatoria

| Categoria | Esempio | Azione |
|---|---|---|
| runtime normativo | `.codex/agents/*.toml` | eliminare pin non necessario |
| fonte canonica | `canonical-subagents.yaml` | rendere model-agnostic |
| documentazione operativa corrente | README / guide vive | rimuovere esempi che sembrano raccomandazioni correnti |
| documentazione storica | analisi milestone datate | mantenere solo se chiaramente storica |
| fixture parser | transcript con `gpt-5.4` | **non** aggiornare automaticamente |
| test di compatibilità analytics | assert su storico fixture | mantenere se testa correttamente il parser |

Il piano deve quindi introdurre un audit semantico e non un ban cieco sulla stringa `gpt-5.4`.

---

# 4. Il problema più grave: il catalogo è canonico solo parzialmente

## 4.1 Lista ruoli duplicata in `portable-agents-lib.js`

Esiste:

```javascript
const ROLE_IDS = [
  'scout',
  'implementer',
  'technical_analyst',
  'code_reviewer',
  'test_writer',
  'docs_writer',
  'ui_ux_engineer'
];
```

Questa lista duplica la fonte YAML.

Può essere tollerabile come assertion di schema minimo, ma non deve essere usata come inventario runtime indipendente.

Target:

```text
canonical-subagents.yaml
        |
        +--> generated catalog
        +--> generated runtime profiles
        +--> generated availability IDs
        +--> generated routing vocabulary
        +--> generated docs role summary
```

Nessuna nuova feature deve richiedere l'aggiunta manuale dello stesso ruolo in più elenchi.

---

## 4.2 `subagent-routing-policy.mjs` omette ruoli canonici

File:

```text
scripts/hooks/subagent-routing-policy.mjs
```

Contiene:

```javascript
const ROLE_PRIORITY = [
  'code_reviewer',
  'test_writer',
  'technical_analyst',
  'implementer',
  'scout'
];
```

Mancano:

```text
docs_writer
ui_ux_engineer
```

Anche `PHASE_SIGNALS` copre solo i cinque ruoli sopra.

Quindi il resolver dichiara di consumare il catalogo canonico, ma parte della selezione continua a dipendere da una lista manuale incompleta.

### Effetto secondario

L'ordinamento usa:

```javascript
ROLE_PRIORITY.indexOf(left.agent.id)
  - ROLE_PRIORITY.indexOf(right.agent.id)
```

Per i ruoli mancanti `indexOf()` restituisce `-1`.

Questo rende il tie-break non rappresentativo della policy dichiarata.

---

## 4.3 `prompt-routing-options.mjs` omette gli stessi ruoli

File:

```text
scripts/hooks/prompt-routing-options.mjs
```

Contiene regex hardcoded equivalenti a:

```javascript
const SUBAGENT_ROLE =
  '(?:scout|explorer|implementer|technical[_ -]?analyst|code[_ -]?reviewer|test[_ -]?writer)';
```

e:

```javascript
const EXPLICIT_AGENT_ID_PATTERN = ...
```

Mancano:

```text
docs_writer
ui_ux_engineer
```

### Conseguenza concreta

Un prompt:

```text
delega al code_reviewer la review
```

può attivare la richiesta esplicita.

Un prompt:

```text
delega a ui_ux_engineer questa modifica
```

può non essere riconosciuto come richiesta di subagente dalla stessa pipeline.

In assenza di `!agents` il risultato può restare:

```text
subagentMode = off
```

anche se l'utente ha nominato esplicitamente un ruolo canonico.

Questo spiega una parte del comportamento:

> "a volte vengono eseguiti gli spawn e a volte no".

---

## 4.4 `SUBAGENTS.md` è una seconda descrizione manuale dei ruoli

File:

```text
shared-agent-rules/SUBAGENTS.md
```

contiene una lista manuale dei ruoli:

```text
scout
implementer
technical_analyst
code_reviewer
test_writer
docs_writer
```

ma non contiene:

```text
ui_ux_engineer
```

Contemporaneamente `AGENTS.md` dice esplicitamente:

```text
Per implementazione con validation-loop usa l'agente ui_ux_engineer.
```

Quindi esistono due instruction layer che descrivono insiemi diversi di agenti.

### Target

`SUBAGENTS.md` non deve mantenere un inventario di ruoli scritto a mano.

Opzioni ammesse:

1. generare automaticamente la sezione da `canonical-subagents.yaml`;
2. sostituirla con una regola del tipo:
   ```text
   Usa esclusivamente i ruoli dichiarati nel catalogo agenti disponibile.
   ```
3. mantenere solo principi generali e puntare alla fonte generata/canonico.

Preferire l'opzione 2 o una combinazione 1+2.

---

# 5. Availability attuale non è runtime-specific

File:

```text
scripts/runtime/state-manager.js
```

`buildAgentAvailabilityManifest()` verifica quattro target:

```text
~/.codex/agents
~/.copilot/agents
~/.gemini/agents
~/.claude/agents
```

e calcola:

```javascript
const configured = targets.some(...)
```

Poi produce:

```json
{
  "id": "code_reviewer",
  "availability": "configured"
}
```

### Problema

Questo valore significa:

```text
configurato in almeno uno dei runtime
```

ma il router lo interpreta come disponibilità generale.

Esempio:

```text
code_reviewer installato solo in Claude
        |
agent-availability.json -> configured
        |
sessione corrente = Codex
        |
router -> code_reviewer disponibile
```

Non è sufficiente.

### Target manifest v2

Proposta:

```json
{
  "version": 2,
  "generatedAt": "...",
  "agents": [
    {
      "id": "code_reviewer",
      "availabilityByRuntime": {
        "codex": "configured",
        "copilot": "unavailable",
        "claude": "configured",
        "antigravity": "unknown",
        "cursor": "unsupported"
      }
    }
  ]
}
```

Distinguere:

```text
configured
unknown
unavailable
unsupported
```

`unsupported` significa che il runtime non possiede quel concetto/meccanismo, non che il file è semplicemente assente.

---

# 6. Il hook non conosce in modo autorevole il runtime corrente

`sophia-user-prompt-submit.mjs` è condiviso tra più host.

Oggi non emerge un contratto autorevole equivalente a:

```text
--runtime codex
--runtime claude
--runtime copilot
--runtime antigravity
--runtime cursor
```

per il routing agenti.

Senza runtime identity non è possibile decidere correttamente:

```text
questo ruolo è effettivamente spawnabile qui?
```

### Intervento

Estendere il wiring degli hook:

```text
scripts/hooks-generator-lib.js
scripts/generate-*-hooks.js
adapter host-specifici
```

in modo che il processo riceva un runtime ID canonico.

Esempio:

```bash
node sophia-user-prompt-submit.mjs \
  --runtime codex \
  ...
```

oppure equivalente nel payload/adattatore.

Il runtime ID non deve essere dedotto dal path del progetto o dal contenuto del prompt.

---

# 7. Il routing seleziona un ruolo, ma non esegue lo spawn

La documentazione interna lo dichiara esplicitamente:

```text
La policy è pura e non invoca spawn_agent né altri host API.
```

`sophia-user-prompt-submit.mjs` produce testo del tipo:

```text
Recommended specialized delegation:
technical_analyst + skill mcp-technical-analyst.
Prefer these declared roles over a generic/default agent...
```

e:

```text
The main agent must ... delegate at least one bounded...
```

Questo è un **hint**, non un binding di esecuzione.

### Conseguenza

L'host/model può:

```text
- seguire l'hint e usare technical_analyst
- delegare a un agente generico
- delegare a un ruolo host built-in equivalente
- non delegare
- scegliere un ruolo diverso
```

a seconda di:

- modello;
- host;
- tool esposti;
- prompt accumulato;
- availability effettiva;
- istruzioni concorrenti.

Quindi il comportamento osservato non va corretto solo aumentando la forza della prosa.

Serve un contratto macchina più preciso.

---

# 8. Direct spawn che bypassano il catalogo

La ricerca nel repository ha individuato almeno un caso esplicito:

```text
.agents/skills/graphify/SKILL.md
```

con istruzione equivalente a:

```text
spawn_agent(agent_type="worker", ...)
```

`worker` non è un ruolo canonico Sophia.

Questo crea esattamente il pattern:

```text
esiste scout / technical_analyst / ...
ma la skill usa un agente host generico "worker"
```

e quindi può generare:

> "sub equivalente ma non esattamente quello".

### Regola target

Ogni istruzione repository-managed che avvia un subagente deve scegliere una delle due categorie:

```text
A. canonical_role
B. explicitly declared host persona exception
```

Mai:

```text
arbitrary generic worker
```

senza registrazione esplicita.

### Caso Graphify

Valutare:

```text
worker di sola estrazione
```

contro:

```text
scout
```

Se il comportamento è sostanzialmente read-only/extraction, migrare a `scout`.

Se `worker` è semanticamente diverso e necessario, introdurre un nuovo ruolo canonico, ad esempio:

```text
extractor
```

solo se vi sono almeno più use case reali e una differenza di contratto verificabile.

Non creare un ruolo solo per preservare un nome host-specific.

---

# 9. Persona subagents e agenti funzionali non sono la stessa cosa

È presente anche:

```text
skills/mcp-ui-ux/references/playbooks/impeccable/impeccable-critique.md
```

che usa due valutazioni/persona indipendenti.

Questo caso non deve essere forzato nello stesso modello semantico di:

```text
code_reviewer
technical_analyst
implementer
```

Proposta:

```text
canonical functional role
    +
optional persona overlay
```

Esempio:

```json
{
  "agentId": "code_reviewer",
  "persona": "visual-design-critic-a"
}
```

La persona:

- non cambia permissions;
- non cambia modello;
- non cambia ownership;
- non diventa un nuovo `agentId`;
- non può bypassare il catalogo.

---

# 10. Nickname Codex: solo display, mai identità

`canonical-subagents.yaml` contiene `nickname_candidates`.

Il generatore li proietta solo in:

```text
.codex/agents/*.toml
```

La documentazione del repository correttamente specifica che Codex gestisce collisioni e suffix.

Quindi:

```text
agentId = code_reviewer
nickname = Batman
```

deve significare:

```text
identità semantica: code_reviewer
label visuale runtime: Batman
```

Mai:

```text
nickname -> routing identity
```

### Acceptance rule

Nessun componente di:

- routing;
- availability;
- analytics;
- matching;
- fallback;

deve usare il nickname come chiave primaria.

---

# 11. Target architecture

## 11.1 Separare quattro concetti

### A. Logical role

Fonte:

```text
canonical-subagents.yaml
```

Esempio:

```yaml
id: code_reviewer
routing_role: review
capabilities:
  - code-review
  - diff-review
write_policy: read-only
```

### B. Runtime projection

Esempio:

```text
Codex       -> .codex/agents/code_reviewer.toml
Copilot     -> .copilot/agents/code_reviewer.agent.md
Claude      -> .claude/agents/code_reviewer.md
Antigravity -> .gemini/agents/code_reviewer.md
```

### C. Execution policy

Esempio:

```yaml
model_policy: inherit
reasoning_policy: inherit
context_policy: bounded
fallback_policy: exact_or_main
```

### D. Runtime execution observation

Esempio:

```json
{
  "requestedAgentId": "code_reviewer",
  "actualAgentKind": "custom",
  "actualAgentId": "code_reviewer",
  "runtime": "codex",
  "binding": "exact",
  "spawnOutcome": "success"
}
```

Questi concetti non devono essere mescolati.

---

# 12. Schema canonico v2 proposto

## 12.1 Eliminare model ID dalla semantica del ruolo

Target indicativo:

```yaml
roles:
  - id: code_reviewer

    aliases: []

    purpose: ...

    routing:
      role: review
      priority: 80
      task_phases:
        - review
        - test
      capabilities:
        - code-review
        - diff-review
      not_for:
        - editing-files

    execution_policy:
      model_policy: inherit
      reasoning_policy: inherit
      context_policy: bounded
      fallback_policy: exact_or_main

    runtime_permissions:
      codex_sandbox_mode: read-only

    skill_affinities:
      - mcp-code-reviewer

    nickname_candidates:
      - ...
```

Non è obbligatorio adottare esattamente questa struttura YAML.

È obbligatorio raggiungere questi invarianti:

1. model ID concreto non richiesto;
2. alias dichiarati nella fonte canonica;
3. priorità routing non mantenuta in una seconda lista;
4. fallback dichiarato;
5. identità logica separata da nickname;
6. policy runtime separata dalla semantica.

---

## 12.2 Compatibility migration

Per una release transitoria il parser può accettare:

```yaml
recommended_model_profile:
```

come campo legacy.

Comportamento:

```text
legacy field presente
    -> warning di migrazione
    -> non deve diventare automaticamente un pin runtime
```

Poi rimuoverlo dopo aggiornamento di:

- YAML canonico;
- generated profiles;
- tests;
- docs.

Non mantenere indefinitamente due schemi.

---

# 13. Model policy target

## 13.1 Default

```text
model_policy = inherit
```

Significa:

- usare il modello già risolto dal runtime/sessione;
- non imporre un nome modello dal repository;
- non fare retry automatico con un modello "più forte";
- non cambiare provider;
- non cambiare reasoning effort in modo implicito.

---

## 13.2 Override esplicito

Se serve davvero un override:

```text
model_policy = explicit_override
```

deve provenire da configurazione runtime/utente, non dall'identità canonica del ruolo.

Esempio di configurazione locale opzionale:

```json
{
  "version": 1,
  "runtimes": {
    "codex": {
      "agents": {
        "technical_analyst": {
          "model": "..."
        }
      }
    }
  }
}
```

File indicativo:

```text
~/.mcp-servers/agent-runtime-policy.json
```

Il nome può cambiare durante l'implementazione.

### Vincoli

- nessun default concreto nel repository;
- nessun auto-upgrade del modello;
- override non disponibile -> fallback al parent se consentito;
- override `required` non disponibile -> spawn rifiutato con errore esplicito;
- mai fallback silenzioso a modello più costoso.

---

## 13.3 Reasoning policy

Preferire:

```text
inherit
```

come default.

Consentire profili semantici solo se realmente necessari:

```text
low
medium
high
inherit
```

ma senza legarli a una specifica generazione modello.

Se il runtime non supporta l'override:

```text
ignore + diagnostic
```

non errore.

---

# 14. Runtime capability matrix

Introdurre una struttura canonica o derivata:

```json
{
  "runtime": "codex",
  "capabilities": {
    "customAgents": true,
    "exactAgentSelection": true,
    "agentNicknameCandidates": true,
    "modelInheritance": "probe-or-documented",
    "perAgentModelOverride": "probe-or-documented"
  }
}
```

Ripetere per:

```text
codex
copilot
claude
antigravity
cursor
```

Non assumere che tutti i client supportino:

- profili custom;
- auto-delegation;
- exact agent ID;
- model inheritance;
- reasoning override;
- nickname;
- recursive delegation.

Per Cursor, se non esiste un equivalente custom-agent supportato dal framework corrente:

```text
customAgents = false
```

e il router deve produrre:

```text
unsupported
```

anziché inventare un equivalente.

---

# 15. Agent availability manifest v2

## 15.1 Schema

Implementare un manifest per-runtime.

Esempio:

```json
{
  "version": 2,
  "generatedAt": "2026-09-23T00:00:00.000Z",
  "catalogFingerprint": "...",
  "agents": [
    {
      "id": "scout",
      "runtimes": {
        "codex": {
          "availability": "configured",
          "profilePresent": true,
          "invocationSupported": true
        },
        "claude": {
          "availability": "configured",
          "profilePresent": true,
          "invocationSupported": true
        },
        "copilot": {
          "availability": "unavailable",
          "profilePresent": false,
          "invocationSupported": true
        },
        "antigravity": {
          "availability": "unknown",
          "profilePresent": false,
          "invocationSupported": true
        },
        "cursor": {
          "availability": "unsupported",
          "profilePresent": false,
          "invocationSupported": false
        }
      }
    }
  ]
}
```

---

## 15.2 Backward compatibility

Reader:

```text
manifest v2 -> runtime-aware
manifest v1 -> availability=unknown for exact runtime, never "configured" cross-runtime
missing      -> unknown
invalid      -> unknown
```

Non usare il vecchio `configured` aggregato come prova che il ruolo sia disponibile nell'host corrente.

---

# 16. Runtime identity nel hook

## 16.1 CLI contract

Aggiungere:

```text
--runtime <id>
```

a:

```text
sophia-user-prompt-submit.mjs
```

Il valore deve arrivare dal generatore host-specifico.

Esempio:

```text
Codex hooks       -> --runtime codex
Claude hooks      -> --runtime claude
Copilot hooks     -> --runtime copilot
Antigravity hooks -> --runtime antigravity
Cursor adapter    -> --runtime cursor
```

---

## 16.2 Test

Per lo stesso prompt:

```text
!agents fai code review del diff
```

con manifest:

```text
code_reviewer:
  codex: unavailable
  claude: configured
```

atteso:

```text
runtime=codex
recommendedAgents=[]
fallbackReason=explicit-agent-unavailable | no-runtime-agent
```

e non:

```text
code_reviewer configured
```

---

# 17. Eliminare le liste ruolo hardcoded dal parsing del prompt

## 17.1 Alias canonici

Introdurre:

```yaml
aliases:
  - explorer
```

sul ruolo:

```text
scout
```

Spostare quindi:

```text
explorer -> scout
```

fuori dalle regex e dentro la fonte canonica.

---

## 17.2 `detectExplicitAgentId()`

Deve ricevere:

```text
catalog agents + aliases
```

e costruire il matching da lì.

Non deve conoscere staticamente:

```text
scout
implementer
technical_analyst
...
```

---

## 17.3 `detectExplicitSubagentRequest()`

Separare:

```text
richiesta di delega
```

da:

```text
nome del ruolo
```

Esempio:

```text
"delega a" + <catalog-agent-or-alias>
```

Il vocabolario dei ruoli viene dal catalogo.

### Acceptance

Devono essere equivalenti:

```text
delega a code_reviewer ...
delega al code reviewer ...
delega a ui_ux_engineer ...
delega al ui ux engineer ...
usa docs_writer ...
usa docs writer ...
```

---

# 18. Eliminare `ROLE_PRIORITY`

La priorità deve provenire dal canonico.

Opzione preferita:

```yaml
routing_priority: 80
```

oppure:

```yaml
routing:
  priority: 80
```

Alternativa accettabile:

```text
ordine dei record nel file canonico
```

solo se dichiarato formalmente e testato.

La priorità numerica è più esplicita e meno fragile.

---

# 19. Rendere il routing role-complete

Ogni ruolo canonico deve poter dichiarare i propri trigger/routing signals senza aggiungere codice in `PHASE_SIGNALS`.

Opzione:

```yaml
routing:
  intents:
    - code review
    - review diff
  task_phases:
    - review
```

Oppure usare i metadata semantici già presenti più scoring generico.

Non introdurre un nuovo dizionario enorme di keyword se il catalogo semantico esistente può essere riutilizzato.

### Vincolo

L'aggiunta futura di:

```text
new_role
```

deve richiedere idealmente:

```text
1 modifica canonica
+ generator/test automatici
```

non:

```text
canonical YAML
ROLE_IDS
ROLE_PRIORITY
SUBAGENT_ROLE regex
EXPLICIT_AGENT_ID_PATTERN
SUBAGENTS.md
...
```

---

# 20. Contratto di esecuzione deterministico

Introdurre un oggetto interno, ad esempio:

```typescript
interface AgentExecutionPlan {
  mode: "off" | "requested" | "required";
  activeRuntime: RuntimeId;

  selectedAgentId: string | null;
  selectedSkillId: string | null;

  selectionSource:
    | "explicit-lock"
    | "deterministic-routing"
    | "skill-affinity"
    | "fallback";

  runtimeAvailability:
    | "configured"
    | "unknown"
    | "unavailable"
    | "unsupported";

  bindingPolicy:
    | "exact"
    | "canonical-fallback"
    | "main-agent-fallback";

  modelPolicy:
    | "inherit"
    | "explicit-override";

  contextPolicy:
    | "bounded"
    | "full-history-exception";

  reasonCodes: string[];
}
```

Il nome finale può differire.

L'importante è che una sola struttura alimenti:

- testo hint;
- analytics;
- test;
- planning carry-forward;
- eventuali adapter host.

---

# 21. Fallback policy

## 21.1 Agent esplicitamente richiesto

Prompt:

```text
!agents usa code_reviewer
```

oppure:

```text
delega a code_reviewer
```

Se `code_reviewer` non è disponibile:

```text
NO generic replacement
NO reviewer equivalente inventato
NO worker
```

Output:

```text
exact-agent-unavailable
```

e il main agent procede solo se la policy/utente consente fallback al main.

---

## 21.2 Agent raccomandato automaticamente

Se la policy suggerisce:

```text
scout
```

ma non è disponibile, può essere ammesso:

```text
main-agent-fallback
```

Non scegliere automaticamente un altro custom agent semanticamente diverso.

Un eventuale fallback canonico deve essere dichiarato:

```yaml
fallback_roles:
  - ...
```

e non inferito dal modello.

---

## 21.3 `!agents`

`!agents` significa:

```text
delegation required
```

ma non deve significare:

```text
qualsiasi subagent va bene
```

Se nessun ruolo canonico eseguibile è disponibile:

```text
delegation-unavailable
```

deve essere esplicito.

Non usare un agente generico host solo per soddisfare formalmente l'hotword.

---

# 22. Exact custom agent binding

Il framework non può assumere che una frase nel prompt equivalga a un dispatch esatto.

Per ogni runtime supportato occorre documentare e testare il meccanismo concreto.

Esempio astratto:

```text
Codex:
  selected logical role
    -> runtime profile ID
    -> host dispatch using exact custom type/agent

Copilot:
  selected logical role
    -> custom agent name
    -> task/session custom agent

Claude:
  selected logical role
    -> .claude/agents/<id>.md
    -> host subagent selection

Gemini/Antigravity:
  selected logical role
    -> .gemini/agents/<id>.md
    -> runtime-supported subagent invocation
```

### Importante

Se l'host non espone un API/tool che consente all'hook di effettuare direttamente lo spawn, il framework deve essere onesto:

```text
selection is deterministic
execution remains host-mediated
```

In quel caso la soluzione non è dichiarare "deterministic spawn", ma:

1. generare istruzione host-specifica più precisa;
2. osservare l'esecuzione effettiva;
3. rilevare mismatch;
4. non fingere che hint = spawn.

---

# 23. Audit di tutte le istruzioni di spawn nel repository

Creare:

```text
scripts/audit-agent-spawn-contracts.mjs
```

Lo script deve cercare almeno:

```text
spawn_agent
startSubagent
agent_type
fork_context
fork_turns
sub-agent
subagent
worker
reviewer
explorer
```

nelle aree:

```text
skills/
.agents/skills/
shared-agent-rules/
docs/agents/
AGENTS.md
scripts/hooks/
```

Classificare ogni match:

```text
canonical-role-reference
host-generic-agent
persona-overlay
historical-doc
test-fixture
false-positive
```

Output esempio:

```text
[ERROR] .agents/skills/graphify/SKILL.md
        uses non-canonical agent_type="worker"

[INFO] skills/.../impeccable-critique.md
       persona workflow; canonical base role not declared

[OK] docs/agents/...
     canonical role reference
```

CI deve fallire solo sulle categorie normative/eseguibili, non su documenti storici o fixture.

---

# 24. Correzione Graphify

Per:

```text
.agents/skills/graphify/SKILL.md
```

rimuovere l'hardcode:

```text
agent_type="worker"
```

### Opzione A - preferita

Usare:

```text
scout
```

per chunk read-only/extraction se il contratto coincide.

### Opzione B

Aggiungere un ruolo canonico:

```text
extractor
```

solo se viene dimostrato che:

- ha capabilities diverse;
- ha output contract diverso;
- ha least-privilege diverso;
- viene riutilizzato oltre Graphify.

### Non accettabile

```text
worker
```

mantenuto come eccezione non catalogata.

---

# 25. Correzione dei workflow persona UI/UX

Per i workflow con più critici/persona:

```text
base role = code_reviewer | ui_ux_engineer read-only review mode
persona = overlay
```

Non usare la persona come identificatore runtime.

Esempio:

```text
role: code_reviewer
persona: accessibility-focused-critic
```

La persona può essere un campo nel delegation packet, non nel catalogo agenti portabili.

---

# 26. Generazione dei runtime profile model-agnostic

## 26.1 Claude

Conservare:

```yaml
model: inherit
```

se conforme al runtime supportato.

---

## 26.2 Gemini / Antigravity

Conservare:

```yaml
model: inherit
```

se conforme al runtime supportato.

---

## 26.3 Copilot

Rimuovere il campo `model` dal generated profile di default.

La documentazione GitHub corrente specifica che, se non impostato, il custom agent eredita il modello di default/sessione.

Anche `reasoningEffort` dovrebbe essere omesso di default se la policy è `inherit`.

Produrre override solo quando esplicitamente configurato.

---

## 26.4 Codex

Non assumere nel piano che una specifica versione installata accetti esattamente lo stesso schema di Copilot.

Implementare un adapter con due modalità:

```text
inherit-capable
explicit-required
```

La modalità deve essere verificata rispetto al runtime Codex effettivamente supportato dal progetto.

Target preferito:

```text
nessun model pin
```

Se il runtime richiede un model field:

```text
risolverlo da config locale/runtime
```

e non dal ruolo canonico.

In ogni caso non deve esistere:

```text
canonical-subagents.yaml
    -> hardcoded model generation name
```

come dipendenza obbligatoria.

---

# 27. Eliminare `copilot_multiplier` legato a un modello

`copilot_multiplier` è semanticamente instabile se il model viene ereditato.

Se serve per planning/cost analytics:

- spostarlo fuori dalla definizione del ruolo;
- derivarlo dal modello effettivamente osservato quando disponibile;
- oppure sostituirlo con una classe qualitativa provider-neutral.

Non mantenere:

```text
role -> fixed multiplier
```

se:

```text
role -> inherited model
```

---

# 28. Model compatibility guard

Aggiungere un controllo di build/installazione che distingua:

```text
inherited
explicit override verified
explicit override unverified
explicit override unsupported
```

Non è necessario interrogare la rete ad ogni startup.

Regola:

```text
inherit
    -> sempre valido lato Sophia

explicit override
    -> validare se il runtime espone discovery
    -> altrimenti status=unverified
```

`unverified` non deve causare auto-upgrade.

---

# 29. Audit dei model ID nel repository

Creare:

```text
scripts/audit-agent-model-bindings.mjs
```

oppure integrare la funzione in:

```text
scripts/audit-agent-spawn-contracts.mjs
```

Classificare match di model ID in:

```text
runtime-profile
canonical-config
live-doc
historical-doc
analytics-fixture
parser-test
```

### Gate

Errore CI per:

```text
runtime-profile + concrete model not explicitly allowlisted
canonical-config + concrete model
```

Warning per:

```text
live-doc
```

Ignorare come errore:

```text
historical-doc
analytics-fixture
parser-test
```

---

# 30. Telemetria: planned vs actual agent

Questa fase deve coordinarsi con `20260923_audit_statistics_accuracy.md`.

Registrare eventi privacy-safe, ad esempio:

```text
AgentDelegationPlanned
AgentDelegationObserved
AgentDelegationMismatch
```

Campi ammessi:

```json
{
  "runtime": "codex",
  "requested_mode": "required",
  "selected_agent_id": "code_reviewer",
  "selection_source": "explicit-lock",
  "runtime_availability": "configured",
  "binding_policy": "exact",
  "actual_agent_id": "code_reviewer",
  "actual_agent_kind": "custom",
  "outcome": "exact"
}
```

Non registrare:

- task prompt;
- output subagente;
- transcript;
- argomenti tool;
- path sensibili;
- nickname come identità primaria.

---

# 31. Codex lifecycle observation

L'adapter analytics Codex riconosce già eventi come:

```text
collab_agent_spawn_end
collab_close_end
```

La fixture contiene anche campi equivalenti a:

```text
new_thread_id
new_agent_nickname
new_agent_role
```

Oggi l'analytics salva soprattutto il lifecycle generico.

Estendere in modo privacy-safe solo quanto necessario per misurare:

```text
custom exact
generic fallback
unknown
```

Non è necessario conservare il nickname se non serve alla diagnosi.

Preferire:

```text
logical role / host role normalized
```

e HMAC per identificatori tecnici quando necessario.

---

# 32. Mismatch taxonomy

Definire reason code stabili:

```text
AGENT_EXACT_MATCH
AGENT_RUNTIME_UNSUPPORTED
AGENT_PROFILE_MISSING
AGENT_EXPLICIT_LOCK_UNAVAILABLE
AGENT_CATALOG_UNAVAILABLE
AGENT_GENERIC_FALLBACK_BLOCKED
AGENT_HOST_FALLBACK_OBSERVED
AGENT_DIFFERENT_CUSTOM_ROLE_OBSERVED
AGENT_SPAWN_NOT_OBSERVED
AGENT_MODEL_OVERRIDE_UNSUPPORTED
AGENT_MODEL_OVERRIDE_UNVERIFIED
AGENT_CONTEXT_POLICY_MISMATCH
```

Non usare stringhe libere nei KPI.

---

# 33. Fase 0 - Baseline riproducibile

Prima di modificare codice:

1. salvare commit baseline;
2. rigenerare agent catalog;
3. rigenerare portable agents;
4. eseguire i check correnti;
5. catturare output per un dataset di prompt.

Dataset minimo:

```text
!agents analizza questo modulo
delega a scout e trova i file
delega a technical_analyst
delega a code_reviewer
delega a test_writer
delega a docs_writer
delega a ui_ux_engineer
delega a explorer
implementa questa fix
fai code review del diff
scrivi la documentazione
sistema questa UI
```

Per ogni runtime simulato:

```text
codex
copilot
claude
antigravity
cursor
```

registrare:

```text
subagentMode
explicitAgentId
recommendedAgents
availability
fallbackReason
rendered hint
```

---

# 34. Fase 1 - Canonical schema v2

Modificare:

```text
docs/agents/canonical-subagents.yaml
scripts/portable-agents-lib.js
scripts/build-agent-catalog.mjs
scripts/hooks/agent-catalog-schema.mjs
tests/portable-agents.test.cjs
tests/subagent-routing-policy.test.mjs
```

Obiettivi:

- alias nel canonico;
- priority nel canonico;
- model policy agnostica;
- reasoning policy;
- fallback policy;
- eventuale context policy;
- nessun model ID obbligatorio.

---

# 35. Fase 2 - Runtime rendering model-agnostic

Modificare i renderer:

```text
renderCodexToml
renderCopilotAgent
renderGeminiAgent
renderClaudeAgent
```

Target:

```text
Codex: no concrete repository model by default
Copilot: omit model by default
Gemini: inherit
Claude: inherit
```

Aggiungere test snapshot.

---

# 36. Fase 3 - Runtime-aware availability

Modificare:

```text
scripts/runtime/state-manager.js
scripts/hooks/agent-catalog-runtime.mjs
installer/runtime tests
```

Produrre manifest v2 per runtime.

Aggiungere compatibilità reader v1.

---

# 37. Fase 4 - Runtime identity nei hook

Modificare:

```text
scripts/hooks-generator-lib.js
scripts/generate-codex-hooks.js
generatori Claude/Copilot/Antigravity/Cursor
adapter host-specifici
scripts/hooks/sophia-user-prompt-submit.mjs
```

Propagare:

```text
runtimeId
```

fino a:

```text
resolveSubagentRouting()
```

---

# 38. Fase 5 - Routing derivato dal catalogo

Rimuovere come fonti indipendenti:

```text
ROLE_PRIORITY
SUBAGENT_ROLE
EXPLICIT_AGENT_ID_PATTERN
manual explorer alias
manual role list in SUBAGENTS.md
```

Sostituire con:

```text
catalog roles
catalog aliases
catalog routing priority
catalog capabilities/task phases
```

Aggiungere test per tutti i ruoli.

---

# 39. Fase 6 - Spawn contract audit e remediation

Eseguire:

```text
scripts/audit-agent-spawn-contracts.mjs
```

Correggere:

- Graphify `worker`;
- eventuali altri `agent_type` generici;
- persona workflow;
- direct spawn che bypassano policy;
- `fork_context` / `fork_turns` non conformi al piano subagent precedente.

Nessun direct spawn normativo deve rimanere non classificato.

---

# 40. Fase 7 - Planned/actual reconciliation

Integrare con analytics:

```text
recommendation
    -> planned event
spawn lifecycle
    -> observed event
correlation
    -> exact/mismatch/not-observed
```

La correlation deve usare ID tecnici/HMAC quando possibile, non testo del task.

---

# 41. Fase 8 - Aggiornamento instruction layer

Aggiornare almeno:

```text
AGENTS.md
shared-agent-rules/SUBAGENTS.md
docs/agents/local-orchestration-playbook.md
docs/mcp-skills-agents-development-guide.md
.codex/agents/README.md
eventuali README host
```

Correggere anche il residuo concettuale:

```text
Lo scopo primario dei subagents resta token/cost optimization
```

in coerenza con `20260923_audit_subagent_usage.md`.

---

# 42. Test obbligatori

## 42.1 Canonical parity

Per ogni ruolo canonico:

```text
exists canonical
exists generated Codex profile
exists generated Copilot profile
exists generated Claude profile
exists generated Gemini profile
exists agent catalog entry
exists availability entry
```

salvo runtime dichiaratamente unsupported.

---

## 42.2 Role completeness

Test automatico:

```text
catalog IDs
==
router-visible IDs
==
explicit-agent parser IDs
```

Nessuna lista manuale.

---

## 42.3 Explicit role tests

Devono passare:

```text
delega a scout
delega a implementer
delega a technical_analyst
delega a code_reviewer
delega a test_writer
delega a docs_writer
delega a ui_ux_engineer
delega a explorer
```

---

## 42.4 Cross-runtime availability

Scenario:

```text
code_reviewer installed only in Claude
```

Atteso:

```text
Claude -> configured
Codex -> unavailable/unknown
Copilot -> unavailable/unknown
```

Mai:

```text
all runtimes -> configured
```

---

## 42.5 Model agnosticism

Assert:

```text
canonical YAML contains no required concrete runtime model IDs
```

Generated:

```text
Claude/Gemini -> inherit
Copilot -> no model override by default
Codex -> no repository-pinned generation ID by default
```

Se Codex necessita un valore:

```text
resolved from runtime-local policy
```

e testato separatamente.

---

## 42.6 No automatic expensive fallback

Simulare:

```text
explicit override unavailable
```

Atteso:

```text
inherit parent
```

se policy permissiva, oppure:

```text
spawn refused
```

se override required.

Mai:

```text
retry with stronger/newer model
```

---

## 42.7 Exact agent lock

Prompt:

```text
!agents usa code_reviewer
```

Con profile missing:

```text
explicit-agent-unavailable
```

Mai:

```text
general-purpose
worker
reviewer
scout
```

come sostituzione silenziosa.

---

## 42.8 Graphify

Nessun match normativo:

```text
agent_type="worker"
```

dopo remediation, salvo eccezione formalmente registrata e testata.

---

## 42.9 Nickname

Verificare:

```text
nickname change
```

non altera:

```text
agentId
routing
analytics identity
availability
```

---

## 42.10 Planning carry-forward

Il piano deve registrare:

```text
agentId
skillId
ownership
runtime compatibility
```

senza memorizzare:

```text
model concreto
nickname obbligatorio
```

---

# 43. Acceptance matrix funzionale

| Caso | Target |
|---|---|
| Prompt normale | 0 subagenti automatici |
| `!agents` | almeno 1 ruolo canonico se runtime lo supporta |
| agente esplicito valido | exact lock |
| agente esplicito non installato | errore/fallback esplicito, no equivalente silenzioso |
| `docs_writer` esplicito | riconosciuto |
| `ui_ux_engineer` esplicito | riconosciuto |
| alias `explorer` | risolve a `scout` dal canonico |
| ruolo disponibile solo in altro runtime | non considerato configured |
| custom agent host unsupported | `unsupported`, no fake mapping |
| concrete model non configurato | inherit/default host |
| concrete override non disponibile | no escalation automatica |
| Graphify extraction | ruolo canonico |
| persona UI audit | base role canonico + persona overlay |
| nickname diverso | stessa identità logica |
| mismatch host | telemetria esplicita |

---

# 44. KPI before/after

Misurare su dataset controllato:

```text
explicit_role_detection_rate
exact_custom_role_recommendation_rate
runtime_false_positive_availability_rate
generic_fallback_rate
spawn_not_observed_rate
different_custom_role_rate
model_pin_count_live_config
model_spawn_failure_rate
catalog_drift_count
noncanonical_spawn_reference_count
```

Target:

```text
explicit_role_detection_rate = 100%
runtime_false_positive_availability_rate = 0%
model_pin_count_live_config = 0 default pins
noncanonical_spawn_reference_count = 0
catalog_drift_count = 0
```

`exact_custom_role_recommendation_rate` deve essere 100% sui casi in cui il runtime dichiara supporto e il profilo è configured.

L'`exact_custom_role_execution_rate` va misurato separatamente perché dipende anche dalla capacità dell'host di rispettare il binding.

---

# 45. File prioritari da modificare

## Core

```text
docs/agents/canonical-subagents.yaml
scripts/portable-agents-lib.js
scripts/build-agent-catalog.mjs
scripts/hooks/agent-catalog-schema.mjs
scripts/hooks/agent-catalog-runtime.mjs
scripts/hooks/subagent-routing-policy.mjs
scripts/hooks/prompt-routing-options.mjs
scripts/hooks/sophia-user-prompt-submit.mjs
scripts/runtime/state-manager.js
scripts/hooks-generator-lib.js
```

## Generated/runtime

```text
.codex/agents/*
.copilot/agents/*
.claude/agents/*
.gemini/agents/*
```

## Rules/docs

```text
AGENTS.md
shared-agent-rules/SUBAGENTS.md
docs/agents/local-orchestration-playbook.md
docs/mcp-skills-agents-development-guide.md
README.md
```

## Known spawn bypass candidates

```text
.agents/skills/graphify/SKILL.md
skills/mcp-ui-ux/references/playbooks/impeccable/impeccable-critique.md
```

## Tests

```text
tests/portable-agents.test.cjs
tests/subagent-routing-policy.test.mjs
tests/routing-hooks.test.mjs
scripts/smoke-codex-hooks.js
scripts/test-user-runtime.js
```

---

# 46. Nuovi tool di audit consigliati

## 46.1 `scripts/audit-agent-spawn-contracts.mjs`

Responsabilità:

- trovare spawn/direct agent references;
- classificare canonical/noncanonical/persona/historical;
- controllare context strategy;
- controllare generic fallback.

---

## 46.2 `scripts/audit-agent-model-bindings.mjs`

Responsabilità:

- trovare model ID concreti;
- distinguere live config da fixture storiche;
- bloccare pin runtime non autorizzati;
- produrre report senza modificare file.

---

## 46.3 `scripts/audit-agent-runtime-parity.mjs`

Responsabilità:

```text
canonical
vs generated
vs installed
vs availability
vs router
```

Output per runtime:

```text
role
profile_present
catalog_present
availability
invocation_supported
model_policy
drift
```

---

# 47. Piano PR consigliato

## PR 1 - Canonical agent contract v2 + audit

Scope:

- aliases;
- routing priority;
- model policy;
- fallback policy;
- audit spawn/model references;
- nessun comportamento runtime modificato oltre validation.

Acceptance:

```text
npm run/test affected dedicati verdi
audit report pulito o baseline esplicita
```

---

## PR 2 - Model-agnostic runtime profiles

Scope:

- generatori Codex/Copilot/Claude/Gemini;
- removal dei default model IDs;
- reasoning inherit;
- cleanup live docs;
- fixture storiche preservate.

Acceptance:

```text
no default concrete model pin
generated drift = 0
```

---

## PR 3 - Runtime-aware availability

Scope:

- manifest v2;
- runtime ID;
- hook wiring;
- compatibility manifest v1.

Acceptance:

```text
agent installed in Claude only
!=
configured in Codex
```

---

## PR 4 - Catalog-driven routing

Scope:

- rimozione role regex/list hardcoded;
- aliases;
- priority;
- tutti i ruoli riconosciuti;
- `docs_writer` e `ui_ux_engineer` coperti.

Acceptance:

```text
all canonical roles explicit detection = pass
```

---

## PR 5 - Spawn contract hardening

Scope:

- Graphify;
- persona workflows;
- generic fallback rules;
- exact lock;
- bounded context integration con piano subagent precedente.

Acceptance:

```text
0 noncanonical executable spawn references
```

---

## PR 6 - Execution reconciliation + analytics

Scope:

- planned/observed/mismatch events;
- Codex lifecycle metadata safe;
- dashboard/audit opzionale;
- KPI.

Acceptance:

```text
planned != actual
```

deve essere osservabile senza salvare contenuto conversazionale.

---

# 48. Dipendenze con `20260923_audit_subagent_usage.md`

Questo piano deve essere implementato insieme, o immediatamente dopo, le fasi del documento precedente.

Ordine consigliato complessivo:

```text
A. fan-out / context / depth controls
B. canonical model/runtime contract
C. runtime-aware agent availability
D. exact role routing
E. spawn contract cleanup
F. planned-vs-actual telemetry
G. tuning finale
```

Le modifiche seguenti del vecchio piano sono qui rese più specifiche:

```text
"rendere il modello opzionale"
```

diventa:

```text
model policy model-agnostic + runtime-local override
```

e:

```text
"usare il ruolo raccomandato"
```

diventa:

```text
catalog role -> runtime availability -> execution plan -> observed execution
```

---

# 49. Non obiettivi

Non introdurre in questa iterazione:

- un orchestratore LLM remoto per scegliere agenti;
- auto-spawn dal hook;
- un nuovo provider model registry online obbligatorio;
- sostituzione automatica del modello con "ultimo disponibile";
- un agent ID diverso per ogni persona;
- fallback indiscriminato su agenti built-in dell'host;
- una nuova tassonomia enorme di ruoli.

Il lavoro deve restare deterministico, locale, testabile e compatibile con runtime diversi.

---

# 50. Definition of Done

Il punto è chiuso quando:

- [ ] la fonte canonica non richiede model ID concreti;
- [ ] i generated profile sono model-agnostic per default;
- [ ] nessun retry automatico cambia modello/costo;
- [ ] l'agent availability è per-runtime;
- [ ] il hook conosce il runtime corrente;
- [ ] ogni ruolo canonico è riconoscibile esplicitamente;
- [ ] `docs_writer` e `ui_ux_engineer` non sono più ruoli "di seconda classe";
- [ ] alias come `explorer` sono canonici, non regex ad-hoc;
- [ ] non esiste più `ROLE_PRIORITY` mantenuto separatamente;
- [ ] `SUBAGENTS.md` non mantiene un catalogo ruolo divergente;
- [ ] gli spawn normativi usano agent ID canonici;
- [ ] `worker`/generic agent non bypassano il catalogo;
- [ ] le persona sono overlay e non identità runtime;
- [ ] explicit lock non degrada silenziosamente;
- [ ] nickname non è usato come identità;
- [ ] planned-vs-actual è osservabile;
- [ ] fixture storiche dei modelli restano valide;
- [ ] audit model/spawn/parity sono eseguibili;
- [ ] test cross-runtime e drift check sono verdi;
- [ ] documentazione operativa aggiornata;
- [ ] gate finale `npm run test:affected -- --strict --base <baseline>` passa secondo governance del repository.

---

# 51. Prompt operativo da passare agli agenti implementatori

```text
Implementa il piano descritto in 20260923_audit_agent_model_routing.md
nel repository sophiadeveloper/mcp-servers.

Obiettivo:
rendere il sistema dei subagenti Sophia model-agnostic, catalog-driven e
runtime-aware, impedendo fallback silenziosi verso agenti/modelli equivalenti
ma diversi da quelli selezionati.

Vincoli principali:

1. docs/agents/canonical-subagents.yaml resta la fonte canonica dei ruoli.
2. La definizione canonica non deve richiedere model ID concreti.
3. Il default dei runtime profile deve essere inherit/default host.
4. Non sostituire semplicemente gpt-5.4 con un modello più nuovo.
5. Mantieni i riferimenti storici nei fixture/test analytics quando servono
   a verificare parsing di sessioni pregresse.
6. Elimina liste ruolo duplicate da:
   - prompt-routing-options.mjs
   - subagent-routing-policy.mjs
   - shared-agent-rules/SUBAGENTS.md
   quando possono essere derivate dal catalogo.
7. docs_writer e ui_ux_engineer devono essere riconosciuti allo stesso livello
   degli altri ruoli.
8. Sposta explorer -> scout in aliases canonici.
9. Introduci availability per-runtime; un ruolo configurato in Claude non deve
   risultare automaticamente configurato in Codex.
10. Propaga al routing un runtime ID autorevole dai generatori/adapters hook.
11. Un ruolo esplicitamente richiesto è un exact lock:
    se non è eseguibile nel runtime, non sostituirlo silenziosamente con
    worker/general-purpose/reviewer/scout o altro.
12. Audita tutte le istruzioni spawn_agent/agent_type/fork_context/fork_turns.
13. Rimuovi l'uso non canonico agent_type="worker" da Graphify oppure,
    solo se semanticamente necessario e riusabile, introduci un ruolo canonico.
14. Le persona UI/UX devono essere overlay sopra un ruolo canonico, non agent ID.
15. Nickname Codex è solo display metadata.
16. Non introdurre auto-spawn dal hook.
17. Il hook può restare host-mediated, ma selection ed execution plan devono
    essere deterministici e osservabili.
18. Integra telemetria privacy-safe planned-vs-actual senza salvare prompt,
    risposte o task text.
19. Coordina le modifiche con 20260923_audit_subagent_usage.md:
    fan-out, bounded context, depth e token/cost discipline restano validi.
20. Mantieni compatibilità progressiva e patch reviewable.

Implementa per PR/milestone indipendenti:

PR1 canonical schema v2 + audit
PR2 model-agnostic runtime profiles
PR3 runtime-aware availability
PR4 catalog-driven routing
PR5 spawn contract hardening
PR6 planned-vs-actual telemetry

Prima delle modifiche:
- acquisisci baseline Git;
- fotografa output routing per tutti i ruoli e runtime;
- esegui gli audit in read-only.

Per ogni PR:
- aggiorna test;
- aggiorna generated artifacts solo tramite generatori;
- non hand-editare runtime profiles come fonte primaria;
- verifica Windows/macOS/Linux dove il codice tratta path/runtime differenti;
- lascia changelog tecnico e rischi residui.

Gate finale:
npm run test:affected -- --strict --base <baseline>

Non eseguire refactor fuori scope e non modificare automaticamente documenti
storici/fixture solo perché contengono nomi modello vecchi.
```

---

# 52. Risultato atteso finale

A regime:

```text
User / skill / policy
        |
        v
canonical agent catalog
        |
        +--> exact logical agentId
        |
        v
active runtime capability
        |
        v
runtime-specific availability
        |
        v
AgentExecutionPlan
        |
        +--> model: inherit by default
        +--> bounded context
        +--> explicit fallback policy
        |
        v
host-mediated exact custom agent dispatch
        |
        v
privacy-safe observed execution
        |
        +--> exact
        +--> mismatch
        +--> unsupported
        +--> unavailable
```

Il sistema deve poter rispondere in modo verificabile a queste domande:

```text
Quale ruolo Sophia era stato selezionato?
Era installato sul runtime corrente?
Quel runtime supportava l'invocazione custom?
Quale policy modello era stata applicata?
È stato eseguito proprio quel ruolo?
Se no, perché?
È avvenuto un fallback?
Il fallback era autorizzato?
```

Se una di queste risposte oggi dipende solo dall'interpretazione del modello,
il lavoro non è ancora concluso.
