# STANDARD_AI_PRODOTTO — Configurazione AI di Prodotto AgileHub Suite

> Standard cross-suite per progettare, configurare e mantenere ogni "AI di prodotto" della suite AgileHub seguendo il template di riferimento TRPG come gold standard.
>
> **Slug**: `ai-prodotto`
> **Versione**: 1.0 (proposed — pending sub-approval utente per seed in `nexus_hub.hub_standards`)
> **Owner**: Agile AI (Architetto AI di prodotto + KB governance)
> **Applies to**: tutti i prodotti suite AgileHub (`*`) — TRPG, TRPG-PRO, SUSTAINAI, NIS2, AllTax, LG231, DFM-PRO, ALLRISK, WMS, MADEBYCLOUD, CertiSource + AgileHub stesso (AI runtime "Agile")
> **Reference implementation**: TRPG (gold standard per Support, Sales, Plan-mode; Lead qualification ha riferimento separato Giulia EDUCATION)
> **Sostituisce**: nessuno (standard nuovo). Convive con `installer-integration` v1.0.1, `ticket-tags` v1.0, `outbound-campaigns` v1.0, `telephony-integration` v1.0
> **Data redazione**: 2026-04-23 (sessione 33 part 6 — kickoff AGI-2 master plan v2.1)
> **Prossima revisione attesa**: dopo AGI-5 test E2E (~settimana 4-5 master plan v2.1) o all'introduzione di L3 PERSONA Lotto F Avatar Registry

---

## §1 Premessa & autorità

### 1.1 Cos'è una "AI di prodotto"

Una **AI di prodotto** è un'entità conversazionale Claude-based, esposta agli utenti di un prodotto della suite AgileHub, che opera con:

- una **persona dichiarata** (nome, tono, lingua)
- un **obiettivo specifico** (qualificare lead, risolvere ticket prima di escalare, dimostrare prodotto in landing, dialogare con approver durante plan mode, ecc.)
- una **knowledge base** (`product_knowledge` filtrata per prodotto/tenant/livello)
- un **set di tool** dichiarativi che il backend esegue per suo conto
- **guardrails** espliciti su cosa NON deve mai fare
- **cost tracking** per attribuire spesa LLM/RAG al prodotto + tenant + sessione

NON è una AI di prodotto:
- un **agente Claude specialista** (es. Agile AI, VOX, MAESTRO) — vivono in chat dello sviluppatore, non parlano a utenti finali
- un **content generator** (`contentController.js`) — genera contenuti marketing offline, non dialoga
- un **classifier puro** (es. `voiceDialogController.js` interpretTurn) — è un sub-componente di una AI di prodotto, non una AI standalone

### 1.2 Perché serve uno standard

Audit `nexus-ai-ms` (sessione 33 part 6, AGI-1) ha rivelato 5 famiglie di AI conversazionali coesistenti, ciascuna con propria convenzione divergente:

| Famiglia | File chiave | Persona | Modello | KB binding | Persistenza config |
|---|---|---|---|---|---|
| **ARIA Support post-vendita** | [`supportPrompts.js`](../nexus-ai-ms/src/prompts/supportPrompts.js) | ARIA | Sonnet (default) | `product_knowledge` keyword | `ai_agent_profiles` riassunto + template hardcoded |
| **ARIA Lead qualification verticali** | [`basePrompts.js`](../nexus-ai-ms/src/prompts/basePrompts.js) | ARIA (4 verticali) | Sonnet | nessuno (solo `tenantConfig`) | `ai_agent_profiles` (Giulia per EDUCATION) |
| **Anna Sales pre-vendita** | [`publicDemoController.js`](../nexus-ai-ms/src/controllers/publicDemoController.js) | Anna | Haiku | PRODUCT_CARD pinned + RAG keyword | hardcoded controller, non in DB |
| **Anna Voice intent classifier** | [`voiceDialogController.js`](../nexus-ai-ms/src/controllers/voiceDialogController.js) | Anna | Haiku | PRODUCT_CARD snippet | hardcoded controller, non in DB |
| **Gaia Plan-mode dialog approver** | [`gaiaController.js`](../nexus-ai-ms/src/controllers/gaiaController.js) | Gaia | dinamico (URGENT→Opus, default Sonnet) | PRODUCT_CARD pinned + RAG keyword score top-3 | in-memory `sessions Map`, non in DB |

**Drift osservato vs aspettativa**:
- Naming inconsistente (ARIA vs Anna vs Gaia, nessuna regola)
- 3 di 5 famiglie NON usano `ai_agent_profiles` (single source of truth attesa)
- `system_prompt_voice` field esiste in DB ma è NULL su tutti gli ARIA_SUPPORT (voice prompt hardcoded in controller)
- KB pollution: 3 articoli `PRODUCT_CARD` AGILEHUB sono HOW_TO mal-categorizzati (id 720, 729, 730 — `JSON_VALID(answer)=0`)
- Cost tracking opzionale (`opts.sessionId && opts.productSlug` → reporter chiamato solo se entrambi presenti)
- Vertical ENUM `ai_agent_profiles` include `HEALTH/LEGAL/REALTY` ma DB ne ha 0 record

Lo standard **chiude questi gap** definendo conformance bloccanti per AGI-4 retrofit.

### 1.3 Relazione con altri standard cross-suite

| Standard | Slug | Ruolo |
|---|---|---|
| `installer-integration` v1.0.1 | INSTALLATORE | Lifecycle deployment cliente — questo standard descrive cosa l'installatore deve provisionare in termini di AI runtime |
| `ticket-tags` v1.0 | hub-ms | Catalogo tag cross-prodotto — AI di prodotto usano questi tag quando creano ticket via `open_ticket`/`escalate_to_ticket` |
| `outbound-campaigns` v1.0 | lead-ms | Campagne outbound — AI di prodotto Sales pre-vendita può essere triggerata da campaign outbound |
| `telephony-integration` v1.0 (proposed) | call-ms | Pipeline call → Pipecat — AI di prodotto voice channel rispetta questo contratto |
| **`ai-prodotto` v1.0 (questo)** | **`ai-prodotto`** | **Configurazione canonical AI prodotto suite** |

### 1.4 Autorità Agile AI

Agile AI (agente Claude specialista, ex GAIA, rinominato 2026-04-23 sessione 33 part 6) è **owner unico** di:

- Questo documento + future versioni
- Tabella `nexus_hub.hub_standards` slug `ai-prodotto`
- Tabella `nexus_ticket_db.product_knowledge` (CRUD + retention + audit pollution)
- Tabella `nexus_ai_db.ai_agent_profiles` (CRUD + validation conformance)
- Conformance audit AGI-4 retrofit (gap report formale per prodotto)
- Coordinamento con MAESTRO su blocchi AWE AI runtime (`C09_RetrieveFromKB`, `D02_LoadAvatarKB`, `AC11_GenerateAIResponse`)
- Coordinamento con VOX su KB binding L3 PERSONA (`ai_profiles.knowledge_id`)

Modifiche allo standard richiedono sub-approval esplicita utente (pattern come `STANDARD_INSTALLER_INTEGRATION.md`).

---

## §2 Naming convention netto

> **Cruciale**: 4 categorie distinte, mai confondere. Drift naming è la prima causa di confusione cross-team.

### 2.1 AI di prodotto (runtime, esposta agli utenti)

| Naming | Cosa | Esempi |
|---|---|---|
| `<NomePersona>` (italiano) | Persona conversazionale visibile all'utente finale | "Anna" (Sales TRPG/AGILEHUB), "Aria" (Support generico), "Gaia" (TRPG plan-mode) |
| `<NomePersona> <Verticale>` | Specializzazione per verticale lead qualification | "Giulia Master e Certificazioni", "Giulia Abilitazioni Estere" |
| **"Agile"** ⭐ | AI runtime di **AgileHub** stesso (caso speciale meta) | "Agile" — esposta in `/admin/*` per governance + agli utenti dei prodotti che chiedono "come usare AgileHub" |

