# 03 — Instruction supply chain

Fonte evidenze: `instruction-supply-chain.raw.json` (subagente B, verificato dal main agent). Branch: `master` salvo dove indicato.

## Catena

```text
global rules (AGENTS.md, shared-agent-rules/*)
→ hooks (scripts/hooks/sophia-*.mjs, adapters Cursor/Antigravity)
→ catalog generation (scripts/build-routing-catalog.mjs → scripts/hooks/routing-catalog.json [GENERATO, gitignored])
→ runtime routing (sophia-user-prompt-submit.mjs + routing-engine.mjs)
→ skill (skills/<name>/SKILL.md → frontmatter = input del catalogo)
→ references (skills/<name>/references/*.md, caricamento on-demand)
→ MCP tools (*-node/)
→ eval (skills/<name>/evals/evals.json [documentali] + tests/ e scripts/*test* [eseguibili])
```

```mermaid
flowchart TD
    A[AGENTS.md root<br/>governance minima] --> H
    G[shared-agent-rules/<br/>GLOBAL.md, SUBAGENTS.md,<br/>TOKEN_DISCIPLINE.md, appendici CF/Yii] --> H
    S[skills/*/SKILL.md<br/>frontmatter + trigger] -->|build-routing-catalog.mjs| C[routing-catalog.json<br/>GENERATO gitignored]
    C --> H[sophia-user-prompt-submit.mjs<br/>UserPromptSubmit hook]
    K[DOMAIN_KEYWORDS + SKILL_HINTS<br/>tabelle hand-curated NEL hook] --> H
    H --> R[routing-engine.mjs<br/>routePrompt: intents/locks/soglia 3]
    R --> O[hint finali max 2 + routing-control]
    Y[docs/agents/canonical-subagents.yaml<br/>CANONICO] -->|sync-portable-agents.js| T[.codex/agents/*.toml<br/>GENERATI ma committati]
    P[sophia-pretool-*.mjs<br/>sql / coldfusion / memory / projectfs] --> O2[reminder PreToolUse]
    G -.prosa duplicata.-> P
    HG[hooks-generator-lib.js<br/>HOOKS array canonico] --> W[generate-codex-hooks.js<br/>wiring per client]
```

## Fonti di verità e file generati

| Artefatto | Tipo | Generatore | Nota |
| --- | --- | --- | --- |
| `AGENTS.md`, `shared-agent-rules/*` | sorgente | — | prosa governance, distribuita a progetti esterni |
| `skills/*/SKILL.md` | sorgente | — | input del catalogo routing |
| `scripts/hooks/routing-catalog.json` | **generato** | `build-routing-catalog.mjs` | gitignored (`.gitignore:39`) — corretto |
| `.codex/agents/*.toml` | **generato** | `sync-portable-agents.js` da `docs/agents/canonical-subagents.yaml` | **committato in git** nonostante `.codex/agents/README.md:13,51-52` dica "derived, non editare a mano" — rischio di edit manuale su file generato (FACT) |
| `DOMAIN_KEYWORDS` / `SKILL_HINTS` in `sophia-user-prompt-submit.mjs:249-267,289-306` | sorgente hand-curated | — | overlay indipendente dal catalogo generato (FACT) |
| `hooks-generator-lib.js` (array HOOKS) | sorgente | — | canone del wiring hook per Codex/Claude/Cursor/Antigravity |
| Branch candidato: `routing-semantic-overrides.json` | sorgente | — | metadata semantici hand-authored, mergiati nel catalogo generato |
| Branch candidato: `scripts/hooks/mcp-catalog.json` | **generato** | `build-mcp-catalog.mjs` da `MCP_SERVER_REGISTRY` | gitignored — corretto |

## Duplicazioni rilevate (FACT, path:righe nel raw)

