# Pilastro AI "vero consulente NIS2" — corpus normativo incluso/aggiornato + persona consulente > Deliverable agente design 2026-05-31 (richiesta utente: "come TRPG, contesto normativo incluso e aggiornato + AI istruita, un vero consulente"). Sola analisi; nessun codice applicato. > Riferimento incrociato: [[DESIGN_MODULO_QUESTIONARI_FORNITORI]] §13. ## 0. Stato attuale (già esistente in produzione) La pipeline RAG c'è già e funziona — NON si riparte da zero: - `EmbedService` (Voyage `voyage-3-lite`, 512-dim), `VectorService` (Qdrant `nis2_kb`, Cosine, filtro authz 3 livelli), `RagService` (embed→search→format). - `AIService::askWithRag()` (top-5, minScore 0.28, fallback graceful) + `authoritativeSourcesBlock()` (anti-allucinazione). - `AiController` → `POST /api/ai/ask` (rate-limited, audit). Persona **ARIA_SUPPORT_NIS2** (id=4, operativa). - Registry fonti `application/config/nis2_sources.php` (7 fonti). Ingest `scripts/ingest-nis2-sources.php` — **eseguito 2026-05-29: 287 chunk** (NIS2 171 + CER 77 + Det.333017 25 + Det.164179 9 + Ambiti 5). - Feed `normative_updates` + ACK (mig.009) — ma **scollegato dalla KB**. - Catalogo requisiti ACN granulari: mig.031 + `docs/nis2/allegati_acn/acn_requirements.json` (87 imp + 116 ess) — in DB/JSON ma **non in KB**. ## 1. Gap del corpus (da colmare — priorità) 1. **D.Lgs. 138/2024 ASSENTE** (`file => null` nel registry) — fonte primaria obblighi italiani. **Priorità massima.** 2. **203 requisiti ACN granulari** (Allegati 1-2) non in KB → ingerire come **chunk-per-requisito** con payload ricco (`subcategory=GV.SC-04`, `function`, `entity=essenziale/importante`, `source`). È il salto da "conosce la direttiva" a "conosce i requisiti puntuali da audit". 3. Assenti dal registro/KB: **Reg. UE 2024/2690**, **ENISA Good Practices Supply Chain**, **NIST SP 800-161r1 / CSF 2.0**, **DORA (Reg. UE 2022/2554)**. 4. Fix banale: commento `EmbedService` dice "1024 dim" ma il codice forza 512 (coerente con la collection) → allineare per evitare ricreazioni errate. > Copyright: ISO 27001 e materiali ENISA/NIST → ingerire solo sintesi/mappature proprie o testi a licenza aperta, non riproduzioni integrali protette. ## 2. Aggiornamento del corpus (chiudere il ciclo) Oggi `normative_updates` (feed UI/ACK) e `nis2_kb` (Qdrant) sono disgiunti. Design: - **Versioning fonte** in `nis2_sources.php`: `version`, `published_at`, `supersedes`, `status (in_force|superseded|draft)`, `content_sha`. - **Idempotenza** ingest: `doc_uuid` deterministico per-fonte (`uuid5(ns,key)`) + `content_sha` nel payload → skip re-embed se invariato (risparmio Voyage). - **Feed → KB**: estendere `NormativeController::create()` per ingerire opzionalmente in `nis2_kb` (scope SYSTEM) quando un super_admin pubblica un update con testo. Aggiungere `normative_updates.kb_indexed`, `kb_doc_uuid`. Così l'ACK audit e la conoscenza AI nascono dallo stesso atto. - **Cron** settimanale `ingest-nis2-sources.php` (cron registry AgileHub, TZ Europe/Rome, log `/var/log/nis2/`), `--dry-run` confronta `content_sha`, re-ingerisce solo i delta. - **Provenienza nei payload**: `version`, `published_at`, `url` → `formatContext()` espone la data ("secondo la Determina ACN 164179 del 14/04/2025…"). - **Cruscotto** `GET /api/knowledgebase/corpus-status` (super_admin): fonti, versione ingerita, ultimo ingest, drift vs registry. > Caveat: `kb_uploaded_documents` (mig.013) potrebbe non essere applicata su prod → applicare migrazioni KB su Hetzner (`mysql -h localhost`) prima di basarvi il cruscotto. ## 3. Persona consulente — rafforzare i system prompt Debolezze attuali di `askWithRag()`: prompt generico ("cita quando rilevante" → non obbligatorio), nessun tono/scope/persona, nessun comportamento esplicito quando la KB non copre, nessun disclaimer consulenza legale. Inoltre `suggestRisks`/`generatePolicy` **non** iniettano le fonti certe (incoerenza). ### Bozza system prompt (da iniettare in askWithRag, conforme a persona-conversational-rules v2.0) ``` # IDENTITÀ Sei ARIA, consulente esperto di cybersecurity e compliance NIS2 della piattaforma "NIS2 Agile". Operi come un consulente NIS2 reale: rigoroso, concreto, orientato all'azione. Rispondi sempre in italiano professionale. Se ti viene chiesto esplicitamente, dichiari di essere un assistente AI. # AMBITO Direttiva (UE) 2022/2555 (NIS2), (UE) 2022/2557 (CER), D.Lgs. 138/2024, Determinazioni ACN (specifiche di base, classificazione/notifica incidenti), Framework Nazionale (GV/ID/PR/DE/RS/RC) e l'uso operativo dei moduli della piattaforma. # REGOLE DI CITAZIONE (vincolanti) 1. OGNI affermazione normativa DEVE citare la fonte: articolo/comma, determina+allegato, o il riferimento [n] del contesto documentale. 2. Col contesto presente, cita i riferimenti [1],[2]… dei documenti forniti. 3. NON inventare numeri di articolo, determine, allegati, date o requisiti. Se incerto, dichiaralo e rimanda alla fonte ufficiale. 4. Preferisci D.Lgs.138/2024 + Determine ACN per gli OBBLIGHI OPERATIVI; la Direttiva UE per i PRINCIPI. # QUANDO MANCA IL CONTESTO Dichiaralo ("Non ho trovato un riscontro nelle fonti indicizzate") e rispondi con conoscenza generale chiaramente etichettata come tale, senza citare fonti inventate. # FUORI AMBITO (rifiuto cortese, niente eco di parole problematiche) "Mi occupo di compliance NIS2 e cybersecurity. Per [tema] ti consiglio di rivolgerti alla funzione competente." # LIMITI (no deception / GDPR) Orientamento di compliance, NON consulenza legale vincolante: per decisioni formali rimanda a un legale o all'ACN. Non includere mai dati identificativi dell'organizzazione. # STILE Conciso e strutturato: (1) risposta diretta, (2) base normativa citata, (3) azione consigliata nella piattaforma. Niente preamboli. ``` Sotto si concatenano `authoritativeSourcesBlock()` + contesto documentale numerato. ### Centralizzazione Estrarre i blocchi prompt in `application/config/ai_persona.php` (single source of truth) e iniettarli in tutti i metodi `AIService` (oggi solo classifyIncident/askWithRag sono grounded). ## 4. Integrazione coi questionari fornitori (primo caso d'uso del consulente in-context) - **(a) "Perché te lo chiediamo?"** (lato azienda): pulsante per domanda → `POST /api/ai/ask` precompilata "Spiega in 2 frasi il requisito {nis2_ref} e perché è rilevante per la sicurezza della catena di fornitura". Grounded sul chunk-per-requisito. - **(b) Guida compilazione** (lato fornitore, no-auth): endpoint dedicato **read-only, rate-limited** `POST /api/supplier-portal/explain` che accetta solo il `nis2_ref` e risponde da cache pre-generata / RAG scope SYSTEM (no esposizione di askWithRag completo a non autenticati, niente PII). - **(c) `AIService::suggestSupplierRemediation(negativeAnswers, supplierContext)`** grounded: per ogni vuln_flag/"no" propone rimedio citando GV.SC/PR + Art.21.2(d) → alimenta piano trattamento fornitore o NCR/CAPA. Anonimizzare (no nome/P.IVA nel prompt). ## 5. Piano incrementale - **Fase 0 (igiene, ~0.5g)**: allineare commento EmbedService 512; grounding anche in `suggestRisks`/`generatePolicy`. - **Fase 1 (corpus, alto valore)**: procurare D.Lgs.138/2024 (Gazzetta Ufficiale), promuovere Allegati 1-2 a fonti KB, ingerire i 203 requisiti chunk-per-requisito, eseguire `seed_acn_requirements.php`. Su Hetzner (Qdrant+Voyage), non in devenv. - **Fase 2 (persona, ~basso rischio)**: `ai_persona.php` + nuovo prompt askWithRag; aggiornare help.js + KB ARIA; smoke 10-15 domande note + 3 fuori scope + 1 senza copertura. - **Fase 3 (ciclo aggiornamento)**: versioning registry + doc_uuid/content_sha + feed→KB + cron + cruscotto corpus-status. - **Fase 4 (AI nei questionari)**: dipende dal modulo questionari — "perché te lo chiediamo", `supplier-portal/explain`, `suggestSupplierRemediation`. ## 6. Rischi trasversali Qdrant IP drift (assegnare ipv4 statico, conferma utente) · PHP-FPM Alpine env/DNS (mantenere multi-source lookup + IP letterale) · DB topology = host MySQL · disciplina commit (USR2→smoke→commit) · copyright ISO/ENISA/NIST.