**Regola**: ogni AI di prodotto deve avere un `display_name` (per UI + voice) **e** un `agent_key` interno (per DB + log + cost tracking) `<TIPO>_<PRODUCT>` pattern, es. `ARIA_SUPPORT_TRPG`, `ANNA_SALES_TRPG`, `GAIA_PLANMODE_TRPG`, `AGILE_RUNTIME` (per "Agile" meta).

### 2.2 Agente Claude specialista (sviluppo, qui in chat)

| Naming | Cosa | Esempi |
|---|---|---|
| `<NomeAgente>` (UPPERCASE meta) | Specializzazione di Claude Code per task di sviluppo AgileHub | REGENT, VOX, MAESTRO, CICERONE, PRISMA, INSTALLATORE, **Agile AI** (con suffisso AI per distinguerlo da "Agile" runtime) |

**Regola**: gli agenti specialisti non parlano agli utenti finali, vivono solo nella chat sviluppatore (`docs/AGENT_<NAME>.md` autoritativo). Distinzione netta da AI runtime.

### 2.3 AI marketing pre-vendita (lead-facing pubblico)

Sub-categoria di "AI di prodotto" con vincoli GDPR aggiuntivi (vedi §8):
- Vede solo articoli `product_knowledge` con `category IN ('PRODUCT_CARD', 'HOW_TO', 'URL_CHUNK')` pubblici (no L2 COMPANY dati cliente)
- Tone: caldo, commerciale, breve
- Naming: "Anna" (canonical su tutti i landing — drift Charlotte vs Sarah voice da chiudere VOX)

### 2.4 Persona vocale plan-mode

Sub-categoria con scope ristretto a **dialogo agente AI ↔ approver umano** durante PENDING_APPROVAL ticket:
- Naming: "Gaia" (TRPG pilota — non confondere con "Gaia agente specialista" che sarebbe estensione futura)
- Tone: tecnica, prima persona femminile, ammette limiti
- Tool readonly via devenv-gateway (vedi §6.3)

### 2.5 Tabella riassuntiva naming

| Termine | Significato | Esempio |
|---|---|---|
| **"Agile"** | AI runtime di AgileHub (prodotto meta) | "Ciao, sono Agile, posso aiutarti su AgileHub" |
| **"Agile AI"** | Agente Claude specialista (in chat dev) | "Ciao Agile AI Go!" |
| **"Anna"** | AI marketing pre-vendita (canonical) | Anna su `/public/demo-lead-trpg` |
| **"Aria"** | AI Support post-vendita (canonical) | ARIA_SUPPORT_TRPG widget viola |
| **"Gaia" persona vocale** | AI plan-mode dialog approver TRPG | Gaia parla con approver durante PENDING_APPROVAL |
| **"Giulia"** | AI Lead qualification verticali EDUCATION | GIULIA_TRIAGE, GIULIA_LAUREE, ecc. |

---

## §3 Anatomia di una "AI di prodotto" — 12 elementi obbligatori

Ogni AI di prodotto, per essere conforme allo standard, deve esplicitare **12 elementi**. La conformance checklist (§10) si basa su questa anatomia.

| # | Elemento | MUST/SHOULD | Dove vive |
|---|---|---|---|
| 1 | Identità persona | MUST | `ai_agent_profiles.name` + system_prompt opening |
| 2 | Obiettivo dichiarato | MUST | system_prompt sezione "Il tuo obiettivo" |
| 3 | Modello Claude | MUST | `opts.model` in chiamata `anthropicService.chat/runAgentLoop` |
| 4 | System prompt strutturato | MUST | `ai_agent_profiles.system_prompt` (canonical) |
| 5 | KB binding | MUST | `product_knowledge` filter clauses |
| 6 | Tool list dichiarativa | MUST se sub-template Support/Sales/Plan-mode/Lead | `nexusTools.js` subset |
| 7 | Guardrails LIMITI ASSOLUTI | MUST | system_prompt sezione finale |
| 8 | Voice rules | MUST se canale voice | `VOICE_RULES` const condivisa |
| 9 | FSM rules | MUST se lead qualification | `FSM_RULES` const condivisa |
| 10 | Channel-aware | SHOULD | `ai_agent_profiles.system_prompt_voice` separato |
| 11 | Tenant context injection | MUST | `tenantConfig.{agentName, companyName, greeting}` |
| 12 | Cost tracking | MUST | `opts.{caller, sessionId, productSlug}` ad ogni chiamata |

### 3.1 Identità persona (MUST)

Pattern canonical:
```
Sei <NomePersona>, <ruolo> di <Prodotto/AgileHub>.
Parli in <lingua>, con tono <descrittore tono>.
```

Esempio TRPG (`buildSupportPrompt(TRPG)`):
> Sei ARIA, assistente di supporto intelligente per TRPG Pro (Gender Pay Gap & Compliance).

**Regole**:
- Nome persona scelto dal catalogo §2 (Anna/Aria/Gaia/Giulia/Agile) o nuovo previa approvazione Agile AI
- Lingua dichiarata esplicita (default `it`, supportare `en` da v1.1)
- Genere consistente (es. femminile per Anna/Aria/Gaia)

### 3.2 Obiettivo dichiarato (MUST)

Pattern canonical: 1-3 frasi che dichiarano cosa l'AI deve fare. Massimo 1 obiettivo primario + 2 sub-obiettivi.

Esempio TRPG Support:
> IL TUO OBIETTIVO: Aiutare l'utente a RISOLVERE il problema SENZA creare un ticket.

