Pacchetto di design completo (nessun codice applicato, nessuna migrazione eseguita): - DESIGN aggiornato con 5 review agenti + 3 decisioni utente + pilastro AI consulente (sez. 12-14) - docs/supplier-portal/template-nis2-base.questions.json: 26 domande GV.SC (Allegato 2 ACN) con nis2_ref/vuln_flag e fonti certe verbatim - docs/supplier-portal/AI_CONSULENTE_NORMATIVO.md: corpus normativo aggiornato + persona consulente (modello TRPG) - docs/supplier-portal/UX_MINI_SPEC.md: mini-spec portale fornitore (stati/copy/autosave/mobile/a11y/editor no-code) - docs/sql/032-035: migrazioni idempotenti proposte (modulo, suppliers, portale auth, migrazione 027->campaigns) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
7.9 KiB
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(Voyagevoyage-3-lite, 512-dim),VectorService(Qdrantnis2_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). Ingestscripts/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à)
- D.Lgs. 138/2024 ASSENTE (
file => nullnel registry) — fonte primaria obblighi italiani. Priorità massima. - 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". - 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).
- Fix banale: commento
EmbedServicedice "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_uuiddeterministico per-fonte (uuid5(ns,key)) +content_shanel payload → skip re-embed se invariato (risparmio Voyage). - Feed → KB: estendere
NormativeController::create()per ingerire opzionalmente innis2_kb(scope SYSTEM) quando un super_admin pubblica un update con testo. Aggiungerenormative_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-runconfrontacontent_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/askprecompilata "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/explainche accetta solo ilnis2_refe 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.