1. **Hotword `!quick`/`!agents`**: `AGENTS.md:55-61` + `shared-agent-rules/SUBAGENTS.md:11-14` + implementazione in `prompt-routing-options.mjs` e `sophia-user-prompt-submit.mjs:832-850`.
2. **ProjectFS-first**: 3 file di prosa (`shared-agent-rules/AGENTS.md:3,7`, `GLOBAL.md:24-25`, `SUBAGENTS.md:3`) + **2 stringhe hint indipendenti e divergenti** nei hook (`sophia-pretool-projectfs.mjs:91-124` vs `PROJECTFS_HINT` in `sophia-user-prompt-submit.mjs:282-285`).
3. **Guardrail SQL**: `GLOBAL.md:12,30` + `sophia-pretool-sql.mjs:61-66`.
4. **cf_bridge.evaluate passive-only**: `COLDFUSION.md:19-21` + `sophia-pretool-coldfusion.mjs:61-66` (quasi-verbatim).
5. **Memory write discipline**: `GLOBAL.md:57-70` + `sophia-pretool-memory.mjs:61-66`.
6. **Mappa skill→dominio**: 4 livelli — `AGENTS.md:26-29`, `GLOBAL.md:36-55`, catalogo generato, tabelle hand-curated nel hook. Ognuno può driftare dagli altri (INFERENCE ad alto supporto).
7. **Token discipline**: `TOKEN_DISCIPLINE.md:1-64` + `GLOBAL.md:103-115`.
8. **Ruoli subagent**: `SUBAGENTS.md:16-21` + `canonical-subagents.yaml` + `.codex/agents/*.toml` generati.

## Owner multipli / precedenze non definite

- **Routing keywords a 4 owner** (duplicazione 6): è la divergenza più pericolosa perché due dei quattro livelli sono *eseguibili* (catalogo, tabelle nel hook) e due sono prosa. Nessun file dichiara la precedenza tra `DOMAIN_KEYWORDS` (+3) hand-curated e keywords del catalogo (+1): la precedenza esiste solo *implicitamente* nei pesi dello scoring (FACT: `sophia-user-prompt-submit.mjs:620-703`).
- **Wording ProjectFS**: 5 formulazioni della stessa regola; una modifica a una non si propaga alle altre (FACT).
- **Ruoli subagent**: il canonico dichiarato è `canonical-subagents.yaml`, ma i `.toml` generati sono committati e `SUBAGENTS.md` mantiene una restatement indipendente (FACT).
- **Nota positiva**: la duplicazione prosa↔hook per i guardrail (SQL, CF, memory) è in parte *intenzionale by design* — la prosa serve i client senza hook, il hook serve l'enforcement runtime (INFERENCE; vedi anche `09-do-not-change.md`). Il problema non è l'esistenza della duplicazione ma l'assenza di un meccanismo che ne rilevi il drift.

## Flusso runtime (master) — verificato

`sophia-user-prompt-submit.mjs` (UserPromptSubmit) → parse hotword (`prompt-routing-options.mjs:16-77`) → load catalogo con fallback a catalogo vuoto se assente/invalido (`:38-56`, fail-open deterministico) → detect repo context e marker CF/Yii (`:94-239`) → `scoreSkills` con pesi +3 curated / +1 catalog keyword / +5 promptPattern / +4 repo boost (`:620-703`) → anti-pattern suppress/deprioritize (`:583-606`) → `routePrompt` in `routing-engine.mjs:168-240` (intents con priorità 300/200/100, locks, soglia score ≥3) → max 2 hint + routing-control hints → log analytics best-effort.

## Rischi di catena (sintesi Fable)

| Rischio | Tipo | Gravità |
| --- | --- | --- |
| Drift silenzioso tra le 4 fonti della mappa routing | INFERENCE | Alta |
| Edit manuale dei `.toml` generati committati | HYPOTHESIS (nessun drift osservato oggi; `tests/portable-agents.test.cjs` copre parte del rischio) | Media |
| Freshness del catalogo generato non garantita a runtime (generatedAt 2026-07-16 vs hook modificati 07-19) | **RISOLTO in verifica runtime 2026-07-19**: rigenerato il catalogo e confrontato col precedente — identico al netto di generatedAt, nessun drift (v. `12-audit-corrections.md`) | Bassa (residuo: nessun check automatico di freshness, ma rebuild in test:routing:catalog e install) |
| Doppio hint ProjectFS con wording diverso → istruzioni incoerenti allo stesso modello nella stessa sessione | FACT | Media |
| Il branch candidato aggiunge una 5ª fonte semantica (`routing-semantic-overrides.json`) che deve restare sincrona con skill reali — mitigato: `validateSemanticOverrides` fallisce su id mancanti/sconosciuti | FACT (mitigazione verificata) | Bassa |