**Regole**:
- Obiettivo deve essere actionable (verbo all'infinito + risultato misurabile)
- Niente claim di onniscienza ("sono in grado di tutto") → ammettere ambito ristretto
- Allineato al sub-template (§4)

### 3.3 Modello Claude (MUST)

Decision tree obbligatorio:

| Caso d'uso | Modello | Motivazione |
|---|---|---|
| Voice intent classifier (output JSON ristretto, < 200 token) | **Haiku** | Latenza minima, costo basso, accuracy sufficiente per classification |
| Greeting / saluto / messaggio singolo breve | **Haiku** | Idem, una sola interazione |
| Sales pre-vendita / chat lead-facing (3-4 frasi per turn) | **Haiku** | Volume alto, costo critico |
| Support post-vendita (dialog completo, RAG retrieval) | **Sonnet** | Default — bilanciato |
| Lead qualification (FSM transition + tool use) | **Sonnet** | Tool use con multi-step |
| Plan-mode dialog approver (priorità default/MEDIUM) | **Sonnet** | Tool use + reasoning su codice |
| Plan-mode dialog approver (priorità URGENT/HIGH) | **Opus** | Reasoning profondo per bug critici (pattern Gaia) |
| Code analysis / outcome evaluation post-call | **Sonnet** | Pattern OutcomeEvaluator nexus-call-ms |

**Regole**:
- Modello esplicito via `opts.model` — NO usare default global `process.env.ANTHROPIC_MODEL`
- Modello dinamico per priorità è encouraged (vedi pattern Gaia `gaiaController.js:670-676`)
- Modello deprecato → mai usare (vedi `MODELS` const in [`anthropicService.js`](../nexus-ai-ms/src/services/anthropicService.js))

### 3.4 System prompt strutturato (MUST)

Template canonical 7 sezioni:

```
[1. Identità persona]
Sei <Nome>, <ruolo> di <Prodotto>. Parli in <lingua>, tono <descrittore>.

[2. Obiettivo]
IL TUO OBIETTIVO: <1-3 frasi azione concreta>.

[3. Tono e stile]
TONO E STILE:
- <regola 1>
- <regola 2>
...

[4. Procedura operativa]
PROCEDURA:
1. <step 1>
2. <step 2>
...

[5. KB inject (se KB binding)]
SCHEDA PRODOTTO:
<getProductCardSnippet output>

CONOSCENZA DI DOMINIO RILEVANTE:
<top-K articoli RAG>

[6. Tenant context (se tenant injection)]
AZIENDA: <companyName>
SALUTO INIZIALE: <greeting>

[7. Limiti assoluti]
LIMITI ASSOLUTI:
- <limite 1>
- <limite 2>
...
```

**Regole**:
- Ordine sezioni vincolante (riproducibile cross-prodotto)
- Sezioni 5/6 opzionali ma se presenti devono usare il pattern esatto
- Sezione 7 OBBLIGATORIA (no-op fallback se non si sa cosa scrivere: "Non garantire prezzi/scadenze/disponibilità senza verifica")

### 3.5 KB binding (MUST)

Pattern obbligatorio (vedi §5 dettaglio):
1. Recuperare PRODUCT_CARD pinned via `getProductCardSnippet(product)` ([`productKbSnippet.js`](../nexus-ai-ms/src/services/productKbSnippet.js))
2. Recuperare top-K articoli RAG keyword score via `getRelevantHelpArticles(product, query, K=3)` (idem)
3. Iniettare entrambi nella sezione 5 del system prompt
4. Filtrare per `tenant_id` se context tenant disponibile (L2 COMPANY)
5. Filtrare per `knowledge_filter_slug` se context avatar disponibile (L3 PERSONA, futuro Lotto F)

**Eccezioni**: AI Voice intent classifier (output JSON ristretto, KB superflua) — sufficiente PRODUCT_CARD snippet.

### 3.6 Tool list dichiarativa (MUST se sub-template Support/Sales/Plan-mode/Lead)

Subset del catalogo `NEXUS_TOOLS` (11 tool) — vedi §6 matrice.

**Regole**:
- Tool list dichiarata esplicita nel chiamante (no global)
- Tool custom (es. Gaia `read_file`/`grep`/...) richiedono spec docs separato
- Tool con side-effect (es. `open_ticket`, `escalate_to_ticket`) devono passare per `ToolExecutor` — mai chiamati direttamente da AI

### 3.7 Guardrails LIMITI ASSOLUTI (MUST)

Pattern canonical sezione 7 system_prompt:

```
LIMITI ASSOLUTI:
- Non <azione 1 vietata>
- Non <azione 2 vietata>
...
```

**Limiti minimi obbligatori per ogni AI di prodotto**:
- Non garantire prezzi non confermati / disponibilità senza verifica
- Non inventare feature/funzionalità non presenti nella KB
- Non fornire informazioni mediche/legali/finanziarie personalizzate (sub-template specifici)
- Non rivelare informazioni di altri tenant (multi-tenant isolation L2)

### 3.8 Voice rules (MUST se canale voice)

Importare e includere `VOICE_RULES` da [`basePrompts.js`](../nexus-ai-ms/src/prompts/basePrompts.js):

```
REGOLE CANALE VOCE:
- Massimo 2 frasi per turno conversazionale
- Mai elenchi puntati o numerati
- Mai markdown di alcun tipo
- Intercalari italiani naturali ("certo", "capisco", "perfetto", "ottimo", "mi dica")
- Inizia le risposte con un breve acknowledgment poi vai al punto
- Numeri pronunciati in lettere ("seimilacinquecento" non "6.500")
- Date in forma estesa ("settembre duemilaventisei")
- Se hai bisogno di tempo: "Un attimo, sto verificando..."
- Poni UNA SOLA domanda per turno
```

**Regole**:
- `VOICE_RULES` invariato — modifiche richiedono coordinamento VOX
- `system_prompt_voice` (campo `ai_agent_profiles`) deve includere VOICE_RULES + sub-template adattato a voice (più stringato)
- AI con canale dual (text + voice) hanno DUE prompt distinti, mai unificati

### 3.9 FSM rules (MUST se lead qualification)

Importare e includere `FSM_RULES` da [`basePrompts.js`](../nexus-ai-ms/src/prompts/basePrompts.js):

```
REGOLE OPERATIVE FSM:
- Mantieni sempre un solo current_state
- Poni SOLO la domanda prevista dallo stato corrente
- Dopo ogni risposta del lead, chiama il tool fsm_transition con:
  - current_state, trigger normalizzato, raw_answer
- NON eseguire MAI calcoli di score (lookup backend)
- Se isTerminal=true, chiama complete_scoring
- Se sideEffects, esegui i tool corrispondenti
```

**Regole**:
- `FSM_RULES` invariato — modifiche richiedono coordinamento MAESTRO (FSM engine integration)
- AI senza FSM (Support, Sales generico, Anna voice intent) NON includono FSM_RULES

### 3.10 Channel-aware (SHOULD)

Se la AI di prodotto può operare su più canali (chat web, voice IVR, mobile), DEVE avere prompt distinti.

Pattern: `ai_agent_profiles` ha 2 campi:
- `system_prompt` (default canale text/chat)
- `system_prompt_voice` (override per canale VOIP/voice)

Logica selezione: `sessionService.js:103-107` — se `agent.systemPrompt` esiste lo usa, altrimenti chiama `buildSystemPrompt(vertical, channel, ...)`.

**Drift attuale da chiudere AGI-4**: tutti gli ARIA_SUPPORT hanno `system_prompt_voice = NULL` → se un giorno aggiungono canale voice, il fallback `buildSystemPrompt('SUPPORT', 'VOIP_3CX', ...)` non funziona (SUPPORT non ha `voice` key in `PROMPTS` const di basePrompts.js). Fix: AGI-4 popola `system_prompt_voice` per ogni ARIA_SUPPORT_<PRODUCT>.

### 3.11 Tenant context injection (MUST)

Pattern canonical (`buildSystemPrompt` riga 207-216):
```js
if (tenantConfig.agentName) prompt = prompt.replace(/Sei ARIA/, `Sei ${tenantConfig.agentName}`);
if (tenantConfig.companyName) prompt += `\n\nAZIENDA: ${tenantConfig.companyName}`;
if (tenantConfig.greeting) prompt += `\nSALUTO INIZIALE: ${tenantConfig.greeting}`;
```

**Regole**:
- Sostituzione `agentName` rispetta convention §2 (Nome persona, non ruolo)
- `companyName` proviene da `tenants.config.brandName` (DB hub-ms)
- `greeting` opzionale — se assente, AI usa pattern fisso "Ciao, come posso aiutarti?"

### 3.12 Cost tracking obbligatorio (MUST bloccante)

Pattern obbligatorio per ogni chiamata `anthropicService.chat()` o `runAgentLoop()`:

```js
const result = await anthropicService.chat(messages, systemPrompt, tools, {
  model: anthropicService.MODELS.SONNET,         // §3.3 esplicito
  caller: 'support-trpg',                         // identificativo per log
  sessionId: session.sessionKey,                  // tracciabilità sessione
  productSlug: 'trpg',                            // attribuzione cost-sdk
  tenantId: session.tenantId,                     // per metering tenant
  sessionType: 'support',                         // 'support'|'sales'|'gaia'|'demo'|'voice_dialog'
});
```

**Regole**:
- `caller` MUST (string)
- `sessionId` MUST (string univoca per sessione)
- `productSlug` MUST (lowercase code prodotto)
- `tenantId` SHOULD (se context tenant disponibile)
- `sessionType` SHOULD (per analytics segmentation)
- Cost reporter è fire-and-forget (no impact su latency) — vedi `anthropicService.js:96-110`

**Impatto AGI-4 retrofit**: ogni caller esistente che NON passa `caller+sessionId+productSlug` è non conforme. Fix richiesto in:
- `voiceDialogController.js:144-150` — già conforme ✅
- `gaiaController.js:580-584,683-685` — già conforme ✅
- `publicDemoController.js:171-178,184-189` — già conforme ✅
- `sessionService.js:127-133` — **NON conforme** ❌ (`runAgentLoop` chiamato senza opts) → fix in AGI-4

---

## §4 Quattro sub-template (famiglia AI di prodotto)

Ogni AI di prodotto deve appartenere a uno dei 4 sub-template. Sub-template definiscono: tool list canonical, KB binding, modello, tone, channel.

### 4.1 Sub-template "Support post-vendita"

**Reference implementation**: ARIA_SUPPORT_TRPG ([`supportPrompts.js`](../nexus-ai-ms/src/prompts/supportPrompts.js))

| Elemento | Valore canonical |
|---|---|
| Persona | "ARIA" (Aria nel parlato) |
| Obiettivo primario | Risolvere il problema dell'utente PRIMA di creare ticket |
| Modello | Sonnet (default) |
| KB binding | `product_knowledge` cat IN ('FAQ','HOW_TO','TROUBLESHOOT','KNOWN_ISSUE','TRAINING') + PRODUCT_CARD pinned |
| Tool list | `search_knowledge_base`, `forward_to_expert`, `escalate_to_ticket` (3) |
| Channel | text (canale voice futuro pending) |
| FSM | NO |
| Tenant context | obbligatorio (tenant esiste post-login) |
| Multi-livello KB | L0 + L1 + L2 (filtra `tenant_id`) |
| Anti-pollution | si — solo articoli APPROVED + active |

**Distingue formazione vs bug** (regola business critica):
- FORMAZIONE: "non so dove si trova", "come faccio a", ... → `forward_to_expert`
- BUG: "da errore", "non funziona", "crash", ... → `escalate_to_ticket`

### 4.2 Sub-template "Sales pre-vendita"

**Reference implementation**: Anna su [`publicDemoController.js`](../nexus-ai-ms/src/controllers/publicDemoController.js) (`/public/demo-lead-trpg`)

| Elemento | Valore canonical |
|---|---|
| Persona | "Anna" (canonical cross-prodotto) |
| Obiettivo primario | Presentare prodotto + qualificare lead + lead capture (email/contatto) |
| Modello | Haiku (volume alto, costo critico) |
| KB binding | PRODUCT_CARD pinned (obbligatoria) + `getRelevantHelpArticles` cat IN ('HOW_TO','URL_CHUNK','FAQ','DOC_CHUNK') |
| Tool list | (base): nessun tool. (demo agent): `show_feature`, `run_macro`, `query_product_state` (3 demo tool) |
| Channel | text (chat web) — voice futuro |
| FSM | NO |
| Tenant context | NO (lead-facing pubblico, no auth) |
| Multi-livello KB | SOLO L0 + L1 (NO L2 dati cliente — vincolo GDPR §8) |
| Anti-pollution | si + filter `category!='TROUBLESHOOT'` (no info bug interni) |
| Lead capture | dopo 4-5 turni: `"Ti mando una demo personalizzata. Come ti contatto?"` |
| Demo mode flag | `demo_enabled=true` per attivare 3 demo tool (iframe pilot) |

### 4.3 Sub-template "Plan-mode dialog approver" (Gaia)

**Reference implementation**: Gaia TRPG ([`gaiaController.js`](../nexus-ai-ms/src/controllers/gaiaController.js))

| Elemento | Valore canonical |
|---|---|
| Persona | "Gaia" (TRPG pilota; nome alternativo per altri prodotti TBD) |
| Obiettivo primario | Dialogare con approver umano per raffinare proposta diagnosi ticket PENDING_APPROVAL |
| Modello | dinamico: URGENT/HIGH→Opus, default→Sonnet |
| KB binding | PRODUCT_CARD pinned + RAG keyword top-3 articoli `product_knowledge` |
| Tool list | 11 tool readonly via devenv-gateway: `read_file`, `grep`, `list_dir`, `git_log`, `git_blame`, `run_tests`, `dry_run_sql`, + side-effect: `update_proposal`, `mark_ready`, `request_approver_decision`, `trigger_apply` |
| Channel | voice (Charlotte ElevenLabs `XB0fDUnXU5powFXDhCwa` — drift Sarah da chiudere VOX) |
| FSM | NO (state machine session in-memory) |
| Tenant context | obbligatorio (ticket scoped) |
| Multi-livello KB | L0 + L1 + L2 (tenant del ticket) |
| Stallo detection | dopo 12 turni / 15 min / 3 request_approver_decision → status `STALLED` + ticket → PENDING_HUMAN_REVIEW |
| Anti-loop | max 60 tool call per sessione |
| Persistenza | in-memory `sessions Map` (TODO: persistere in `gaia_sessions` per metrics §metrics endpoint) |

**Caratteristica unica**: ha tool readonly che chiamano `devenv-gateway` (porta 4220 nel container DevEnv prodotto) per ispezionare codice/tests/SQL. Pattern non replicabile direttamente su altri prodotti senza scaffold gateway dedicato.

### 4.4 Sub-template "Lead qualification verticali"

**Reference implementation**: Giulia (7 agent EDUCATION, basate su `basePrompts.js` PROMPTS const)

| Elemento | Valore canonical |
|---|---|
| Persona | "Giulia" (EDUCATION), "ARIA Health/Legal/Realty" (verticali pending — 0 record DB) |
| Obiettivo primario | Qualificare lead tramite FSM verticale-specifica (D1-D23 EDUCATION, H1-H8 HEALTH, L1-L8 LEGAL, R1-R9 REALTY) |
| Modello | Sonnet (tool use multi-step) |
| KB binding | nessuno (verticali pre-vendita non hanno KB di dominio prodotto) |
| Tool list | 5 base FSM: `fsm_transition`, `complete_scoring`, `open_ticket`, `schedule_callback`, `flag_high_priority` |
| Channel | text + voice (entrambi configurati con `system_prompt_voice` separato) |
| FSM | OBBLIGATORIA (config FSM via `fsmConfigId` foreign key) |
| Tenant context | obbligatorio |
| VOICE_RULES | OBBLIGATORIE se canale voice |
| FSM_RULES | OBBLIGATORIE sempre |

**Verticali ENUM ammessi** in `ai_agent_profiles.vertical`: `EDUCATION`, `HEALTH`, `LEGAL`, `REALTY` (proposta v1.1: aggiungere `SUPPORT`, `SALES`, `PLAN_MODE`, `META` per coprire altri sub-template — oggi vertical=`SUPPORT` è hack).

---

## §5 KB binding multi-livello (L0 / L1 / L2 / L3)

### 5.1 Definizione livelli

| Livello | Scope | Tenant ID | Esempio TRPG | Owner aggiornamento |
|---|---|---|---|---|
| **L0 SYSTEM** | Cross-prodotto, regole AgileHub generali | `tenant_id=1` (system) + `product='AGILEHUB'` | "Cosa è plan vs bypass mode", "Come funzionano i ticket" | Agile AI |
| **L1 FIRM** | Per prodotto, dominio applicativo (no dati cliente) | `tenant_id=1` (system) + `product=<PROD>` | TRPG: "Cos'è D.P.R. 151/2011" | Agile AI + esperto verticale prodotto |
| **L2 COMPANY** | Per tenant cliente specifico | `tenant_id != 1` + `product=<PROD>` | TRPG Tremolada (`tenant_id=3`): 294 articoli formula bonus | Tenant admin + Agile AI validation |
| **L3 PERSONA** ⭐ futuro | Per avatar specifica (vestizione) | `tenant_id != 1` + `product=<PROD>` + `knowledge_filter_slug='<slug>'` | "Anna Tremolada Consulente Senior TRPG" → solo articoli marcati `trpg-tremolada-consulente` | Agile AI + VOX (Lotto F Avatar Registry) |

### 5.2 PRODUCT_CARD pinned obbligatoria

Ogni prodotto MUST avere **esattamente 1** record `product_knowledge` con:
- `category='PRODUCT_CARD'`
- `tenant_id=1` (L1 base)
- `active=TRUE`, `review_status='APPROVED'`
- `answer` = JSON valido struttura `{description, scope[], target_buyer, free_markdown}`

**Anti-pollution check** (per audit AGI-4): query
```sql
SELECT product, COUNT(*) as cards, SUM(JSON_VALID(answer)) as valid_json
FROM product_knowledge
WHERE category='PRODUCT_CARD' AND active=TRUE
GROUP BY product
HAVING cards != 1 OR valid_json != cards;
```

**Drift attuale (audit 2026-04-23)**:
- AGILEHUB: **3** PRODUCT_CARD (id 720, 729, 730) tutti con `JSON_VALID=0` → fix AGI-4: UPDATE category='HOW_TO' (sono articoli AWE M1/M2/Orchestration mal-categorizzati)
- TRPG: 1 PRODUCT_CARD ✅ valido
- LG231/ALLTAX/SUSTAINAI/NIS2: **0** PRODUCT_CARD ❌ → fix AGI-4: scaffold scheda base

### 5.3 Schema `product_knowledge` esteso (proposta migration)

Schema attuale (verificato Hetzner 2026-04-23):
```
id, tenant_id, product, category, question, answer, tags JSON, keywords,
source ENUM, source_type ENUM, source_url, source_file_path, source_source_id,
content_hash, fetched_at, chunk_index, chunk_total,
learned_from_session_id, learned_from_ticket_id, expert_id,
review_status ENUM, views, helpful, language, active, created_at, updated_at
```

**Migration proposta v1.0 → v1.1** (NON applicare in v1.0, sub-approval separata):
```sql
ALTER TABLE product_knowledge
  ADD COLUMN kb_level ENUM('L0','L1','L2','L3') NULL DEFAULT NULL AFTER product,
  ADD COLUMN knowledge_filter_slug VARCHAR(64) NULL DEFAULT NULL AFTER kb_level,
  ADD INDEX idx_kb_level (kb_level),
  ADD INDEX idx_knowledge_filter (knowledge_filter_slug);
```

Backfill `kb_level`:
- `tenant_id=1 AND product='AGILEHUB'` → `L0`
- `tenant_id=1 AND product!='AGILEHUB'` → `L1`
- `tenant_id!=1 AND knowledge_filter_slug IS NULL` → `L2`
- `tenant_id!=1 AND knowledge_filter_slug IS NOT NULL` → `L3` (futuro Lotto F)

### 5.4 Retrieval keyword (oggi) → Voyage AI embedding (futuro)

**Oggi** (LIVE produzione):
- `getRelevantHelpArticles(product, query, K)` ([`productKbSnippet.js`](../nexus-ai-ms/src/services/productKbSnippet.js))
- Tokenizzazione naive: split query in token >3 char, scoring `LIKE %token%` su `keywords` (peso 3) + `question` (peso 2) + `answer` (peso 1)
- Order by `score DESC, views DESC LIMIT K`
- **Limiti**: nessun semantic match (sinonimi, riformulazioni), no re-ranking, latency dipende da MySQL

**Roadmap v1.1+** (decision Agile AI + utente):
- **Opzione A**: Voyage AI embedding service ($0.10/M token) → vector column → cosine similarity
- **Opzione B**: rimanere keyword + aggiungere stemming italiano + sinonimi manuali
- **Opzione C**: Claude Haiku re-ranking layer (cross-encoder LLM) sul top-N keyword
- **Trigger decisione**: quando articoli per prodotto > 100 con KB binding multi-tenant attivo

### 5.5 Anti-pollution principle

Memoria persistente `feedback_no_demo_data_production.md`:
> Articoli `product_knowledge` seedati con contenuti fuori scope inquinano RAG ranking.

**Regole vincolanti**:
1. NO articoli demo/test in produzione: usare `product='TEST_DEMO'` per testing
2. NO PRODUCT_CARD multipli per stesso `(tenant_id, product)`
3. NO PRODUCT_CARD con `JSON_VALID(answer)=0`
4. NO articoli con `language` diverso dal default tenant senza override esplicito
5. Spot check periodico Agile AI (almeno mensile + post AGI-4 retrofit)

### 5.6 L3 PERSONA forward-looking (vestizione avatar)

Concetto introdotto sessione 33 part 4 (visione utente Avatar Registry):

```
AVATAR TECNICO        +  VESTIZIONE       =  PERSONA PUBBLICA
(voice_id +              (display_name +      visibile cliente
 replica_id)              knowledge_id +      "Anna Tremolada
                          system_prompt +     Consulente Senior")
                          cost_per_minute)
```

**Implementazione Lotto F (settimane 2-3 master plan v2.1)** — coordinata con VOX Lotto A foundation:

1. Migration `ai_profiles` (nexus-presenter-ms) ADD COLUMN `knowledge_id VARCHAR(64) NULL` (slug logico filtro KB)
2. Migration `product_knowledge` ADD COLUMN `knowledge_filter_slug VARCHAR(64) NULL` (vedi §5.3)
3. Modify `getRelevantHelpArticles` per accettare `knowledge_filter_slug` opzionale: `WHERE (knowledge_filter_slug IS NULL OR knowledge_filter_slug = ?)`
4. Ranking weight per livello: L0=0.5, L1=1.0, L2=1.5, L3=2.0
5. Seed esempi:
   - Avatar "Anna Generica" → `knowledge_id='agilehub-default'`
   - Avatar "Anna Tremolada Consulente TRPG" → `knowledge_id='trpg-tremolada-consulente'`
   - Articoli AGILEHUB esistenti → marcare `knowledge_filter_slug='agilehub-default'`
   - Articoli TRPG L2 Tremolada → marcare `knowledge_filter_slug='trpg-tremolada-consulente'`

**Coordinamento**:
- VOX: schema `ai_profiles` esteso (Lotto A) + voice integration
- MAESTRO: blocchi AWE `D02_LoadAvatarKB(slug)` + `C09_RetrieveFromKB(query, knowledge_id, livello)`
- PRISMA: UI tab agenti `/admin/agents` con KB binding selector (Lotto C, approval gate)

**Status v1.0**: documentato come `PROPOSED` — implementazione conforme richiesta da v1.1 dopo deploy Lotto F.

---

## §6 Tool list standard

### 6.1 Catalogo NEXUS_TOOLS (11 tool)

Da [`nexusTools.js`](../nexus-ai-ms/src/tools/nexusTools.js):

| # | Tool | Family | Side-effect | Eseguito da |
|---|---|---|---|---|
| 1 | `fsm_transition` | FSM | Sì (FSM state) | nexus-fsm-ms via `ToolExecutor.fsmTransition` |
| 2 | `complete_scoring` | FSM | Sì (lead score) | nexus-lead-ms (futuro; oggi log) |
| 3 | `open_ticket` | FSM | Sì (ticket new) | nexus-ticket-ms (futuro; oggi log) |
| 4 | `schedule_callback` | FSM | Sì (calendario) | log only oggi |
| 5 | `flag_high_priority` | FSM | Sì (lead flag) | log only oggi |
| 6 | `search_knowledge_base` | Support | NO (read-only) | nexus-ticket-ms `/product-knowledge/search` |
| 7 | `forward_to_expert` | Support | Sì (expert notification) | nexus-ticket-ms `/support-sessions/:id/forward-expert` |
| 8 | `escalate_to_ticket` | Support | Sì (ticket new) | nexus-ticket-ms `/support-sessions/:id/escalate` |
| 9 | `show_feature` | Demo | Sì (iframe message) | client postMessage via `demoActions[]` accumulator |
| 10 | `run_macro` | Demo | Sì (iframe message) | client postMessage via `demoActions[]` accumulator |
| 11 | `query_product_state` | Demo | NO (read-only) | placeholder MVP — futuro live state pull |

### 6.2 Tool list per famiglia (matrice sub-template × tool)

| Tool | Support | Sales | Plan-mode | Lead qualif |
|---|---|---|---|---|
| `fsm_transition` | NO | NO | NO | **MUST** |
| `complete_scoring` | NO | NO | NO | **MUST** |
| `open_ticket` | NO | SHOULD (lead capture) | NO | SHOULD |
| `schedule_callback` | NO | SHOULD | NO | SHOULD |
| `flag_high_priority` | NO | NO | NO | SHOULD |
| `search_knowledge_base` | **MUST** | NO | NO | NO |
| `forward_to_expert` | **MUST** | NO | NO | NO |
| `escalate_to_ticket` | **MUST** | NO | NO | NO |
| `show_feature` | NO | SHOULD se `demo_enabled` | NO | NO |
| `run_macro` | NO | SHOULD se `demo_enabled` | NO | NO |
| `query_product_state` | NO | SHOULD se `demo_enabled` | NO | NO |
| `read_file`/`grep`/`list_dir`/`git_log`/`git_blame` (custom Gaia) | NO | NO | **MUST se Plan-mode** | NO |
| `run_tests`/`dry_run_sql` (custom Gaia) | NO | NO | SHOULD se Plan-mode | NO |
| `update_proposal`/`mark_ready`/`request_approver_decision`/`trigger_apply` (custom Gaia) | NO | NO | **MUST se Plan-mode** | NO |

### 6.3 Estensioni custom (Gaia readonly via devenv-gateway)

Pattern Gaia (TRPG pilota, [`gaiaController.js:228-250`](../nexus-ai-ms/src/controllers/gaiaController.js)):

```js
const PRODUCT_GATEWAYS = {
  TRPG: {
    url: process.env.TRPG_GATEWAY_URL || 'http://trpg-pro-agile-devenv:4220',
    key: process.env.TRPG_GATEWAY_KEY || process.env.DEVENV_GATEWAY_KEY,
    displayName: 'TRPG',
  },
};

async function callGateway(product, toolName, args) {
  const gw = PRODUCT_GATEWAYS[product];
  // POST a http://<gateway>/tools/<toolName> con X-Internal-Key
}
```

**Regole estensione custom tool**:
- Tool con prefisso `read_*`/`grep`/`list_*`/`git_*` SHOULD essere readonly
- Tool con side-effect su prodotto target richiedono devenv-gateway dedicato per quel prodotto
- Spec contratto separato (es. `docs/SPEC_DEVENV_GATEWAY_TOOLS.md` futuro)
- Audit obbligatorio (vedi `gaia_audit_log` per Gaia)

### 6.4 Cost estimation per tool (D6 metering)

Tool che usano LLM hanno cost esplicito tracciato via cost-sdk. Tool che usano solo HTTP/DB → cost trascurabile, no metering.

Esempio Gaia (per session):
- LLM cost: cumulato via `runAgentLoop` → `result.totalUsage.{inputTokens,outputTokens}` × pricing modello
- Tool readonly cost: trascurabile (HTTP locale)
- Tool `dry_run_sql`: trascurabile (snapshot readonly DB)

---

## §7 Guardrails minimi obbligatori

### 7.1 Pattern canonical LIMITI ASSOLUTI

Sezione 7 system_prompt deve sempre presente, formato:
```
LIMITI ASSOLUTI:
- Non <azione vietata 1>
- Non <azione vietata 2>
...
```

### 7.2 Limiti minimi per famiglia

**Support post-vendita**:
- Non inventare funzionalità non presenti nella KB
- Non chiedere informazioni tecniche complesse (log, stack trace) — quello lo farà il team tecnico
- Non superare 6 scambi senza proporre `forward_to_expert` o `escalate_to_ticket`
- Se la KB non ha risultati, dirlo onestamente

**Sales pre-vendita**:
- Non inventare feature non presenti nella scheda
- Non garantire prezzi non confermati ("dipende dal volume — te lo vedo dopo")
- Non promettere SLA/disponibilità senza verifica
- Non sminuire prodotti competitor (etica commerciale)
- Tool MAI proattivamente — solo su richiesta esplicita utente (regola FERREA `demo_enabled`)

**Plan-mode dialog approver (Gaia)**:
- Non modificare mai il codice sorgente del prodotto (tool readonly only)
- Non eseguire SQL non-SELECT (`dry_run_sql` enforced backend)
- Ammettere quando non si sa
- Non chiamare `trigger_apply` in altre situazioni che non sia approvazione esplicita approver

**Lead qualification verticali**:
- Non garantire posti/disponibilità senza verifica
- Non indicare prezzi non confermati
- Non promettere esiti concorsi/graduatorie/cause/vendite (per verticale)
- (HEALTH) Non formulare diagnosi, non suggerire farmaci
- (LEGAL) Non dare consulenza legale personalizzata, non citare articoli di legge specifici
- (REALTY) Non garantire prezzi/valutazioni senza sopralluogo

### 7.3 Limiti universali (cross-famiglia, MUST sempre)

- Rispondere SEMPRE in italiano (default; `en` se tenant lo richiede)
- Rispettare scoping multi-tenant (mai rivelare dati altri tenant)
- Non superare il limite turni configurato (anti-loop)
- Non inventare valori KB ("preferisco verificare col team — ti rispondo se mi lasci un contatto")

---

## §8 GDPR — split AI prodotto vs AI marketing

### 8.1 Principio

Memoria persistente `project_ai_prodotto_vs_marketing.md`: due cervelli AI separati per GDPR compliance.

| Tipo AI | Dati accessibili | Audience | Hosting |
|---|---|---|---|
| **AI prodotto** (server-side) | L0 + L1 + L2 (dati cliente reali) | utenti autenticati del cliente | post-login, scoped tenant_id |
| **AI marketing** (pubblico) | L0 + L1 SOLO `category IN ('PRODUCT_CARD','HOW_TO','URL_CHUNK')` filtrati pubblici | lead anonimi su landing | pre-login, no tenant context |

### 8.2 Implementazione filtro

Per **AI Sales pre-vendita** (publicDemoController):
```sql
WHERE product = ?
  AND tenant_id = 1                              -- L0/L1 only
  AND category IN ('PRODUCT_CARD','HOW_TO','URL_CHUNK','FAQ','DOC_CHUNK')
  AND review_status = 'APPROVED'
  AND active = TRUE
  AND (language IS NULL OR language = ?)
```

Per **AI Support post-vendita / Plan-mode** (autenticati):
```sql
WHERE product = ?
  AND (tenant_id = 1 OR tenant_id = ?)           -- L0/L1 + L2 cliente
  AND review_status = 'APPROVED'
  AND active = TRUE
```

### 8.3 GDPR Right to be Forgotten

- DELETE articoli L2 con `tenant_id = <cliente_da_dimenticare>`: cascade + audit log
- L3 PERSONA (futuro): DELETE articoli con `knowledge_filter_slug = '<cliente>-<persona>'`
- Endpoint dedicato: `DELETE /ai/products/:product/knowledge?tenant_id=X&confirm=YES_GDPR`
- Backup retention: 30 giorni dopo delete (compliance retention)

### 8.4 Anti-leak vincolante

- AI marketing NEVER deve restituire articoli con `tenant_id != 1`
- AI prodotto NEVER deve restituire articoli di altri `tenant_id` rispetto al chiamante
- Log query KB con `tenant_id` filter applicato (per audit GDPR)

---

## §9 Cost tracking MUST (cost-sdk integration)

### 9.1 Pattern obbligatorio

Vedi §3.12. Chiamata canonical:
```js
const result = await anthropicService.chat(messages, systemPrompt, tools, {
  model: anthropicService.MODELS.SONNET,
  caller: 'support-trpg',         // MUST
  sessionId: session.sessionKey,  // MUST
  productSlug: 'trpg',            // MUST
  tenantId: session.tenantId,     // SHOULD
  sessionType: 'support',         // SHOULD
});
```

### 9.2 Anti-pattern (NON conforme AGI-4)

```js
// BAD: opts mancanti
const result = await anthropicService.chat(messages, systemPrompt, tools);
//                                                                    ^ 4° arg vuoto
```

### 9.3 Esempio TRPG conforme

Da `voiceDialogController.js:144-150`:
```js
const result = await anthropicService.chat(messages, systemPrompt, null, {
  model: anthropicService.MODELS.HAIKU,
  caller: 'voice-dialog',
  sessionId,
  productSlug: (ticket?.product ? String(ticket.product).toLowerCase() : 'agilehub'),
  sessionType: 'voice_dialog',
});
```

Da `gaiaController.js:683-685`:
```js
{ model: preferredModel, caller: `gaia:${priority}`, sessionId: session.sessionId,
  productSlug: (session.product || 'agilehub').toLowerCase(), sessionType: 'gaia' }
```

### 9.4 Cost reporter implementation

Vedi `anthropicService.js:6-23` + `shared-libraries/cost-sdk` integration:
- Fire-and-forget (no impact su latency)
- Endpoint: `POST {HUB_URL}/api/cost/log` (nexus-hub-ms Fase 2 LIVE)
- Visibility dashboard: `/admin/cost?month=YYYY-MM` (admin_tenant role)

### 9.5 Telemetria di base (anche senza cost-sdk)

Pattern `anthropicService.js:93-95` (sempre attivo se `opts.caller || AI_USAGE_LOG=1`):
```js
logger.info(`[ai-usage] caller=${opts.caller} model=${model} in=${usage.inputTokens} out=${usage.outputTokens}`);
```

Quindi `caller` è MUST anche per debug/log baseline.

---

## §10 Conformance checklist (per audit AGI-4 retrofit)

### 10.1 Matrice 12 elementi × MUST/SHOULD

Per ogni AI di prodotto (tabella `ai_agent_profiles` + caller controllers):

| # | Elemento | Verifica | Fix se mancante |
|---|---|---|---|
| 1 | Identità persona | `ai_agent_profiles.name` valorizzato + system_prompt riga 1 = "Sei <Nome>" | UPDATE `name` + UPDATE `system_prompt` (header) |
| 2 | Obiettivo dichiarato | `system_prompt` contiene "IL TUO OBIETTIVO" o equivalente | UPDATE `system_prompt` aggiungere sezione 2 |
| 3 | Modello Claude esplicito | grep caller per `opts.model` | Modificare caller con `opts.model: MODELS.X` |
| 4 | System prompt strutturato 7 sezioni | `LENGTH(system_prompt) > 800` AND contiene marker sezioni | UPDATE `system_prompt` con template canonical |
| 5 | KB binding | sub-template Support/Sales/Plan-mode → caller chiama `getProductCardSnippet` + `getRelevantHelpArticles` | Modificare caller con KB inject |
| 6 | Tool list dichiarativa | sub-template !=Lead generico → tool list non vuota nel caller | Modificare caller passando tools |
| 7 | LIMITI ASSOLUTI | `system_prompt` contiene "LIMITI ASSOLUTI" + N bullet | UPDATE `system_prompt` aggiungere sezione 7 |
| 8 | VOICE_RULES (se voice) | `system_prompt_voice` contiene `VOICE_RULES` text | UPDATE `system_prompt_voice` |
| 9 | FSM_RULES (se Lead) | `vertical IN ('EDUCATION','HEALTH','LEGAL','REALTY')` → `system_prompt` contiene `FSM_RULES` | UPDATE `system_prompt` |
| 10 | Channel-aware | se canale voice supportato → `system_prompt_voice IS NOT NULL` | UPDATE `system_prompt_voice` |
| 11 | Tenant context | caller chiama `buildSystemPrompt(vertical, channel, tenantConfig)` con tenantConfig valorizzato | Modificare caller passare tenantConfig |
| 12 | Cost tracking MUST | `caller` + `sessionId` + `productSlug` in ogni `anthropicService.{chat,runAgentLoop}` call | Modificare caller passando opts |

### 10.2 Score conformance

Per ogni AI di prodotto:
- 12/12 MUST + tutti SHOULD applicabili → **CONFORME** ✅
- 12/12 MUST, alcuni SHOULD mancanti → **CONFORME PARZIALE** ⚠️ (warning, no block)
- < 12 MUST → **NON CONFORME** ❌ (bloccante AGI-4 sign-off)

### 10.3 Procedura audit AGI-4 per prodotto

1. Agile AI esegue audit checklist → produce `docs/AGI4_GAP_<PRODUCT>.md`
2. Gap report contiene: matrice 12 elementi compilata, fix proposti per ogni gap, effort stimato
3. Sub-approval esplicita utente per applicare fix
4. Apply (modifiche `nexus-ai-ms/src/...`) — pattern §10.3 team roster (modifiche file di prodotto AgileHub stesso, OK)
5. Smoke test: 3-5 query reali AI prodotto post-fix
6. Aggiornamento `ai_agent_profiles` + commit + sub-approval push Gitea

---

## §11 "Agile" — AI runtime di AgileHub (caso speciale)

### 11.1 Scope deciso (sessione 33 part 6, decisione utente AGI-2 domanda 4)

**Entrambi (full)**: una sola "Agile" AI con context routing.

| Context | Trigger | System prompt | Tool list | KB |
|---|---|---|---|---|
| **Admin AgileHub** | Chiamata da pagine `/admin/*` autenticato role `admin_tenant`/`admin_global` | "Agile per amministratori" — governance tone | `query_master_plan`, `query_standard`, `query_agent_status`, `query_workflow_runs`, `query_cost`, `search_kb_agilehub` | L0 AGILEHUB + L1 ADMIN |
| **Utenti finali prodotti** | Chiamata da widget cross-prodotto / pagine `/help`-style | "Agile per utenti" — assistente tone | `search_kb_agilehub`, `escalate_to_support` | L0 AGILEHUB + L1 USER (subset pubblico) |

### 11.2 Naming canonical

- `display_name`: "Agile"
- `agent_key`: `AGILE_RUNTIME` (in `ai_agent_profiles`)
- `vertical`: nuovo ENUM `META` (proposta v1.1 schema migration)

### 11.3 System prompt template "Agile"

```
Sei Agile, l'assistente AI di AgileHub.

[Context routing — admin]
Stai parlando con un amministratore di AgileHub. Aiutalo a:
- Conoscere lo stato del sistema (master plan settimana corrente, agenti specialisti, standard cross-suite, workflow runs AWE, cost mese corrente)
- Trovare articoli nella KB AGILEHUB
- Suggerire azioni concrete (es. "vuoi consultare REGENT per arbitrato?")

[Context routing — utente finale]
Stai parlando con un utente di un prodotto AgileHub. Aiutalo a:
- Capire come usare AgileHub (workflow editor, dashboard, mobile)
- Trovare guide nella KB AGILEHUB
- Escalare a support se serve

[KB inject: top-K articoli AGILEHUB rilevanti]
[Tool list: query_* per admin, search/escalate per user]
[LIMITI ASSOLUTI: non rivelare info di altri tenant; non inventare feature non presenti in KB]
```

### 11.4 Modello Claude

- Default: **Sonnet** (dialogo + tool use)
- Greeting / messaggio singolo: Haiku
- Reasoning profondo (es. "perché workflow run è failed?"): Opus on-demand

### 11.5 KB binding

- L0 AGILEHUB: 52 articoli esistenti (ground truth audit 2026-04-23) — id 720+
- L1 ADMIN/USER: split via nuovo campo `audience ENUM('admin','user','all')` in product_knowledge (proposta v1.1 schema)
- L3 PERSONA: `display_name='Agile Admin'` vs `display_name='Agile Helper'` con stessi voice_id ma KB filter differente (futuro Lotto F)

### 11.6 Implementazione AGI-3 (~5-6gg)

Step:
1. INSERT `ai_agent_profiles` record `AGILE_RUNTIME` con system_prompt template
2. Nuovo controller `agileController.js` con context routing logic
3. Tool dispatcher: `query_master_plan`, `query_standard`, ecc. (5-7 tool nuovi)
4. Endpoint `/ai/agile/chat` con auth detection (role admin → admin context)
5. Widget UI in `/admin/agile` (Agile chat panel — coordinamento PRISMA approval gate)
6. Smoke test: 5 query admin + 5 query user
7. Cost tracking conformance MUST

**Dipendenze AGI-3**:
- AGILE AI design tool list + system prompt template (questo doc + estensione)
- MAESTRO co-owner workflow integration (chiamare blocco AWE da Agile)
- PRISMA reviewer UI exposure (`/admin/agile` panel)
- Sub-approval utente prima del deploy LIVE

---

## §12 Stato adoption per prodotto (snapshot 2026-04-23)

### 12.1 Tabella matrice prodotto × elementi standard

Audit DB Hetzner 2026-04-23 (`SELECT product, count, has_card, kb_levels FROM ...`):

| Prodotto | Tot articoli KB | PRODUCT_CARD | KB livelli presenti | ai_agent_profiles | Score conformance | Note |
|---|---|---|---|---|---|---|
| **AGILEHUB** | 52 | **3 (pollution)** ❌ | L0 only | 0 ❌ | NON CONFORME | Fix AGI-4: UPDATE 2 PRODUCT_CARD → HOW_TO; creare AGILE_RUNTIME (AGI-3) |
| **TRPG** | 295 | 1 ✅ | L1 (1) + L2 (294 Tremolada) | 1 (ARIA_SUPPORT_TRPG) ⚠️ short prompt | CONFORME PARZIALE | Fix: estendere `system_prompt` ARIA_SUPPORT_TRPG a template completo; aggiungere ANNA_SALES_TRPG + GAIA_PLANMODE_TRPG in DB |
| **TRPG-PRO** | 0 | 0 ❌ | nessuno | 0 ❌ | NON CONFORME | Fix: scaffolding L1 base + ai_agent_profiles ARIA_SUPPORT_TRPG_PRO |
| **SUSTAINAI** | 27 | 0 ❌ | L1 (1) + L2 (26 cliente 5) | 1 (ARIA_SUPPORT_SUSTAINAI) ⚠️ short prompt | NON CONFORME | Fix: scaffolding PRODUCT_CARD + estendere system_prompt |
| **NIS2** | 2 | 0 ❌ | L1 (1) + L2 (1 cliente 7) | 1 (ARIA_SUPPORT_NIS2) ⚠️ short prompt | NON CONFORME | Fix: scaffolding KB completo + PRODUCT_CARD |
| **AllTax (TAXAI)** | 83 | 0 ❌ | L2 only (cliente 6) | 1 (ARIA_SUPPORT_ALLTAX) ⚠️ short prompt | NON CONFORME | Fix: scaffolding L1 base + PRODUCT_CARD |
| **LG231** | 91 | 0 ❌ | L1 (1) + L2 (90 cliente 8) | 1 (ARIA_SUPPORT_LG231) ⚠️ short prompt | NON CONFORME | Fix: scaffolding PRODUCT_CARD + estendere system_prompt |
| **DFM-PRO** | 0 | 0 ❌ | nessuno | 0 ❌ | NON CONFORME | Scope completo retrofit AGI-4 |
| **ALLRISK** | 0 | 0 ❌ | nessuno | 0 ❌ | NON CONFORME | Scope completo retrofit AGI-4 |
| **WMS** | 0 | 0 ❌ | nessuno | 0 ❌ | NON CONFORME | Scope completo retrofit AGI-4 |
| **MADEBYCLOUD** | 0 | 0 ❌ | nessuno | 0 ❌ | NON CONFORME | Fuori scope AGI-4 master plan v2.1 |
| **CertiSource** | 0 | 0 ❌ | nessuno | 0 ❌ | NON CONFORME | Fuori scope AGI-4 master plan v2.1 |

### 12.2 Drift cross-prodotto da chiudere

| Drift | Affected | Fix |
|---|---|---|
| `system_prompt` ARIA_SUPPORT troppo corto (220-300 char vs template ~3000 char) | TRPG, SUSTAINAI, ALLTAX, NIS2, LG231 | AGI-4: UPDATE `system_prompt` con `buildSupportPrompt(<PRODUCT>)` rendered text |
| `system_prompt_voice` NULL su tutti ARIA_SUPPORT | tutti | AGI-4: popolare `system_prompt_voice` se voice supportato |
| Anna Sales non in `ai_agent_profiles` (hardcoded controller) | tutti i prodotti con landing demo | AGI-4: INSERT `ANNA_SALES_<PRODUCT>` per ogni prodotto con landing |
| Gaia Plan-mode in-memory (no record DB) | TRPG (pilota) | AGI-4 (post AGI-5): persistere config in `ai_agent_profiles` `GAIA_PLANMODE_TRPG` + tabella `gaia_sessions` per metrics |
| 7 Giulia EDUCATION non hanno fsm_config_id valorizzato (`has_fsm=0` query DB) | tutti i 7 Giulia | AGI-4: link FSM config |
| Cost tracking opzionale in `sessionService.js:127` | tutti i caller `runAgentLoop` legacy | AGI-4: passare opts cost-sdk |

### 12.3 Priorità retrofit AGI-4

Settimane 3-4 master plan v2.1 (~7-10gg):

| Settimana | Prodotti | Effort |
|---|---|---|
| 3 (8-14/5) | AGILEHUB (fix pollution + creare Agile AGI-3) | 5gg |
| 3-4 (12-21/5) | TRPG estendere ARIA_SUPPORT + creare ANNA_SALES + GAIA_PLANMODE | 2gg |
| 4 (15-21/5) | SUSTAINAI + NIS2 + ALLTAX + LG231 (fix existing ARIA_SUPPORT + scaffold PRODUCT_CARD) | 3gg |
| 5 (22-28/5) | DFM-PRO + ALLRISK + WMS (scope completo) | 4gg |
| Backlog v1.1 | MADEBYCLOUD + CertiSource | TBD |

---

## §13 Cronologia versioni

| Data | Versione | Modifica | Owner |
|---|---|---|---|
| 2026-04-23 | 1.0 (proposed) | Creazione standard. Sub-template Support + Sales + Plan-mode + Lead qualif. KB multi-livello L0/L1/L2 + L3 PERSONA forward-looking. Cost tracking MUST. Naming convention netto (Agile vs Agile AI vs Anna vs Gaia). Conformance checklist 12 elementi. Tabella adoption snapshot 12 prodotti. | Agile AI (AGI-2 master plan v2.1) |
| _(future)_ | 1.1 | Migration `kb_level` + `knowledge_filter_slug` + `audience` columns. ENUM vertical esteso (`META`, `SUPPORT`, `SALES`, `PLAN_MODE`). L3 PERSONA promosso da `PROPOSED` a STANDARD. Embedding service decision. | TBD |

---

**Documento mantenuto da**: Agile AI (Architetto AI di prodotto + KB governance)
**Distribuzione**: in attesa sub-approval utente per seed `nexus_hub.hub_standards` slug=`ai-prodotto` v1.0 + distribuzione cross-suite (pattern `installer-integration`)
**Riferimento operativo**: [`docs/AGENT_AGILE_AI.md`](AGENT_AGILE_AI.md) v1.0 + [`docs/BRIEFING_AGILE_AI.md`](BRIEFING_AGILE_AI.md) v1.0
**Master Plan link**: [`docs/MASTER_PLAN_GO_LIVE_4_WEEKS.md`](MASTER_PLAN_GO_LIVE_4_WEEKS.md) v2.1 sezione AGI-1...AGI-6
