Salta al contenuto principale
ValidaAggiornamenti

Changelog

Tutte le modifiche rilevanti all'applicazione sono documentate in questo file.
Il formato segue Keep a Changelog.


v1.97.2

Fix — F81 (1.4.1) non riconosceva un indicatore testuale in prossimità DOM immediata

  • checkF81_RequiredColorOnly (src/lib/wcag-techniques/checks/static/forms.ts) — riconosce ora anche un indicatore testuale espresso come testo diretto del genitore o del fratello DOM immediato (es. un asterisco in uno <span> adiacente al campo), non solo via label/aria-label/aria-describedby. Chiudeva un backlog aperto dal 2026-07-25 (f81-indicatore-solo-prossimita-dom-non-rilevato) dopo 3 round di fix falliti sulla stessa classe di bug (contaminazione cross-campo): la generalizzazione via .text() ricorsivo su parent()/prev()/next() faceva "filtrare" l'indicatore di un campo in un campo fratello senza indicatore proprio. Il 4° tentativo applica in modo uniforme la correzione già parziale del round 2 (nodi di testo diretti, mai .text() ricorsivo) sia al genitore sia ai fratelli — il leak residuo del round 2 veniva esattamente dall'incoerenza tra i due. Nuovo limite residuo, più stretto e onesto: un indicatore annidato un livello più in profondità nel fratello (es. <span><em>*</em></span>) resta non rilevato — documentato in /help-valutazione.

v1.97.1

Fix — /cookie-policy reindirizzava al login

  • auth.config.tsisPublicPath() non includeva /cookie-policy: una pagina puramente informativa GDPR/legale, senza logica di sessione propria, veniva quindi trattata come area riservata e reindirizzata a /login per chiunque non fosse autenticato. Aggiunto path === '/cookie-policy' alla whitelist.

Fix — "0 progetti" silenzioso su Home con sessione scaduta

  • DashboardClient.tsx — Il pattern fetch difensivo esteso in 1.97.0 (fetch('/api/dashboard') con fallback silenzioso) assorbiva anche il caso 401 (sessione JWT stale dopo rebuild container, vedi 1.96.4), mostrando "Nessun progetto presente" senza alcun indizio che la causa fosse una sessione scaduta e non un portfolio vuoto. Aggiunto rilevamento esplicito di r.status === 401 con banner "Sessione scaduta" (pulsante "Accedi" verso /login) al posto dello stato vuoto silenzioso.

v1.97.0

Osservabilità — Sentry Uptime Monitoring (chiude uptime-monitoring-sentry / uptime-monitoring-esterno-mancante)

  • Monitor Sentry Uptime — Configurato un monitor esterno (valida-app-main-health, progetto javascript-nextjs) su https://valida-app.xyz/api/health, interval 10 minuti, regioni EU+US. Il piano Sentry free/Developer consente al massimo 1 Uptime Monitor totale (non 1 per progetto come pianificato originariamente): un secondo monitor dedicato al renderer-service è stato creato e ha superato il test iniziale, ma la sua attivazione ha fallito ("Unable to update monitor") perché richiede budget pay-as-you-go, quindi è stato eliminato. Copertura equivalente ottenuta con due assertion in Verification sull'unico monitor — Status Code (2xx, default) + JSON Path $.services.renderer equals ok — che sfrutta il campo già presente nel body di /api/health. Alert rule 694602 ("Send a notification for high priority issues") collegata. Documentazione completa in SENTRY_UPTIME_SETUP.md e second-brain/superpowers/specs+plans/2026-08-06-uptime-monitoring-sentry*. Test end-to-end (downtime simulato → alert → recovery) ancora da eseguire.

Fix — ON CONFLICT arbiter su indice parziale dom_hash (cross-section-issues)

  • src/app/api/cross-section-issues/route.ts — La clausola ON CONFLICT (valutazione_id, criterion_id, dom_hash) DO NOTHING non ripeteva il predicato WHERE dom_hash IS NOT NULL dell'indice unico parziale definito in src/db/migrate.ts, causando "no unique or exclusion constraint matching the ON CONFLICT specification" (Sentry JAVASCRIPT-NEXTJS-A). Aggiunto il predicato mancante alla clausola; nuovo test di integrazione (on-conflict.integration.test.ts, esegue query reali contro Postgres) copre la regressione.

Fix — Estensione pattern fetch difensivo a più viste

  • DashboardClient.tsx, ValutazioneClient.tsx, DettaglioClient.tsx, PagineClient.tsx — Dopo un restart con cookie di sessione stale, le API rispondono con un oggetto errore invece dell'array/oggetto atteso, causando crash su .filter()/.map() o accesso a proprietà mancanti. Estende il pattern difensivo già introdotto in 1.96.4 (fetch(url).then(r => r.ok ? r.json() : fallback)) ai fetch di risultati/componenti in queste viste, e a versions?.ibm/versions?.verapdf in LibraryVersionsBlock.

v1.96.4

Fix — Build rotta su HEAD (commit ae25c7b incompleto)

  • src/lib/utils/portfolio.ts + src/__tests__/portfolio.test.ts — Il commit ae25c7b introduceva l'import di @/lib/utils/portfolio in DashboardClient.tsx ma i due file non erano stati aggiunti al commit (rimanevano untracked nel working tree). HEAD era quindi rotto: tsc --noEmit falliva con TS2307: Cannot find module '@/lib/utils/portfolio'. Commit di follow-up d142afa aggiunge i file mancanti; build e test suite (1548 test) tornano verdi.

Dashboard — lastRoundDate per ordinamento portfolio Home

  • API (/api/dashboard) — Aggiunto campo lastRoundDate al payload di ogni progetto (data dell'ultimo round, formato YYYY-MM-DD), consumato da selectRecentProjects() per mostrare in Home solo gli ultimi 5 progetti con almeno una valutazione, ordinati per data più recente.

Accessibilità — Target touch 44×44px su .btn (WCAG 2.5.5)

  • src/app/globals.css — La regola globale button, select, [role="button"] { min-height: 2.75rem } non copriva <a>/<Link> renderizzati con classe .btn. Estesa la regola a .btn; .btn--sm resta esplicitamente più piccolo (min-height: unset) per le varianti compatte volute.

Fix — Crash "Si è verificato un errore imprevisto" dopo rebuild container

  • DashboardClient.tsx, AiChatbotSidebar.tsx — Dopo docker compose up --build -d, sessioni JWT/cookie stale facevano restituire alle API /api/dashboard, /api/dashboard/workflow, /api/dashboard/live, /api/chatbot/sessions un oggetto errore 401 {"error":"Non autenticato"} invece degli array attesi. Il client chiamava .filter() sull'oggetto → TypeError: u.filter is not a function → error boundary root global-error.tsx. Fix difensivo: Array.isArray(data) su /api/dashboard e /api/chatbot/sessions; typeof data === 'object' && data !== null (con log) su /api/dashboard/workflow e /api/dashboard/live. L'errore viene loggato in console invece di far crashare l'app. Causa radice probabile: AUTH_SECRET=dev-secret-not-for-production + JWT senza maxAge esplicito; da valutare header x-build-id per rilevare mismatch client/server su deploy.

v1.96.3

Estensione Chrome — Visibilità capacità degradate (capability gap) nei report (chiude capabilita-degradate-visibilita-report)

  • Backend (persistence.ts)buildProvenance() ora ritorna EvaluationProvenance anche per status N/D quando capabilityGaps non è vuoto (in precedenza ritornava null incondizionato per N/D). Questo permette di tracciare il motivo del degrado (es. real-hover, viewport-resize non disponibili nell'estensione) fino al database.
  • Label map (capability-labels.ts) — Nuova mappa CAPABILITY_LABELS: Record<DriverCapability, string> per tradurre le 5 capability (real-hover, viewport-resize, multi-navigation, cross-browser, screenshot) in italiano leggibile.
  • Confidence UI (provenance.ts) — Nuovo tier capability-degradato in describeConfidence() che appare solo quando confidence === null (status N/D) e capabilityGaps è popolato. Badge "Capacità degradata" (warning), tooltip con label umane.
  • Dettaglio criterio (DettaglioClient.tsx) — Badge "Capacità degradata" nella colonna trail con tooltip dedicato: "Capacità mancante: Hover reale non disponibile (estensione)... — l'esito N/D è un degrado, non una non-valutazione".
  • Triage (triage/route.ts, TriageClient.tsx) — Query allargata per includere N/D con provenance->capabilityGaps IS NOT NULL (ordinati per sortOrder, non confidence). Badge identico a Dettaglio.
  • Export Excel (excel/route.ts) — Colonna Note arricchita con nota "[Capacità degradata] Hover reale non disponibile (estensione); Ridimensionamento viewport non disponibile (estensione)" — nessuna nuova colonna per mantenere compatibilità foglio standard aziendale.
  • Test: 1542 test verdi, TypeScript clean, build Next.js riuscito.
  • Documentazione: spec 2026-08-05-capabilita-degradate-visibilita-report-design.md (status → fatto), piano 2026-08-05-capabilita-degradate-visibilita-report.md, riga decisione in MOC-Valutazione.md.

Estensione Chrome / Guida — Aggiornamenti per capability gap

  • Pagina Estensione (EstensioneClient.tsx) — Aggiornata la descrizione dei limiti: specificato che reflow (1.4.10) e hover-focus (1.4.13) degradano a N/D con capabilityGap esplicito, non "restituiscono N/D" generico. Aggiunto riferimento al badge "Capacità degradata" visibile in Dettaglio/Triage/Excel.
  • Guida Valutazione (LimitazioniSection.tsx) — Paragrafo limiti estensione affinato: "entrambe restituiscono un esito esplicitamente degradato con capability gap" invece di "esito esplicitamente degradato". Nota che il gap è ora visibile in UI (badge Dettaglio/Triage) ed export Excel.

v1.96.2

UI/UX — Home: Portfolio mostra ultimi 5 progetti con valutazione + Project nav deduplicata

  • Home (DashboardClient.tsx) — Il blocco "Portfolio" ora mostra solo gli ultimi 5 progetti che hanno ricevuto almeno un round di valutazione, ordinati per data dell'ultima valutazione (più recente prima). Progetti senza round restano accessibili da /progetti ma non affollano la home.
  • Project page (ProgettoClient.tsx) — Rimosso il tab "Dashboard" dalla navigazione a pill: restano solo Riepilogo / Storico / Panoramica. /progetti/[id]/dashboard rimane accessibile via URL diretto ma non linkato (contenuto duplicato di Panoramica).
  • API (/api/dashboard) — Aggiunto lastRoundDate al payload per supportare l'ordinamento.

v1.96.1

Fix — Testo residuo non allineato dopo l'attivazione dei 19 agenti (estensione-agentic-19-agenti)

  • chrome-extension/popup.html: la checkbox "Esegui agenti comportamentali" dichiarava ancora (7 — form/auth) mentre popup.js invoca già validaRunAgenticProbes() senza argomenti (tutti e 19 gli agenti, dal Task 5 del piano v1.96.0) — testo fuorviante nell'unico punto dove l'auditor decide se abilitare la fase agentica. Corretto in (19).
  • src/app/estensione/EstensioneClient.tsx: titolo pagina fermo a "Valida v1.4" (il manifest.json era già a 1.5.0 dal merge precedente) e step 4 delle istruzioni d'uso ancora "le 7 sonde form/autenticazione (WCAG 3.3.1, 3.3.3, 3.3.4, 3.3.7, 3.3.8, 2.2.1, 4.1.2)" — aggiornato a "tutti e 19 gli agenti" con link alla sezione "Fase agentica" della guida.
  • src/app/help-valutazione/components/AutomaticoSection.tsx: refuso preesistente e scorrelato trovato durante la verifica — "otto pattern di interazione" per state-reveal a riga 145, ma REGISTERED_AGENTS (src/lib/state-reveal/index.ts) ne registra 7 (modal, accordion, tab, dropdown, lazy-load, carousel, wizard), coerente con "sette pattern" già usato correttamente più sotto nello stesso file (riga 182, cookie banner escluso perché non è un pattern di reveal ma un dismiss one-off separato). Corretto a "sette".
  • chrome-extension/manifest.json1.5.1 (patch: comportamento osservabile invariato, solo testo).

v1.96.0

Estensione Chrome — attivazione completa dei 19 agenti agentici (chiude estensione-agentic-19-agenti)

  • Attivati tutti i 19 agenti agentici da estensione Chrome (prima solo 7, cluster form/auth) — derivazione automatica da AGENT_REGISTRY, nessuna lista hardcoded residua né in popup.js né in src/lib/agentic-engine/extension-support.ts.
  • description esportata dall'interfaccia Agent — fonte unica per il testo iniettato nel prompt Claude, non più copiato a mano nella whitelist server-side.
  • EXTENSION_AGENTS/EXTENSION_AGENT_IDS derivati da AGENT_REGISTRY/ALL_AGENT_IDSparseAgenticEvidence() continua a fare fail-closed validation, ma contro l'insieme reale di 19 agenti invece di una whitelist di 7 mantenuta a mano.
  • browser-entry.ts riscritto con lookup table (BROWSER_AGENT_REGISTRY) al posto di 19 branch if con criterionCode ripetuto — legge criterionCode direttamente dall'agente importato; validaRunAgenticProbes() ha ora default a tutti gli agenti supportati ed espone .AGENT_IDS.
  • popup.js non mantiene più AGENTIC_LOTTO1_IDS — chiama validaRunAgenticProbes() senza argomenti, usa il default esposto dal bundle generato.
  • Inclusi reflow (1.4.10) e hover-focus (1.4.13) — degradano a N/D con capabilityGap esplicito quando eseguiti da estensione (capacità fisica non disponibile in un content script), mai un esito approssimato in silenzio.
  • capabilityGap end-to-end fino a EvaluationProvenance per il percorso estensione resta esplicitamente fuori scope — gap preesistente, tracciato per un topic futuro separato.

Fix

  • Corretto testo fuorviante in LimitazioniSection.tsx (/help-valutazione) che dichiarava la copertura completa dei 19 agenti prima che fosse effettivamente vera ("Sette tutti e 19..." → "tutti e 19").

Testing

  • Test suite verde lungo tutti i 6 task di implementazione (description su Agent, AGENT_REGISTRY esportato, EXTENSION_AGENTS derivato, browser-entry.ts lookup table, popup.js senza lista hardcoded, testo LimitazioniSection + copertura test extensionAgenticInterpret).

Spec: second-brain/superpowers/specs/2026-08-04-estensione-agentic-19-agenti-design.md. Piano: second-brain/superpowers/plans/2026-08-04-estensione-agentic-19-agenti.md.


v1.95.0

Bugfix — Motore deterministico EN 301549 (4.2.x) + fix Best Practice (BP.*)

  • Nuovo motore deterministico per i criteri EN 301549 Cap.4 (Functional Performance Statements, 4.2.1–4.2.8) in src/lib/en301549-fps.ts — i criteri vengono ora derivati automaticamente aggregando (worst-case) gli esiti dei criteri WCAG 2.2 già valutati e mappati. Risolve il bug per cui i 4.2.x restavano bloccati a Da verificare/N/D da settimane perché nessun motore automatico li processava (solo lo schema dati esisteva, Sezione 1 dello spec originale, ma la Sezione 2 "engine layer" non era mai stata scritta). Il mapping FPS→WCAG (8 righe, validato con l'utente) è tracciabile via sourceCodes[] nel risultato derivato.
  • Aggancio automatico in applyEvaluations() (src/lib/evaluation-pipeline/persistence.ts) — la derivazione FPS è ora eseguita ad ogni scrittura di risultati WCAG, garantendo auto-consistenza indipendentemente da quale motore ha scritto per ultimo (statico, IBM, Claude, Gemini, estensione Chrome, coerenza cross-pagina). Sostituito il vecchio placeholder N/D piatto per gli EN-only che produceva sempre N/D indipendentemente dallo stato WCAG reale.
  • Esclusione 4.2.x e BP. dal prompt Claude* (src/lib/ai-engine/index.ts) — i criteri derivati e i Best Practice (derivati da IBM) non finiscono più nel prompt AI, riducendo di 13 criteri su 69 i token in input.
  • Esito "Superato" esplicito per Best Practice (BP.*) (src/lib/ibm-engine/index.ts) — quando IBM non trova raccomandazioni per una categoria BP.* le cui regole sono note (mappate in IBM_RULE_TO_BP), ora genera un esito Superato con nota [IBM Best Practice] Nessuna raccomandazione rilevata invece di restare assente (che risultava in un N/D fuorviante via placeholder). Funzione pura buildBestPracticeFindings() estratta ed esportata per testabilità.
  • Script di backfill one-off (scripts/backfill-en301549-fps.ts) — ricalcola i 4.2.x per tutti i 58 round esistenti con risultati WCAG applicabili: 463 criteri aggiornati, rispetta le correzioni manuali esistenti (stesso guard force della pipeline live). I BP.* toccati solo per round con best_practices_enabled=1 (0 a oggi, loggato esplicitamente).
  • Nessuna correzione manuale sovrascritta — il guard force preserva eventuali override dell'esperto (status ≠ N/D/Da verificare).
  • Test: 8 test mapping/aggregazione (en301549-fps.test.ts), 2 test integrazione (persistence-fps.test.ts), 4 test BP (ibm-engine-bp.test.ts), 1 test query filtrata (get-all-criteria.test.ts). Tutti i 63 test dei moduli toccati passano; tsc --noEmit pulito.
  • Documentazione: spec 2026-08-04-en301549-fps-engine-design.md (status → fatto), riga decisione in MOC-Valutazione.md, piano 2026-08-04-en301549-fps-engine.md.

Spec: second-brain/superpowers/specs/2026-08-04-en301549-fps-engine-design.md. Piano: second-brain/superpowers/plans/2026-08-04-en301549-fps-engine.md.


v1.94.0

UX — Filtro per stato nella vista di sola lettura "Dettaglio" (chiude filtro-stato-vista-dettaglio-readonly)

  • Nuovo filtro per stato (Superato/Non superato/Da verificare/N/D/Tutti) nella vista "Dettaglio" di sola lettura (/progetti/[id]/valutazioni/[roundId]/dettaglio/[componentId]) — estende la feature già presente nella vista di editing (ComponenteClient.tsx) anche alla pagina di consultazione per revisori/PM/RTD.
  • Componente condiviso StatusFilterChips (src/components/evaluation/StatusFilterChips.tsx) — estratto dal markup esistente in ComponenteClient.tsx, riusabile tra entrambe le viste con stessa accessibilità (role="group", aria-label, aria-pressed, toggle-off al riclick, annuncio aria-live="polite").
  • Logica di filtro pura centralizzata in src/lib/result-filter.ts (ResultFilter, filterResultsByStatus) — usata da entrambe le viste e dal componente condiviso, con test unitari dedicati (4+3 test).
  • Applicazione mirata: il filtro agisce solo sul tab "Criteri WCAG 2.2" (sostituisce la griglia di 6 stat-card statiche con la riga di chip); il tab "EN 301 549 esclusivi" (En301549Panel) resta invariato, riceve sempre results non filtrato.
  • Conformità (%) non interattiva — chip score-chip--meta in coda alla riga, mostra la percentuale calcolata sempre su results non filtrato (non sul sottoinsieme filtrato), con tooltip esplicativo.
  • Chip "Tutti" = reset + conteggio — sostituisce la card "Criteri totali", click imposta filtro 'all'.
  • Stato vuoto + screen reader — messaggio "Nessun criterio con stato «X» — torna a «Tutti» per vedere l'elenco completo." + annuncio sr-only con aria-live="polite".
  • Nessuna nuova CSS — riuso completo di .score-chip, .score-chip--all/pass/fail/check/na/meta, .is-active già in globals.css.
  • Persistenza solo in-page (useState), nessun URL/localStorage.
  • Test: 4 test per filterResultsByStatus, 3 per countByStatus; tsc --noEmit pulito; suite completa 179/183 file passati (5 fallimenti pre-esistenti in renderer-service non correlati).
  • Documentazione: spec 2026-08-03-filtro-stato-vista-dettaglio-readonly-design.md, piano 2026-08-03-filtro-stato-vista-dettaglio-readonly.md, riga decisione in MOC-Valutazione.md.

Spec: second-brain/superpowers/specs/2026-08-03-filtro-stato-vista-dettaglio-readonly-design.md. Piano: second-brain/superpowers/plans/2026-08-03-filtro-stato-vista-dettaglio-readonly.md.

Architettura — PageDriver: migrazione completa di tutti i 19 agenti agentic-engine

  • Interfaccia PageDriver estesa con 9 nuovi metodi (getUrl, focus, type, fill, boundingBox, setViewportSize, screenshot, evaluateHandle, evaluateHandleOn, moveAway) + 2 nuove DriverCapability (viewport-resize, screenshot) — mappatura completa per ogni metodo/agente documentata in types.ts.
  • Split collectEvidence()/run(): contratto condiviso (runViaCollectEvidence) per tutti i 19 agenti — centralizza try/catch + interpretWithClaude, mai più 19 blocchi quasi identici.
  • Migrazione completa 19 agenti su PageDriver: aria-state (pilota, Piano 1), no-trap, skip-nav, label-in-name, on-focus-input, pause-stop-hide, focus-order, error-identification, accessible-auth, form-validation, keyboard, error-prevention, redundant-entry, timing-adjustable, resize-text, focus-visible, live-region, reflow, hover-focus. Ogni agente ha test di parità su PlaywrightDriver (Chromium live) e BrowserDriver (jsdom).
  • Capability gap system: reflow-agent (1.4.10) degrada con capabilityGap=viewport-resize quando eseguito via BrowserDriver; hover-focus-agent (1.4.13) con real-hover. Propagazione → EvaluationProvenance.capabilityGaps in buildProvenance() + toEvaluationResult().
  • AgentContext.page rimosso (campo deprecato dalla migrazione incrementale): tutti i 19 agenti e 23 file test aggiornati a driver solo.
  • browser-entry.ts completo: tutte le 19 sonde agenti registrate in validaRunAgenticProbes, compilato via npm run build:extension.

Architettura — PageDriver: chiusura Piano 2, migrazione state-reveal e rimozione porting manuali

  • Migrazione completa 8 pattern state-reveal su PageDriver: selector-path.ts/capture.ts (libreria condivisa) + accordion/dropdown/tab/modal/carousel/lazy-load/wizard-reveal-agent. Ogni pattern ha test di parità su PlaywrightDriver (Chromium live) e BrowserDriver (jsdom).
  • Screenshot capability-aware: capture.ts usa driver.supports('screenshot') — sempre undefined su BrowserDriver (nessuna API di cattura schermo disponibile a un content script), mai un errore: l'HTML catturato resta valido comunque.
  • state-reveal/browser-entry.ts (nuovo): espone window.validaRunStateReveal, compilato via npm run build:extension insieme al bundle agentic già esistente.
  • Rimozione definitiva dei porting manuali ES5: chrome-extension/agentic-probes.js (949 righe) e chrome-extension/state-reveal-probes.js (657 righe) eliminati — popup.js inietta ora solo generated/agentic-probes.js/generated/state-reveal-probes.js. download/route.ts semplificato: rimosso il fallback isGeneratedProbesComplete() introdotto da fix/extension-generated-probes-placeholder, non più necessario perché il bundle generato è ora sempre completo per costruzione.
  • Chiude definitivamente codegen-sync-agentic-probes-estensione e l'intero piano estensione-pagedriver-architettura (Piano 1 + Piano 2).

Testing

  • 1547 test totali (fase agentic-engine): 1542 passati (5 fallimenti pre-esistenti non correlati in seed-data e JSDOM Tab nav). Nuovi test: page-driver (6+11), agentic-runner (3), 15 file di test agenti (~65 test di parità), capability-gap (5 test). npm run build:extension confermato (bundle 9.6kb, nessun SDK Anthropic/Node trascinato).
  • 11 file / 63 test state-reveal (selector-path, capture, 7 agenti reveal, orchestratore runStateReveal). Suite completa: 1496/1501 test passati (5 fallimenti pre-esistenti non correlati, verificati con git stash). npm run typecheck pulito, npm run build:extension genera entrambi i bundle (77.9kb + 22.3kb), nessun SDK Anthropic trascinato.

Documentazione — guida alla valutazione allineata al Piano 2

  • Pagina /estensione: numero agenti comportamentali aggiornato da 7 a 19, versione visualizzata v1.3v1.4 (coerente con chrome-extension/manifest.json).
  • Guida alla valutazione (/help-valutazione) — sezione "Copertura di stati dinamici": rimosso il riferimento a "un'implementazione indipendente specifica per il content script" per i pattern state-reveal — ora dichiara esplicitamente lo stesso codice TypeScript condiviso via PageDriver.
  • Sezione "Limitazioni" — card "Estensione Valida": rimosso il conteggio obsoleto "7 agenti / 12 residui (~6 portabili)", sostituito con "tutti e 19 gli agenti" e i due capability gap reali (reflowviewport-resize, hover-focusreal-hover) che degradano esplicitamente invece di essere assenti.
  • Backlog second-brain: aggiunta voce rendered-context-collectors-porting-manuale-non-centralizzato (i 3 collector RenderedContext — focus styles/target size/text spacing — restano un porting manuale ES5 non centralizzato, mai stato nello scope del piano PageDriver); ripristinate 3 voci (pdf-ocg-bookmark-collassati, dashboard-osservabilita-sentry-sonarqube, sentry-blind-spot-processi-esterni) rimosse per errore da un commit non correlato del 2 agosto; chiuse 3 voci superate dal Piano 2 (estensione-agentico-lotto2, codegen-sync-agentic-probes-estensione, estensione-consolidare-persistenza-con-pipeline-principale).

v1.93.3

Architettura — PageDriver: eliminata duplicazione comportamentale tra pipeline web ed estensione Chrome

  • Interfaccia PageDriver unificata con due implementazioni (PlaywrightDriver server, BrowserDriver estensione) che sostituisce la duplicazione manuale ES5 (agentic-probes.js, state-reveal-probes.js) — stessa logica TypeScript compilata per entrambi i target via esbuild, niente più drift silenzioso tra pipeline web ed estensione.
  • Capability system per funzionalità non universalmente disponibili: real-hover (movimento puntatore OS), multi-navigation (page.goto), cross-browser (Firefox/WebKit) — dichiarate esplicitamente con degradazione tracciata (capabilityGap in AgentResult e EvaluationProvenance), mai approssimazione silenziosa.
  • Safety contract ("mai submit reale") responsabilità strutturale di BrowserDriver.runSession() — intercetta automaticamente evento submit + HTMLFormElement.prototype.submit per tutta la sessione agenti, zero rischio per sessioni autenticate reali.
  • Migrazione pilota aria-state-agent (criterio 4.1.2) su PageDriver — stesso identico esito verificato su PlaywrightDriver (Chromium live) e BrowserDriver (jsdom), pattern validato per gli altri 18 agenti + 8 pattern state-reveal (lavoro successivo).
  • Build toolchain esbuild (npm run build:extension) genera chrome-extension/generated/agentic-probes.js da un'unica entry point TypeScript — file generati mai editati a mano, check di freschezza in pack.sh blocca build se sorgenti sono più recenti del bundle (chiude codegen-sync-agentic-probes-estensione).
  • Persistenza estensione consolidata su applyEvaluations (stessa pipeline web) — elimina extension-persistence.ts duplicato e più povero, risolve bug noto: passing_evidence non persistita (chiude estensione-consolidare-persistenza-con-pipeline-principale), confidence/browserDivergence/capabilityGaps ora arrivano automaticamente anche all'estensione.
  • ace.js versioning:
    • Bug fix: costante ACE_ENGINE_VERSION hardcoded a 4.0.24 in popup.js (server a ~4.0.29) → ora letta da nuovo endpoint GET /api/extension/ace-version (riusa aceEngineVersion() esistente).
    • Avviso staleness: ace-version.json marker scritto da setup.sh e /api/extension/download, confrontato all'avvio del popup con versione server — avviso non bloccante se divergono.
    • Marker ace-version.json incluso nello zip scaricato da /api/extension/download (tutti e 3 i code path: cache locale, CDN fetch, placeholder CDN unreachable).
  • Schema: campo additivo capabilityGaps?: string[] su EvaluationProvenance (jsonb, nessuna migrazione) — traccia capacità mancanti che hanno degradato un esito (es. real-hover via estensione).

Affidabilità — capabilityGaps come nuovo segnale di qualità

  • Campo capabilityGap su AgentResult e capabilityGaps su EvaluationProvenance tracciano esplicitamente quando un esito è stato degradato per capacità mancante nel contesto di esecuzione (es. real-hover via estensione).
  • Nuova voce backlog registrata: capabilita-degradate-visibilita-report — UI per visualizzare questi segnali (stesso punto di browserDivergence), deliberatamente fuori scope qui.

Refactor — Consolidamento persistenza estensione su pipeline principale

  • src/app/api/extension/submit/route.ts usa ora applyEvaluations (stessa funzione della pipeline web Inngest) invece di saveEvaluations duplicato e più povero.
  • Risolve bug noto: passing_evidence non persistita dall'estensione (ora scritta correttamente via applyEvaluations).
  • Miglioramenti futuri alla pipeline principale (confidence, placeholder N/D EN-only, batch upsert, accumulo browserDivergence/capabilityGaps) arrivano automaticamente all'estensione.
  • File rimossi: src/lib/extension/extension-persistence.ts e test associato.
  • Bonus fix: extensionAgenticInterpret.ts aggiornato allo stesso pattern.

Build — Prima toolchain per l'estensione Chrome

  • npm run build:extension compila via esbuild l'entry point src/lib/agentic-engine/browser-entry.tschrome-extension/generated/agentic-probes.js (IIFE, browser platform).
  • pack.sh guadagna check di freschezza: fallisce se generated/agentic-probes.js è più vecchio dei sorgenti condivisi (src/lib/agentic-engine/, src/lib/page-driver/) — un porting dimenticato diventa errore di build bloccante, non drift silenzioso.
  • esbuild promosso a devDependency esplicita (era solo transitiva via Vitest).
  • .gitignore aggiornato con chrome-extension/generated/.

Fix — ace.js versioning

  • Bug fix: costante ACE_ENGINE_VERSION = '4.0.24' hardcoded in chrome-extension/popup.js (package.json a ~4.0.29) — ogni submit dichiarava versione ACE sbagliata anche quando ace.js scaricato era aggiornato.
  • Nuovo endpoint GET /api/extension/ace-version espone aceEngineVersion() (già esistente in src/lib/extension/ace-version.ts) con autenticazione estensione standard.
  • popup.js risolve la versione all'avvio via fetch (fallback a undefined, mai blocca il popup).
  • setup.sh e /api/extension/download scrivono ace-version.json marker accanto ad ace.js nello zip.
  • checkAceVersionStaleness() in popup.js confronta marker locale vs server all'avvio, mostra avviso non bloccante se divergono (class="feedback warn" coerente con design system esistente).

Testing

  • 1482 test passati (suite completa), 5 fallimenti pre-esistenti in renderer-service/ non correlati.
  • Nuovi test: page-driver (6+5 test), aria-state-agent (3 test parità driver), ace-version/route.test.ts (3 test), download/route.test.ts (nuovo test ace-version.json in zip).
  • Fix round su test batch-upsert (route.test.ts, revealed-states.test.ts): indici batch a blocchi da 12 invece di indici fissi; mock wrapping in revealed-states.test.ts per la vera applyEvaluations.
  • Fix CSS: classe .warning inesistente → .feedback.warn (esistente in design system).
  • tsc --noEmit pulito, nessuna regressione oltre i 5 fallimenti pre-esistenti renderer-service/ (dipendenza express mancante, non correlato).

v1.93.2

Fix — Raccomandazioni IBM Equal Access senza dettaglio + badge mancante sulla nota estensione (segnalazione esperti)

  • Le "Raccomandazioni" IBM Equal Access mostravano solo il messaggio grezzo (es. "1) Heading element has no descriptive content"), senza rule ID, riga sorgente o snippet HTML — a differenza del blocco "Problemi rilevati", che li include sempre. rec‍Lines in evaluateWithIbm (e il suo omologo mapIbmResults nel path estensione Chrome) ora include [ruleId] + snippet, stesso stile già usato per problemLines e bestPracticeFindings.
  • Un criterio con solo finding di livello RECOMMENDATION (nessuna violazione/potenziale) restava senza alcun dettaglio consultabile: le note citavano un conteggio ("49 problemi rilevati") ma il campo problems era null, quindi il blocco "Problemi rilevati" spariva del tutto dalla UI (DettaglioClient.tsx lo renderizza solo se non vuoto). Aggiunto un fallback: quando violazioni+potenziali sono entrambi vuoti, problemLines usa le raccomandazioni come dettaglio — le raccomandazioni pure restano comunque nel campo recommendations come prima, senza duplicazione nel caso comune (violazioni/potenziali presenti).
  • Le note IBM originate dal path estensione Chrome (prefisso [IBM ACE – Browser]) non ricevevano alcun badge colorato in formatNotes/formatters.tsx, a differenza di Claude/Gemini/Agentico/Tecniche WCAG/IBM (path server) — cadevano nel fallback "nessun badge". Aggiunta una entry dedicata in SOURCE_BADGE_LABELS per il prefisso [IBM ACE …].
  • Root cause verificata su dati reali del DB locale (stessa pipeline) prima del fix, e sul motore IBM live dopo il fix (stessa pagina reale, stesso criterio) — non solo su unit test.
  • Test: 1 nuovo test per il badge [IBM ACE – Browser] in formatters-notes.test.ts. Suite esistente (84 test su ibm-engine, extension/submit/route.test.ts, formatters-notes.test.ts) verde, tsc --noEmit pulito. Riguarda solo i dati generati dalle prossime valutazioni IBM — le righe già in DB restano col vecchio formato finché non vengono ri-eseguite.

v1.93.1

Affidabilità — Divergenza cross-browser come segnale di confidence (chiude divergenza-cross-browser-confidence)

  • **Nuovo segnale di affidabilità: la divergenza reale tra browser reali (chromium/firefox/webkit) abbassa la confidence a 0.4 e genera un badge dedicato "Browser discordanti" nei pannelli Dettaglio/Triage — non un'altra nota testuale persa nel rumore, ma un cap numerico identico a quello già usato per l'arbitraggio AI (Claude vs Gemini), con lo stesso pattern di persistenza cross-fase.
  • Merge deterministico (mergeBrowserEvaluations) normalizza le chiavi browser/viewport (normalizeBrowserKey, modulo condiviso) e calcola browserDivergence solo tra browser reali distinti — niente falsi positivi in scan combinati multi-browser + responsive.
  • Confidence cap 0.4 in computeConfidence (stesso di arbitrated), nessuna doppia penalità se un criterio è sia arbitrato sia browser-divergente. Accumulo cross-fase via accumulateBrowserDivergence (union con provenance già persistita) — sopravvive al passaggio fase tecnica → Claude/Gemini sia nella pipeline Inngest async sia nel percorso sincrono dev/fallback. Fix mirato in mergeAiResultsPreservingRevealedStates per il percorso sincrono (merge AI sostituiva l'intero oggetto perdendo il campo), e fix inline in technical-phase.ts per preservare il campo attraverso i merge IBM/best-practice.
  • UI dedicata: describeConfidence guadagna tier browser-divergente con priorità su arbitrato (stesso valore 0.4, label diversa). Badge "Browser discordanti (40%)" con tooltip elenco browser in DettaglioClient e TriageClient. Ordinamento coda triage per confidence crescente mette i criteri divergenti in cima.
  • Persistenza additiva: EvaluationProvenance.browserDivergence?: string[] su valutazione_results (jsonb, nessuna migrazione). Campo omonimo su CriterionEvaluation in memoria — nessun remapping tra livelli.
  • Test regressione: 7 test per mergeBrowserEvaluations (incluso false-positive combined mode), 6 per accumulateBrowserDivergence, 3 per describeConfidence tier, 2 per fix sync path in mergeAiResultsPreservingRevealedStates, plus IBM merge preservation regression. Suite completa 179 file / 1481 test, tsc --noEmit pulito.
  • MOC: riga decisione in MOC-Attendibilita-Knowledge-Base.md. Seed Ipotizzato ripulito (divergenza-cross-browser-confidence rimosso). Spec/piano status fatto.

Spec: second-brain/superpowers/specs/2026-07-31-divergenza-cross-browser-confidence-design.md. Piano: second-brain/superpowers/plans/2026-07-31-divergenza-cross-browser-confidence.md.


v1.93.0

Sicurezza — Rimossi token live da .claude/settings.json, chiude secrets-live-esposti-claude-settings-json

  • Token API live (Render, 2× SonarQube, 1× TestSprite) incorporati in chiaro in 41 regole di permesso Bash di .claude/settings.json (tracciato in git, non gitignored — visibile a chiunque avesse accesso in lettura al repo). Finiti lì perché sessioni precedenti hanno salvato il comando esatto eseguito (token incluso) come regola di permesso, invece di un pattern generico. Trovato verificando il gate gitleaks introdotto il 2026-07-23 (bug, priorità alta).
  • Render: token revocato (non serve più — migrato a Hostinger, hostinger-migration-fase1). Rimosse 12 regole Bash con Authorization: Bearer in chiaro, 11 regole mcp__render__*, 4 regole WebFetch/curl residue, e il server MCP render da ~/.claude.json.
  • SonarQube: token ruotato su dashboard locale, nuovo valore solo in .env.local (gitignored). 27 regole con token in chiaro rimosse — sostituite da una singola regola a match esatto Bash(./sonar-scan.sh) (lo script legge già SONAR_TOKEN da env var).
  • TestSprite: chiave API ruotata — scoperta e inclusa nello scope solo durante questa sessione (non menzionata nella nota di backlog originale). 2 regole con chiave in chiaro rimosse, registrazione MCP locale aggiornata.
  • Finding di una review di sicurezza post-commit (non pre-esistente — introdotto e corretto nella stessa sessione): la generalizzazione inizialmente scelta per le regole SonarQube usava un wildcard a metà stringa (Bash(SONAR_TOKEN=* ./sonar-scan.sh)) — un wildcard che non è l'ultimo carattere del pattern matcha l'intera stringa successiva, permettendo di eseguire comandi concatenati arbitrari dopo il prefisso. Stessa classe di escape già corretta in questo repo il 2026-07-23 (gitleaks version *, python3 * rimosso interamente). Corretto con match esatto e rimozione secca delle query curl senza generalizzazione sicura possibile.
  • Nessuna riscrittura della history git (decisione esplicita): i valori storici restano leggibili nei commit passati ma sono inerti dopo revoca/rotazione.
  • .gitleaks-baseline.json rigenerato — le entry per l'HEAD attuale spariscono per assenza di match; restano 14 entry per 2 commit storici di .claude/settings.json (history non riscritta, coerente con la decisione sopra).
  • Promemoria anti-ricorrenza aggiunto a CLAUDE.md (sezione Convenzioni di sviluppo): regole di permesso Bash con segreti inline vanno generalizzate omettendo il segreto (mai con un wildcard a metà stringa) o rimosse se nessuna generalizzazione sicura è possibile.

Spec: second-brain/superpowers/specs/2026-07-31-secrets-live-esposti-claude-settings-json-design.md. Piano: second-brain/superpowers/plans/2026-07-31-secrets-live-esposti-claude-settings-json.md.


v1.92.9

Hardening — Guardrail di coerenza technique-map.ts ↔ codice dei check + 3 bugfix

  • TECHNIQUE_MAP (wcag-techniques) poteva disallinearsi silenziosamente dal codice che emette davvero i risultati, senza alcun segnale automatico (hardening): terza volta in una settimana che questa classe di bug viene trovata solo per audit manuale (dopo H58_PARTS/G161/G83_PROX il 24 luglio e F44/F85 il 25 luglio). Aggiunto un guardrail a 3 invarianti in technique-map-coherence.ts — nessun techniqueId emesso assente dalla mappa (invariante A), il type dichiarato deve comparire tra i type effettivamente emessi per quell'id (invariante B — non "ogni emissione deve coincidere", formula verificata contro ~20 pattern legittimi già in produzione), ogni tecnica static/rendered dichiarata è emessa oppure allowlistata con motivazione (invariante C) — più una guardia inversa che rileva quando un'entry allowlist diventa obsoleta. L'estrazione è statica (regex sui sorgenti checks/), non richiede eseguire i check con fixture. technique-map-gap-allowlist.ts documenta le 87 coppie (criterio, tecnica) dichiarate ma non emesse, classificate come coperte da un altro motore (14), duplicato dichiarativo con una variante già implementata (28), o gap reale non implementato in questo lavoro (45).
  • 3 bug reali trovati e corretti durante l'audit: dead code checkFocusAppearance/collectFocusAppearance (C45/F110b, calcolava un risultato sempre scartato, residuo della rimozione del criterio AAA 2.4.13 del 27 luglio); F103_FORM (errore form senza live region, 3.3.1) mai dichiarato in TECHNIQUE_MAP pur essendo già emesso da checkARIA22_F103 — risultato scartato silenziosamente; H44_PH (placeholder come unica etichetta di un campo, 3.3.2) dichiarato failure ma emesso sempre sufficient — un campo con solo placeholder non faceva mai scattare "Non superato", falso negativo silenzioso in produzione, quarta istanza della stessa classe di bug dopo H58_PARTS/G161/G83_PROX.
  • Un finding della review finale whole-branch, corretto prima del merge: findTypeMismatches costruiva una mappa keyed su techniqueId che, in presenza di due dichiarazioni dello stesso id con type diverso (es. sotto criteri diversi), manteneva silenziosamente solo l'ultima — esattamente la classe di bug che il guardrail esiste per intercettare. Nessun id nel repository attiva oggi questo caso, ma la funzione ora itera su ogni dichiarazione anziché deduplicare per id.

Verifica: suite completa 1446/1448 test verdi (i 2 falliti sono un bug pre-esistente e indipendente in scripts/lib/seed-ipotizzato.test.mjs, non correlato a questo lavoro — confermato identico su main prima del merge), tsc --noEmit ed eslint puliti. Sviluppato via subagent-driven-development (7 task + review finale whole-branch con 1 fix round). Chiude wcag-techniques-consistenza-guardrail-technique-map-vs-codice. Spec second-brain/superpowers/specs/2026-07-29-wcag-techniques-consistenza-guardrail-design.md, piano second-brain/superpowers/plans/2026-07-29-wcag-techniques-consistenza-guardrail.md.


v1.92.8

Hardening — Istrumentazione Sentry per renderer-service (chiude parzialmente il blind spot sui processi esterni)

  • renderer-service (worker Playwright su Hostinger) senza alcuna osservabilità Sentry, unico processo esterno del sistema a non riportare errori (hardening): un crash Firefox-specific in v1.87.4/v1.87.5 era passato inosservato per circa un mese perché i fallimenti parziali del rendering multi-browser (array failures di Promise.allSettled) finivano solo in console.warn, mai come errore tracciato. Aggiunta @sentry/node@10.64.0 con DSN dedicato (SENTRY_DSN_RENDERER, separato da quello dell'app principale) e auto-instrumentation Express: 10 catch espliciti su /render, /ibm-scan, /agentic-run, /capture-element-snippets, /capture-dynamic-state-snippets, /pdf-remediation/reading-order, agid-export.ts, snippets.ts, pdf-remediate.ts; più captureMessage a livello warning per i fallimenti parziali multi-browser precedentemente visibili solo via log.
  • Due deviazioni dal design emerse in implementazione: il campo dell'integrazione HTTP per sopprimere il body si chiama maxIncomingRequestBodySize nella versione installata (non maxRequestBodySize come da doc Sentry di riferimento); i test HTTP-level richiedono una guardia if (process.env.VITEST !== 'true') attorno ad app.listen() in server.ts per evitare EADDRINUSE quando più suite importano ./server nello stesso processo Vitest.
  • Residuo esplicito, non chiudibile da codice: creazione manuale del progetto Sentry dedicato (DSN, alert rule) sul dashboard — precondizione per lo smoke test end-to-end reale. Chiude solo la parte renderer-service del blind spot: estensione Chrome e sidecar veraPDF restano fuori scope.

Verifica: tsc --noEmit pulito su entrambi i tsconfig (app + renderer-service), eslint 0 errori, suite completa 171 file / 1418 test verdi, build Docker pulita, /health confermato healthy, log puliti senza SENTRY_DSN_RENDERER configurata. Sviluppato via subagent-driven-development (9 task + review finale whole-branch). Spec second-brain/superpowers/specs/2026-07-28-sentry-renderer-service-instrumentation-design.md.


v1.92.7

Evolutiva — Fase 2 migrazione Hostinger: motore Agentic e snippet stati dinamici delegati al renderer-service

  • Motore Agentic (19 agenti Playwright) inutilizzabile in produzione dopo lo slimming dell'immagine valida-app (evolutiva): lanciava sempre Chromium in-process, mai raggiungibile sul VPS Hostinger senza binari Playwright — degradava a N/D per ogni round con agenticEnabled=true. Estratto verso renderer-service con nuovo endpoint POST /agentic-run (stesso pattern "delega HTTP quando WORKER_URL è settato" già usato da IBM engine/PDF-remediation/reading-order/AGID-export): il worker esegue lancio browser + N agenti + chiusura in un'unica chiamata, screenshot ritornati come base64 grezzi (nessuna credenziale storage lato worker) e caricati su MinIO/R2 lato app. Avvolto in withHeavyOpLock('agentic', ...), sia il percorso worker sia il fallback locale, per rispettare il guardrail "una sola operazione pesante alla volta" del VPS.
  • captureDynamicStateSnippets (snippet focus/hover per Gemini Vision, criteri 2.4.7/1.4.13/2.5.5) con lo stesso gap, mai delegata (evolutiva): sorella di captureElementSnippets nello stesso file, che aveva già ricevuto la delega in un fix round precedente — degradava già onestamente (array vuoti + log distinto), ma non funzionava mai in produzione. Estratta con lo stesso pattern verso renderer-service — nuovo endpoint POST /capture-dynamic-state-snippets, avvolta in withHeavyOpLock('capture-dynamic-state-snippets', ...) su entrambi i rami (delega e fallback locale). La review finale whole-branch ha trovato che le due funzioni ora condividono lo stesso lock ma venivano lanciate concorrentemente nello stesso Promise.all da due chiamanti (technical-phase.ts, visual-phase.ts) — corretto sequenziandole nei chiamanti, così la seconda non rischia più di attendere l'intero MAX_WAIT_MS (120s) e degradare di nuovo a risultato vuoto.

Verifica: suite completa 168 file / 1405 test verdi, tsc --noEmit pulito (app + renderer-service). Spec second-brain/superpowers/specs/2026-07-08-hostinger-migration-design.md §12/§13, piani 2026-07-28-agentic-engine-estrazione-worker-fase2.md e 2026-07-28-capture-dynamic-state-snippets-estrazione-worker-fase2.md.


v1.92.6

Refactor + Fix — 2 voci di backlog chiuse: criteri AAA sprecati in technique-map, checkLanguageOfParts esteso ai form

  • technique-map.ts mappava 3 criteri di livello AAA mai valutabili (refactor): 2.4.9 (Scopo del link, solo link), 2.4.12 (Focus non oscurato, avanzato) e 2.4.13 (Aspetto del focus) sono fuori dai 56 criteri A/AA ufficiali (data/wcag22-criteria.json) — runTechniqueEngine calcolava comunque inizializzazione/aggregazione/instradamento verso AI per questi 3 codici ad ogni valutazione web, risultati mai persistiti (nessun id corrispondente in wcag_criteria). Verificato prima del fix che nessun consumer reale dipende dai 3 codici, poi rimosse le entry da TECHNIQUE_MAP. Aggiunto un test guardrail che confronta TECHNIQUE_MAP con l'elenco ufficiale in entrambe le direzioni, per prevenire un futuro disallineamento. Scoperta laterale fuori scope: 2.4.12 dichiarava la tecnica C43_AA, mai emessa da alcun check (solo C43) — non riceveva mai un risultato reale nemmeno prima di questo fix, terza istanza della stessa classe di bug già tracciata in backlog.
  • checkLanguageOfParts (3.1.2) non copriva option/select né altri controlli di form (fix): il selettore per il testo straniero senza lang era limitato a p, li, td, th, dd, blockquote, span, div — un blocco in script non-Latino dentro un <option>, <button>, <label> o <legend> non veniva rilevato, anche se identico per struttura a un <p>/<div> già coperto. Esteso il selettore ai 5 tag. Il gap più difficile — parole inglesi in alfabeto latino dentro contenuto italiano (il caso realmente segnalato: "All" in una <option> popolata via AJAX) — resta un limite accettato del checker statico, non implementato: richiederebbe un dizionario/allowlist per non generare falsi positivi su prestiti legittimi (email, PDF, login). Guida /help-valutazione aggiornata di conseguenza.

Verifica: TDD per entrambi i fix (test RED→GREEN prima dell'implementazione), suite completa 1331/1331 test verdi, tsc --noEmit pulito. Spec dedicati in second-brain/superpowers/specs/2026-07-27-technique-map-criteri-aaa-calcolo-sprecato-design.md e second-brain/superpowers/specs/2026-07-27-checker-lingua-parti-non-copre-select-option-e-inglese-latino-design.md.


v1.92.5

Fix — 2 tecniche WCAG senza ramo di fallimento (F69, F101)

  • F69 (1.4.4, Ridimensionamento del testo) non veniva mai eseguita fuori dalla pipeline con rendering (fix): checkViewportZoom aveva già un ramo fail funzionante ma viveva in rendered-checks.ts pur non usando mai renderedContext (legge solo <meta name="viewport">) — nell'harness statico (es. golden dataset) non girava mai, nonostante technique-map.ts la dichiarasse correttamente mode: 'static'. Spostata in checks/static/structure.ts, registrata in runAllStaticChecks.
  • F101 (2.5.2, Annullamento del puntatore) restava sempre "Da verificare", mai "Non superato" (fix): checkF101 rilevava azioni su mousedown/pointerdown/touchstart ma produceva solo outcome: 'warning', nonostante il criterio fosse dichiarato type: 'failure'. Aggiunto un pattern ad alta confidenza (submit/rimozione/navigazione/checkout eseguiti sul down-event invece che sull'up-event) che promuove il risultato a fail; gli handler ambigui restano warning come prima. Il pattern è stato rivisto durante la review finale per eliminare 5 falsi positivi reali su codice legittimo (classList.remove(), la parola "delete" dentro una stringa qualsiasi, checkout/purchase come substring di un identificatore più lungo).
  • 9 tecniche esaminate e chiuse come "nessun intervento": F99 (2.1.4), F103 (4.1.3), H96 (1.2.1), C22 (1.4.5), C8/C21 (1.4.12), G19 (2.3.1), G84 (3.3.3), H100_A (3.3.8) — per ciascuna la scelta di non aggiungere un ramo fail è motivata caso per caso (assenza di una tecnica "sufficient" non è mai un fallimento WCAG di per sé, oppure il criterio richiede intrinsecamente un motore diverso dal solo HTML statico). Dettaglio in second-brain/superpowers/specs/2026-07-25-wcag-techniques-check-senza-esito-fallimento-design.md §2.
  • Bugfix collaterale — mergeByTopic() perdeva la nota descrittiva dello spec quando il file di piano associato non ne aveva una propria: la sovrascrittura "il piano vince" (voluta per lo status) si applicava per errore anche a note, azzerando la colonna Note dell'indice generato per il topic appena chiuso. Aggiunto un fallback dedicato, con test di regressione.

Verifica: suite completa 152 file / 1323 test verdi, tsc --noEmit pulito, eslint pulito. Sviluppato in worktree isolato con subagent-driven-development: 3 task con review per-task (Task 3 con 2 round di fix), review finale sull'intero branch con 1 fix wave sulla regex F101 (approvata dall'utente prima di procedere). Guida /help-valutazione aggiornata con i 2 limiti espliciti (F99, F103).


v1.92.4

Feature — 7 tecniche WCAG dichiarate ma mai implementate + bugfix id orfano F44

  • 7 criteri con una tecnica dichiarata in technique-map.ts senza alcuna funzione implementante nel codice (feat): 1.2.3 (G78), 1.2.5 (G78_V), 1.3.2 (G57), 1.4.1 (F81), 1.4.10 (C32), 2.4.3 (F44), 3.3.7 (G221) — una violazione di questi criteri non intercettata da altri motori passava silenziosamente. Implementate tutte e 7: G78/G78_V condividono un'unica funzione (checkG78_AudioDescriptionTrack, track kind="descriptions" su video); C32 rileva @media nel CSS incorporato; G57 rileva la proprietà CSS order come proxy di riordino visivo; F81 rileva campi obbligatori indicati solo dal colore (unica altra tecnica failure oltre F44); G221 è un'euristica proxy per l'inserimento ridondante (mai oltre warning/cannot-tell, limite strutturale dichiarato — la vera verifica richiede confronto tra step di un form multi-pagina, non possibile da un singolo snapshot statico).
  • Bugfix — 2.4.3/F44 era orfano, non assente (fix): checkTabindexPositive (interactions.ts) implementava già la logica di F44 ma taggava il risultato con id 'F85', mai dichiarato in technique-map.tsbuildTechniqueToCriteriaMap() lo scartava silenziosamente, 2.4.3 non riceveva mai questo segnale nonostante il codice funzionante esistesse. Rinominato l'id.
  • Correzioni emerse in review durante l'implementazione: G57, la regex di rilevamento order matchava falsamente dentro border: (proprietà CSS comunissima) — corretta con ancoraggio a word boundary. F81, il rilevamento CSS solo-colore inizialmente non correlava la regola alla specifica coppia campo↔selettore (una classe .required su un elemento non correlato poteva salvare un campo genuinamente privo di indicatore) e non ignorava i commenti CSS — corretti; dopo 3 round della stessa classe di bug su un'estensione della ricerca per prossimità DOM, la generalizzazione a testo di genitore/fratelli è stata rimossa: F81 riconosce ora solo label/aria-label/aria-describedby, limite noto e documentato in /help-valutazione.
  • Gap di piano trovato nella review finale sull'intero branch: 4 delle 7 tecniche (G78/G78_V/G57/G221) aggiungono un pass che rimuove il criterio dalla coda di verifica AI. G221 (3.3.7, nessuna tecnica rendered/ai con cui interferire) corretto a cannot-tell con confidence 0.5, coerente con il proprio limite già dichiarato; G57 lasciato invariato per non regredire il caso comune in cui il rendering (sempre disponibile nella pipeline reale) verifica già correttamente 1.3.2.

Verifica: suite completa 1287/1287 test verdi (nessuna regressione, F1 golden-dataset invariato a 0.7654), tsc --noEmit pulito, eslint pulito. Sviluppato in worktree isolato con subagent-driven-development: 7 task con review per-task, poi review finale sull'intero branch con 3 round di fix (ciascuno confermato con l'utente prima di procedere).


v1.92.3

Fix — navigazione tra criteri: la pagina non si riposizionava sull'accordion appena aperto

  • Aprendo un nuovo criterio nell'accordion di valutazione, la vista non si riposizionava sulla nuova intestazione e il focus da tastiera andava perso (fix): nessuna gestione di scroll/focus esisteva in ListResultsView.tsx — l'intestazione appena aperta poteva finire coperta dalla TopBar sticky (64px) o restare fuori dal viewport, causando salti di layout e perdita di contesto durante la valutazione sequenziale dei criteri. Segnalato dai colleghi durante l'uso reale (osservazioni-utenti-2026-07-20.md §1).
  • Fix: scroll-padding-top: 4rem + scroll-behavior: smooth su html (globals.css) — stessa tecnica già raccomandata dal motore di remediation del progetto per il criterio 2.4.11 (operable.ts, tecnica WCAG C43), applicata qui alla propria interfaccia. In ListResultsView.tsx, un useEffect sul criterio espanso richiama focus({ preventScroll: true }) e scrollIntoView({ block: 'start' }) sul bottone .crit-row corrispondente. scroll-behavior: smooth è già neutralizzato per prefers-reduced-motion da una regola preesistente.

Verifica: nessuna infrastruttura di test component-level nel progetto (vitest gira in environment: node) — verificato dal vivo con script Playwright ad-hoc contro il container Docker ricostruito: intestazione riposizionata esattamente sotto la TopBar (~64px), focus conservato sul bottone appena aperto, zero errori console, comportamento istantaneo con prefers-reduced-motion. 1261/1261 test verdi, tsc --noEmit pulito.


v1.92.2

Fix — 6 bug UI segnalati (widget flottante, dialog, formattazione, technical note, pulsante morto)

  • Widget "Assistente AI" copriva e intercettava i click su contenuto reale (fix): .cbot-launcher (position: fixed, z-index: 50) non aveva safe-area riservata — nascondeva sia l'ultima riga del portfolio in Home sia i link del footer (Changelog/Cookie Policy). Alzato bottom del launcher (24→80px) e padding-bottom del <main> (16→24, layout.tsx).
  • Modale "Elimina progetto" illeggibile (fix): la regola dialog { background: transparent; border: none; padding: 0 } in globals.css era fuori da ogni @layer — per la CSS Cascade Layers spec le regole non-layered vincono sempre su quelle layered, quindi sovrastava le utility Tailwind (bg-white, border, p-6) applicate allo stesso <dialog>. Spostata in @layer base (pattern standard Tailwind v4 per estendere Preflight).
  • Grassetti resi a blocco in "Come eseguire un audit" (estensione) (fix): display:flex su un <li> con testo inline misto a <strong> trasformava ogni run di testo e ogni <strong> in flex-item separati, rompendo il flusso di lettura. Avvolto il testo di ogni voce in uno <span> aggiuntivo — solo numero e blocco testo restano flex-item.
  • Technical note del criterio 2.4.2 (divergenza cross-browser) troncata (fix): extractJson() (json-parser.ts) e la logica di parsing in DettaglioClient.tsx usavano una regex non-greedy che si fermava al primo fence invece dell'ultimo — quando `technicalNote` conteneva un blocco di codice d'esempio annidato (html...), il JSON risultava troncato/non parsabile e il contenuto oltre il blocco annidato andava perso. Sostituita con `lastIndexOf('')` (regex greedy scartata: SonarQube segnalava rischio di backtracking super-lineare). Aggiunto test di regressione.
  • Rimosso .home-fab in Home (fix): pulsante "Apri strumenti rapidi" senza alcun onClick da quando è stato introdotto (255ef55, 2026-06-03) — mai più toccato, nessuna spec lo documenta, rimasto invisibile finché il widget AI lo copriva (sopra). Un controllo visibile che non fa nulla al click è peggiore di uno assente, specialmente per screen reader.
  • "All" in inglese tra le option di una select popolata via AJAX: non un bug lato Valida (nessuna option hardcoded nel codice). Documentato invece un gap reale del checker WCAG 3.1.2 "Lingua delle parti" (checkLanguageOfParts, non scansiona option/select, non rileva parole inglesi in alfabeto latino) nella guida /help-valutazione (sezione Limitazioni) e in backlog — nessuna euristica introdotta per evitare falsi positivi affrettati su prestiti linguistici legittimi.

Verifica: bug su widget/dialog/formattazione verificati con Playwright sulla CSS compilata reale dell'app (nessun login necessario). 1229/1229 test verdi, tsc --noEmit pulito.


v1.92.1

Fix — canvas/pdfjs-dist, allowlist Bash, screenshot Gemini Vision su dialog reali

  • Rendering PDF→immagine falliva con "Image or Canvas expected" (fix): pdfjs-dist senza un CanvasFactory esplicito crea le canvas ausiliarie per gli inline image XObject con @napi-rs/canvas, incompatibile col pacchetto canvas usato per la canvas principale. Aggiunto un NodeCanvasFactory custom in render-pages.ts che usa canvas ovunque — confermato con test di integrazione reale su un PDF con immagini. Chiude canvas-pdfjs-rendering-pdf-immagine-rotto, bug preesistente già segnalato in v1.87.0.
  • Allowlist Bash di .claude/settings.local.json troppo permissiva (fix): i pattern con wildcard finale ("gitleaks version *", "python3 *") matchano l'intera stringa di comando dopo il prefisso, non solo gli argomenti — un comando concatenato con ;/&&/backtick sarebbe stato auto-approvato senza prompt. Ristretto gitleaks version * a match esatto, rimosso interamente python3 *.
  • Gemini Vision non vedeva mai un dialog reale aperto di default al load (fix): hideDistractingOverlays() (estratta da un blocco inline in renderer/index.ts) nascondeva qualunque overlay fixed/sticky a piena copertura schermo o con keyword modal|popup nell'attributo prima dello screenshot passato a Gemini Vision — colpendo anche un dialog semanticamente reale (role="dialog"/aria-modal="true"), non solo cookie banner cosmetici. Ora esclude gli elementi con semantica dialog, stessa definizione già usata da modal-reveal-agent.ts. Chiude gemini-vision-nasconde-modali-attivamente.

Verifica: 1224/1224 test verdi, tsc --noEmit pulito. Ciascun fix accompagnato dal proprio test di regressione (verificato fallire contro il codice pre-fix).


v1.92.0

Feature — gate CI per secret committati per errore + fix di robustezza state-reveal

  • Nuovo job secrets-scan in CI (.github/workflows/ci.yml): gitleaks via Docker (non l'Action ufficiale, licenza a pagamento su repo privati oltre la prova gratuita) sull'intera history del repo. .gitleaks-baseline.json sopprime i 32 finding già noti al momento dell'introduzione del gate (generato con --redact: nessun valore reale in chiaro, solo fingerprint/metadati) — un secret nuovo, su qualunque file/riga/commit non già in baseline, fa comunque fallire il job. Aggiunto SECURITY.md con policy di disclosure minima.
  • Scoperto durante la verifica: .claude/settings.json (tracciato) conteneva ancora un token Render e 2 token SonarQube live, incorporati in regole di permesso Bash salvate da sessioni precedenti. Rotazione rimandata su richiesta esplicita — tracciata come voce di backlog priorità alta invece di sparire silenziosamente nella baseline.
  • Fix H2 (Tecniche WCAG) forzava sempre 'pass' su 1.1.1 anche in pagine senza alcun link con immagine, mascherando <img> senza alt: ora ritorna 'not-applicable' in quel caso, coerente col pattern già usato da H24/H46/ARIA6_SVG.
  • Fix dropdown-reveal-agent (server): mancava il controllo di visibilità post-click già presente nei gemelli modal/accordion e nell'estensione Chrome — un dropdown che non si apriva davvero per un bug JS della pagina sotto test veniva comunque catturato come "rivelato".
  • Fix lazy-load (estensione + server): il marker transiente usato per il tracking scroll finiva nell'outerHTML catturato invece di essere rimosso prima; aggiunto anche un log esplicito quando si raggiunge il cap MAX_LAZY_SCROLLS senza aver trovato il fondo reale della pagina (stesso pattern già in uso per MAX_IBM_RESCANS).
  • Dependabot npm settimanale (.github/dependabot.yml) — chiude il gap di dependency-scanning (48 vulnerabilità npm audit note, 1 critical).

Verifica: 1218/1218 test verdi, tsc --noEmit pulito. Ciascun fix accompagnato dal proprio test di regressione (verificato fallire contro il codice pre-fix).


v1.91.1

Fix — dialog nativi non centrati, documentazione Piano 3

  • Modale nativa (showModal()) renderizzata in alto a sinistra invece che centrata (es. conferma eliminazione progetto in ProgettiClient.tsx): Tailwind v4 Preflight azzera margin su tutti gli elementi, incluso <dialog>, sovrascrivendo il margin: auto nativo dei browser che centra i dialog aperti con showModal(). Fix root-cause in src/app/globals.css (regola dialog {} esistente) — corregge in un colpo solo tutti i dialog nativi showModal()-based dell'app.
  • Documentazione aggiornata per Piano 3 (v1.91.0): la guida alla valutazione (/help-valutazione, sezioni Automatico e Limitazioni) e la pagina /estensione ora descrivono la copertura di stati dinamici disponibile anche dall'estensione Chrome (checkbox "Rivela stati dinamici").

Verifica: fix del dialog isolato e verificato via riproduzione live (Playwright + getComputedStyle) in una sessione precedente; nessun dialog dell'app imposta un margin in conflitto (verificato via grep). Solo modifiche CSS/documentazione — nessun impatto sulla logica applicativa.


v1.91.0

Feature — Copertura di stati dinamici, Piano 3: porting estensione Chrome

  • Completa gli 8 pattern dello spec originale su entrambe le architetture (Piano 1/2 li avevano portati solo lato pipeline web): i 7 RevealAgent (modale, accordion, tab, dropdown, carousel, wizard, lazy-load) + il dismiss cookie-banner sono ora portati anche nell'estensione Chrome "Valida", in un nuovo chrome-extension/state-reveal-probes.js — controlled-duplication port (stesso pattern collaudato di agentic-probes.js: ES5 vanilla, nessun import/export, iniettato in MAIN world), non un riuso diretto del codice server-side (Playwright-based, non eseguibile in un content script del browser reale dell'auditor).
  • Divergenza architetturale migliorativa: mentre la pipeline Playwright rigioca IBM Equal Access su un secondo page.goto() indipendente seguendo una recipe di interazione (da cui il follow-up noto state-reveal-selettori-non-univoci-replay-ibm, un selettore bare-tag può matchare l'elemento sbagliato in ri-navigazione), l'estensione rivaluta IBM sul posto, nello stesso DOM appena mutato, senza mai ri-navigare — il bug non può manifestarsi in questo porting per costruzione. Stesso principio "riferimento DOM live, mai un selettore ricostruito" già applicato a tab-reveal-agent.ts lato server, qui generalizzato a tutti e 7 i pattern.
  • Nuova checkbox opt-out "Rivela stati dinamici" in popup.html (checked di default, stessa convenzione della checkbox agentica esistente) — l'utente può disattivarla, ma la funzionalità gira di default; iniezione in MAIN world sia di ace.js (istanza dedicata, distinta da quella ISOLATED usata per l'audit statico) sia di state-reveal-probes.js.
  • POST /api/extension/submit esteso per valutare revealedStates[]: ogni stato inviato dall'estensione viene rivalutato con gli stessi motori della baseline (tecnica statica + motore statico + gli issue IBM già scansionati client-side + Claude se evalMode lo prevede), fuso con la baseline tramite collapseByWorstStatus/mergeAiResultsPreservingRevealedStates (estratte in un nuovo modulo leggero merge-revealed-state.ts, senza le dipendenze pesanti di technical-phase.ts) — un "Superato" da uno stato rivelato non maschera mai una violazione nota della baseline per lo stesso criterio.
  • Fix di visibilità post-click sul dropdown applicato SOLO in questo porting: a differenza del gemello server (dropdown-reveal-agent.ts, che non ha ancora questo controllo — gap tracciato separatamente), l'estensione verifica che il click abbia davvero reso visibile il menu prima di catturarlo come "rivelato".
  • Quattro bug reali trovati e corretti durante l'implementazione, presenti verbatim nel codice fornito dal piano stesso (non deviazioni dell'implementatore): (1) il carousel accettava <a> come trigger "avanti" senza alcuna guardia di navigazione, in violazione del vincolo "mai una seconda navigazione" — corretto con un controllo window.location.href prima/dopo ogni click, che preserva gli stati già catturati nei container precedenti; (2) il matching testo del wizard concatenava textContent||aria-label||value con OR prima del test regex, perdendo i pulsanti solo-icona con aria-label — corretto testando le tre fonti indipendentemente; (3) la marcatura "già visto" del lazy-load copriva solo l'elemento di frontiera, non i discendenti — contenuto annidato veniva ri-catturato come "nuovo" a ogni livello, corretto marcando l'intero sottoalbero; (4) nel submit route, evaluateHtml() e l'output non filtrato del motore tecniche applicati a frammenti HTML nudi producevano falsi "Non superato" garantiti per criteri page-level (lingua pagina, titolo, skip-link, orientamento, navigazione/identificazione coerente) che avrebbero mascherato un "Superato" corretto della baseline su quasi ogni submit reale — corretto allineando al comportamento già corretto di evaluateRevealedStates() lato pipeline web (rimosso evaluateHtml sui frammenti, aggiunto lo stesso filtro di esclusione page-level).
  • Verifica end-to-end live con estensione Chrome non pacchettizzata caricata in un browser reale via Playwright, dev server connesso ai servizi Docker in esecuzione, fixture con tutti i 7 pattern: revealedStatesCount corretto (7 con la checkbox attiva, 0 disattivata), nessuna navigazione né submit reale durante l'intero audit, persistenza confermata con query diretta al database (provenance.revealedState intatto in valutazione_results).

Verifica: 12 task via subagent-driven-development in un worktree isolato, ognuno con review dedicata + fix dove necessario (4 bug plan-mandated corretti su segnalazione, sempre con conferma esplicita prima del fix). 1204/1204 test verdi (oltre ai 2 fallimenti pre-esistenti non correlati) · tsc --noEmit pulito. Chiude lo spec [[2026-07-19-copertura-stati-dinamici-oltre-load-design]] a fatto — tutti gli 8 pattern coperti su entrambe le architetture (Piano 1+2 lato pipeline web, Piano 3 lato estensione Chrome). Piano: second-brain/superpowers/plans/2026-07-21-copertura-stati-dinamici-oltre-load-piano-3.md (topic copertura-stati-dinamici-oltre-load-piano-3).


v1.90.2

Fix — estensione Chrome: seconda pagina impossibile su URL invariata (wizard/SPA multi-step)

  • Un esperto segnalava che l'estensione non riusciva ad aggiungere una seconda pagina al round quando la URL era identica a una già inviata — caso reale: wizard di reset password a 6 step la cui URL resta invariata su tutti gli step. Causa: POST /api/extension/submit faceva match del componente solo su (roundId, url) — trovando la URL già presente, riusava sempre il primo componente fondendoci dentro i nuovi risultati, ignorando anche un nome distinto digitato nel campo "Nome componente" (mai usato per rinominare un esistente — no clobber).
  • Fix a basso attrito: nuovo campo opt-in saveAsNewPage nel payload di submit + nuova checkbox nel popup "Salva come pagina/stato distinto" — default invariato (zero click in più sul caso comune di ri-audit sulla stessa pagina), da attivare solo quando la stessa URL rappresenta uno stato logico diverso da tracciare separatamente.
  • Verificato che la piattaforma web non era affetta: l'aggiunta manuale pagina e la copia pagine tra round non fanno mai questo matching per URL.

Verifica: 2 nuovi test in route.test.ts (TDD), suite completa 1143/1145 verde (i 2 falliti sono il seed pianificazione pre-esistente, non correlato — confermato via git stash), tsc --noEmit pulito. Bump estensione 1.1.4 → 1.1.5.


v1.90.1

Documentazione — audit interno /a11y di help-valutazione

  • La pagina che spiega come Valida valuta l'accessibilità dei siti terzi presenta essa stessa violazioni WCAG 2.2 AA: audit su richiesta (skill /a11y) dei 22 file sorgente di src/app/help-valutazione/, in parte verificato live con Playwright contro valida-app.xyz. 1 CRITICA (il TOC non sposta mai il focus da tastiera dopo la navigazione), 4 HIGH (contrasto insufficiente su più badge, role="listbox" senza il comportamento tastiera del pattern, regioni scrollabili irraggiungibili da tastiera, smooth-scroll che ignora prefers-reduced-motion), 4 MEDIUM, 3 LOW.
  • Nessun fix applicato in questo rilascio: solo tracciamento. Dettaglio completo in second-brain/superpowers/specs/2026-07-21-help-valutazione-a11y-audit.md (status: ipotizzato), in attesa di pianificazione.

Verifica: nessuna modifica al codice applicativo in questo rilascio — solo documentazione e bump di versione.


v1.90.0

Feature — Copertura di stati dinamici, Piano 2: tab, dropdown, carousel, wizard, lazy-load, cookie banner

  • Completa la copertura degli 8 pattern di interazione previsti dallo spec originale (v1.88.0 ne copriva 2 di 8): il meccanismo state-reveal introdotto per modali e accordion viene esteso a tab non selezionati, dropdown/menu chiusi, carousel/slider, wizard multi-step e contenuto caricato al lazy-load/scroll, più un cookie banner accettato automaticamente una sola volta prima di qualunque cattura (non un RevealAgent come gli altri sette — sblocca l'intera pagina per tutti i motori, non solo per lo screenshot Gemini).
  • Estensione infrastrutturale per pattern sequenziali: carousel, wizard e lazy-load non si raggiungono con un solo click come modali/accordion/tab/dropdown, ma con una sequenza di passi (N click "avanti", N scroll) — RevealedState guadagna interactionPath (la sequenza cumulativa da rigiocare) e action: 'click' | 'scroll', e IBM Equal Access rigioca l'intero percorso sul proprio caricamento pagina indipendente, non solo l'ultimo passo.
  • Carousel e wizard non ripristinano la pagina al termine (a differenza di modali/accordion/tab/dropdown/lazy-load): sono stati sequenziali, non alternativi — tornare indietro vanificherebbe lo scopo di attraversarli. Per questo sono registrati per ultimi nell'ordine di attivazione degli agenti, cosicché ogni altro meccanismo di scoperta trovi ancora la pagina intatta.
  • Guardie di sicurezza sul wizard: un passo "avanti" non viene mai attivato dentro un form classificato finanziario/legale/di modifica dati sensibili (stessa classificazione già usata per il criterio 3.3.4), né se il testo del pulsante suggerisce invio/pagamento/conferma; se un click causa una navigazione reale della pagina, l'esplorazione si interrompe immediatamente senza catturare nulla dalla nuova pagina — mai un secondo caricamento indipendente.
  • Tre bug reali trovati e corretti durante l'implementazione: (1) l'agente accordion (già in produzione da v1.88.0) poteva intercettare anche i trigger dropdown per selettore troppo generico — corretto escludendo esplicitamente aria-haspopup; (2) il ripristino della selezione originale nei tab si basava su un selettore CSS ricostruito, che falliva silenziosamente su tab senza id o con id da neutralizzare — corretto catturando un riferimento diretto all'elemento; (3) contenuto lazy-load aggiunto direttamente come figlio diretto della pagina (non dentro un contenitore dedicato) veniva scartato silenziosamente dal rilevamento — corretto includendo la pagina stessa nel confronto.

Verifica: 12 task via subagent-driven-development in un worktree isolato, ognuno con review dedicata + fix dove necessario, più review finale whole-branch (4 correzioni: guardia wizard resa "fail-closed" su errore invece di procedere per default, rimosso il tag <a> dai candidati del cookie banner per evitare una navigazione reale silenziosa su un falso positivo, due precisazioni di documentazione). Tre limiti noti tracciati come backlog dedicato per un giro successivo, non bloccanti: un selettore di fallback non sempre univoco nel replay IBM (eredità di v1.88.0, non solo di questo rilascio), un controllo di visibilità mancante sul dropdown, un test di regressione che non copre lo specifico caso corretto sui tab. Suite 133/133 file, 1143/1143 test verdi su main dopo il merge · tsc --noEmit pulito. Piano: second-brain/superpowers/plans/2026-07-20-copertura-stati-dinamici-oltre-load-piano-2.md (topic copertura-stati-dinamici-oltre-load-piano-2).


v1.89.0

Feature — Verifica round-trip dei suggerimenti di remediation (sinergia con il golden dataset)

  • Nessuna garanzia che un suggerimento di correzione risolva davvero la violazione secondo i motori di Valida (feature): la libreria curata di remediation (23 correzioni, riferimenti a tecniche W3C) offriva codeExamples.good corretti secondo la documentazione ufficiale, ma nessuno verificava se i motori automatici li riconoscessero davvero come "Superato". Nuovo modulo verifyLibraryRoundtrip() — riusa runEngines() del golden dataset senza duplicarne la logica — esegue ogni esempio conforme sui due motori statici e lo considera verificato se almeno uno dei due lo riconosce Superato: non serve l'unanimità, i due motori hanno coperture complementari.
  • Esposto nella Scheda di affidabilità esistente: nuovo campo remediationRoundtrip in GET /api/knowledge/reliability, nuova sezione nel pannello Knowledge Base → Insights con badge Verificato/Non verificato/N-D per ogni voce — stesso endpoint, stesso pannello, nessuna nuova route.
  • Scope v1: solo criteri verificabili staticamente. I criteri che richiedono stili calcolati (contrasto 1.4.3/1.4.11, focus non ostruito 2.4.11, dimensione target 2.5.8, focus visibile 2.4.7) sono dichiarati esplicitamente non verificabili con questo motore (badge N/D), non marcati come suggerimenti errati.
  • Due bug reali scoperti nei motori stessi, non nella libreria di remediation: la tecnica H2 di Tecniche WCAG ("Link con testo e immagine") ritorna sempre "pass" anche quando la pagina non contiene alcun link con immagine — combinato con la tecnica di fallimento F65 ("alt mancante") dichiarata ma mai implementata, un <img> senza alt viene marcato erroneamente "Superato" dal solo motore Tecniche WCAG per il criterio 1.1.1 (il motore statico principale lo rileva correttamente). Non corretto in questo rilascio — tracciato come voce di backlog dedicata, priorità alta.

Verifica: 4 task via subagent-driven-development (1 con round di fix sul design — ripristinato il controllo su entrambi i motori dopo un tentativo di scorciatoia su un solo motore — 1 con node_modules ritracciato per errore, corretto in review) + fix da review finale whole-branch (2.4.7 spostato tra i criteri non verificabili staticamente). Suite 127/127 file, 1118/1118 test verdi · tsc --noEmit pulito. Piano: second-brain/superpowers/plans/2026-07-20-remediation-roundtrip-verification.md (topic remediation-roundtrip-verification).


v1.88.1

Fix — 4 bug da QA live su un round di valutazione

  • Titolo pagina troncato a metà parola nella nota del criterio 2.4.2 (fix): buildTechniqueSummary() tagliava ogni messaggio di tecnica a 80 caratteri senza alcun indicatore di troncamento — per i messaggi "Superato" che riportano il titolo pagina (H25_Q) era l'unico punto in cui il testo compariva (nessuna passing evidence salvata per quel caso), quindi il taglio produceva una perdita reale di informazione. Cap portato a 200 caratteri, con quando il testo viene effettivamente troncato.
  • Criteri EN 301549 esclusivi (4.2.x) sempre "N/D", su tutti i progetti, non solo nel round segnalato (fix): le righe erano seminate correttamente nel DB e la vista Wizard le includeva già, ma principleOrder nella vista Lista — quella di default per tutti tranne i delegate — elencava solo i 4 principi WCAG POUR; i criteri con principio EN301549 finivano in un gruppo calcolato ma mai iterato in fase di render, quindi mai visibili né editabili in nessun progetto. Aggiunta la sezione dedicata "EN 301 549 — Criteri esclusivi" alla vista Lista, verificata in browser con form completo ed editabile.
  • Il validator W3C riportava quasi sempre "riga 0" per il criterio 4.1.1 (fix): il Nu Html Checker valorizza firstLine/firstColumn solo per i messaggi che coprono un range multi-riga; i messaggi puntuali (la maggioranza) hanno solo lastLine/lastColumn, e il codice ripiegava direttamente su 0 quando firstLine mancava. Ora il fallback usa lastLine/lastColumn prima di 0.
  • Enumerazione "(1) ... (2) ... (3) ..." nelle note (es. criterio 2.1.1) non riconosciuta come lista (fix): il parser delle note riconosceva solo lo stile "1) ..." (parentesi finale), non "(1) ..." (parentesi completa) — pattern usato da note generate da Claude quando spiega quali evidenze mancano per una valutazione definitiva. Aggiunto un riconoscimento dedicato, attivo solo su una sequenza stretta 1,2,3… per non scambiare riferimenti come "(vedi 2.4.3)" per un elenco.

Verifica: suite 126/126 file, 1107/1107 test verdi (test-first su tutti e 4 i fix) · tsc --noEmit pulito · next build pulito · fix EN 301549 verificato anche live in browser (Playwright, dopo rebuild immagine Docker).


v1.88.0

Feature — Copertura di stati dinamici oltre il caricamento iniziale (modali, accordion)

  • Ogni motore valutava la pagina solo così com'era al primo caricamento (feature): un contenuto rivelato solo dopo un'interazione (una modale che si apre al click, un pannello accordion chiuso) non veniva mai raggiunto — una violazione reale al suo interno risultava "Superato" per assenza di verifica, non perché davvero conforme. Nato rispondendo a un dubbio degli esperti ("i risultati includono anche le modali normalmente nascoste al caricamento?"), poi generalizzato: l'indagine ha trovato lo stesso gap strutturale su 7 pattern di interazione oltre le modali (tab, accordion, dropdown, carousel, wizard, lazy-load, cookie banner).
  • Nuovo meccanismo state-reveal: durante il rendering Playwright, la pagina viene esplorata per due pattern pilota — modali nascoste al caricamento (role="dialog"/aria-modal="true") e pannelli accordion chiusi (aria-expanded="false"). Ogni trigger trovato viene attivato nella stessa sessione di pagina già usata per il rendering (mai un secondo fetch/goto indipendente), il contenuto rivelato viene valutato da IBM Equal Access (rigioca il click prima dello scan) e dal motore Tecniche WCAG (modalità frammento, con esclusione dei criteri page-level — lingua pagina, titolo pagina, bypass blocks, orientamento, coerenza cross-pagina — che genererebbero falsi positivi su un sottoalbero isolato), poi la pagina viene ripristinata prima di proseguire. Ogni esito riporta in provenance.revealedState quale trigger l'ha rivelato (estensione del campo provenance jsonb già esistente, nessuna migration).
  • Limiti noti e accettati in questa prima iterazione: altri 6 pattern di interazione (tab, dropdown/menu, carousel, wizard multi-step, lazy-load/scroll, cookie banner) restano fuori scope, in roadmap per un piano successivo. L'analisi Claude AI e Gemini Vision sul contenuto rivelato funziona solo nel percorso di valutazione sincrono (/api/evaluate, dev/fallback) — nella pipeline asincrona di produzione (Inngest) il contenuto rivelato riceve oggi solo IBM + Tecniche WCAG, non ancora l'analisi AI, perché quella pipeline separa i tre step in file diversi (ai-phase.ts, visual-phase.ts) non ancora collegati a questo meccanismo. Quando RENDERER_URL è impostato (rendering delegato al microservizio remoto, usato in Docker/produzione), lo state-reveal non gira sul percorso remoto.
  • Tre bug reali trovati e corretti durante l'implementazione (nessuno presente nel design originale): (1) Claude poteva scattare durante lo step tecnico asincrono di Inngest, pensato esplicitamente senza AI — corretto con gating esplicito su fase ed evalMode; (2) un bug di merge silenzioso poteva far vincere un esito "Superato" proveniente da uno stato rivelato su un "Non superato" di baseline per lo stesso criterio, mascherando esattamente il tipo di falso negativo che questa feature esiste per eliminare — corretto con un merge che preserva sempre lo stato peggiore tra quelli in conflitto; (3) l'agente di rilevamento modali poteva aprire pannelli accordion (selettore trigger troppo ampio) e abbandonarli aperti senza ripristino, contaminando la cattura della pagina di base — corretto verificando la semantica del target prima del click, non dopo.

Verifica: 11 task via subagent-driven-development, ognuno con review dedicata + fix dove necessario, più review finale whole-branch (2 problemi Critical/Important trovati e risolti sulle interazioni tra task). Suite 124/124 file, 1100/1100 test verdi su main dopo il merge · tsc pulito.


v1.87.5

Fix — Causa reale del crash Firefox nella matrice multi-browser: $HOME inesistente per l'utente non-root

  • Il rendering Firefox andava in timeout dopo 180s su ogni round multi-browser, in ogni viewport (fix): la visibilità aggiunta in 1.87.4 ha mostrato per la prima volta l'errore reale — browserType.launch: Timeout 180000ms exceeded, con stderr pieno di unable to create directory '/home/nextjs/.cache/dconf': Permission denied e Unable to revert mtime: .../firefox/fonts. Causa: nel Dockerfile l'utente nextjs viene creato con useradd --system senza --create-home/home/nextjs non esiste mai sul filesystem pur essendo il valore di $HOME nella passwd entry, e /home è root:root mode 755, quindi nextjs non può crearla nemmeno al volo. Chromium e WebKit tollerano un $HOME non scrivibile; Firefox scrive cache GTK/dconf e stato di profilo sotto $HOME all'avvio e resta bloccato a ritentare finché Playwright non va in timeout — per questo Firefox risultava assente da ogni scan (v1.87.4) mentre Chromium/WebKit funzionavano regolarmente.
  • Fix: aggiunto --create-home alla useradd nel Dockerfile. Riprodotto e verificato isolatamente: stesso hang esatto ricreando l'immagine base Playwright + useradd identico senza --create-home (identico stderr, identico path /ms-playwright/firefox-*/firefox); con --create-home il lancio riesce in ~250ms invece di andare in timeout.

Verifica: rebuild locale immagine runner completata · lancio Firefox isolato (repro Docker minimale) passa prima/dopo il fix.


v1.87.4

Fix — Divergenza cross-browser: nota grezza duplicata nel pannello Note + Firefox mai visibile nella matrice multi-browser

  • Il blocco [Analisi Divergenza Cross-Browser] torna a comparire nel pannello "Note" generico, JSON grezzo compreso (fix): il 26/6 (b04571b) formatNotes() era stata corretta per non mostrare più questo blocco nel pannello "Note" — resta comunque visibile, formattato, nel pannello dedicato "AI Divergence Expert". Due giorni dopo (027de78) quella correzione era stata revertita per errore insieme a un fix di tipografia non collegato ("matching the pre-change behaviour"), senza che nessun test se ne accorgesse — formatNotes() non aveva copertura. Ripristinato lo strip e aggiunto un test di regressione che riproduce esattamente il caso reale (fallback quando il parsing JSON di Claude fallisce): un bullet per ogni riga del JSON grezzo nel pannello Note, duplicato rispetto al pannello già stilizzato sotto.
  • Firefox risultava assente da ogni scan multi-browser/responsive in produzione, in silenzio, da almeno un mese (fix): verificato sul Postgres di produzione che browser_results non contiene mai la chiave firefox in nessun round campionato dal 25/6 a oggi, nonostante sia configurato. Causa: renderPageMulti() usa Promise.allSettled e scarta le combinazioni browser/viewport il cui rendering fallisce, senza loggare nulla (commento nel codice: "silently omitted") — riducendo silenziosamente la matrice cross-browser a solo Chromium+WebKit. renderPageMulti() (sia nel percorso inline sia nel microservizio renderer-service) ora ritorna anche l'elenco dei fallimenti con il motivo del rigetto; technical-phase.ts li registra come warning in execution_logs. Non è ancora una correzione della causa ultima del crash di Firefox — finché il fallimento era invisibile non c'era un errore reale da diagnosticare; questa modifica serve a farlo emergere al prossimo round multi-browser, per poi intervenire sulla causa vera.

Verifica: tsc pulito (app + renderer-service) · suite 1052/1052 · lint pulito sui file toccati.


v1.87.3

Fix — Estensione Chrome: 413 persistente su pagine molto ripetitive + Passing Evidence mai salvata

  • Il filtro dei PASS (v1.87.2) non bastava sulle pagine con moltissime violazioni reali (fix): su un listato lunghissimo (~13.000 risultati IBM ACE, quasi tutti violazioni vere, non PASS) l'estensione continuava a sfondare i 5 MB — il solo array ibmResults pesava 10+ MB. Causa: la stessa regola può fallire su migliaia di elementi quasi identici (es. ogni card di un catalogo), e inviarne ogni istanza è puro spreco. popup.js ora raggruppa i risultati per regola+esito e ne invia al massimo 15 campioni per gruppo, riportando il conteggio vero a parte (ibmRuleCounts) così stato, priorità e note dei criteri restano accurati (non più basati sul campione troncato). Aggiunto anche un log diagnostico in Console che scompone il payload per byte, per non dover reinterpretare a mano il tab Payload di DevTools a ogni pagina che fallisce. Bump estensione 1.1.2 → 1.1.4.
  • Le prove di conformità (Passing Evidence) non venivano mai salvate per i criteri "Superato" via estensione (fix): il motore statico calcola l'evidenza per ogni criterio superato (elementi verificati, metodo), già persistita correttamente dalla pipeline web — ma il percorso di salvataggio dell'estensione non includeva affatto quella colonna nella query di scrittura, scartando silenziosamente un dato già calcolato in memoria. Riproducibile su qualunque criterio "Superato" via estensione (osservato su 1.3.2 e 1.3.5), non specifico a un criterio. I dati già salvati prima di questo fix restano senza evidenza: serve rifare l'audit da estensione sulla pagina interessata per ripopolarli.
  • Rinominata anche la cartella wrapper dello ZIP scaricabile (a11y-snapshot/valida-extension/, file valida-extension.zip), residuo del brand precedente.

Verifica: tsc pulito · suite 1045/1045.


v1.87.2

Fix — Estensione Chrome: 413 "Payload troppo grande" su pagine PA voluminose

  • popup.js inviava anche i risultati PASS di IBM ACE (fix): su pagine ricche di elementi (portali PA media-rich) l'estensione andava in 413 nonostante il limite di 5 MB fosse stato dimensionato apposta per farle entrare comodamente (v1.86 §9g). Causa: runPageAudit() inviava l'intero report ace.js, incluse le entry PASS — scartate comunque server-side da mapIbmResults (stesso pattern del motore IBM lato server). Sulle pagine con molti elementi i PASS sono la stragrande maggioranza del report: puro peso morto nel payload.
  • Fix: i PASS vengono ora filtrati client-side prima dell'invio; il conteggio originale è inviato a parte (ibmResultsTotal) così il messaggio "N regole verificate" resta accurato. Il limite dei 5 MB non è stato toccato — il bug era nel payload sprecato, non nella soglia.
  • Bump versione estensione manifest.json 1.1.1 → 1.1.2.

Verifica: tsc pulito · suite 1041/1041.


v1.87.1

Fix — Estensione Chrome: icone disallineate dal brand e ZIP di download incompleto

  • Icone ferme a un rebrand precedente (fix): l'icona della toolbar (manifest.jsonicons/icon16/48/128.png) e il logo dell'header del popup (valida-icon.svg) erano rimasti al design del 2026-05-10, mai aggiornati dopo l'ultimo rebrand del 2026-06-20 (unico usato dal resto del prodotto, public/favicon.svg). generate-icons.js disegnava inoltre una "A" placeholder scollegata da qualunque SVG reale — ogni futura rigenerazione avrebbe ripetuto la stessa deriva. Ora valida-icon.svg è allineato al design ufficiale e generate-icons.js rasterizza da quel file via sharp; rimosso icons/icon.svg, un terzo design orfano del 2026-03-24 mai referenziato.
  • GET /api/extension/download distribuiva un pacchetto incompleto (fix): la whitelist di file inclusi nello ZIP non conteneva valida-icon.svg (icona rotta nell'header del popup per chi installa l'estensione via download) né rendered-context-collectors.js e agentic-probes.js (iniettati da popup.js via chrome.scripting.executeScript, quindi funzionalmente assenti dal pacchetto scaricato). Aggiunti tutti e tre, con test di regressione sul contenuto dello ZIP.
  • Bump versione estensione manifest.json 1.1.0 → 1.1.1.

Verifica: tsc pulito · suite 1036/1036.


v1.87.0

PDF — arricchimento vision delle proposte di remediation (§9-ter.3.1)

  • Analisi visiva Gemini per gli alt text (feat): POST /api/pdf-remediation ora renderizza fino a 10 pagine del PDF (PDF_VISION_MAX_PAGES) e le invia a Gemini Vision insieme al testo estratto, per correggere gli alt text proposti "alla cieca" da Claude con testi basati sul contenuto visivo reale delle figure. Claude (proposte testuali di metadati/heading/lingua) resta invariato — riusa il pattern già collaudato in reading-order/route.ts e nel motore web gemini-engine.
  • Rilievi visivi informativi (feat): contrasto insufficiente e tabelle con struttura complessa rilevati visivamente vengono mostrati come note in sola lettura nello strumento di remediation (visualFindings) — non applicabili automaticamente via pikepdf, richiedono intervento manuale sul documento sorgente.
  • Degradazione automatica (feat): se la chiave Gemini non è configurata o la chiamata vision fallisce, il flusso prosegue esattamente come prima (solo proposte Claude testuali) — nessun impatto sul comportamento esistente.

Nota operativa: la verifica end-to-end reale è risultata bloccata da un bug preesistente non introdotto da questo lavoro — il rendering PDF→immagine (canvas+pdfjs-dist, usato anche dall'endpoint reading-order già in produzione) fallisce con "Image or Canvas expected" in questo ambiente, riprodotto identico su main pre-esistente. Da investigare separatamente.

Verifica: tsc pulito · suite 1031/1031 · spec e piano in docs/superpowers/{specs,plans}/2026-07-18-vision-pdf-remediation-*.


v1.86.0

Estensione Chrome — chiavi API per-valutatore (§9-quater P7)

  • Chiavi personali per-valutatore (feat): la chiave API statica condivisa dell'estensione Chrome (app_settings.extension_api_key) è sostituita da chiavi personali hashate SHA-256 (nuova tabella extension_api_keys), una attiva per utente — rigenerare revoca automaticamente la precedente. Self-service da /estensione ("La mia chiave API"), pannello admin separato per elenco/revoca di tutti gli utenti (/api/extension-keys/admin*, non un unico endpoint con branching di ruolo, per sicurezza strutturale). validateExtensionApiKey passa da confronto a tempo costante su un segreto condiviso a lookup per hash.
  • Attribuzione multi-valutatore (feat): components.submitted_by viene popolato ad ogni submit da estensione con l'utente proprietario della chiave usata, aggiornato a ogni invio successivo (non è un campo no-clobber) — abilita l'attribuzione dei componenti negli audit condotti da più valutatori.
  • Cutover (fix): rimossa la UI della vecchia chiave condivisa da Impostazioni → Generale; nessuna migrazione dati necessaria, chi ha ancora la vecchia chiave configurata deve generarne una personale da /estensione.
  • Accessibilità: la nuova UI (self-service + tabella admin) è stata verificata con la skill /a11y — corretti focus management dopo generazione/revoca chiave, annunci screen reader per copia riuscita, stato di elaborazione (aria-busy) sui pulsanti.

Verifica: tsc pulito · suite 1003/1003 · next build ok. Spec e piano in docs/superpowers/{specs,plans}/2026-07-16-estensione-chiavi-api-per-valutatore-*.


v1.85.0

Attendibilità — confidence e provenienza per esito (§3.1)

  • Confidence e provenienza persistite (feat): nuovi campi confidence (0–1) e provenance (JSON: motori coinvolti, arbitrato, automatico) su valutazione_results, calcolati in applyEvaluations dalla policy di merge già esistente (stessa formula della confidence KB: 0.5 + 0.1 × motori concordi, cap 1.0; arbitrato → 0.4; override manuale → 1.0). Badge fascia/percentuale in DettaglioClient.tsx (Alta/Media/Bassa fiducia, Arbitrato, Verificato manualmente), fallback identico al comportamento precedente per le righe storiche pre-migrazione — nessuna migrazione distruttiva, nessun backfill.
  • Fix di un gap reale: l'arbitraggio Claude/Gemini non girava mai in produzione (fix): la funzione arbitrate() (Claude vs Gemini → "Da verificare" quando in disaccordo) veniva eseguita solo nel percorso sincrono di sviluppo/fallback; la pipeline Inngest asincrona reale (usata in produzione) non confrontava mai i due modelli — ogni fase sovrascriveva la precedente in sequenza, senza mai produrre il badge "arbitrato" introdotto in v1.84.0. visual-phase.ts ora legge lo stato già persistito prima di applicare i fallimenti di Gemini Vision e arbitra il conflitto (arbitrateAgainstPersisted()), colmando il gap nella direzione "era Superato, Gemini dice fallito".
  • Coda di triage (feat): nuova tab "Triage" nel round di valutazione (GET /api/results/triage) — elenco piatto pagina×criterio ordinato per confidence crescente, per portare in cima gli esiti meno affidabili o arbitrati e prioritizzare la revisione esperta.

Trovati e corretti in corso d'opera: un helper SQL esportato per errore da un file route.ts di Next.js rompeva silenziosamente npm run build (non intercettato da tsc/vitest, solo dalla build stessa) — spostato nel modulo di persistenza (persistence.ts); il badge dell'override manuale mostrava "Alta fiducia (100%)" invece di "Verificato manualmente".

Residuo aperto (non un difetto, fedele alla formula scelta): nella pipeline asincrona ogni fase calcola la confidence guardando solo i motori della propria chiamata, quindi un criterio toccato dall'IA può fermarsi a una confidence più bassa di quanto meriterebbe anche quando i motori tecnici erano concordi, mentre il percorso sincrono di sviluppo (lista motori fusa) converge più vicino a 1.0 per lo stesso criterio — loggato come voce "Ipotizzato" confidence-accumulo-cross-fase per un giro successivo.

Verifica: tsc pulito · suite 970/970 · next build ok. Spec e piano in docs/superpowers/{specs,plans}/2026-07-16-confidence-provenance-per-esito-*.


v1.84.1

Fix — valutazione PDF falliva per documenti su MinIO

  • handlePdfEvaluation non seguiva la migrazione a MinIO (fix): dopo la migrazione dello storage PDF a MinIO (v1.x, prefix pdfs/), src/lib/evaluation-pipeline/pdf-evaluation.ts era l'unico punto rimasto a leggere component.filePath con fs.existsSync/fs.readFileSync — un controllo sul filesystem locale che fallisce sempre per una chiave MinIO. Ogni valutazione PDF innescata dalla pipeline Inngest per un documento caricato dopo la migrazione terminava con Error: File PDF non trovato: pdfs/... e falliva senza retry (404 è tra i codici non ritentabili), segnalato in produzione da Sentry (JAVASCRIPT-NEXTJS-3). Sostituito con resolvePdfBuffer() (già usato da tutte le route pdf-remediation/), che gestisce sia le chiavi MinIO sia i path legacy. Nuovi test in pdf-evaluation.test.ts coprono sia il caso di risoluzione riuscita sia il 404 quando la chiave non risolve e non c'è un url di fallback.

Verifica: tsc pulito · suite 944/944 · eslint 0 errori.


v1.84.0

Onda quick-win — confidence badge, igiene KB, fix WCAG/contrasto (§16)

  • Badge provenance: distingui esiti arbitrati (feat): detectArbitration() in provenance.ts legge il marker [Arbitraggio AI già scritto in notes quando Claude e Gemini divergono (technical-phase.ts) ma finora mai letto da nessuna UI. In DettaglioClient.tsx il badge diventa badge--warning con label "arbitrato" (invece del conteggio motori) e tooltip esteso quando l'esito è stato arbitrato — nessuna migrazione DB, solo lettura di dati già persistiti (engine_sources, notes).
  • Fix falso positivo 1.3.1 in wcag-mapper.ts (fix): il criterio aggregava senza filtro messaggio gli errori di 6 checker condivisi con altri criteri. Un link "salta al contenuto" mancante (competenza di 2.4.1) e gli errori del checker aria (competenza di 4.1.2, già catturati indipendentemente da quel criterio) contaminavano erroneamente 1.3.1. Audit completo dei 6 checker, filtro esteso allo stesso pattern già usato da 2.4.1, fixture golden dataset (2.4.1-no-skip-link) estesa con un secondo ground truth per bloccare la regressione. Scoperto dal golden dataset (§3.2), mai corretto prima.
  • Cron di decadimento temporale KB (feat): applyTimeDecay() (half-life 90/180gg, soft-delete sotto 0.3 di confidence) era completamente implementata ma senza alcun chiamante — il decadimento non avveniva mai in produzione. Nuova funzione Inngest kbTimeDecay, trigger { cron: '0 3 * * *' } (primo cron del progetto, gli altri 3 job esistenti sono event-triggered), registrata in src/app/api/inngest/route.ts.
  • Fix contrasto text-warm-500/600 (fix): token usati su testo in 81 file sotto src/; warm-500 era 2.82:1 su bianco (falliva anche la soglia AA-large di 3:1), warm-600 4.18:1 (falliva AA-normale, 4.5:1). Scuriti centralmente a #7E7154/#7A7162 (4.80:1/4.81:1 su bianco, 4.55:1/4.57:1 su ivory) — effetto noto e accettato: i due token diventano visivamente quasi indistinguibili tra loro. Trovato dalla skill /a11y durante la sessione golden-dataset del 14/07, mai corretto prima.
  • Disambigua title /admin/knowledge-base (fix): dichiarava title: 'Knowledge Base Avanzata' ma la pagina renderizza <h1>Chatbot</h1> — facilmente confuso con la vera Knowledge Base esperti (/kb). Rinominato a "Chatbot — Fonti documentali".

Copertura: chiude 5 voci "Ipotizzato" indipendenti di docs/stato-evolutive.md, nessuna migrazione DB, nessuna dipendenza tra i task. Skill /a11y eseguita su DettaglioClient.tsx (nuovo stato badge) e sui token di contrasto aggiornati — nessun problema nuovo trovato (contrasto badge ~5.97:1, testo warm ≥4.80:1). Smoke reale in browser del badge e verifica del cron nella Inngest Dev UI (:8288) restano un passo manuale residuo — stack Docker non attivo durante l'implementazione.

Verifica: tsc pulito · suite 914/914 · eslint 0 errori (67 warning pre-esistenti, invariati) · next build ok. Spec e piano in docs/superpowers/{specs,plans}/2026-07-14-quickwin-confidence-kb-a11y-*.

v1.83.0

Attendibilità — golden dataset e precision/recall per motore (§3.2)

  • Golden dataset di verità nota (feat): nuovo modulo src/lib/golden-dataset/ — 24 fixture HTML su 12 criteri pilota (1.1.1, 1.2.2, 1.3.1, 1.3.5, 2.4.1, 2.4.2, 2.4.4, 2.4.6, 3.1.1, 3.3.2, 4.1.1, 4.1.2), ciascuno con una pagina in violazione e una gemella conforme, verità nota in sidecar .expected.json accanto a ogni HTML (scartato un manifest TS unico, per non ricreare un file monstre — §4.1). loader.ts valida l'integrità dell'accoppiamento html/json e fallisce esplicitamente su file orfani.
  • Motore di calcolo precision/recall/F1 (feat): runner.ts esegue evaluateHtml() (motore statico) e runTechniqueEngine() in modalità static (Tecniche WCAG) su ogni fixture; metrics.ts classifica ogni esito come TP/FP/FN/TN (positivo = Non superato, l'evento che conta per uno strumento di audit) e aggrega a tre livelli — per (motore, criterio), per motore, e complessivo. computeReliabilityReport() (index.ts) è la funzione pubblica unica, usata sia dal test CI sia dalla route API, nessuna duplicazione di logica.
  • Endpoint GET /api/knowledge/reliability (feat): stesso pattern di autenticazione di /api/knowledge (admin/auditor). Calcolo dal vivo a ogni richiesta, nessuna tabella DB né cache — i due motori in scope sono deterministici e girano in millisecondi su 24 fixture.
  • Pannello "Scheda di affidabilità" in /kb/insights (feat): nuovo ReliabilityPanel.tsx, tabella criterio × motore con badge F1 colorato (verde ≥90%, giallo ≥70%, rosso sotto) sempre accompagnato dal valore numerico in testo — mai il colore come unico segnale (WCAG 1.4.1). Skill /a11y eseguita sul pannello prima del merge.
  • Test CI non bloccante (feat): reliability.test.ts verifica l'integrità del dataset, l'assenza di NaN nelle metriche, stampa una tabella leggibile in console e asserisce solo un floor aggregato permissivo (F1 medio ≥ 0.4) — gate informativo, non blocca la build per la regressione di un singolo criterio mentre il dataset è ancora piccolo.
  • Fix Critical da review finale whole-branch (fix): l'endpoint legge le fixture da disco a runtime (readdirSync/readFileSync, non import) — il file tracing di Next.js per l'output standalone (quello usato nell'immagine Docker) non le vede automaticamente. Senza outputFileTracingIncludes in next.config.ts, la cartella src/lib/golden-dataset/fixtures/ restava fuori dal build di produzione e l'endpoint rispondeva 500 solo in Docker/Render, mai in locale (npm run dev) — il tipo di regressione più difficile da notare prima del rilascio.

Copertura v1, esplicitamente dichiarata: solo i due motori statici e deterministici (motore statico Cheerio, Tecniche WCAG in modalità static). IBM Equal Access (richiede un URL live raggiungibile), Claude AI (costo/chiave per chiamata) e il motore agentico (richiede un contesto Playwright) restano fuori scope — stesso harness, iterazioni successive. Persistenza storica delle metriche e gate CI bloccante anch'essi rimandati.

Verifica: tsc pulito · suite 904/904 (+39 rispetto al baseline pre-feature) · eslint 0 errori (67 warning pre-esistenti, invariati) · next build ok. 8 task con review dedicata + review finale whole-branch (1 Critical trovato e corretto, il fix outputFileTracingIncludes sopra). Spec e piano in docs/superpowers/{specs,plans}/2026-07-13-golden-dataset-precision-recall-*.

Corretto

  • Estensione Chrome — pagina /estensione disallineata da Onda 3: la pagina era ferma a "Valida v1.0" (solo IBM Equal Access), senza menzionare il motore statico, il validatore W3C, i 7 agenti comportamentali né il campo "Nome componente" introdotti dalle release precedenti. Aggiornata a v1.1 con i passaggi e i permessi correnti, e un link diretto alla sezione limitazioni della guida.
  • Warning CJS di Vite nei test (chore): vitest@2.1.9 innesca un require('vite') interno che ri-triggera l'auto-warning di deprecazione di Vite su se stesso a ogni npm test, indipendentemente dal codice del progetto (nessun vitest.config.ts in questo repo). Silenziato con VITE_CJS_IGNORE_WARNING=1 sugli script test/test:watch — il flag ufficiale documentato da Vite per questo scenario, non una soppressione ad hoc. La causa radice è risolvibile solo con un upgrade major di vitest (attuale 2.1.9 vs stabile 4.1.10), rimandato: il problema è puramente cosmetico nell'output.
  • ESLint scansionava i worktree manuali (fix): .worktrees/** (il percorso usato dal fallback manuale di superpowers:using-git-worktrees) non era escluso dalla configurazione ESLint come già lo era .claude/** — un worktree duplica l'intero albero incluso il proprio node_modules, producendo 31812 falsi problemi invece di 0 errori reali.
v1.82.0

Estensione Chrome "Valida" — motore agentico lotto 1 + completamento parità motori (Onda 3)

Con questa release la valutazione avviata dall'estensione copre 7 dei 19 agenti comportamentali e tutti i motori server-side che la pipeline web esegue senza dipendere da un browser Playwright proprio (statico, W3C, effort). Il gap residuo rispetto alla piattaforma web si restringe ora al motore agentico lotto 2 (~6 agenti ancora portabili) e a un piccolo insieme di capacità con limite strutturale del browser (nessun engineering lo colma).

Gamba A — Motore agentico, lotto 1 (form/auth, 7 agenti)

  • Sonde comportamentali in content-script (feat): nuovo chrome-extension/agentic-probes.js, un modulo-funzione per agente riscritto in JS classico (nessuna API Playwright) per i 7 criteri del cluster form/autenticazione — 3.3.3 (form-validation, dati invalidi tipizzati + qualità del messaggio d'errore), 3.3.1 (error-identification, stessa sonda del form-validation con lente diversa), 3.3.4 (error-prevention, classificazione form critici legali/finanziari/modifica-dati + meccanismi G98/G99/G168), 3.3.7 (redundant-entry, campi duplicati + copertura autocomplete/H100), 3.3.8 (accessible-auth, classificazione CAPTCHA + probe paste-block + alternative cognitive-free), 2.2.1 (timing-adjustable, meta-refresh F40/F41 + probe countdown a 2,5s), 4.1.2 (aria-state, toggle con ripristino al secondo click). Le evidenze grezze (RawEvidence[], stesso formato del motore web) sono interpretate dopo il submit dalla nuova funzione Inngest extensionAgenticInterpret (src/inngest/functions/extensionAgenticInterpret.ts, evento extension/agentic-interpret), che riusa invariato interpretWithClaude — nessuna duplicazione di logica AI, solo delle sonde — e applica gli esiti con engine source agentic-extension rispettando la skip-logic anti-overwrite esistente. Le evidenze grezze sono persistite nella nuova tabella extension_agentic_evidence (id/audit_round_id/component_id/agent_id/criterion_code/evidence jsonb/status pending→interpreted|failed/created_at/interpreted_at) — l'evento porta solo { roundId, componentId }, la funzione legge le righe pending, così i retry Inngest restano idempotenti senza limiti di payload sull'evento.
  • Politica "mai submit reale" (decisione di sicurezza vincolante): le sonde girano nella sessione autenticata reale dell'utente (non in una sessione anonima Playwright) — un submit vero potrebbe creare record, protocollare pratiche o inviare email su sistemi di produzione dell'ente. Interceptor submit in capture-phase sul document, installato prima di ogni sonda e rimosso in finally (preventDefault() + stopPropagation()); le sonde usano solo reportValidity()/requestSubmit(), mai form.submit(). Un fix Critical emerso in review (task 8, commit 0e603dc) ha chiuso un bypass reale: un handler change della pagina che chiamava form.submit() imperativamente scavalcava l'interceptor (che intercetta solo l'evento submit, non la chiamata al metodo) — la sonda ora neutralizza temporaneamente HTMLFormElement.prototype.submit durante la finestra di sonda e lo ripristina in finally, riprodotto con test comportamentale RED→GREEN prima del fix.
  • Iniezione in world: 'MAIN' (vincolo binding di review, task 11): sia il file agentic-probes.js sia la chiamata a validaRunAgenticProbes devono essere iniettati con chrome.scripting.executeScript({ world: 'MAIN' }), entrambi nello stesso mondo — i mondi isolati (default dell'estensione) non condividono i prototipi JS con la pagina: senza world: 'MAIN' la neutralizzazione di form.submit sarebbe silenziosamente inerte in produzione, un fallimento invisibile ai test (jsdom è single-world, resta verde comunque). Ordine di iniezione nel popup: ace.js → screenshot (P1, Onda 2/B) → RenderedContext (P3, Onda 2/B) → sonde agentiche per ultime, perché mutano temporaneamente la pagina e lo screenshot deve restare pulito.
  • Guard sui form critici per l'agente aria-state (2 fix Critical/Important in review, task 10): l'agente 4.1.2 salta gli elementi dentro form classificati critici da 3.3.4 (niente toggle/click su pulsanti tipo "Elimina account"). Il guard iniziale riusava MAX_FORMS=3 (limite di campionamento dell'evidenza) come limite di sicurezza — un form critico oltre il terzo restava fuori dall'esclusione e il click reale su un pulsante distruttivo era riproducibile; corretto con un exclusion set uncapped (l'evidence sampling resta cappato, solo l'esclusione no). Un secondo fix ha chiuso un fail-open: il guard confrontava selettori CSS round-trip e falliva aperto (form incluso, non escluso) su un id non valido come identificatore CSS (es. form#2fa-elimina, dove querySelectorAll lancia) — riprodotto con click reale sul pulsante "Elimina account"; corretto facendo consumare al guard gli elementi DOM già raccolti, mai un round-trip tramite stringa di selettore.
  • Single-flight guard cross-sessione: btnAudit.disabled non basta a impedire due esecuzioni concorrenti delle sonde se il popup viene chiuso e riaperto a metà run (il disabled si perde con la chiusura del popup, ma la pagina resta mutata dalla sonda precedente); nuovo flag in-page window.__validaAgenticProbesRunning, che sopravvive alla chiusura/riapertura del popup perché vive sulla pagina, non sull'estensione.
  • Popup: nuova checkbox «Esegui agenti comportamentali (7 — form/auth)», default attiva; payload esteso agenticEvidence: [{ agentId, criterionCode, evidence }]. manifest.json1.1.0, pack.sh verificato includere agentic-probes.js nella ZIP distribuita.

Gamba B — Completamento parità motori server-side nel submit da estensione

  • Motore statico, 13 checker Cheerio (feat): evaluateHtml(html, url) estratto da evaluateUrl (refactor behavior-preserving, a11y-engine/index.ts) — evaluateUrl diventa fetch + evaluateHtml, la pipeline web non cambia comportamento. /api/extension/submit chiama ora evaluateHtml(rawHtml, url) invece di lasciare il motore statico completamente assente: evaluateUrl(url) avrebbe rifatto un fetch server-side dell'URL, colpendo la pagina di login sulle pagine dietro autenticazione — proprio il caso d'uso primario dell'estensione. Engine source static-extension. Lo step Claude riceve ora la base fusa statico+tecniche (non solo tecniche), a parità con la pipeline web (fix di un drift di parametro trovato in review, task 2).
  • W3C validator (feat): gated sul flag per-round esistente (round.w3cEnabled, stesso gate della pipeline web), con sourceCode ora persistito sull'upsert — prima la colonna Excel del report per submit da estensione restava vuota per i criteri W3C. Un secondo fix di review ha convertito lo UPDATE diretto in COALESCE(EXCLUDED.source_code, source_code) sull'upsert: senza, un submit successivo privo di W3C avrebbe azzerato (null-clobber) il codice sorgente già salvato da un submit precedente.
  • Effort (feat): saveEffortScores(auditRoundId, componentId) chiamato dopo il salvataggio delle valutazioni, stesso punto della pipeline web, best-effort (un fallimento non blocca il submit).

Residuo dichiarato (matrice di parità, §7 della spec)

  • Agentico: 7/19 coperti da questa onda. ~6 agenti del lotto 2 restano portabili in linea di principio (via DOM/dispatchEvent) e sono la priorità della prossima onda. 4-5 agenti non sono portabili nemmeno in teoria, limite strutturale del browser, non di sforzo ingegneristico: focus-order/skip-nav (un evento sintetico non sposta il focus reale — serve un vero Tab da tastiera via CDP), hover-focus (il vero :hover CSS segue la posizione reale del cursore, non eventi sintetici), reflow (richiede un vero resize del viewport). Uno sblocco futuro via chrome.debugger/CDP è tecnicamente possibile ma è una permission invasiva — decisione di prodotto rimandata.
  • Gemini Vision, screenshot di evidenza per-elemento (enrichEvaluations) e AX-Tree snapshot restano fuori scope: richiedono rispettivamente snippet per-elemento dal content script, un crop server-side dallo screenshot P1 (idea a costo medio per il lotto 2), e l'accessibility API di CDP/Playwright.

Verifica: tsc pulito · suite 865/865 (+61 dal baseline pre-onda 804/804 di v1.81.0) · eslint 0 errori (67 warning pre-esistenti, invariati) · next build ok. Spec e piano in docs/superpowers/{specs,plans}/2026-07-10-extension-agentic-parity-*. 13 task, ognuno con review dedicata, 3 fughe di sicurezza reali trovate e chiuse durante l'implementazione (mai esposte su main): bypass form.submit() dell'interceptor (task 8), guard aria-state fail-open su form critici oltre il terzo/su id non-CSS-ident (task 10), sonda accessible-auth priva dell'interceptor sul proprio evento paste (trovata dalla final whole-branch review, non da un review per-task).

Smoke test reale eseguito (post-merge, controller diretto, non delegato a subagent): container ricostruito dal branch e ridistribuito su Docker locale; sonde eseguite in un browser Chromium reale (non jsdom) via iniezione diretta dello script su una pagina di test con form/CAPTCHA/countdown/toggle ARIA — tutti e 7 gli agenti hanno prodotto evidenza realistica (inclusi i messaggi di validazione HTML5 nativi del browser in italiano); canary di sicurezza superati: nessuna navigazione avvenuta, HTMLFormElement.prototype.submit ripristinato all'originale, valori campo e stato ARIA ripristinati. Payload reale inviato a /api/extension/submit su stack Docker completo (Postgres/Inngest/W3C sidecar): motore statico e W3C confermati funzionanti con dati reali (3.1.1 rilevato su <html> senza lang, sourceCode W3C persistito su 6 criteri via il fix COALESCE), effort_static popolato; le 7 righe di evidenza agentica sono state persistite pending, l'evento Inngest consumato e le 7 interpretazioni Claude fallite con grazia per credito API esaurito (stesso limite noto da Onda 2/B) — nessuna riga rimasta bloccata, nessun crash, percorso di degradazione verificato in produzione. Non verificato (residuo dichiarato, nessun tool disponibile per caricare un'estensione MV3 reale in questa sessione): il caricamento effettivo tramite chrome.scripting con semantica world: 'MAIN' dal popup reale, e il rendering dei nuovi esiti nella UI risultati autenticata — entrambi da controllare al primo utilizzo reale dell'estensione pacchettizzata.

v1.81.0

Estensione Chrome "Valida" — parità con la piattaforma web (Onda 2/B)

  • Coerenza cross-pagina raggiungibile anche da round popolati da estensione (feat): /api/extension/submit chiama ora extractPageSnapshot() (nav fingerprint, help position, landmark map) per ogni pagina ricevuta — prima le pagine da estensione restavano invisibili all'analisi di coerenza cross-pagina, indipendentemente da come/quando veniva lanciata. L'evento Inngest che ricalcola la coerenza è stato rinominato in round/consistency-recompute e viene ora emesso dopo ogni pagina "assestata" (web e estensione) — lo stesso trigger era di fatto un bug preesistente mai cablato da nessuna parte del codice. Un round popolato solo da pagine da estensione produce quindi un'analisi di coerenza completa (3.2.3 link di navigazione, 3.2.4 etichette incoerenti, 3.2.6 posizione aiuto), visibile nel pannello "Coerenza Cross-Pagina" della pagina round.
  • Guardia round completato su submit da estensione (fix): /api/extension/submit verificava solo l'esistenza del round, non il suo status, a differenza di /api/evaluate//api/evaluate/async che già bloccano con 403. Ora replica la stessa guardia: submit su round completata403 con messaggio esplicito, mostrato nel popup.
  • Avviso non bloccante di mismatch dominio (feat): il popup confronta il dominio della tab attiva con l'URL del progetto selezionato (ora esposto da /api/extension/projects) e mostra un avviso non bloccante quando non coincidono, per intercettare submit accidentali sul progetto sbagliato.
  • Campo extensionOnly sui componenti + blocco ri-valutazione automatica (feat): nuova colonna components.extensionOnly, valorizzata sui componenti creati da estensione (pagine raggiungibili solo con la sessione autenticata del browser dell'estensione, non da Playwright). La piattaforma ora esclude questi componenti dalla ri-valutazione automatica ("Auto" disabilitato con tooltip esplicativo, esclusi dall'isEvaluable di evaluateAll con nota riassuntiva sul numero saltato) e li segnala con badge "Da estensione" nella lista componenti — risolve il bug per cui la piattaforma tentava comunque di raggiungere pagine autenticate aggiunte solo da estensione, bloccandosi sull'autenticazione.

Estensione Chrome — P1 screenshot di evidenza

  • Screenshot dell'intera tab al submit (feat): chrome.tabs.captureVisibleTab cattura lo screenshot al momento dell'audit, caricato su MinIO (uploadExtensionScreenshot, path screenshots/round-{id}/extension/component-{id}.jpg) e linkato al componente (screenshot_key/screenshot_at). Best-effort: un fallimento di cattura o upload non blocca mai il submit. Le pagine dietro login — il caso d'uso primario dell'estensione — non sono più le uniche prive di evidenza visiva.

Estensione Chrome — P2 analisi Claude AI

  • Step Claude AI sul rawHtml inviato dall'estensione (feat): lo step "Claude" (evaluateWithAi + injection KB) viene eseguito rispettando l'evalMode effettivo del round (tecnica-claude/tecnica-claude-gemini), dopo il salvataggio di IBM/tecniche statiche per non farne sovrascrivere lo snapshot.

Estensione Chrome — P3 RenderedContext parziale dal browser reale

  • Collettori RenderedContext portati in content-script (feat): 3 dei 4 criteri rendered originariamente coperti dal renderer Playwright sono ora disponibili anche da estensione — 2.4.7 (focus visibile), 2.5.8 (target size), 1.4.12 (text spacing overflow) — tramite rendered-context-collectors.js, riscrittura in JS classico (nessuna API Playwright, solo getComputedStyle) dei collettori di collect-rendered-context.ts, iniettato via chrome.scripting.executeScript insieme ad ace.js prima dello screenshot. Il popup invia il risultato sotto renderedContext, consumato da runTechniqueEngine(..., { renderedContext }). 1.4.13 (contenuto aggiuntivo su hover/focus) resta esplicitamente fuori scope: è l'unico dei 4 criteri che richiede una vera interazione hover, non esprimibile con un passaggio DOM iniettato.
  • renderedTechniqueScope — il RenderedContext parziale non influenza più criteri fuori scope (fix): runTechniqueEngine applicava il RenderedContext in modo tutto-o-niente, eseguendo tutti i ~24 check rendered anche con un contesto parziale come quello dell'estensione — i check sui campi assenti (es. contrasto in hover) restituivano cannot-tell, potendo retrocedere a Da verificare anche criteri Superato mai nello scope di questa onda. Nuova opzione renderedTechniqueScope in TechniqueEngineOptions filtra i risultati rendered ai soli techniqueId che l'estensione raccoglie davvero (C15/G149 → 2.4.7, C42/F110 → 2.5.8, C36/F104 → 1.4.12), passata solo da /api/extension/submit; la pipeline web non la usa mai (comportamento identico a prima). Solo i 3 criteri sopra sono influenzati dal RenderedContext da estensione.

Verifica: tsc pulito · suite 804/804 · eslint 0 errori · next build ok. Smoke test reale in browser su tutte le funzionalità sopra: coerenza cross-pagina rilevata correttamente su due pagine con menu di navigazione incoerente (link mancante 3.2.3 + etichetta diversa 3.2.4); guardia round completato → 403 visibile nel popup; screenshot recuperabile via /api/screenshots per componenti da estensione (~30 KB ciascuno); step Claude eseguito con chiamata reale (errore di credito API catturato e mostrato per esteso, non silenzioso — la verifica con credito disponibile resta da fare); RenderedContext su pagina di test con focus-outline rimosso, target sotto 24px e testo che trabocca con spaziatura aumentata — tutti e tre rilevati correttamente. Spec e piano in docs/superpowers/{specs,plans}/2026-07-09-extension-p1-p3-consistency-*. Residuo noto: motore agentico (19 agenti comportamentali) non ancora portato all'estensione — 14-15/19 agenti sono riscrivibili via DOM/dispatchEvent, 4-5 (focus-order/skip-nav, hover-focus, reflow) non sono portabili nemmeno in teoria per limite strutturale del browser; priorità immediata della prossima onda (§9-quater P8 del documento di analisi).

v1.80.0

Osservabilità — Sentry error tracking (Onda 2/A)

  • Sentry EU, solo errori (feat): @sentry/nextjs installato e wired su server/edge/client (sentry.{server,edge,client}.config.ts + src/instrumentation.ts, opzioni centralizzate in src/lib/sentry-options.ts), regione EU, tracesSampleRate: 0 (nessun tracing/performance, solo cattura errori). Copre i tre punti di crash dell'app: server (auto-instrumentation sui route handler), client (src/app/global-error.tsx, error boundary root) e pipeline Inngest (onFailureSentry.captureException con contesto { function, componentId }).
  • PII scrubbing (feat): src/lib/sentry-scrub.ts (Web Crypto, non Buffer — eseguibile anche su Edge/client) hasha l'email utente e rimuove IP/cookie/authorization/body dagli eventi prima dell'invio, via beforeSend.

Sicurezza — CSP script-src enforcing con nonce per-request (Onda 2/A)

  • Nonce-based script-src (feat): script-src promosso da Report-Only a enforcing, con nonce generato per ogni richiesta in src/middleware.ts (Web Crypto, Edge runtime) e costruito da buildEnforcingCsp() (src/lib/security/csp.ts); propagato come header x-nonce (letto in src/app/layout.tsx, che forza il rendering dinamico per la propagazione) e come header di risposta Content-Security-Policy. Fallback 'strict-dynamic' https: 'unsafe-inline' mantenuto per i browser senza supporto al nonce; nessuna libreria del bundle ha mostrato bisogno reale di 'unsafe-eval' in produzione, non aggiunto alla direttiva enforcing.
  • Hardening auth (fix): durante l'implementazione è emerso un bug latente in auth.config.ts — con il wrapper middleware custom richiesto per generare il nonce, NextAuth v5 non esegue più il redirect automatico quando authorized() ritorna il booleano false su una pagina protetta da anonimo (lo fa solo se authorized() ritorna direttamente una Response), servendo 200 invece del redirect a /login. Corretto ritornando un NextResponse.redirect esplicito, byte-per-byte identico al comportamento nativo di NextAuth (stesso nextUrl.clone(), callbackUrl assoluto, 307), verificato per parità contro una baseline pre-fix su 4 classi di rotta. Il bug non è mai stato esposto in produzione (introdotto e corretto nello stesso branch, mai mergiato su main), ma chiude un gap di sicurezza reale prima del merge.

Verifica: tsc pulito · suite 787/787 · eslint 0 errori · next build ok. Verifica browser reale su build di produzione (il dev server usa eval() per l'HMR di webpack e non è rappresentativo per il controllo CSP): /login pubblica + login reale su /progetti, /progetti/[id]/dashboard e /kb/insights (entrambe fortemente recharts) — zero violazioni script-src nuove, idratazione corretta ovunque, grafici renderizzati. Spec e piano in docs/superpowers/{specs,plans}/2026-07-08-sentry-csp-enforcing-*. Residuo noto: style-src resta in Report-Only (§5.1 del documento di analisi); delivery Sentry a un progetto reale non verificata (nessun DSN disponibile in questo ambiente).

v1.79.0

Remediation RAG & Accessibilità

  • Fallback RAG Remediation (feat): introdotto il fallback RAG nell'endpoint per i criteri senza entry manuale curata; aggiunto un trigger UI (pulsante) per attivare la spiegazione RAG; esposti gli errori dell'endpoint AI in UI. Aggiunto trigger lato admin per l'ingestione del corpus RAG. Hardening per parsePersisted.
  • A11y Card "Come correggere" (fix): rimosso problema id duplicati su contesti RAG usando useId() per aria-labelledby nella RemediationCard; migliorato il contrasto del bordo del trigger RAG (border-leaf-700); correzioni accessibilità finali sulla card.
v1.78.0

Knowledge Base — Import/Export JSON (Onda 1/C)

  • Export GET /api/knowledge/export (admin/auditor): dump JSON di tutta la KB ({ schemaVersion: 1, exportedAt, count, entries }), scaricabile come allegato; filtri opzionali (criterion/scope/type/active). Omette id/created_by (instance-specific), preserva lo stato appreso (confidence/decay/occurrence/reviewerRole).
  • Import POST /api/knowledge/import (admin-only): merge per chiave naturale (criterion_code::knowledge_type::original_status::corrected_status::content_type::scope) — inserisce le entry nuove, salta le esistenti (o le aggiorna con ?mode=overwrite), con dedup intra-batch. created_by sempre null (mai dal payload), solo colonne whitelisted, guard body 5 MB (letto prima del parse), invalidazione cache KB. Risposta { inserted, updated, skipped, errors }.
  • UI: pulsanti «Esporta KB» (admin/auditor) e «Importa KB» (admin) nel pannello /kb. Abilita backup, portabilità tra istanze e seed di KB curate per nuovi clienti.
v1.77.0

Provenienza — versioning prompt/modello sugli snapshot (Onda 1/B)

  • ai_model + ai_prompt_version su evaluation_snapshots: ogni snapshot di criterio prodotto da un'AI registra ora il modello e la versione del prompt che l'hanno generato, rendendo il verdetto riproducibile e difendibile (rilevante in PA). Valorizzati dalle fasi Claude (ai-phase), Gemini (visual-phase) e Claude-PDF (pdf-evaluation) tramite applyEvaluations; upsert con COALESCE(EXCLUDED, esistente) così l'ultima AI che tocca il criterio vince e una fase non-AI (null) non azzera il valore. Le versioni prompt sono costanti per-engine (AI_PROMPT_VERSION, GEMINI_PROMPT_VERSION) da bumpare a mano al cambio del template. Migrazione idempotente; criteri solo-tecnici restano null. UI ed eventuale backfill storico non inclusi.
v1.76.0

Osservabilità — tracing per-step Inngest + rollout logger completo (Onda 1/A)

  • Tracing per-step della pipeline: nuovo wrapper tracedStep() (src/lib/evaluation-pipeline/step-trace.ts) attorno a ogni step.run() di evaluationPipeline (mark-running, technical/claude/visual/agentic-eval, mark-completed) e consistencyAnalysis. Registra per ogni step nome, durata (ms), esito ed errore in execution_logs (categoria SYSTEM, details JSON, executionId stabile sui replay Inngest via step memoizzato trace-init) più una riga sul logger strutturato. Scrittura best-effort: un errore di logging non può mai far fallire uno step reale, e l'errore originale dello step viene rilanciato invariato. Le tracce compaiono nella exec-log UI per componente (useExecLogs); la function di consistency (per-round, senza componentId) traccia solo su logger.
  • Rollout logger completo: migrati tutti i console.* residui di src/lib (11 file) e src/app/api (12 file) al logger strutturato (logger.child con auditRoundId/componentId/requestId dove disponibili, chiavi evento snake_case, Error normalizzati). Regola ESLint no-console promossa da warn a error su src/lib e src/app/api per prevenire regressioni (il sink logger.ts resta esente).
  • Fix a11y: i blocchi di codice scrollabili (<pre>) delle card «Come correggere» ora hanno role="group" + aria-label (regione scrollabile nominata, focalizzabile da tastiera per lo scroll — WCAG 2.1.1).
v1.75.0

Motore agentic — lotto 2: 3 nuovi agenti (19 totali) e supporto multi-browser

  • Agente error-prevention (WCAG 3.3.4 — Prevenzione errori): classifica i form come critici — legali (dichiarazioni, consensi, autocertificazioni, istanze, contratti), finanziari (IBAN, carte di credito, pagamenti, bonifici) o di modifica dati (cancellazioni, disdette, revoche) — e verifica la presenza di almeno un meccanismo di prevenzione richiesto da G98/G99/G168: step di revisione/riepilogo, checkbox di conferma esplicita («confermo», «dichiaro di aver letto») o possibilità di annullare/modificare. Esito N/D sulle pagine senza form critici.
  • Agente redundant-entry (WCAG 3.3.7 — Inserimento ridondante): rileva campi con la stessa etichetta ripetuti nella pagina (le conferme di sicurezza come «conferma password» sono riconosciute come eccezioni ammesse dal criterio) e campi dato-personale (nome, email, telefono, indirizzo, codice fiscale…) privi di token autocomplete (H100), il principale meccanismo anti-ridondanza.
  • Agente timing-adjustable (WCAG 2.2.1 — Regolazione tempi di esecuzione): rileva meta http-equiv="refresh" con ritardo tra 0 e 20 ore (F40/F41) e countdown di sessione (role="timer", testi con orari vicino a «sessione/scade»), con probe comportamentale: il testo dei candidati viene riletto dopo 2,5 secondi — se cambia, il timer è attivo e serve un meccanismo di estensione.
  • Multi-browser opt-in: nuova variabile d'ambiente AGENTIC_BROWSERS (csv di chromium/firefox/webkit, default chromium — comportamento invariato se assente). Gli agenti girano su ogni engine configurato e gli esiti vengono fusi per criterio con logica worst-case; status divergenti producono una nota [Divergenza browser] nell'evidenza. Gli engine non installati nell'ambiente vengono saltati con warning nel log di esecuzione (in Docker resta operativo il solo Chromium finché l'immagine non include i browser Playwright).
  • Guida in linea aggiornata: sezione «Form e comportamento» a 6 agenti, nuova area «Interazione visiva e tempo» a 4 agenti, conteggi a 19.

Verifica: tsc pulito · suite 628/628 · eslint 0 errori · next build ok. Spec in docs/superpowers/specs/2026-07-04-agenti-lotto2-multibrowser-design.md.


v1.74.0

Motore agentic — 2 nuovi agenti (16 totali) e limiti configurabili

  • Agente form-validation (WCAG 3.3.3 — Suggerimento per errori): compila i campi form con dati invalidi tipizzati (email malformata, URL errata, numero fuori range, pattern non conforme; i campi required vengono lasciati vuoti), sottomette e valuta la qualità del messaggio di errore — un buon messaggio identifica il campo e suggerisce la correzione (formato atteso o esempio) via aria-errormessage, aria-describedby, validationMessage o testo adiacente. Complementare a error-identification (3.3.1, submit a vuoto), la cui descrizione criterio è stata ristretta al solo 3.3.1.
  • Agente accessible-auth (WCAG 3.3.8 — Autenticazione accessibile): sulle pagine con form di login verifica il supporto ai password manager (autocomplete credenziali, probe comportamentale del blocco-incolla sul campo password), classifica gli eventuali CAPTCHA (reCAPTCHA/hCaptcha cognitivi, Cloudflare Turnstile no, captcha immagine) e rileva le alternative senza test cognitivo (SPID, CIE, CNS, OAuth, passkey, codice via email/SMS). Esito N/D sulle pagine senza autenticazione.
  • Limiti di campionamento configurabili: nuova env AGENTIC_MAX_ELEMENTS (sample-limits.ts) che può solo alzare i cap per-agente (mai abbassarli, tetto 200); applicata ai nuovi agenti e a no-trap (5), error-identification (3), hover-focus (8).
  • Il fallback agentic_active_agents (setting assente) ora deriva dal registry (ALL_AGENT_IDS) invece di una lista hardcoded di 4 agenti; guida in linea aggiornata (sezione «Form e comportamento» a 4 agenti, conteggi a 16).
  • Nota: la proposta «agente 2.5.7 dragging» del documento di analisi non è stata implementata perché il criterio è già coperto dal motore WCAG Techniques rendered (G215/F108 su dragListeners).

Analisi di coerenza cross-pagina (3.2.3 / 3.2.4 / 3.2.6) completata

  • helpPosition ora estratto dall'HTML (euristica contatti/aiuto/assistenza/supporto/FAQ/help con posizione header/nav/main/aside/footer): prima era sempre null e il check 3.2.6 non scattava mai.
  • Check ordine relativo dei link di navigazione (G61): oltre alla presenza, viene confrontato l'ordine dei link comuni tra le pagine del round (3.2.3).
  • Nuovo check etichette incoerenti (F31): stesso href con testi diversi tra le pagine → issue 3.2.4; usa il nuovo campo retro-compatibile NavFingerprint.links (righe storiche senza il campo vengono ignorate).
  • Persistenza degli esiti: POST /api/consistency/[roundId]/analyze (e la funzione Inngest consistency-analysis) ora scrivono per ogni criterio coinvolto una valutazione Da verificare (mai un fallimento automatico) su tutti i componenti del round, con evidenza aggregata e engine_sources: ['consistency']; la skip-logic esistente protegge i risultati già rivisti dall'esperto.

Verifica: tsc pulito · suite 604/604 · eslint 0 errori · next build ok. Spec e piano in docs/superpowers/{specs,plans}/2026-07-04-nuovi-agenti-*.


v1.73.2

Manutenzione — scomposizione file «monstre», secondo lotto (§4.1)

Refactor interno behavior-preserving (nessun cambiamento funzionale, UI o API): scomposti i due file rimasti fuori scope dalla Fase 3, entrambi oltre le 1.000 righe.

  • src/lib/renderer/collect-rendered-context.ts 1690 → 134 righe: estratti nove moduli fratelli per famiglia WCAG (rendered-context-shared, -focus, -target-link, -spacing-hover, -drag-motion, -dyslexia-flashing, -interaction, -contrast, -reflow-sequence) con un barrel che preserva invariata l'unica API pubblica (collectRenderedContext). Le quattro copie della formula di contrasto con soglie leggermente divergenti (0.03928 / 0.04045) sono state spostate verbatim, senza deduplicarle, per non alterare un comportamento storicamente differenziato.
  • HelpValutazioneClient.tsx 2680 → 163 righe: estratti tipi, utility, due hook (useWcagCriteriaCatalog, useActiveSection), quattro primitivi presentazionali (AccordionItem, CodeBlock, Badge, AgentEntry) e tredici sotto-componenti di sezione (dodici statici, uno dinamico con la ricerca nel catalogo criteri).

Verifica: tsc pulito · suite 563/563 · eslint 0 errori · smoke reale in browser (login, scroll-spy TOC, accordion, ricerca/selezione criteri) · review finale.


v1.73.1

Manutenzione — scomposizione file «monstre» (§4.1 / Fase 3)

Refactor interno behavior-preserving (nessun cambiamento funzionale, UI o API): scomposti i tre file sorgente ad alto churn oltre le 1.000 righe, che concentravano troppa responsabilità e rallentavano ogni intervento d'area.

  • src/lib/ai-engine/index.ts 1133 → 293 righe: estratti sette moduli fratelli (usage, client, html-context, response-parser, prompts, arbitration, divergence) con un barrel che preserva invariata l'API pubblica (evaluateWithAi, evaluatePdfWithAi, mergeEvaluations, arbitrate, analyzeBrowserDivergence, EntityContext).
  • QualitaClient.tsx 1400 → 531 righe: estratti tipi, utility, SortableHeader, tre hook (useReadabilityData, useIssueTracking, useRewrite) e cinque pannelli presentazionali.
  • ComponenteClient.tsx 1882 → 616 righe: estratti tipi, utility, sei sotto-componenti (log esecuzione, matrice cross-browser, divergence expert, confronto visivo, wizard, lista) e l'hook useExecLogs.

Verifica: tsc pulito · suite 563/563 · eslint 0 errori · next build 96/96 route. Riprende e completa una Fase 3 precedentemente annullata.


v1.73.0

Estensione Chrome — quick win 9f–9h (§9-quater)

Portati a terra i tre quick win residui dell'estensione «Valida», il canale per le pagine dietro autenticazione dove Playwright non arriva.

Riproducibilità del motore (9f)

  • Pin di ace.js alla versione di accessibility-checker installata sul server (nuovo modulo src/lib/extension/ace-version.ts; usato da /api/extension/download e da setup.sh), con warning se la versione non è risolvibile. La versione motore viaggia ora nel payload di submit e viene registrata come ibm-extension@<versione> in engine_sources. pack.sh fallisce se ace.js manca (prima produceva silenziosamente una ZIP inutilizzabile).

Sicurezza dell'endpoint di submit (9g)

  • Rate-limit per IP (20 richieste/minuto → 429 con Retry-After) e guard sulla dimensione del body (max 5 MB → 413) su /api/extension/submit, prima privo di entrambi (rawHtml illimitato).

UX post-submit nel popup (9h)

  • Il submit restituisce projectId/created/componentName; il popup mostra il pulsante «Apri in Valida» che apre direttamente la pagina del componente, un campo opzionale «Nome componente» (usato solo alla creazione, senza sovrascrivere componenti esistenti) e l'esito «Nuovo componente creato / Componente aggiornato».

v1.72.0

Backlog Fasi 0–2 — Attendibilità, sicurezza e quick win

Smaltita buona parte del backlog di analisi (§14): igiene di release, quick win UI/API e quick win verticali sui motori. Merge di 11 interventi.

Attendibilità e trasparenza degli esiti

  • Badge motori/provenienza nel dettaglio criterio: esposto engine_sources (già in evaluation_snapshots) tramite /api/results e mostrato con un badge in DettaglioClient.
  • Export Excel con citazione della tecnica WCAG e dei motori che hanno deciso l'esito — src/lib/export/technique-citation.ts.

Sicurezza

  • Endpoint di raccolta report CSP /api/csp-report + direttiva report-uri in next.config.ts, così la fase Report-Only produce finalmente dati. Endpoint pubblico (i browser inviano i report senza sessione) con guard sulla dimensione del body.

Motori di valutazione

  • PDF remediation (pikepdf): applicazione reale di heading (/H1..6) e language tag per elemento — prima dichiarati nelle proposte ma non applicati (scripts/pdf_remediate.py).
  • Agentic: screenshot di evidenza per ogni elemento fallito (caricati su MinIO), visibili nel dettaglio criterio.
  • Leggibilità: riscrittura assistita per frase in Plain Language AGID — /api/readability/rewrite-sentence + bottone "Proponi riscrittura" nella pagina Qualità.
  • PDF: limite pagine configurabile (PDF_MAX_PAGES) con avviso non silenzioso oltre il limite (prima troncamento muto a 50 pagine).

Igiene e strumenti

  • Route dedicata /kb/insights.
  • Logger strutturato nei punti caldi della pipeline + regola ESLint no-console (warn) su src/lib e src/app/api.
  • Guard CI di coerenza package.json ↔ CHANGELOG (scripts/check-version.mjs) per prevenire i disallineamenti di versione.
  • Roadmap in CLAUDE.md aggiornata; rimappatura porta 3002 spostata in docker-compose.override.yml locale.

v1.71.0

Export AgID — Correzione PDF, font e sintesi dichiarazione

Tre correzioni agli export dell'Allegato 2 AgID e della Guida alla compilazione.

PDF che scaricava un Word (risolto)

L'interfaccia dichiarava formato PDF ma veniva scaricato un DOCX. Causa: l'opzione bootstrap di LibreOffice era passata come --env:UserInstallation (doppio trattino); soffice richiede il trattino singolo -env: e con il doppio trattino restituiva Error in option, facendo fallire ogni conversione e attivando sempre il fallback DOCX.

  • src/app/api/export/agid-report/route.ts e src/app/api/export/agid-dichiarazione/route.ts — corretto --env:-env: nella chiamata soffice. La conversione PDF ora va a buon fine e viene scaricato un vero PDF.

Font Garamond nei testi compilati (risolto)

I testi inseriti nell'Allegato 2 (note e stati per criterio) comparivano in Garamond invece del Calibri del resto del documento. Causa: i segnaposto {n_...}/{s_...} del template non hanno formattazione di run esplicita ed ereditavano lo stile Normale, definito in Garamond.

  • templates_doc/AGID-Modello-Autovalutazione-Template.docx — stile Normale portato da Garamond a Calibri, coerente con il testo fisso del modello.
  • Dockerfile — aggiunto fonts-crosextra-carlito (font metrico-compatibile con Calibri) così che LibreOffice renda correttamente il Calibri nel PDF.

Sintesi troppo stringata nella Guida alla compilazione (migliorato)

Il campo AgID «sezioni, contenuti e funzioni non accessibili» ammette fino a 2000 caratteri: la sintesi AI ora sfrutta lo spazio disponibile e, per ogni problema, richiama il punto di controllo WCAG coinvolto (codice + titolo del criterio).

  • src/lib/reports-ai/index.ts — riscritto il prompt di summarizeEvidencesForDichiarazione (testo più completo, riferimento esplicito a codice e titolo del criterio, cap a 2000 caratteri con taglio a fine frase). Esportata la costante DICHIARAZIONE_FIELD_MAX_CHARS.
  • src/app/api/export/agid-dichiarazione/route.ts — evidenze più ricche (3 campioni per criterio), fallback che preserva i riferimenti al criterio entro il limite di 2000 caratteri, e celle di testo lungo che ora rendono correttamente elenchi e paragrafi multilinea.

v1.70.0

Motore AI — Valutazioni deterministiche

Impostato temperature: 0 su tutti i motori AI (Claude e agentic interpreter) per eliminare la variabilità stocastica tra round successivi sulla stessa pagina.

Problema risolto

Round successivi sulla stessa pagina con configurazione identica (Tecnica + Claude + Gemini, stessi browser) producevano verdetti significativamente diversi. L'analisi comparativa su 3 round di produzione (66 → 69 → 72) ha evidenziato oltre 25 criteri con status diverso tra un round e l'altro — inclusi flip critici come 1.1.1, 4.1.1, 2.5.3 — senza alcuna modifica alla pagina né alla configurazione. La causa primaria era l'assenza del parametro temperature nelle chiamate Claude API: il valore di default (1.0) introduce massima variabilità stocastica nelle risposte.

Correzione

  • src/lib/ai-engine/index.ts — aggiunto temperature: 0 nel body della richiesta API in callClaude(): a parità di HTML e prompt, Claude produce ora sempre lo stesso verdetto
  • src/lib/agentic-engine/interpreter.ts — aggiunto temperature: 0 in interpretWithClaude(): stessa garanzia per il motore agentic (14 agenti Playwright)
  • src/lib/gemini-engine/index.ts — abbassato temperature da 0.1 a 0 in entrambe le funzioni di chiamata Gemini Vision (singola e multi-immagine): elimina la residua variabilità nel motore visivo

Con temperature: 0 la valutazione AI diventa deterministicamente replicabile: round ripetuti sulla stessa pagina non modificata produrranno risultati identici, rendendo i delta tra round indicativi di cambiamenti reali nella pagina o nel sito.


v1.69.0

Accessibilità WCAG 2.2 AA e UI

Interventi di conformità WCAG 2.2 AA sull'interfaccia dell'applicazione e correzioni alle note di valutazione nel dettaglio di criterio.

Accessibilità (WCAG 2.2 AA)

  • Focus ring — opacità sufficiente (WCAG 2.4.11): elevata l'opacità del box-shadow di focus su tutti gli schemi cromatici (navy 0.55, green 0.75, tomato-error 0.75) per soddisfare il requisito di contrasto minimo 3:1 rispetto allo sfondo adiacente
  • Focus ring chatbot: elevata l'opacità del focus ring dell'input chatbot da 0.10 a 0.55 — il precedente valore era insufficiente per ogni standard di contrasto
  • Rimosso anti-pattern focus:ring-0: sostituito con focus:ring-2 focus:ring-navy-700 sul <select> in ProgettiClient — rimozione della soppressione del focus che rendeva l'elemento non operabile da tastiera
  • Modal nativi <dialog> — 4 componenti migrati: delete-project (ProgettiClient), delete-round (ValutazioniClient), RevisionModal (RtdClient) e DeclarationModal convertiti da implementazioni custom div-based al nativo <dialog> HTML5 — gestione focus trap, Escape key, aria-modal e role correttamente delegata al browser
  • Lifecycle dialog robusto: stabilito il pattern dialog.close()onSuccess() per garantire che la chiusura del modal avvenga prima di qualsiasi aggiornamento di stato (elimina race condition); aggiunto guard onCancel per intercettare la chiusura via Escape senza sopprimere l'evento
  • Focus management SPA: introdotto componente FocusReset nel layout radice che, ad ogni navigazione Next.js, sposta il focus sul tag <main> (tabIndex={-1}) — evita la perdita di posizione del focus tra le rotte in applicazioni single-page

UI — Note di valutazione

  • Pannello Analisi Divergenza Cross-Browser: il pannello AI Divergence Expert nel dettaglio di criterio ora esegue il rendering completo delle note tecniche tramite ReactMarkdown con componenti custom allineati al design system (text-sm text-warm-700, bg-warm-100 text-[#962819] per code, heading text-xs font-semibold) — i contenuti erano in precedenza illeggibili (testo grezzo o markdown non interpretato)
  • Contenuto note ripristinato: rimossa la logica di stripping del blocco [Analisi Divergenza Cross-Browser] in formatNotes che tronca il contenuto della nota all'altezza del marcatore; il testo completo fluisce ora nel pipeline di formattazione standard con badge sorgente, riferimenti di riga e lista strutturata

UI — Tab EN 301 549

  • Accordion EN 301 549 non si aprivano: nel tab EN 301 549 esclusivi del dettaglio componente, il corpo di ogni accordion non veniva mai visualizzato. La causa era una condizione errata che subordinava il rendering al fatto che il criterio avesse problems o recommendations valorizzati — campi sempre nulli per i criteri esclusivi (4.2.x), che vengono valutati manualmente. Lo stato si aggiornava correttamente (il chevron ruotava), ma nessun contenuto compariva
  • Soluzione: rimossa la guard sul contenuto; il pannello si apre sempre al click e mostra i dettagli se presenti oppure "Nessun dettaglio registrato per questo criterio." come empty state esplicito
  • Miglioramenti accessibilità correlati: i trigger accordion convertiti da div[role=button] a <button> nativo; aggiunte coppie id/aria-controls per la relazione semantica tra trigger e pannello

v1.68.1

Hotfix — CSP che bloccava il rendering dell'intera applicazione

La CSP in enforcement introdotta in 1.68.0 conteneva default-src 'self'. In assenza di una direttiva script-src esplicita, gli script ricadono su default-src, e 'self' non consente gli script inline: gli script inline di bootstrap/idratazione di Next.js venivano bloccati, lasciando tutte le pagine vuote.

Correzione

  • CSP enforcement: rimosso default-src dalla policy in enforcement, che ora contiene solo le direttive realmente sicure da bloccare subito (frame-ancestors 'none', object-src 'none', base-uri 'self'). Le direttive che governano il rendering della pagina (default-src/script-src/style-src…) restano in Content-Security-Policy-Report-Only finché le violazioni non saranno verificate. La protezione anti-clickjacking resta attiva
  • Verifica: il fix è stato validato con un caricamento reale della pagina in browser (idratazione React confermata, zero violazioni CSP), non solo a livello di build
v1.68.0

Sicurezza, affidabilità operativa, performance e brand

Insieme di interventi infrastrutturali (quick-win dall'analisi di codebase), nuovo brand favicon e rifiniture sulla rilevazione degli acronimi nel motore di leggibilità.

Sicurezza

  • Content Security Policy: introdotti header CSP con strategia a doppio binario — direttive critiche in enforcement (es. frame-ancestors anti-clickjacking) e il resto in Content-Security-Policy-Report-Only per osservare le violazioni senza rompere l'app prima dell'enforcement completo

Affidabilità operativa

  • Health check readiness: l'endpoint /api/health verifica ora anche la raggiungibilità di MinIO (object storage) e Inngest (orchestrazione job), oltre al database — readiness reale dei servizi dipendenti
  • CI build verification: la pipeline di CI esegue ora anche il build di produzione Next.js, intercettando in anticipo gli errori che sfuggono a type-check e lint

Performance

  • Rendering multi-browser limitato: introdotta concorrenza controllata (p-limit) su renderPageMulti per evitare la saturazione di risorse quando si renderizzano più browser in parallelo — soglia configurabile via RENDER_CONCURRENCY

Brand

  • Nuovo favicon Valida: installato il set completo di icone (favicon, Apple touch, icone PWA) dal design handoff ufficiale, con metadata Next.js configurati per il supporto completo

Leggibilità (AGID)

  • Rilevazione acronimi per-blocco: il rilevatore di acronimi non spiegati analizza ora i blocchi di testo foglia (h1, p, li…) e salta i blocchi prevalentemente in maiuscolo (titoli/heading stilizzati ≥60% parole maiuscole), eliminando i falsi positivi su titoli e nomi propri (es. "ALPE D'ATTIA") spezzati da apostrofi e punteggiatura
v1.67.0

Qualità dei contenuti e leggibilità (AGID)

Nuovo livello di analisi della qualità dei contenuti secondo le linee guida AGID / Designers Italia e diagnostica strutturale della leggibilità.

Qualità dei contenuti (AGID)

  • Regole di linguaggio AGID — motore deterministico (senza costo AI): dizionario burocratese → alternativa di Plain Language (~50 voci, es. "al fine di" → "per", "istanza" → "domanda"), inglesismi → italiano (~23 voci, es. "form" → "modulo", "download" → "scarica"), rilevazione della forma passiva, dei link con testo generico ("clicca qui", "leggi di più") e degli acronimi non spiegati al primo uso; punteggio di linguaggio 0–100
  • Diagnostica strutturale per-frase: frasi troppo lunghe (oltre 25 parole), lessico complesso, tempo di lettura stimato e media parole/frase — feedback azionabile che affianca l'indice Gulpease
  • Analisi AI di leggibilità arricchita con i principi AGID (frasi brevi, forma attiva, dare del "tu", niente burocratese o inglesismi evitabili, acronimi spiegati, link descrittivi)
  • Pagina "Qualità dei Contenuti": nuovi pannelli Linguaggio chiaro (AGID) e Struttura del testo nel dettaglio di ogni pagina, con termine → alternativa suggerita, frase di contesto evidenziata e collegamento alle linee guida ufficiali

Affidabilità

  • Parsing Gemini Vision: gli elementi non validi (nulli o non-oggetto) nella risposta del modello vengono ora scartati singolarmente invece di far fallire l'intera analisi visiva
v1.66.0

Build, qualità del codice e tooling

Ottimizzazione dell'infrastruttura Docker e consolidamento della qualità del codice tramite analisi SonarQube. Nessuna modifica funzionale per l'utente finale.

Build / infrastruttura

  • veraPDF nativo arm64: il sidecar di validazione PDF/UA non usa più l'immagine verapdf/rest solo-amd64 (che girava in emulazione Rosetta/qemu su Apple Silicon). Nuovo build multi-stage (verapdf-service/) che copia gli artefatti Java arch-indipendenti su una base Temurin 11 multi-arch — esecuzione nativa, avvio e validazione più rapidi

Qualità del codice (SonarQube)

  • Affidabilità: risolti 4 bug di reliability (ordinamento con compare function, operatori ternari a rami identici) — rating Reliability portato ad A
  • Hardening ReDoS: irrobustite le espressioni regolari su input non fidato (CSS di pagine analizzate) per eliminare backtracking super-lineare in structure, interactions
  • Sicurezza: nome della directory temporanea della Dichiarazione AGID generato con crypto.randomBytes invece di Math.random
  • Pulizia: rimosse type-assertion ridondanti e introdotto optional chaining dove equivalente (~50 code smell); rimossi i .DS_Store tracciati
  • Security hotspots: 81 rivisti e chiusi (fix reali + triage motivato di falsi positivi: riferimenti EN 301 549 scambiati per IP, http su rete interna, random non crittografico)
  • Coverage: aggiunto @vitest/coverage-v8 per la generazione del report lcov
  • Quality Gate verde: impostata la baseline "New Code" così il gate valuta solo il codice nuovo (suite di 503 test verde, type-check e lint puliti)
v1.65.0

Sicurezza — autorizzazione per-oggetto (IDOR) e SSRF

Completamento della messa in sicurezza delle API: ogni rotta che riceve un identificativo di risorsa (progetto, round, componente) verifica ora che il chiamante possa effettivamente accedervi, oltre alla semplice autenticazione. Nessuna modifica funzionale per gli utenti autorizzati.

Autorizzazione a livello di oggetto

  • Esportazioni (Excel, DOCX, PDF, Dichiarazione e Allegato 2 AGID): verifica di accesso al round prima della generazione — impedisce l'esportazione di report di enti terzi tramite ID
  • Componenti e risultati: mappa strutturale, analisi nomi accessibili, risultati aggregati, stima effort AI e leggibilità ora vincolati alla visibilità del chiamante
  • Bonifica PDF: aggiunta autenticazione per-handler (lettura e creazione task)
  • Import Excel: l'import in un progetto esistente richiede l'accesso al progetto
  • AX-Tree (snapshot, cronologia, divergenze cross-browser) e confronto round: vincolati al round/progetto
  • Dichiarazione AGID per round: un RTD può completarla solo per i round del proprio ente
  • Notifiche (valutatore, RTD): vincolate a progetto/round
  • Knowledge Base (modifica/eliminazione voci): riservata a ruoli Auditor/Admin
  • Centralizzazione nel modulo assertCanAccess{Project,Round,Component} con regola fail-closed

SSRF

  • Nuovo safe-fetch: ogni redirect viene ri-validato contro la lista di indirizzi privati/riservati, chiudendo il bypass via reindirizzamento (adottato in crawler, recupero titoli e fetch secondari di sitemap/robots)
  • Validazione URL con risoluzione DNS degli indirizzi effettivi (anti DNS-rebinding)

Qualità

  • Esclusione dei worktree interni dalla suite di test (rimossi i duplicati che gonfiavano il conteggio)
  • type-check e lint puliti, suite di test verde
v1.64.0

Sicurezza, affidabilità e tooling

Consolidamento tecnico a partire dall'analisi di codebase: autorizzazione per-oggetto, hardening SSRF, qualità del codice e pipeline di CI. Nessuna modifica funzionale per l'utente finale.

Sicurezza

  • Autorizzazione a livello di oggetto (IDOR): nuovo helper centralizzato assertCanAccess{Project,Round,Component} con regola di visibilità fail-closed (nessuna sessione ⇒ nessun dato), applicato alla rotta /api/components; predicato puro coperto da test
  • SSRF: la validazione URL ora risolve il DNS e blocca gli indirizzi privati/riservati effettivi (protezione anti DNS-rebinding) su renderer, IBM engine, crawler, snippet e fetch-title
  • Estensione Chrome: confronto della API key a tempo costante (timingSafeEqual), helper condiviso al posto di tre implementazioni duplicate
  • Rate limiting esteso agli endpoint costosi (crawler, chatbot, bonifica PDF) con helper riusabile
  • Security headers HTTP su tutte le risposte (X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, HSTS)
  • Parsing difensivo dell'output AI (guardie su item nulli/non-oggetto, coercizione dei campi)

Qualità e operatività

  • CI GitHub Actions: type-check, test e lint bloccante a ogni push/PR
  • ESLint (flat config + regole jsx-a11y / Next / react-hooks): adozione completa con 0 errori; rimozione di codice morto (funzioni, variabili e import inutilizzati in ~20 file)
  • Logger strutturato JSON con contesto (auditRoundId/componentId) per la diagnosi in produzione
  • Prompt caching sul system prompt del chatbot (riduzione costi e latenza)
  • Listino prezzi modelli AI aggiornato alla tariffazione Claude corrente; allineamento della versione in package.json
  • README di progetto e diagramma ER dello schema database
v1.63.0

Valida Design System — adozione completa interfaccia

Migrazione integrale di tutte le pagine e componenti dal markup Tailwind custom al Valida Design System A11y Edition — token CSS, classi semantiche, paletta navy/leaf/ivory con contrasto WCAG AA garantito.

Layout e pagine

  • Login (LoginClient): split-screen login-shell / login-brand / login-form-col; classi field, input-wrap, btn--accent btn--lg btn--block; brand panel con dark theme accessibile
  • Home / Dashboard (DashboardClient): layout home-summary + home-grid / home-aside; sezioni home-panel per valutazioni attive e feedback; portfolio-row con ConformityBar + punteggi pp-val; collassabile home-libs
  • Nuova valutazione (NuovaValutazioneClient): SelectCards e SettingCards DS; pannelli note-panel con toggle
  • Nuovo progetto (NuovoProgettoClient): fieldset / fieldset--agid, radio/dot, config-card, action-bar; estratto helper getUrlPlaceholder per ridurre complessità ciclomatica
  • Panoramica round (ValutazioneClient): audit-head + meta-pills, tab link-based con usePathname, conf-grid (3 pannelli), coherence panel, effort-row, table-wrap pagine con ConformityBar
  • Consumi (ConsumiClient): grafici a barre CSS-only al posto di Recharts; filter-bar, tabelle breakdown DS; log denso; fix linter (Readonly props, chiavi stabili, nessun role=img)
  • Chatbot (ChatbotClient): layout cbot-* completo — thread ivory, header navy, pulsante send leaf; brand mark ValidaMarkSVG in header, avatar, stato vuoto e launcher; animazione typing dots
  • Storico / Confronta (StoricoClient / ConfrontaClient): vcheck checkbox DS, barre trend-row/tbar, tabelle tbl-*, dialog modale DS; ConfrontaClient ricostruito con KpiCards estratti, cmp-head/cmp-summary/cmp-section; rimosso breadcrumb ridondante

Componenti

  • LibraryCard / LibraryVersionsBlock: ricostruiti con classi lib-item, libs-card-head, libs-grid
  • ProjectSubNav: tab DS .tabs.tabs--pill; aggiunto tab Riepilogo/progetti/[id]; rimossi Tailwind underline-tabs
  • BrowserMatrix: allineamento DS; classe bstatus--div aggiunta a globals.css con contrasto migliorato

Token e CSS globali

  • Palette CSS vars: aggiunta scala completa (--navy-900, --leaf-500, ecc.) a :root in globals.css — fix critico che rendeva trasparenti btn--primary, barre conformità e icone pannello
  • Testo: scala tipografica portata a 16 px base (text-sm → 16px) per edizione accessibilità
  • Animazioni: aggiunte @keyframes spin / pulse; fix vc-check color: transparent su stato non selezionato (contrasto WCAG 1.4.11)
  • Token colore: sostituzione sistematica di tutti i token blue-* Tailwind con navy / leaf DS — FAB, chatbot, cookie policy, ruoli, admin, pagine componenti

v1.62.0

Criteri esclusivi UNI EN 301 549 — visibilità FPS

  • Pannello round summary (ValutazioneClient): nuovo pannello espandibile "Criteri esclusivi — Functional Performance Statements (Cap. 4)" sotto le score card; mostra stato worst-case per criterio 4.2.1–4.2.8 con breakdown per componente espandibile; badge rosso sull'header se presenti criteri non superati
  • Tab dettaglio componente (DettaglioClient): nuovo tab "EN 301 549 esclusivi" accanto a "Criteri WCAG 2.2"; mostra i criteri 4.2.x per il componente con stato, problemi e raccomandazioni; rosso sul tab se presenti non-conformità
  • Bug fix: DettaglioClient scartava silenziosamente i criteri con principle='EN301549' perché non inclusi nel principleOrder array — corretto
  • Utility: src/lib/en301549-utils.ts con filterEnOnly, worstCaseStatus, groupByCode — 12 test vitest

v1.61.0

W3C Validator — display avanzato + fix WCAG H58 BCP47

W3C Validator — pannello grouped per consultazione

  • W3cGroupedPanel (nuovo componente): nella vista consultazione (/dettaglio/) gli issues del validatore W3C sono ora raggruppati per gravità di impatto sull'accessibilità — ARIA non validi (alto), ID duplicati (alto), Lingua non valida (alto), Struttura heading (medio), Elementi sconosciuti (medio), Elementi obsoleti (basso), Avvisi (info). I gruppi ad alta priorità si aprono automaticamente; tutti gli altri partono collassati
  • group-utils.ts: nuove utility pure categorizeW3cIssues(issues) e formatPosition(firstLine, firstColumn) — 16 unit test copertura completa; formatPosition omette "riga 0" quando firstLine === 0
  • W3cValidatorPanel (fix): rimosso il limite fisso a 20 issues — compare il bottone "Mostra tutti gli altri N →"; corretta la visualizzazione della posizione (non mostra più "riga 0" per issues senza riga specifica)
  • Integrazione nel DettaglioClient per i criteri 4.1.1, 4.1.2 e 1.3.1

Fix WCAG H58 — validazione BCP47 lingua

  • checkLanguageOfParts (H58): aggiunta validazione del formato BCP47 sull'attributo lang; codici lingua non validi come lang="frrr" (4 lettere, non ISO 639) vengono ora correttamente segnalati come fallimento con evidenza del codice lingua errato; prima passavano erroneamente il check

Passing Evidence — layout uniforme

  • PassingEvidencePanel: layout allineato al blocco Note — sfondo warm-50, bordo warm-200, badge sorgente con colori getBadgeClass, spaziatura uniforme; fix alle note di revisione del code review
  • getBadgeClass: esportata da formatters.tsx per riuso in PassingEvidencePanel

Fix agentico

  • Live-region agent (4.1.3): prevenuto crash da errore di navigazione Playwright — l'agente continua la valutazione invece di interrompere il round

v1.60.1

Formatter Note block — design uniforme

Formatter — blocco Note

  • formatNotes: nuovo layout uniforme per il blocco Note — stripping dei simboli di stato iniziali (✓ ✗ ⚠ ➖ ✕ e varianti emoji), header di riepilogo [Analisi statica:] reso come lista bullet con text-sm, sotto-blocchi [Altri motori:] come sezioni separate con badge dedicati
  • stripLeadingStatusSymbols: nuova utility (con test) che rimuove i simboli ✓ ✗ ⚠ ➖ ✕ ⚠️ dai valori testuali prima del rendering; supporta sia le varianti bare (U+2717, U+26A0) sia le varianti emoji (U+FE0F)
  • getBadgeClass: estratto da formatters.tsx come helper riutilizzabile; aggiunto badge W3C Validator nel registry
  • parseAltrMotoriBlocks: pattern di split derivato da SOURCE_BADGE_LABELS (fonte unica di verità); filtro null prima di map per robustezza; rimosso flag /s per compatibilità ES2018

Docker

  • sharp: aggiunto PUPPETEER_SKIP_DOWNLOAD=1 nello step di installazione di sharp per evitare download non necessario di Chromium

v1.60.0

UNI EN 301 549 + Layer Best Practice + W3C HTML Validator

Due nuovi layer di conformità affiancano la valutazione WCAG 2.2 AA: il layer normativo UNI EN 301 549 (sempre attivo) e il layer best practice opzionale per round. Integrato anche il validatore W3C Nu HTML Checker come sidecar Docker.

Layer UNI EN 301 549 (sempre attivo)

  • DB schema: tre colonne booleane su wcag_criteriais_wcag22 (default 1), is_en301549 (default 1), is_best_practice (default 0); colonna best_practices_enabled su valutazioni (default 0)
  • Seed: 8 criteri EN-only (4.2.1–4.2.8, Functional Performance Statements) con is_wcag22=0, is_en301549=1; 5 pseudo-criteri best practice (BP.contrast.enhanced, BP.heading.hierarchy, BP.link.descriptive, BP.form.autocomplete, BP.motion.reduced) con is_best_practice=1
  • IBM engine: configurato con policy EN_301_549 (superset di WCAG 2.1 AA + regole EN extra); nuova costante IBM_RULE_TO_BP che mappa le regole IBM a livello RECOMMENDATION ai codici BP.*; evaluateWithIbm restituisce bestPracticeFindings: CriterionEvaluation[] separati dalle violazioni normative
  • Pipeline tecnica: bestPracticesEnabled aggiunto a SettingsLike; i bestPracticeFindings IBM vengono mergiati nel risultato del round solo se il flag è attivo
  • Score utility: nuova funzione buildComplianceScores(results, bestPracticesEnabled) in src/lib/compliance-scores.ts — restituisce { wcag22, en301549, bp? } con contatori (passed / failed / toVerify / na / total / percentage) filtrati per colonna booleana
  • API dashboard: GET /api/dashboard arricchito con il campo complianceScores per ogni round nella risposta (retrocompatibile)
  • Export APIs: parametro opzionale standard: 'WCAG22' | 'EN301549' | 'all' su Excel, DOCX, PDF (default WCAG22 per retrocompatibilità); parametro referencedStandard: 'WCAG22' | 'EN301549' sull'export Allegato 2 AgID per generare la dichiarazione con lo standard corretto

UI — Score duali e badge standard

  • Creazione round (NuovaValutazioneClient): toggle "Includi raccomandazioni qualitative (non normative)" sotto la selezione modalità; nota informativa statica: "La valutazione include sempre WCAG 2.2 AA e UNI EN 301 549"
  • Panoramica round (ValutazioneClient): due score card affiancate — WCAG 2.2 AA e UNI EN 301 549 — con percentuale, passed/failed/toVerify/N/D; terza card opzionale per Best Practice se il flag è attivo
  • Dettaglio componente (ComponenteClient): badge WCAG (blu) e EN (verde) accanto al codice criterio in entrambe le viste (lista e wizard); criteri con is_best_practice=1 esclusi dalla lista normativa e mostrati in sezione separata "Raccomandazioni qualitative" con disclaimer non-normativo
  • Dashboard (DashboardClient): widget conformità mostra sia lo score WCAG 2.2 AA sia EN 301 549 per ogni round

W3C Nu HTML Checker (validatore markup)

  • Sidecar Docker: servizio w3c-validator (ghcr.io/validator/validator) su porta 8888 nel docker-compose.yml
  • DB: colonna w3c_enabled su valutazioni per attivare il controllo per singolo round
  • Engine: src/lib/w3c-engine/index.ts — invia l'HTML al servizio Nu Checker e mappa gli errori/warning ai criteri WCAG pertinenti (4.1.1 Parsing, 4.1.2 Nome/Ruolo/Valore)
  • Pipeline: integrato nello Step 1 (fase tecnica) dopo IBM; attivato solo se w3cEnabled = true nel round
  • UI creazione round: toggle "Includi validazione W3C Nu Checker (markup HTML)" nella form di creazione
  • Dettaglio componente: pannello W3cValidatorPanel nel tab Errori con badge dedicato; colonna "W3C" nell'export Excel

v1.59.1

Design System v1.0 — audit contrasto completo + fix infrastruttura

Conformità WCAG contrasto colori (Design System v1.0)

  • globals.css: --color-success-fg scurito da #3A8224 a #2D641C; aggiunto token --color-border-input: #847B6A; focus ring globale *:focus-visible aggiornato da #5FB237 a #3A8224 (contrasto 3:1 su sfondo bianco)
  • StatusBadge: text-leaf-700 → text-leaf-800 per stato "Superato"; text-warm-600 → text-warm-700 per stato "N/D"
  • EffortBadge: text-leaf-700 → text-leaf-800 per sforzo minimo (livello 1)
  • TopBar: rimossi icone dai voci di navigazione (riduzione ~80 righe); layout nav semplificato
  • ValidaLogo: aggiunto display: block all'SVG; corretti spazi JSX (val{'val'}, da{'da'})
  • Propagazione focus:ring-leaf-500 → focus:ring-leaf-700 e text-leaf-600 → text-leaf-700/800 su tutti i client: ImpostazioniClient, KnowledgeBaseClient, DashboardClient, ConsumiClient, ProfiloClient, EntiClient, ProgettoClient, PanoramicaClient, ValutazioneClient, QualitaClient, NuovaValutazioneClient, NuovoProgettoClient, RtdClient, PdfRemediationClient

Infrastruttura pipeline

  • agenticModel — nuova impostazione agentic_model in evaluate/route.ts e web-evaluation.ts: consente di configurare un modello separato (es. Haiku) per la fase agentica, indipendente dal modello Claude usato per la fase AI standard. Default: claude-haiku-4-5-20251001
  • Deduplicazione upsert in persistence.ts: aggiunta deduplicazione per criterionId prima dell'upsert batch in evaluation_snapshots e audit_results, prevenendo l'errore ON CONFLICT DO UPDATE cannot affect row a second time quando agenti agentic condividono gli stessi criteri

v1.59.0

Expert Feedback — 5 gap implementati (v1.59.0)

Implementazione dei gap identificati dal feedback degli esperti di accessibilità WCAG 2.2.

Motore statico

  • Gap 1input[type="image"]: aggiunto warning quando aria-label è presente ma alt manca (HTML spec compliance); alt="" non triggera warning (immagine decorativa valida)
  • Gap 2 — Tecnica H2_ADJ: nuovo check per link adiacenti con stesso href dove l'immagine ha alt ridondante — suggerisce alt="" per evitare duplicazione del nome accessibile
  • Gap 3a — Tecnica C22: nuovo check statico per CSS inline (color, background-color, border-color) su elementi semantici come potenziale vettore di informazione senza alternativa testuale (1.3.1)

Motore AI

  • Gap 3b — Hint per 1.3.1: Claude verifica CSS inline informativo nel contesto semantico tramite CRITERION_HINTS map in ai-engine/index.ts
  • Gap 4 — Hint per 1.2.4: Claude distingue contenuti live da contenuti registrati e restituisce N/D motivato se non ci sono stream in diretta

UI e report

  • Gap 5a — ComponenteClient: pill "IBM: N occ." nel pannello dettaglio criterio, parsata dal campo notes IBM
  • Gap 5c — Export Excel/PDF/DOCX: campo/colonna "Occorrenze" con conteggio IBM per criterio (IBM: N (X viol., Y pot.))

v1.58.0

Fase agentica v3 — Gruppo C: 3 nuovi agenti Playwright

Completa il motore agentico con i 3 agenti stub del Gruppo C. Tutti i 14 agenti del registry sono ora implementati; makeStub rimosso da index.ts.

  • focus-visible (WCAG 2.4.7 — Focus visibile): confronto before/after su outline-width, outline-color, box-shadow per ogni elemento focusabile (max 30); outcome: true se almeno una proprietà cambia al focus oppure outline-width > 0px dopo il focus; delega valutazione narrativa a Claude
  • hover-focus (WCAG 1.4.13 — Contenuto al focus/hover): verifica i 3 sub-criteri WCAG per ogni elemento trigger ([title], [aria-describedby], [data-tooltip], [data-tippy-content], [aria-expanded="false"]): appeared (DOM node count), hoverable (pointer sul tooltip), persistent (pointer move-out), dismissable (Escape); max 8 trigger per pagina
  • pause-stop-hide (WCAG 2.2.2 — Pausa, stop, nascondi): rileva video autoplay non-muted, audio autoplay, animazioni CSS infinite o > 5s, carousel (.carousel, [data-bs-ride], .swiper, .slick-slider, [data-glide]), marquee/ticker; per ogni elemento risale 3 livelli di parent cercando un controllo pause/stop (keyword: pausa/pause/stop/ferma/nascondi/hide); max 10 elementi per pagina

v1.57.0

Design System v1.0 — propagazione completa (Phase 5 — Round 2)

Completamento della migrazione DS v1.0 alle sezioni rimanenti dell'applicazione: pagine di valutazione, area RTD, impostazioni, knowledge base e tutti i client secondari. Tutte le pagine dell'applicazione usano ora esclusivamente i token navy/warm/leaf/tomato/saffron.

Pagine valutazione e audit (19 file)

  • ValutazioneClient: badge metodologia e browser, sezione coerenza cross-pagina, log viewer, modal eliminazione — tutto su palette DS; ternari orange medium/low semplificati a binario dopo convergenza semantica
  • ComponenteClient: 174 occorrenze migrate — badge categoria IBM, badge sorgente, log level colors, status counters, conformity bar, KB panel, evidenze di conformità
  • QualitaClient: getGulpeaseColor, getClarityColor, STATUS_CONFIG, TYPE_CONFIG, LOG_LEVEL_COLORS, SortableHeader — tutti su DS
  • NuovaValutazioneClient: radio WCAG version, eval mode, browser toggle (peer-checked:bg-navy-700), viewport chips teal→leaf, modal agenti
  • PagineClient: crawler results, type badge PDF/Web, form submit buttons, error/warning states
  • DettaglioClient, ErroriClient, ConfrontaClient (storico), DivergenzeBrowserClient, ReportValutazioneClient, FlashingAnimationPanel

Sezioni app restanti (18 file)

  • HelpValutazioneClient: badge color-map (amber/sky/emerald/rose/slate → DS), CodeBlock, skip link, sidebar navigazione, 120+ sostituzioni gray→warm
  • RtdClient: AgidStatusBadge, KpiCard, StatPill, DeclarationModal, RevisionModal — rose/amber/emerald/violet → DS
  • PdfRemediationClient: STATUS_CONFIG, action buttons Gemini/download, accordion, reading-order confirm
  • ConsumiClient: KPI cards, colonne cache-read/write, type badge chatbot/indexing, tooltip — pink→navy, orange→saffron
  • ValutazioniClient, ImpostazioniClient (con inputCls helper), KbClient (con ConfidenceBadge, TYPE_COLORS)
  • ProfiloClient, UtentiClient, EntiClient, KnowledgeBaseClient, NotificheImpostazioniClient
  • FeedbackClient, EstensioneClient, KbInsightsPanel, AmbitiClient, LoginClient, ImportaClient

v1.56.0

Design System v1.0 — propagazione completa (Phase 5)

Propagazione della palette Valida Design System v1.0 (Navy + Avorio + Leaf) a tutti i componenti condivisi e alle pagine principali dell'applicazione. Completa il ciclo di migrazione avviato con la TopBar e ProgettiClient in v1.54–v1.55.

Componenti badge e UI primitivi

  • StatusBadge: Superato → leaf-50/leaf-700/leaf-300; Non superato → error-bg/error-fg/tomato-500; N/D → warm-100/warm-600/warm-300; Da verificare → warning-bg/warning-fg/saffron-500
  • PriorityBadge: Critico/Alto → tomato-500/saffron-500; Medio → #E8A93C/navy-900; Basso → navy-100/navy-800; default → warm-200/warm-700
  • EffortBadge: S → leaf; M → navy; L → warning hex; XL/XXL → error hex
  • Toast: success → leaf-600; error → #D63E2A; info → navy-900
  • Breadcrumb: testo e separatori migrati da slate a warm/navy
  • ConfirmModal: backdrop navy-900/60; icona warning-bg/fg; pulsanti warm e saffron-500
  • InfoBanner: da sky a navy (#EEF0F4 / navy-700)
  • ProjectSubNav (tab orizzontale): active → navy-900/navy-50; inactive → warm-600/warm-50

Pagine principali

  • DashboardClient: funzione complianceColor migrata da emerald/amber/rose a leaf/saffron/tomato; tutti i badge e controlli aggiornati; pulse indicator leaf-400/500
  • ProgettoClient: 123 sostituzioni — inputClass, labelClass, conformityConfig (CONFORME/PARZIALMENTE/NON/ND), modal eliminazione, metadata pills, radio accent-leaf-600
  • NotificationBell: pannello dark slate → light white/warm; badge contatore tomato-500
  • NotificheClient: lista notifiche dark → white/warm

Utility e formattatori

  • formatters.tsx: tutti i formattatori React migrati — badge severità (ERRORE/AVVISO), badge sorgente (Agentico/Gemini/Claude/Tecniche WCAG), codice blocchi dark → navy-800/900, link WCAG → navy-700, inline code → warm-100/#962819
  • version-compare.ts: badgeClass e badgeDot migrati da emerald/amber/rose/slate a leaf/saffron/tomato/warm

Pagina Changelog

  • Componente src/app/changelog/page.tsx migrato da slate-/blue- alla palette DS: h1–h3 navy-, paragrafi warm-, bullet navy-900, link navy-700/900

v1.55.0

Fase agentica v2 — Gruppi A+B: 7 nuovi agenti Playwright

Estende la fase agentica (v1.54.0) con 7 nuovi agenti specializzati e un refactor architetturale del runner.

Architettura — page-per-agent isolation

  • runActiveAgents riceve ora browser invece di una singola pagina condivisa: per ogni agente viene creata e chiusa una pagina Playwright dedicata, eliminando la state pollution tra agenti che modificano viewport o font-size
  • AgentId esteso da 12 a 14 valori: aggiunti 'reflow' (1.4.10) e 'resize-text' (1.4.4)
  • RawEvidence.notes?: string — nuovo campo opzionale per trasportare dati strutturati (JSON) all'interprete Claude, usato dagli agenti con logica deterministica

Gruppo A — 4 nuovi agenti

  • skip-nav (WCAG 2.4.1 — Salto di blocchi): naviga con Tab, rileva skip link e verifica che l'attivazione sposti il focus nell'area principale
  • label-in-name (WCAG 2.5.3 — Etichetta nel nome): per ogni elemento interattivo verifica che il testo visibile sia sottostringa del nome accessibile; Claude produce la narrazione
  • reflow (WCAG 1.4.10 — Riadattamento): porta il viewport a 320×480 px e rileva overflow orizzontale, testi troncati con ellipsis, elementi fixed che coprono il contenuto
  • error-identification (WCAG 3.3.1/3.3.3 — Identificazione e suggerimento errori): sottomette ogni form senza compilarlo e verifica la presenza di messaggi di errore accessibili (aria-invalid, aria-errormessage, role=alert)

Gruppo B — 3 nuovi agenti

  • focus-order (WCAG 2.4.3 — Ordine del focus): registra la sequenza di focus (fino a 30 Tab) con coordinate Y e delega la valutazione della coerenza logica a Claude
  • on-focus-input (WCAG 3.2.1/3.2.2 — Al focus / All'input): confronta snapshot del contesto pagina (URL, title, dialog count, DOM children) prima e dopo ogni focus/input; soglie conservative per evitare falsi positivi su SPA
  • resize-text (WCAG 1.4.4 — Ridimensionamento del testo): imposta fontSize: 200% e rileva overflow orizzontale di testo, contenitori con altezza fissa che troncano il testo, elementi sovrapposti

Impostazioni

  • La schermata Impostazioni > Motore Agenti lista ora 14 agenti configurabili (11 reali + 3 stub per il futuro Gruppo C)

v1.54.0

Fase agentica v1 — 4 agenti pilota Playwright

Prima implementazione della fase agentica: agenti Playwright che simulano il comportamento reale di un utente con tecnologie assistive, raccogliendo evidenze comportamentali non rilevabili dai motori statici o AI.

Architettura del motore agentico

  • Nuovo modulo src/lib/agentic-engine/ con types.ts (AgentContext, AgentResult, RawEvidence), interpreter.ts (interpretWithClaude), index.ts (AGENT_REGISTRY, runActiveAgents, toEvaluationResult)
  • Ogni agente riceve una pagina Playwright già navigata, raccoglie RawEvidence[] strutturata e delega la valutazione narrativa a Claude tramite interpretWithClaude
  • src/lib/evaluation-pipeline/agentic-phase.ts — step Inngest dedicato; riceve la pagina renderizzata dal Technical step ed esegue gli agenti attivi in sequenza (timeout 10 min)
  • evalMode esteso con routing verso la fase agentica quando agenticEnabled = true nelle impostazioni del progetto

4 agenti pilota

  • keyboard (WCAG 2.1.1 — Funzionalità da tastiera): raccoglie fino a 40 elementi focalizzabili (a, button, input, select, ecc.) e verifica la raggiungibilità da tastiera tramite Tab/Shift-Tab; Claude valuta le evidenze
  • no-trap (WCAG 2.1.2 — Nessuna trappola tastiera): trova fino a 5 trigger modal/popup (aria-haspopup, aria-controls, aria-expanded), apre il componente, preme Escape e verifica che il focus sia uscito dal dialog
  • live-region (WCAG 4.1.3 — Messaggi di stato): rileva fino a 10 elementi aria-live / role=status|alert|log|progressbar, cattura il contenuto prima e dopo un'eventuale sottomissione form adiacente; Claude valuta la correttezza degli annunci
  • aria-state (WCAG 4.1.2 — Nome, ruolo, valore): trova fino a 20 elementi con aria-expanded, aria-checked, aria-selected, aria-pressed, registra i valori prima dell'interazione, fa click, attende 200 ms e confronta

UI e integrazione

  • Impostazioni → Motore Agenti: nuovo pannello per abilitare/disabilitare la fase agentica e selezionare i singoli agenti attivi per progetto
  • Badge sorgente Agentico (viola) in formatters.tsx per distinguere i risultati agentic dagli altri motori
  • Inngest pipeline estesa con step agentic-phase (eseguito dopo Technical, prima di AI e Visual)

Fix — IBM false positive lang

  • Corretto il regex computeHtmlHasValidLang in ibm-engine/index.ts: xml:lang= senza lang= non è più riconosciuto come attributo valido (HTML5 richiede lang=, non xml:lang=)
  • Aggiornati i test in ibm-false-positives.test.ts e static-checks-v147.test.ts per il comportamento corretto

v1.53.0

Miglioramenti display scheda dettaglio criterio e fix pipeline

Problemi — severity badge, accordion e separazione multi-tecnica

  • formatProblems in src/lib/formatters.tsx divide ora le stringhe multi-tecnica sul separatore newline: ogni tecnica è un blocco indipendente con badge colorato severità (ERRORE rosso / AVVISO arancio) estratto dal prefisso [ERRORE] / [AVVISO]
  • Liste di item lunghe (> 10 voci) sono troncate con accordion <details>: il riepilogo mostra i primi 10 elementi e un link "Mostra altri N…" per espandere
  • Tecnica ARIA16_PREF: rimosso dal campo detail per evitare il rilevamento errato come pattern batch
  • Tecnica C27_SEQ: aggiunto domSelector nel campo detail per consentire all'esperto di identificare l'elemento nel DOM
  • Tecnica F89 (link vuoti): aggiunto href nel campo detail per distinguere le decine di violazioni strutturalmente identiche
  • Tecnica C12 (font-size px): rimosso il ; finale dal valore CSS nel campo detail
  • Tecnica 3.1.1 (lingua pagina): aggiunto fallback xml:lang per pagine XHTML che non usano l'attributo lang standard

Note — badge sorgente come pill, pulizia wrapper e footnote statica

  • formatNotes estrae il badge sorgente dal prefisso tra parentesi quadre — reso come pill colorata arrotondata (Tecniche WCAG, Claude, Gemini Vision) invece di testo grezzo tra parentesi
  • Stripping del wrapper esterno [Valutazione automatica (...)]: la notazione interna della fase è nascosta, resta solo il badge sorgente visibile
  • Stripping dei token [Q:N] (punteggio qualità alt text Gemini): non vengono più mostrati come testo grezzo nel campo Note
  • I segmenti [Analisi statica: ...] sono estratti e resi come footnote corsivo/grigio con bordo superiore separatore
  • Le etichette badge abbreviate: "Claude (fase dedicata)""Claude", "Gemini Vision (fase dedicata)""Gemini Vision"
  • Guard note vuote: se dopo aver estratto il badge non rimane contenuto, formatNotes restituisce nullDettaglioClient nasconde l'intera sezione Note invece di mostrare un box vuoto con solo il badge

Tipografia uniforme su tutti e 4 i campi del criterio

  • PassingEvidencePanel: SourceBadge ora usa pill arrotondata (rounded-full) con colori slate/violet, identica ai badge formatNotes
  • EvidenceItem testo detail: text-xstext-sm leading-relaxed (14 px body allineato alle altre sezioni)
  • Spaziatura EvidenceItem: py-2py-2.5, container py-1py-2
  • formatTextAsList e formatProblemItem: aggiunto text-sm esplicito su tutti i rami
  • DettaglioClient — heading sezioni h4 (Problemi, Raccomandazioni, Note): aggiunto text-sm

IBM Equal Access — badge ID regola e filtro falsi positivi

  • parseProblemText in src/lib/formatters.tsx estrae ora il prefisso [snake_case_id] (nome regola IBM come html_lang_exists, skip_main_exists) in un campo ruleId
  • formatProblemItem mostra l'ID regola IBM come badge monospace grigio muto separato dal testo del messaggio — non più incorporato nella stringa
  • technical-phase.ts: le valutazioni IBM con esito Non superato vengono filtrate quando il motore Tecniche WCAG ha già determinato Superato per lo stesso criterio — previene che check IBM su pagina renderizzata (prima dell'idratazione JS) sovrascrivano risultati statici corretti (es. 3.1.1 con lang="it")
  • Aggiunto test src/__tests__/formatters-problem-item.test.ts per verificare l'estrazione del ruleId
  • Rimosso il prefisso ridondante [Gemini Vision] nell'engine Gemini: persistence.ts lo aggiunge già automaticamente

Dashboard — veraPDF: versione robusta per immagini container datate

  • getVeraPdfInstalledVersion() in check-library-versions/route.ts include ora l'header Accept: application/json nella GET /api
  • Validazione del Content-Type prima del parsing JSON: evita SyntaxError su immagini veraPDF REST più vecchie che restituiscono HTML non-JSON all'endpoint /api
  • Campo debug opzionale nella risposta API: espone il motivo esatto del fallimento (HTTP non-200, risposta non-JSON, campo version assente, eccezione) — visibile in DevTools Network senza accesso ai log server
  • La variabile d'ambiente VERAPDF_REST_VERSION (impostata in docker-compose.yml) resta il fallback; l'aggiornamento in produzione richiede docker compose up --build -d

Analisi chatbot — filtro intervallo date inclusivo

  • analyzeChatbotConversations in src/inngest/functions/analyzeChatbot.ts: il filtro lte sulla data di fine usa ora dateTo + 'T23:59:59.999Z' invece del solo dateTo (che corrispondeva a mezzanotte)
  • In precedenza, le sessioni create nel giorno finale dell'intervallo selezionato venivano escluse dal conteggio e dall'analisi

v1.52.1

Fix — Formattazione problemi, deduplicazione snippet e F89/F77 rilevamento link

formatProblems — pattern batch "intestazione — item; item; …"

  • formatProblems in src/lib/formatters.tsx gestisce ora il pattern prodotto dal motore tecniche WCAG: "N link con testo generico — Testo link generico: "…"; Testo link generico: "…"; …"
  • Gli item identici vengono raggruppati con badge ×N (rosso): la lista non mostra duplicati ma la loro frequenza
  • Guard !/<[a-zA-Z]/.test(body): i corpi che contengono HTML grezzo non vengono mai spezzati su ; — il check evita di trattare snippet HTML come lista di item
  • Fix: uso di lastIndexOf(' — ') invece di indexOf per trovare il separatore corretto tra messaggio ed evidenze — le tecniche C12 (font-size px) e simili includono nel messaggio stesso ("27 dichiarazioni — preferire em/rem — item1; item2; …"), causando un split al posto sbagliato
  • Strip del ; finale da ogni item: le dichiarazioni CSS nel campo detail terminano con ; che veniva preservato nell'output
  • Stesso fix in countProblems per il conteggio occorrenze nel badge dell'intestazione riga

Deduplicazione snippet nel report sorgente (techniqueResultsToEvaluations)

  • Snippet nel campo sourceCode venivano mostrati due volte se la stessa evidenza esisteva con e senza prefisso [Riga N] (prodotto da buildSnippet quando sourceCodeLocationInfo è attivo)
  • Fix in wcag-techniques/index.ts: il confronto per deduplicazione ora normalizza il corpo dello snippet rimuovendo ^\[~?Riga\s+\d+\]\s* prima di inserirlo nel Set; viene preservata la versione con prefisso quando disponibile

checkF89EmptyLinks — riduzione falsi positivi su SPA Vue/React

  • I siti Vue/React con navigazione duplicata (desktop + mobile via v-show o conditional rendering) producevano 2× violazioni per ogni link privo di testo accessibile: la stessa ancora era presente due volte nel DOM di Cheerio come nodi distinti
  • Fix: deduplicazione basata su chiave href||outerHTML (spazi normalizzati): solo la prima occorrenza di ogni link strutturalmente identico viene contata come violazione
  • Migliorato il rilevamento aria-hidden: il check usa ora closest('[aria-hidden="true"]') invece di verificare il solo attributo diretto, escludendo correttamente i link annidati in subtree nascosti
  • Aggiunto skip per link con attributo hidden esplicito
  • La risoluzione di aria-labelledby recupera il testo degli elementi referenziati nel DOM invece di verificare solo la presenza dell'attributo

v1.52.0

Storico & Qualità — 4 feature indipendenti

Wizard filter "Da verificare" (UI)

  • Aggiunto toggle a 2 stati nel header del wizard nel pannello componente: Tutti (N) e Da verificare (M)
  • Il filtro si applica alla lista criteri del wizard: in modalità "Da verificare" vengono mostrati solo i criteri con status Da verificare, aggiornando il contatore "Criterio X di Y" e la progress bar
  • Il pulsante "Da verificare" è disabilitato con tooltip quando nessun criterio ha tale status
  • Entrambi i bottoni hanno aria-pressed per accessibilità con screen reader
  • Lo stato del filtro si azzera automaticamente tornando alla vista lista

Punteggio qualità alt text (Gemini Vision)

  • Gemini Vision include ora un punteggio 0–3 nel campo notes per il criterio 1.1.1, con formato [Q:N]:
    • 0 = alt assente o vuoto su immagine significativa
    • 1 = alt generico non descrittivo (es. "logo", "immagine", "banner")
    • 2 = alt presente ma migliorabile
    • 3 = alt eccellente che descrive accuratamente il contenuto informativo
  • Il punteggio è omesso se status = N/D (nessuna immagine trovata)
  • Badge colorato mostrato accanto all'evidenza 1.1.1 nell'UI: rosso / arancio / ambra / verde
  • Funzione parseAltQualityScore in src/lib/alt-quality.ts estrae il punteggio dalle notes; tipo AltQualityScore = 0 | 1 | 2 | 3

Vista aggregata divergenze cross-browser (UI + API)

  • Nuova tab Divergenze nella navigazione di ogni round di valutazione
  • Nuovo endpoint GET /api/ax-tree-divergences?round_id=X: calcola il diff AXTree tra browser per ogni componente del round e restituisce i conteggi per coppia (Chromium↔Firefox, Chromium↔WebKit, Firefox↔WebKit)
  • La pagina /valutazioni/[roundId]/divergenze mostra una tabella compatta con un link diretto al pannello componente per ciascuna riga con divergenze
  • Stato di caricamento skeleton, banner verde se nessuna divergenza, banner rosso in caso di errore di rete
  • Solo i componenti con almeno 1 divergenza totale sono inclusi nella risposta API

Modalità Storico nell'AXTree viewer (UI + API)

  • Nuovo terzo toggle Storico nell'AXTreeVisualizer (accanto a Singolo e Diff ⚡)
  • Visibile solo quando esiste un round precedente con snapshot per lo stesso componente
  • Layout side-by-side: sinistra = round N-1, destra = round corrente (entrambi Chromium; fallback al primo browser disponibile)
  • La colorazione dei nodi riusa il motore diffAXTrees esistente — nodi modificati, aggiunti o rimossi sono evidenziati in entrambi i pannelli
  • Banner ambra con etichette "Round N-1 → Round N"
  • Il pulsante Storico rimane accessibile anche su componenti con un solo browser disponibile
  • Nuovo endpoint GET /api/ax-tree-snapshot/history?round_id=X&component_id=Y: trova il round precedente per lo stesso progetto tramite round_number, restituisce { current, previous, currentLabel, previousLabel }

v1.51.1

Fix — Gemini Vision: falso positivo "Superato" su criterio 1.4.3

Bug 1 — Selettori elemento mai trasmessi a Gemini

  • In visual-phase.ts i selettori degli elementi problematici venivano estratti tramite techniqueResultsToEvaluations(), funzione che non restituisce il campo elementSelectors. Il risultato era che selectorsByCriterion era sempre vuota: Gemini non riceveva mai snippet a livello di elemento e valutava 1.4.3 unicamente dallo screenshot fullpage, dove le singole violazioni di contrasto non sono distinguibili alla scala ridotta
  • Fix: i selettori vengono ora estratti direttamente da techResult.criterionResults[].techniques[].evidence[].element, che li contiene effettivamente

Bug 2 — Gemini force=true sovrascriveva "Non superato" con "Superato"

  • Il risultato "Superato" di Gemini veniva applicato con force=true, sovrascrivendo il "Non superato" della fase tecnica che aveva dati di contrasto misurati via Playwright (getComputedStyle). Gli screenshot dell'evidenza acquisiti durante enrichEvaluations rimanevano in DB, causando la contraddizione nell'UI: stato "Superato" con ritagli di elementi con contrasto insufficiente
  • Fix: i risultati Gemini "Non superato"/"Da verificare" usano force=true (possono aggiungere evidenza visiva anche su criteri già superati); i risultati "Superato" usano force=false (non possono ribaltare un "Non superato" con dati misurati)

Bug 3 — Nessuna passingEvidence da Gemini su criteri superati

  • Quando Gemini dichiarava un criterio "Superato", non veniva generata alcuna passingEvidence. Il pannello evidenze mostrava sempre il messaggio di fallback "valutazione precedente all'aggiornamento", indipendentemente dall'età della valutazione
  • Fix: parseGeminiResponse aggiunge un'entry source: 'ai' con il ragionamento visivo di Gemini per ogni criterio dichiarato "Superato"
  • Il messaggio di fallback nel PassingEvidencePanel è stato corretto rimuovendo l'attribuzione errata "precedente all'aggiornamento"

v1.51.0

Nuovi check — Chiusura gap vs axe/Lighthouse

G18_HOVER — Contrasto in stato hover (1.4.1)

  • Nuovo collettore Playwright collectHoverFocusContrast: individua fino a 10 elementi interattivi (a[href], button, [role="button"]) visibili, li porta in stato hover via page.hover() e misura il contrasto del testo con getComputedStyle
  • Nuovo rendered check checkHoverFocusContrast (tecnica G18_HOVER): segnala fail se uno o più elementi hanno contrasto insufficiente in hover (< 4.5:1 testo normale, < 3:1 testo grande); pass se nessun problema; cannot-tell se i dati non sono disponibili
  • Colma il gap: scanner statici come axe non rilevano variazioni di contrasto negli stati hover/focus (citato nell'articolo davidmello.com)
  • Wiring in runAllRenderedChecks, technique-map.ts (criterio 1.4.1), e collettore in collect-rendered-context.ts

ARIA16_PREF — Preferenza aria-labelledby (1.3.1, advisory)

  • Nuovo static check checkAriaLabelPreference (tecnica ARIA16_PREF): segnala warning (confidence 0.65) quando un elemento interattivo (button, a, input, select, textarea) usa aria-label ma ha già testo visibile interno ≥ 3 caratteri
  • Eccezione: bottoni icon-only (figli solo svg/img) non vengono segnalati — aria-label è l'unica opzione valida in quel caso
  • Motivazione: aria-label non viene tradotto automaticamente e può divergere dal testo visibile; aria-labelledby è preferito dal W3C per riutilizzare il testo DOM
  • Registrato come advisory in technique-map.ts (criterio 1.3.1)

G83_PROX — Prossimità messaggi errore (3.3.1)

  • Nuovo static check checkErrorProximity (tecnica G83_PROX): per ogni campo con aria-errormessage, verifica che l'elemento referenziato sia entro 2 livelli di antenato del campo (fratello diretto, figlio diretto del parent, o figlio diretto del nonno)
  • Segnala fail (confidence 0.85) se il messaggio errore esiste ma è distante nel DOM — condizione non rilevata da checkARIA21 (che verifica solo l'esistenza dell'id)
  • not-applicable se nessun campo usa aria-errormessage; pass se tutti i messaggi sono adiacenti
  • Registrato in technique-map.ts (criterio 3.3.1)

v1.50.0

Nuovi check — Copertura gap WCAG

H44_PH — Placeholder come unica etichetta (3.3.2)

  • Il check H44_PH in checkFormFieldLabels copriva solo input[type="password"] e input[type="search"]. Espanso a tutti i tipi testuali: text, email, tel, url, number, search, password e textarea
  • Rileva i campi che hanno placeholder come unica fonte di nome accessibile (source = placeholder nell'algoritmo W3C) e segnala il problema con evidenza dettagliata
  • Nessun falso positivo su campi con label, aria-label, aria-labelledby o title corretti
  • Tecnica H44_PH registrata in technique-map.ts sotto il criterio 3.3.2

ARIA5_toggle — Stato ARIA dei toggle (4.1.2)

  • Nuovo collettore Playwright collectToggleStateData: individua fino a 8 elementi [aria-pressed] e [role="switch"] visibili, li clicca uno alla volta e verifica che l'attributo ARIA cambi dopo l'interazione
  • Nuovo rendered check checkToggleState (tecnica ARIA5_toggle): segnala fail se uno o più toggle non aggiornano lo stato (aria-pressed / aria-checked) dopo il click; pass se tutti lo aggiornano; not-applicable se non esistono toggle nella pagina
  • Preme Escape dopo ogni click per ripristinare lo stato della pagina (stesso pattern di collectInteractiveSnapshots)
  • Wiring in runAllRenderedChecks e technique-map.ts (criterio 4.1.2)

C29_DM — Contrasto in dark mode (1.4.3, opt-in)

  • Nuova impostazione globale Testa contrasto dark mode (flag dark_mode_contrast) nelle Impostazioni di Valida
  • Quando abilitata, dopo la raccolta ordinaria del contrasto, il renderer emula prefers-color-scheme: dark via page.emulateMedia(), esegue collectContrastData in dark mode e ripristina il tema originale con try/finally
  • I dati dark mode vengono salvati nel campo darkModeContrastData di RenderedContext
  • Nuovo rendered check checkDarkModeContrast (tecnica C29_DM): stessa logica di checkColorContrast ma su darkModeContrastData; restituisce not-applicable se il flag è disabilitato
  • Wiring completo: renderOptions.darkModeContrast passato attraverso renderPage, renderPageMulti, renderPageMultiRemote e i call site di technical-phase.ts
  • Nessuna dipendenza npm aggiuntiva

v1.49.0

Allegato 2 AgID — Modello Ufficiale

  • Riscrittura completa di POST /api/export/agid-report: il generatore usa ora docxtemplater sul template DOCX ufficiale AgID (AGID-Modello-Autovalutazione-Template.docx) anziché costruire il documento da zero con docx
  • Mapping dei risultati WCAG ai segnaposto del template ({s_X_X_X} / {n_X_X_X} per status e note per ogni criterio)
  • Metadata: {prodotto}, {data}, {responsabile}, {campione_web} popolati dai dati del round
  • Criteri EN 301 549 mobile: default Non applicabile (fuori scope web)
  • Import aggiornati al protocollo node: (node:child_process, node:util, node:fs)
  • Dipendenza docx rimossa, sostituita da docxtemplater + pizzip

UI — Pagina Esporta Report

  • Pagina report ridisegnata con card per formato: Allegato 2 AgID riceve bordo blu e badge "Modello Ufficiale AgID", Excel ha badge XLSX verde, Guida alla compilazione ha badge "Generato con AI" viola
  • Icone Lucide per ogni tipo di export (ShieldCheck, FileSpreadsheet, BookOpen)
  • Barra di avanzamento animata durante la generazione
  • Testo disambiguante sotto il titolo ("L'Allegato 2 è il documento richiesto da AgID per la conformità WCAG")

UI — Sezione Coerenza Cross-Pagina

  • La sezione appare anche quando l'analisi è pulita (condizione consistencyPageCount > 0 anziché consistencyIssues.length > 0)
  • Stato "nessuna inconsistenza" con icona verde e conteggio pagine analizzate
  • Pulsante Analizza ora con spinner per triggerare POST /api/consistency/[roundId]/analyze on-demand
  • loadConsistencyIssues restituisce la Promise per concatenazione asincrona corretta

UI — Badge Confidenza nel Wizard Componente

  • Badge ~XX% su ogni criterio con confidence < 0.85 nella vista wizard del componente
  • Colorazione contestuale: giallo (≥ 0.70), rosso (< 0.70)

UI — Score Regressione nel Confronto Round

  • Visualizzazione di weightedDivergenceScore nella card "criteri peggiorati" del confronto tra round (calcolato come somma delle confidence pesate dei nuovi errori)

Help — Sezione AI

  • Aggiunta nota sul context strutturato per criterio: per i criteri AI-only l'HTML grezzo è filtrato ai soli elementi rilevanti con riduzione stimata 60–80% dei token

v1.48.0

Evoluzione A — ARIA Completeness Map

  • Nuovo file aria-spec.ts con ARIA_ROLE_MAP per 19 ruoli ARIA 1.2 (requiredProps, supportedProps, prohibitedProps, requiredContext)
  • Nuovo check checkAriaRoleProps (ARIA5_PROPS): rileva violazioni di prohibitedProps e requiredContext
  • checkCustomControlsState e checkAriaAttributeValidity refactored per usare ARIA_ROLE_MAP

Evoluzione B — Confidence Scoring

  • Campo confidence: number (0.0–1.0, default 1.0) aggiunto a TechniqueResult
  • Helper result() aggiornati in tutti i moduli check con parametro opzionale confidence
  • I 9 check v1.47.0 ricevono confidence esplicita (0.55–0.98)
  • Badge confidence visibile in UI per check con confidence < 0.85
  • Peso confidence integrato in /api/valutazioni/confronta per weightedDivergenceScore

Evoluzione C — Prompt Engineering

  • Nuovo file criterion-context.ts con 7 estrattori per criteri AI-only (media, interactive, motion, navigation, ui-components, form, status)
  • ai-phase.ts usa buildEnrichedPrompt() con context strutturato per criterio — riduzione stimata 60-80% dei token per criteri con estrattore
  • Fallback a HTML completo (8000 char) per criteri senza estrattore

Evoluzione D — Cross-Page Consistency Engine

  • Nuova tabella DB page_snapshots con fingerprint nav/UI/help per ogni pagina valutata
  • snapshot-extractor.ts integrato in technical-phase.ts (fire-and-forget)
  • consistency-phase.ts: check 3.2.3 (nav), 3.2.4 (UI), 3.2.6 (help) cross-pagina
  • Nuovi endpoint: GET /api/consistency/[roundId], POST /api/consistency/[roundId]/analyze
  • Nuova Inngest function consistency-analysis triggerata da round/all-pages-completed
  • UI: sezione "Coerenza Cross-Pagina" nella pagina round

v1.47.0

Refactoring

  • Suddiviso static-checks.ts (1965 righe) in 6 moduli tematici sotto checks/static/: media.ts, links.ts, forms.ts, aria.ts, structure.ts, interactions.ts. Backward-compatible tramite export *.

Nuovi check statici

  • checkVideoCaption (G87) — rileva video senza <track kind="captions|subtitles"> · 1.2.2, 1.2.4
  • checkLinkPurpose (H30_LP) — rileva testo link generico (clicca qui, leggi di più…) · 2.4.4, 2.4.9
  • checkAriaAttributeValidity (ARIA5_VAL) — rileva attributi aria-* non validi o con valore errato · 4.1.2
  • checkCustomControlsState (ARIA4_STATE) — verifica stati ARIA obbligatori su controlli custom (slider, combobox, checkbox, ecc.) · 4.1.2
  • checkBCP47Lang (H57_BCP47) — verifica che lang su <html> e elementi sia BCP47 valido · 3.1.1
  • checkConsistentHelp (G224_HELP) — rileva meccanismi di aiuto (link contatti/FAQ/form supporto) con posizione · 3.2.6

Nuovi check rendered (Playwright)

  • checkMotionActuation (G213_MOT) — rileva listener deviceorientation/devicemotion senza alternativa UI · 2.5.4
  • checkPointerCancellation (G210_PC) — rileva elementi con down-event senza cancel handler · 2.5.2
  • checkFocusManagement (SCR26) — verifica struttura dialog e spostamento focus all'apertura · 2.4.3

Miglioramenti

  • checkFormFieldLabels: rileva password/search con solo placeholder come etichetta
  • collectContrastData: soglia large text corretta — bold 18.67px usa threshold 3.0:1 (non 4.5:1)
  • checkARIA22_F103: rileva possibili messaggi di errore form senza ARIA live region

v1.46.0

Aggiunto

  • 11 nuovi check statici WCAGcheckHeadingHierarchy (G130, criteri 1.3.1/2.4.6): verifica livelli saltati, heading vuoti, h1 multipli; checkDuplicateIds (H93, 4.1.1): ID duplicati su elementi ARIA-referenziati; checkSvgAccessibility (ARIA6_SVG, 1.1.1/4.1.2): SVG senza alternativa testuale; checkAutocompleteValues (H98_VAL, 1.3.5): validità valori autocomplete vs lista WCAG; checkFormFieldLabels (H44_AN, 3.3.2): campi form senza nome accessibile via motore W3C; checkAltTextQuality (F30_Q, 1.1.1): alt generico o nome file; checkAudioVideoAutoplay (F93_AUTO, 1.4.2): autoplay senza muted; checkAriaRolesMisuse (F15_ROLE, 4.1.2): ruoli interattivi senza tabindex; checkPageTitleQuality (H25_Q, 2.4.2): titolo generico o troppo corto; checkG19 esteso con avviso G19_PRM (2.3.1): animazioni infinite senza prefers-reduced-motion nella stylesheet; checkLanguageOfParts (H58_PARTS, 3.1.2): blocchi di testo in script non-Latino (arabo, cinese/giapponese/coreano, cirillico, devanagari, greco, ebraico, thai) privi di attributo lang
  • 6 nuovi check rendered WCAG (Playwright)checkReflow320 (C31, 1.4.10): scroll orizzontale a 320px; checkKeyboardTrap (F10_TRAP, 2.1.2): focus bloccato durante navigazione Tab; checkSkipLinkFunctional (G1_R, 2.4.1): link di salto verificati funzionalmente; checkColorContrast (G18_CR, 1.4.3): rapporto contrasto testo con formula WCAG inline; checkNonTextContrast (G207_CR, 1.4.11): contrasto bordo/sfondo componenti UI; checkMeaningfulSequence (C27_SEQ, 1.3.2): ordine DOM degli elementi interattivi confrontato con ordine visivo misurato a runtime
  • Soppressione falsi positivi IBMaria_label_misuse su elementi landmark e input_label_exists quando aria-labelledby è già presente vengono filtrati prima della fusione dei risultati

Tecnico

  • Aggiunte interfacce TypeScript SequenceIssue, SequenceData, ReflowData, KeyboardTrapData, SkipLinkData, ContrastItem, NonTextContrastItem in types.ts con relativi campi in RenderedContext
  • 9 nuovi collettori Playwright in collect-rendered-context.ts: contrasto testo, contrasto non-testuale e ordine sequenza in parallelo; reflow, keyboard trap e skip link in sequenziale (modificano stato pagina)
  • Test suite estesa da 247 a 256 test (29 file)

v1.45.0

Aggiunto

  • G19 — rilevamento animazioni rapide per il criterio 2.3.1 (Three Flashes) — il checker checkG19 è stato riscritto per estrarre ogni regola CSS con animation o animation-duration dalla pagina e produrre un'evidence strutturata per ogni selettore con durata < 300 ms; ogni elemento dell'evidence contiene il selettore CSS, il nome dell'animazione, la durata in ms e il frammento di regola CSS originale; accanto alla fase statica (Cheerio), la fase di rendering Playwright raccoglie con collectFlashingAnimations gli elementi DOM effettivamente animati al momento del caricamento (fino a 500 elementi visibili) — il risultato è serializzato come JSON nel campo sourceCode del criterio 2.3.1 tramite patchG19SourceCode, che muta l'array di valutazioni in-place dopo techniqueResultsToEvaluations; gli elementi DOM sono marcati con prefisso [DOM] per distinguerli dagli item statici
  • FlashingAnimationPanel — pannello UI con card espandibili per il criterio 2.3.1 — nuovo componente FlashingAnimationPanel in ComponenteClient.tsx: mostra una card espandibile per ogni animazione rapida rilevata; l'intestazione visualizza il selettore CSS dell'animazione (o il selettore DOM se la regola CSS non è disponibile), un badge con la durata in ms e, su una seconda riga, il selettore DOM dell'elemento renderizzato corrispondente; espandendo la card è possibile leggere la regola CSS originale e il tag HTML dell'elemento; le card CSS e DOM vengono fuse per nome di animazione quando quest'ultimo è diverso da unknown; il pannello è visibile solo per il criterio 2.3.1 e si nasconde automaticamente quando non ci sono evidenze

v1.44.0

Corretto

  • KB — campo "Note" non finisce più in "Ragionamento esperto" — risolto il bug per cui, alimentando la Knowledge Base dalla pagina di valutazione di un criterio, il contenuto del campo "Note" veniva erroneamente scritto nel campo expert_reasoning (visualizzato come "Ragionamento esperto" nella KB); causa: in learnFromCorrections la costante expertReasoning era assegnata da correction.finalNotes || correction.finalProblems, quindi il testo libero delle note di valutazione finiva nel ragionamento KB; fix: expertReasoning viene ora popolato solo da un valore esplicitamente fornito dall'esperto (correction.expertReasoning), altrimenti rimane null; corretto anche l'ordine di priorità in buildRuleDescription che ora preferisce finalProblems a finalNotes per il campo "Motivazione esperto"
  • API PUT /api/results/[id]expertReasoning estratto prima del salvataggio DB — il campo non è una colonna di audit_results; viene ora separato dal body prima dell'UPDATE e passato direttamente a learnFromSingleResult, evitando errori Drizzle su colonne sconosciute

Aggiunto

  • Campo "Ragionamento esperto per KB" nella pagina di valutazione — nuovo campo opzionale con stile emerald (visivamente distinto dal campo "Note") disponibile in entrambe le view (wizard e lista) della pagina componente (ComponenteClient.tsx); quando l'esperto corregge lo stato di un criterio può compilare separatamente il ragionamento — che verrà salvato nella KB come expert_reasoning — e le note di valutazione, che rimangono nel risultato di audit; il campo mostra un helper text esplicativo e viene inviato all'API solo al salvataggio, senza essere scritto nella tabella audit_results

v1.43.0

Aggiunto

  • H24 — checker statico per <area> image map senza alt — implementata la tecnica WCAG H24 in src/lib/wcag-techniques/checks/static-checks.ts (checkH24_AreaAlt): verifica che ogni elemento <area href> in una image map abbia un attributo alt descrittivo (non assente e non vuoto); gli elementi <area> privi di href sono ignorati in quanto non interattivi; quando la pagina non contiene alcuna image map il checker restituisce not-applicable coerentemente con gli altri checker statici; aggiunto a runAllStaticChecks e mappato ai criteri 1.1.1 e 2.4.4 in technique-map.ts; copertura test: 6 casi (pass, fail-alt-mancante, fail-alt-vuoto, no-href, nessuna-image-map, violazioni-multiple)
  • TextSpacingPanel — verifica visiva WCAG 1.4.12 — nuovo componente src/components/evaluation/TextSpacingPanel.tsx che affianca il checker statico checkC8_C21_TextSpacing con uno strumento di verifica interattiva per il criterio 1.4.12 (Spaziatura del testo); il pannello è mostrato inline nella pagina del componente per i risultati Non superato / Da verificare di 1.4.12 (solo componenti web, non PDF); funzionalità: toggle che applica i quattro valori minimi WCAG (line-height 1.5, letter-spacing 0.12em, word-spacing 0.16em, margin-bottom 2em) su testo demo locale; pulsante "Copia bookmarklet" che copia un JavaScript pronto all'uso per iniettare/rimuovere il CSS di test nella pagina reale (gestisce shadow DOM e iframe); cleanup corretto del timeout su smontaggio del componente tramite useRef

v1.42.0

Aggiunto

  • Motore Accessible Name — cascata W3C accname-1.1 a 9 passi — nuovo modulo src/lib/wcag-techniques/accessible-name.ts che implementa computeAccessibleName e analyzeAccessibleName: calcola il nome accessibile di un elemento HTML seguendo la specifica W3C Accessible Name and Description Computation 1.1 con traccia diagnostica passo-passo (1. aria-labelledby, 2. aria-label, 3. input[value], 4. label[for], 5. label ancestor, 6. legend, 7. title, 8. placeholder, 9. testo visibile); ogni passo restituisce { step, source, value, pass } per consentire la visualizzazione della traccia nell'UI; il modulo è condiviso da tutti i checker che necessitano di calcolo del nome accessibile
  • Criterio 2.5.3 — estensione con F111 e F96 — il check per "Etichetta nel nome" ora valuta due failure WCAG distinti: F111 (nome accessibile completamente assente su controllo interattivo) e F96 (nome accessibile presente ma non contenente il testo visibile dell'etichetta); entrambi usano analyzeAccessibleName per la diagnosi; l'evidence WCAG è arricchita con il campo nameTrace contenente la traccia completa della cascata di calcolo
  • Sectioning checker — verifica label su landmark multipli (1.3.1) — nuovo checker in src/lib/a11y-engine/checkers/sectioning.ts che verifica la presenza di label distinti quando lo stesso tipo di landmark compare più volte nella pagina; la prima versione gestisce section e form (con aria-label o aria-labelledby); esteso successivamente a nav, aside, header, footer quando presenti in numero > 1; integrato nel motore statico e mappato al criterio 1.3.1
  • Structural Map extractor — nuovo modulo src/lib/a11y-engine/structural-map.ts che estrae due mappe dalla pagina: Landmark Map (conteggio e stato label per ogni tipo di landmark HTML5: main, nav, header, footer, aside, section, form) e Role ARIA Map (lista elementi con role esplicito, con accessibleName e nameSource calcolati via computeAccessibleName); endpoint GET /api/components/[id]/structural-map servito da src/app/api/components/[id]/structural-map/route.ts
  • StructuralMapPanel — pannello UI mappa strutturale — nuovo componente src/components/evaluation/StructuralMapPanel.tsx caricato on-demand nella pagina componente: presenta la Landmark Map in formato tabella con conteggio e indicatore has_label; presenta la Role ARIA Map con colonna Nome accessibile che mostra il valore calcolato e un badge colorato per la sorgente (aria-labelledby, aria-label, label, title, placeholder, testo visibile); integrato in ComponenteClient.tsx
  • NameTraceCard — traccia visiva del calcolo del nome accessibile — nuovo componente src/components/evaluation/NameTraceCard.tsx che mostra la traccia diagnostica completa per ogni controllo interattivo con violazione 2.5.3: fino a 10 controlli per pagina, ciascuno con la lista dei 9 passi della cascata con indicatori pass/fail e il valore trovato; dati forniti dal nuovo endpoint GET /api/components/[id]/name-analysis; integrato nella vista del risultato 2.5.3 in ComponenteClient.tsx per criterion F111 e F96
  • ARIA checker — refactoring su computeAccessibleName centralizzato — il checker in src/lib/a11y-engine/checkers/aria.ts è stato refactorizzato per usare il modulo condiviso accessible-name.ts al posto della logica di calcolo del nome duplicata; eliminata la dipendenza dalla logica inline; tutti i test del checker passano dopo il refactoring

v1.41.0

Corretto

  • PDF Remediation — storage migrato su MinIO — i file PDF caricati vengono ora archiviati su MinIO (prefisso pdfs/) anziché sul filesystem locale del container Docker; risolve gli errori ENOENT in produzione causati dalla perdita del volume a11y_data durante i rebuild. La funzione resolvePdfBuffer gestisce la retrocompatibilità con i path legacy già presenti in DB
  • PDF Remediation — errore JSON.parse su risposta vuota — rimosso il campo created_at dall'INSERT (usa il DEFAULT now() della colonna); applied_at ora viene impostato con NOW() SQL; aggiunto try/catch globale nel POST handler per garantire sempre una risposta JSON valida anche in caso di eccezione non gestita
  • PDF Remediation — analisi post-bonifica usa il PDF corretto — dopo l'applicazione delle correzioni, il campo file_path del componente viene aggiornato al PDF bonificato su MinIO; le valutazioni successive leggono automaticamente la versione corretta senza richiedere un re-upload manuale

Migliorato

  • Breadcrumb pagina Remediation PDF — il filo d'Arianna mostra ora la gerarchia completa: Home > Progetti > [nome progetto] > Valutazione #N > [nome componente] > Remediation PDF, con link cliccabili per ogni livello; l'API GET /api/components/[id] è stata arricchita con LEFT JOIN su valutazioni e projects per fornire il contesto necessario
  • Pulsante "Correggi" — rinominato il pulsante "Remediation" nella tabella dei componenti in "Correggi" per uniformità con l'interfaccia in italiano

v1.40.0

Migliorato

  • Qualità codice — remediation SonarQube 174 issue, rating affidabilità A (1.0) — sistemazione sistematica di tutte le issue di affidabilità software rilevate dalla nuova tassonomia SonarQube (dual taxonomy), portando il rating da B (2.0) ad A (1.0) con zero issue residue:
    • S6671 — Promise rejection con tipo unknown (6 issue): tutti i catch(e) nei handler di rejection ora wrappano il valore in new Error(String(e)) garantendo type safety e logging corretto degli errori
    • S6843 — Ruolo ARIA ridondante (4 issue): rimossi i role="cell" espliciti da elementi <td> che già possiedono il ruolo implicito di cella secondo le specifiche ARIA
    • S6842 — Listbox su elemento non interattivo (1 issue): rifatto il pattern listbox in HelpValutazioneClient da struttura ul/li a div/div per eliminare il conflitto con la semantica nativa di lista HTML
    • S6845 — Regione scrollabile non accessibile da tastiera (2 issue): aggiunti role="region" e tabIndex ai div scrollabili in ConfrontaClient per renderli navigabili da tastiera
    • S6853 — Label form senza testo accessibile (9 issue): aggiunti attributi aria-label e pattern sr-only nelle label con markup complesso annidato in ImpostazioniClient, NuovaValutazioneClient e PagineClient; il pattern sr-only fornisce il testo accessibile direttamente nel DOM mentre il contenuto visivo viene marcato aria-hidden="true" per evitare duplicazioni da parte dei lettori di schermo
    • S6772 — Spazio ambiguo tra elementi JSX inline (46 issue): aggiunte espressioni {' '} esplicite in 17 file di componenti React per garantire la corretta spaziatura nel rendering (senza {' '}, React può collassare gli spazi tra un tag di chiusura e il testo successivo, causando parole unite)
    • S7781 — Flag /g ridondante in replaceAll() (56 issue): il metodo replaceAll() sostituisce per definizione tutte le occorrenze; convertite le regex con flag globale a stringhe letterali per pattern semplici (es. '&amp;', '-') e a template String.raw per sequenze di escape complesse (backslash, virgolette, parentesi) in 7 file; una chiamata .replace(/pattern/g, ...) convertita nel corretto .replaceAll()
  • Documentazione infrastruttura tecnica — aggiornato docs/tech_stack_infrastructure.md riallineandolo alle versioni da v1.22.0 a v1.38.0: tutte le nuove funzionalità (effort engine, CSS probe, chatbot analytics, PDF remediation estesa, dashboard live, estensione Chrome, galleria screenshot, AX-Tree, cross-browser testing) ora documentate con versione di introduzione

v1.39.0

Aggiunto

  • CSS Probe — analisi criteri CSS con JavaScript disabilitato — nuovo modulo src/lib/renderer/css-probe.ts che valuta i criteri WCAG dipendenti dal CSS su componenti con renderJs = false: durante la pipeline tecnica viene eseguito automaticamente un secondo rendering con CSS preservato e JavaScript disabilitato; i 10 criteri valutabili via CSS (focus style, target size, link stile, orientamento, hover/focus content, text spacing) vengono analizzati e il risultato integrato nella fase tecnica con failure cache in memoria (TTL 10 minuti) per evitare probe ripetuti; il nuovo endpoint POST /api/evaluate/css-probe consente analisi on-demand con retry manuale che bypassa intenzionalmente la failure cache automatica, permettendo all'utente di ritentare sempre
  • CssProbeCard — widget UI per il CSS probe — nuovo componente CssProbeCard.tsx nella vista componente: mostra lo stato del probe (non eseguito / in esecuzione / risultati / errore) con quattro stati espliciti, ARIA live region per annunci screen reader, AbortController per cancellare richieste in volo su smontaggio del componente, pulizia del timeout tramite useRef per prevenire memory leak e errori su componenti smontati; visibile solo per i componenti con renderJs = false che hanno criteri CSS applicabili

Corretto

  • Bug MAJOR — precedenza operatori nel filtro suggerimenti AI — in QualitaClient.tsx la logica di filtro usava ?? 0 > 0 invece di (?? 0) > 0; per le regole di precedenza JavaScript, > si lega più strettamente di ??, portando al confronto 0 > 0 (sempre falso) anziché confrontare la lunghezza con zero; corretto aggiungendo le parentesi necessarie, specularmente al pattern corretto già presente nella riga immediatamente superiore
  • Accessibilità tastiera — 22 elementi interattivi senza handler keyboard (S1082) — 22 elementi con onClick in 15 file erano privi dell'equivalente onKeyDown, escludendo gli utenti che navigano da tastiera; aggiunta gestione Enter/Space per controlli primari (accordion, pannelli screenshot) e Escape per overlay/backdrop con aria-hidden="true" per rimuoverli dall'albero di accessibilità senza interrompere il flusso di navigazione; i file corretti includono ConfirmModal, NotificationBell, VisualComparisonTool, ScreenshotGallery, ScreenshotLightbox, TraversaliPanel, EntiClient, StoricoClient, ProgettiClient, ProgettoClient, ValutazioneClient, QualitaClient, RtdClient, ValutazioniClient, TopBar

v1.38.0

Corretto

  • Numerazione round duplicata — la creazione di una nuova valutazione usava existing.length + 1 come numero di round; se un round veniva eliminato il conteggio scendeva e il round successivo riceveva un numero già in uso. Il calcolo usa ora MAX(round_number) + 1, immune alle eliminazioni e alle race condition. Corretta anche la riga in DB con round_number duplicato (round 8 → 9 per il progetto AlphaGov).

Migliorato

  • Ordinamento valutazioni nel progetto — la lista delle valutazioni in /progetti/[id] è ora restituita dall'API con ordinamento data DESC, id DESC: i round più recenti (o quelli avviati per ultimi nella stessa giornata) appaiono in cima. L'ordinamento interattivo per colonna rimane disponibile nella UI.

v1.37.0

Aggiunto

  • Stima effort di correzione accessibilità (Fasi 1–3) — ogni violazione WCAG 2.2 riceve ora una stima dell'effort necessario alla correzione, su scala T-shirt (S/M/L/XL/XXL) con punteggio numerico 1–5 in DB:
    • Fase 1 — Mapping statico — dizionario WCAG_EFFORT_MAP in src/lib/effort-engine/effort-map.ts mappa 56 criteri WCAG 2.2 al loro effort base; i punteggi vengono calcolati e salvati in effort_static al termine di ogni pipeline tecnica, in modo non bloccante (fire-and-forget)
    • Fase 2 — Analisi AI on-demand — nuovo endpoint POST /api/results/[id]/effort-ai che invoca Claude (modello configurato in app_settings) con il criterio, la descrizione del problema e lo snippet HTML; restituisce { score, label, reasoning } e salva il reasoning in effort_ai_reasoning; il punteggio statico non viene mai sovrascritto
    • Fase 3 — UI badge e controlli — componente EffortBadge (S/M/L/XL/XXL, colori emerald/sky/amber/orange/red) con icona ✏ per override manuale e ✦ per stima AI; il badge appare nella riga di ogni criterio Non superato / Da verificare; nella vista espansa compare il pannello "Stima Effort di Correzione" con stima statica, pulsante "Analizza con AI" (spinner + accept/ignore), select per override manuale con salvataggio dedicato e pulsante "Ripristina auto"
    • Aggregazione per componente — pill ⊕ N pt · XL nell'header dei contatori di ComponenteClient, visibile quando almeno un criterio ha un punteggio; formula: somma dei punteggi effettivi (override ?? static) con conversione totale → label (≤3: S, 4–7: M, 8–12: L, 13–20: XL, >20: XXL)
    • Aggregazione per round — card "Effort Totale Stimato" in ValutazioneClient con punti totali, badge aggregato e conteggio componenti/criteri coinvolti; visibile solo quando almeno un criterio ha un punteggio
    • Schema DB — tre nuove colonne nullable in valutazione_results: effort_static INTEGER, effort_override INTEGER, effort_ai_reasoning TEXT; aggiunte via migrazione ALTER TABLE … ADD COLUMN IF NOT EXISTS non distruttiva
    • API estesaGET /api/results restituisce i campi effort; PUT /api/results/[id] accetta e valida effortOverride (intero 1–5 o null)

v1.36.0

Aggiunto

  • Dashboard home — monitoraggio live — nuova sezione nella home che mostra in tempo reale le valutazioni in corso (polling ogni 5 s via /api/dashboard/live): per ogni round attivo vengono visualizzati progetto, URL, percentuale di completamento e motori attivi; la sezione scompare automaticamente quando non ci sono valutazioni in esecuzione
  • Dashboard home — feedback recenti — blocco che elenca gli ultimi feedback degli utenti con data, progetto e messaggio; alimentato dall'endpoint /api/dashboard/live già presente per il monitoraggio live
  • Dashboard home — stato librerie — badge che indicano la versione installata di IBM Equal Access e veraPDF rispetto all'ultima disponibile; la verifica avviene tramite /api/dashboard/check-library-versions con logica compareVersions per distinguere aggiornata/obsoleta/sconosciuta
  • Analisi conversazioni chatbot — pagina amministrativa /admin/chatbot con metriche aggregate (totale sessioni, messaggi medi, argomenti più discussi, lacune nella KB, ora di picco) calcolate su un intervallo temporale selezionabile; i dati vengono prodotti da analyzeChatbotConversations (funzione Inngest schedulata) e salvati nella tabella chatbot_analysis_snapshots
  • Endpoint /api/chatbot/analyze — GET per leggere l'ultimo snapshot di analisi, POST per avviare un'analisi manuale ad hoc sull'intervallo specificato
  • PDF Remediation — tipo estesoRemediationProposal ora include i campi headings (array di HeadingFix con objectId, livello 1–6 e testo) e languageTags (array di LanguageTagFix con objectId e codice BCP-47); il prompt AI è stato aggiornato di conseguenza e parseRemediationJson è stata esportata con validazione dei livelli
  • PDF Remediation — contatori violazioni — le colonne violations_before e violations_after tracciano le violazioni veraPDF prima e dopo la bonifica; dopo l'applicazione delle correzioni (endpoint /api/pdf-remediation/[taskId]/apply) viene eseguita automaticamente una seconda validazione veraPDF sul file prodotto per popolare violations_after
  • PDF Remediation — analisi ordine di lettura — endpoint POST /api/pdf-remediation/reading-order che renderizza la prima pagina del PDF come immagine PNG (tramite pdfjs-dist + canvas) e, opzionalmente, interroga Gemini Vision per suggerire l'ordine di lettura corretto degli elementi
  • PDF Remediation — cronologia task — il GET /api/pdf-remediation?history=true restituisce gli ultimi 10 task di un componente con stato, date e contatori di violazioni per tenere traccia dell'evoluzione nel tempo

Migliorato

  • PDF Remediation — UI accordion — il pannello di bonifica è stato ristrutturato con sezioni accordion collassabili (Metadati, Testi alternativi, Intestazioni, Tag lingua, Ordine di lettura); la sezione Ordine di lettura appare solo quando le violazioni contengono la clausola 09-003 o la parola chiave "reading order"
  • PDF Remediation — score before/after — quando disponibili, vengono mostrati i contatori di violazioni prima e dopo la bonifica con la riduzione percentuale calcolata
  • PDF Remediation — sezione storico — se esistono task precedenti per il componente, viene visualizzato uno storico collassabile con stato, data e variazione delle violazioni per ogni esecuzione passata

v1.35.0

Migliorato

  • Qualità del codice — remediation SonarQube (~355 issue, 104 file) — applicata la correzione sistematica di sei categorie di violazioni individuate da SonarQube:
    • S6759 — Readonly props (81 issue): tutte le firme di componenti React ora ricevono le props avvolte con Readonly<>, prevenendo mutazioni accidentali in fase di rendering
    • S7773 — Globale numerico (70 issue): sostituiti parseInt, parseFloat e isNaN globali con i metodi del namespace Number (Number.parseInt, Number.parseFloat, Number.isNaN), eliminando ambiguità di tipo in coerenza con le linee guida ES2015+
    • S6594 — RegExp matching (47 issue): convertiti i metodi String.match() in chiamate al metodo test o al metodo corrispondente di RegExp dove la semantica lo consente (escluse le regex con flag /g che richiedono il comportamento "find-all")
    • S7764 — globalThis (45 issue): uniformato il riferimento all'oggetto globale da window/global a globalThis, garantendo compatibilità in ambienti Node, browser e worker senza guard typeof
    • S1128 — Import inutilizzati (14 file): rimossi tutti gli import di tipo e valore che TypeScript non utilizza, riducendo il bundle e il rumore nelle revisioni
    • S4325 — Type assertion ridondanti (~10 casi): rimossi i cast as X che non modificano il tipo effettivo dell'espressione
    • S7735 — Condizioni negate (48 issue): invertite le condizioni nei costrutti if (!x) { A } else { B } e !x ? A : B in modo che il ramo positivo appaia per primo; le catene di sort con !an/!bn riscritte in forma positiva eliminando anche l'assegnazione ridondante a 0

v1.34.0

Aggiunto

  • Navigazione a tab Storico/Panoramica — le pagine /storico e /panoramica di un progetto erano isolate: una volta entrati non era possibile passare all'altra senza tornare alla pagina progetto; aggiunto il componente ProjectSubNav (tab strip con usePathname() per evidenziare il tab attivo) integrato sia in StoricoClient sia in PanoramicaClient; il tab attivo è evidenziato con bordo blu inferiore, sfondo blue-50 e aria-current="page" per accessibilità
  • Route /panoramica (rinomina da /dashboard) — la sub-route del progetto si chiamava /dashboard ma il tab label era già "Panoramica"; creata la route /progetti/[id]/panoramica con PanoramicaClient.tsx; il vecchio percorso /dashboard rimane invariato per retrocompatibilità
  • "Notifica Valutatore" spostato nel header CTA — il pulsante "Notifica Valutatore" era nella sezione navigazione in fondo ai KPI; spostato nella riga del breadcrumb accanto a "Nuova valutazione" (visibile solo agli utenti con ruolo RTD/admin quando declarationUrl è configurato), rendendolo immediatamente accessibile senza scorrimento

v1.33.0

Corretto

  • Home — heading "Dashboard" rinominato "Home" — la pagina principale mostrava il titolo H1 "Dashboard" mentre il link nella barra di navigazione e i breadcrumb delle pagine interne usavano già "Home"; rinominato l'heading in DashboardClient.tsx e il metadata title in page.tsx per eliminare l'incoerenza terminologica segnalata nell'analisi euristica PVA (osservazione #5): "La 'Dashboard' generale diventa 'Home' nel filo di Arianna — userei lo stesso termine"
  • Nuovo progetto — InfoBanner aggiunto — il form di creazione progetto mancava del messaggio informativo iniziale presente negli altri form (es. Importa Excel); aggiunto InfoBanner AGID-style (bordo sinistro azzurro, icona ℹ) che indica all'utente i campi obbligatori contrassegnati con asterisco rosso, in linea con l'osservazione PVA #3 sull'uniformità dei messaggi informativi
  • Nuovo progetto — pulsante "Crea progetto" disabilitato fino a compilazione campi obbligatori — il pulsante era sempre attivo (disabled={saving} durante il solo salvataggio), permettendo il submit senza "Nome del sito / progetto"; aggiunto !name.trim() (e isMobile && !sistemaOperativo per i progetti mobile) alla condizione disabled, rendendo il comportamento coerente con l'osservazione PVA #10: "il pulsante non si attiva fino a quando l'utente non inserisce i dati obbligatori"

v1.32.0

Corretto

  • FAB chatbot — sovrapposizione sul contenuto eliminata — il pulsante flotante del chatbot (posizionato fixed bottom-6 right-6, larghezza 52 px + offset 24 px = 76 px dal bordo destro) si sovrapponeva visivamente a card dashboard, badge errori e link "Elimina pagine" perché <main> usava lg:px-8 (32 px su entrambi i lati); modificato src/app/layout.tsx: padding destro aumentato a lg:pr-20 (80 px) per liberare la colonna FAB e aggiunto pb-20 (80 px) per evitare che il FAB copra il contenuto nella parte inferiore della pagina
  • /chatbot — pagina 404 sostituita con redirect — l'URL /chatbot restituiva 404 se navigato direttamente dall'utente o dai bookmark; aggiunto src/app/chatbot/page.tsx che esegue redirect('/admin/knowledge-base') via Next.js server component
  • BrowserMatrix — stato vuoto quando scansione single-browser — quando effectiveBrowsers.length < 2 il componente BrowserMatrix restituiva null silenziosamente; l'accordion "Matrice Cross-Browser" si apriva mostrando uno spazio vuoto; aggiunto fallback testuale in ComponenteClient ("Nessuna divergenza rilevata tra browser — la scansione ha usato un solo motore di rendering") visibile solo quando il pannello è espanso e il numero di browser è inferiore a due
  • KB Insights — distribuzione confidence mostra tutti i 5 bucket — la query SQL usava GROUP BY bucket con CASE/WHEN, escludendo automaticamente i bucket senza entry (nessuna riga per count = 0); riscritta come CTE WITH buckets(bucket, lo, hi) AS (VALUES ...) con LEFT JOIN su knowledge_entries, garantendo che tutti i bucket da "0.5–0.6" a "0.9–1.0" siano sempre restituiti anche quando vuoti

v1.31.0

Aggiunto

  • Estensione Chrome — interfaccia popup ridisegnata — layout completamente rinnovato con design system Valida (colori primari blu/slate, tipografia Inter, bordi e shadow coerenti con l'app web); status badge reso accessibile con elemento <span> semantico e ruolo esplicito; header con logo SVG ufficiale Valida; sezione "Come usare" con step numerati e icone; form di configurazione API key con helper text e indicatore di sicurezza; bottoni con stati hover/active/disabled espliciti; footer con link alla documentazione
  • Estensione Chrome — icone ufficiali — generate le icone icon16.png, icon48.png, icon128.png dal logo SVG Valida e aggiunte in chrome-extension/icons/; aggiornato manifest.json con i riferimenti corretti
  • Estensione Chrome — script di packaging — aggiunto chrome-extension/pack.sh per generare valida-extension.zip pulito (esclude .sh, .DS_Store, sorgenti SVG), pronto per Chrome Web Store

Corretto

  • Documentazione guida valutazione — nome prodotto e motore browserHelpValutazioneClient.tsx riportava il nome legacy del prodotto e citava Puppeteer come motore di rendering; aggiornato il nome a "Valida" e corretta la documentazione tecnica per riflettere l'uso di Playwright (Chromium/Firefox/WebKit) invece di Puppeteer

v1.30.0

Corretto

  • Qualità — JSON grezzo a video / suggerimenti vuoti (fix definitivo a monte) — la causa radice del double-wrap ricorrente (Gemini inseriva l'intera risposta JSON come stringa dentro paragraphSuggestions) era l'assenza di JSON mode: aggiunto responseMimeType: "application/json" con responseSchema esplicito (clarityScore, issues[], paragraphSuggestions[]) in callGemini; Gemini è ora costretto a produrre JSON strutturato senza wrapping o markdown fence; aumentato maxOutputTokens da 2500 a 4096 per eliminare anche il troncamento che rendeva invalido il JSON interno; nel backend parseAiJson il fence-stripping prima del check { è stato mantenuto come safety net; nel frontend normalizeParagraphSuggestions aggiunto cortocircuito [] per stringhe {-starting (JSON di oggetto), impedendo che JSON grezzo diventi una lista di bullet in qualsiasi futuro edge case

v1.29.0

Aggiunto

  • Scoring WCAG pesato per livello — il calcolo della percentuale di conformità nella dashboard (singolo progetto e vista globale) ora applica i pesi WCAG (livello A = 3, AA = 2, AAA = 1); il denominatore è la somma ponderata dei criteri applicabili, il numeratore la somma ponderata dei criteri superati; le violazioni di livello A hanno quindi impatto triplo rispetto al livello AAA; aggiornati src/app/api/dashboard/project/[id]/route.ts (via SQL aggregation con CASE wc.level) e src/app/api/dashboard/route.ts (via Drizzle join con wcagCriteria e reduce lato TypeScript)
  • Badge occorrenze su criteri con problemi — nella pagina di dettaglio del componente (DettaglioClient) ogni criterio che presenta problemi rilevati mostra ora un badge pill rosso ({n} occorrenze) accanto al badge di stato; il conteggio è calcolato da countProblems() in formatters.tsx che replica la logica di parsing di formatTextAsList (bullet list → liste numerate → split tag motore → multilinea) restituendo un numero invece di ReactNode
  • Guida metodologica aggiornata — nuova sezione "Evidence Layer e Conformità Trasversale" con documentazione di Passing Evidence, storage asincrono screenshot su MinIO e gestione Problemi Trasversali; accordion "Knowledge Base injection" esteso con il ciclo di Continuous Learning (consolidazione → feedback loop → aggiornamento confidence in tempo reale); accordion "Playwright e rendering del DOM" riscritto per documentare la delega al microservizio isolato renderer-service; aggiunta sezione "Strumenti di supporto alla valutazione manuale" con Simulatore di Dislessia ed Estensione Valida; titolo architettura rinominato da "Architettura Pipeline (v1.9.0)" a "Architettura a Fasi (Atomic Pipeline)"

v1.28.0

Corretto

  • Numero di riga mancante negli snippet IBMfindLineNumber confrontava gli snippet IBM (estratti dal DOM renderizzato da Playwright) con il sourceHtml grezzo restituito dalla fetch() diretta; quando il sourceHtml non contiene lo snippet (es. elementi generati o modificati al runtime, o pagine dove il server restituisce HTML diverso da quello renderizzato), il match falliva e lineNum restituiva 0, sopprimendo il badge [Riga N] in tutti i problemi IBM; aggiunta cattura di renderedHtml = await page.content() subito dopo la scansione IBM, prima della chiusura della pagina Playwright; usato come fallback quando sourceHtml non contiene lo snippet; i numeri di riga da DOM renderizzato vengono marcati con [~Riga N] e visualizzati con badge ambra (bg-amber-500) con prefisso ~ e tooltip esplicativo, distinguendoli visivamente dai numeri di riga sorgente esatti (badge blu bg-blue-600); aggiornate le funzioni formatProblemItem, formatSourceCode e formatInlineWithLineRefs in formatters.tsx per riconoscere entrambi i pattern

v1.27.0

Corretto

  • Screenshot puntuali — mai catturati (bug critico) — la funzione enrichEvaluations veniva chiamata solo nel percorso unificato di handleTechnicalPhase (riga 727), raggiungibile solo quando phase è undefined; Inngest chiama sempre con phase='technical' che causa un return anticipato alla riga 477, prima che enrichEvaluations fosse raggiunta; risultato: 0 screenshot salvati in DB, nessun log [evidence]; aggiunta la stessa chiamata fire-and-forget nel blocco phase === 'technical' prima del return

Aggiunto

  • Galleria screenshot con lightbox — nuovo componente ScreenshotGallery che sostituisce il rendering inline in DettaglioClient e ComponenteClient; thumbnails con skeleton di caricamento, stato di errore, badge criterio WCAG e badge contatore; lightbox con navigazione frecce (←/→), tasto ESC, chiusura clic sfondo, contatore ritagli, link "Apri in nuova scheda"; accessibilità completa (role=dialog, aria-modal, focus-trap, keyboard navigation)

v1.26.0

Aggiunto

  • Estensione Chrome rinominata "Valida" — tutti i riferimenti a "A11y Snapshot" aggiornati in manifest.json (name, short_name, default_title), popup.html (titolo e header), popup.js (commento header e log console), background.js, popup.css, setup.sh, EstensioneClient.tsx (UI web, istruzioni, nome file scaricato valida-extension.zip)
  • Endpoint dedicati all'estensione — creati GET /api/extension/projects (lista progetti {id, name}) e GET /api/extension/audit-rounds?project_id=X (round {id, roundNumber, date} per progetto), entrambi protetti da X-Extension-API-Key; il popup ora punta a questi endpoint invece di /api/projects e /api/audit-rounds che richiedevano sessione NextAuth
  • Script pack.sh — nuovo script chrome-extension/pack.sh per generare valida-extension.zip pulito (esclude .sh, .DS_Store, sorgenti SVG), pronto per Chrome Web Store o distribuzione standalone

Corretto

  • Middleware — blocco 401 sulle richieste dell'estensioneauth.config.ts non includeva /api/extension tra i percorsi pubblici; il middleware NextAuth bloccava le richieste dell'estensione prima che raggiungessero la logica di validazione dell'API key; aggiunto path.startsWith('/api/extension') a isPublicPath

v1.25.0

Corretto

  • Knowledge Base: override deterministico cieco rimossoapplyDeterministicOverrides abbinava le entry KB solo per criterionCode + originalStatus, forzando il cambio di stato su qualsiasi pagina che corrispondeva alla coppia senza considerare il contenuto HTML, il ragionamento dell'esperto né le condizioni specifiche che avevano motivato la correzione originale; la funzione è stata disabilitata dalla pipeline tecnica (technical-phase.ts) in attesa di un meccanismo di matching contestuale; l'import inutilizzato è stato rimosso.
  • Knowledge Base: prompt AI riformulato con linguaggio condizionale — l'intestazione del blocco KB iniettato nel prompt Claude recitava "Usale per evitare errori noti" (imperativo assoluto), portando il modello ad applicare le regole indipendentemente dal contesto della pagina corrente; riformulato con linguaggio esplicito: le indicazioni devono essere applicate solo se le stesse condizioni specifiche sono presenti nella pagina, altrimenti ignorate.
  • Knowledge Base: buildRuleDescription cattura la condizione, non solo la transizione — le descrizioni delle regole ora includono la condizione originale che ha scatenato la correzione (autoProblems) e la motivazione dell'esperto (finalNotes/finalProblems), con linguaggio "in passato, quando [condizione], l'esperto ha verificato che..."; limite expert_reasoning nel prompt portato da 120 a 300 caratteri; label rinominata da [NOTA ESPERTO] a [CONTESTO ESPERTO — condizione specifica].

v1.24.0

Corretto

  • Evidenze di conformità mancanti per criteri valutati dal motore statico — dopo il deploy di v1.23.0, i criteri come 3.1.1 (Lingua della pagina), 1.1.1 (Testo alternativo), 4.1.1 (Analisi) e altri valutati esclusivamente dal motore a11y-engine mostravano sempre il banner "Evidenze non disponibili" anche dopo la rivalutazione, perché: (1) mapToWcagCriteria non popolava mai passingEvidence per i criteri "Superato"; (2) il technique engine non ha implementazione per H57; (3) l'AI engine salta criteri già "Superato" per ridurre i token; aggiunta funzione buildStaticPassingEvidence in wcag-mapper.ts che genera un entry sintetico con source: 'static' per ogni criterio che supera la verifica automatica; aggiunto caso UI nel PassingEvidencePanel per entries.length === 0 che mostra "Criterio verificato automaticamente — nessun elemento specifico individuato" invece del banner fuorviante "Rivalutare il componente"

v1.23.0

Aggiunto

  • Evidenze di conformità per criteri superati — nuovo campo passing_evidence TEXT in valutazione_results che memorizza un array JSON PassingEvidence[] per ogni criterio con esito "Superato"; il technique engine estrae le evidenze dalle tecniche con outcome === 'pass' (elementi verificati, snippet HTML con numero di riga); il prompt AI è stato esteso per restituire evidence[] sugli stessi criteri; le due fonti vengono unite e deduplicate in mergeEvaluations(); il componente PassingEvidencePanel mostra in sola lettura la lista delle tecniche verificate (badge tecnica/static/AI, elemento, spiegazione, snippet collassabile) in entrambe le pagine di dettaglio (DettaglioClient) e valutazione (ComponenteClient, lista e modalità wizard); le valutazioni precedenti mostrano il banner "Evidenze di conformità non disponibili — rivalutare il componente per generarle"

v1.22.0

Corretto

  • IBM — falso positivo skip_main_exists — aggiunto filtro pre-scan: se il raw HTML contiene un tag <main>, un attributo role="main", un elemento con id contenente skip o salta, oppure un link con href="#..." il cui testo include skip/salta, la regola viene soppressa; IBM talvolta non rileva skip link o landmark <main> presenti ma nascosti via CSS o renderizzati dinamicamente, generando falsi positivi su WCAG 2.4.1

v1.21.0

Corretto

  • Check rendered — snippet con numero di riga — i check basati su dati Puppeteer (checkTargetSize, checkFocusVisible, checkFocusAppearance, checkLinkColor, checkDraggingMovements) mostravano nella sezione "Codice sorgente coinvolto" solo il selettore CSS grezzo (es. a.element-invisible) senza il markup HTML reale e senza l'etichetta [Riga N]; aggiunta funzione helper snippetFromSelector che usa l'istanza Cheerio per cercare il selettore nell'albero HTML statico: se trovato, restituisce buildCheckerSnippet(el, $) con prefisso [Riga N]; se il selettore non è presente nel DOM statico (elemento iniettato via JS), il fallback è il selettore testuale originale

v1.20.0

Corretto

  • Suggerimenti del linguista — JSON grezzo a video (prima pagina)parseAiSuggestions riassegnava erroneamente paragraphSuggestions al valore di outer.paragraphSuggestions (l'intera stringa JSON) come fallback quando l'LLM usava il "doppio wrapping"; ora il fallback è '', evitando che normalizeParagraphSuggestions spezzasse la stringa JSON per righe e la mostrasse come lista di testo
  • Suggerimenti del linguista — "Analisi AI non disponibile" sulle altre pagine — quando l'LLM avvolgeva l'intero payload in backtick Markdown (```json ... ```), il primo JSON.parse(raw) falliva e la funzione restituiva null; aggiunta pulizia preventiva della stringa raw prima del blocco try, che rimuove eventuali code fence prima del parse

v1.19.0

Corretto

  • Screenshot puntuali — pipeline rotta in DockercaptureElementSnippets chiamava Playwright localmente (getBrowserForType) ma il container a11y-app non ha browser installati; aggiunto controllo RENDERER_URL che delega al renderer-service tramite il nuovo endpoint POST /capture-element-snippets; aggiunto il modulo renderer-service/src/snippets.ts con la logica di cattura elementi
  • Accessibility Tree — mai valorizzato — la funzione walkNode in renderer/index.ts e renderer-service/src/render.ts ricorreva nei figli solo se l'elemento corrente era landmark/interattivo o depth < 3; per i siti con markup annidato (<div><div><main>) gli elementi significativi oltre depth 3 venivano ignorati; rimossa la condizione di guardia per ricorrere sempre fino al limite massimo (depth 15); pruneAXTree restituisce ora alberi non nulli e ax_tree_snapshots viene salvato correttamente
  • Confronto visivo — slider/overlay non funzionanti in modalità responsivasliderLeft/sliderRight venivano inizializzati quando screenshots=[] e rimanevano su 'chromium'/'firefox'; quando i 3 screenshot responsivi (chromium_desktop, chromium_mobile, chromium_tablet) caricavano asincronamente, screenshotMap.get('chromium') restituiva undefined e slider/overlay non renderizzavano nulla; aggiunto useEffect che sincronizza le selezioni quando la prop screenshots cambia, con default intelligente desktop↔mobile

Aggiunto

  • Confronto visivo — UX responsiva migliorata — badge viewport con dimensione (1280px / 768px / 375px), icone dispositivo, rilevamento automatico modalità responsiva con badge "Responsive" nell'header; tooltip informativo nella griglia; default automatico desktop vs mobile per il confronto diretto

v1.18.0

Aggiunto

  • Gemini Vision — retry con backoff esponenziale — aggiunta logica di retry interno nel motore Gemini: in caso di errori temporanei dell'API (HTTP 429, 503 o messaggi "high demand"/"quota"), il sistema attende automaticamente 5 s, 10 s e 20 s prima di ogni nuovo tentativo (fino a 3 retry); i micro-disservizi vengono assorbiti senza esporre Inngest ai retry incondizionati

Corretto

  • Pipeline valutazione — blocco su errore Gemini Vision — la fase visiva restituisce ora HTTP 200 con avviso invece di HTTP 500 quando tutti i retry falliscono; Inngest prosegue con i risultati parziali (tecnici + AI) anziché mandare l'intera valutazione in stato failed per un picco di traffico temporaneo

v1.17.0

Corretto

  • IBM — falso positivo html_lang_valid — esteso il filtro post-scan a html_lang_valid oltre a html_lang_exists; la regex di riconoscimento ora richiede un subtag primario di 2-3 lettere (es. it, en, zh) evitando la soppressione di codici genuinamente invalidi come notalang; supporto aggiunto per lang="it_IT" con trattino basso
  • IBM — falso positivo immagini — aggiunto filtro per img_alt_valid/img_alt_null/img_alt_decorative/img_alt_misuse quando tutte le immagini nel raw HTML hanno già un testo alternativo (alt, aria-label, aria-labelledby, title); il default è null (non 0) quando il raw HTML non è disponibile, evitando la soppressione silenziosa di violazioni reali
  • Leggibilità — un solo suggerimento mostratoparseAiJson nel backend splitta ora paragraphSuggestions stringhe (frasi separate da . seguite da maiuscola) in array di elementi distinti; in precedenza l'intera stringa compariva come un unico suggerimento
  • Leggibilità — JSON grezzo a videonormalizeParagraphSuggestions nel frontend gestisce ora le tre forme: array già corretto, stringa JSON array (anche con virgolette singole), testo piano con frasi concatenate o newline

Aggiunto

  • Numeri di riga nei checker a11y-enginecheckLanguage e checkImages popolano i nuovi campi lineNumber e sourceSnippet (con prefisso [Riga N]) usando sourceCodeLocationInfo di Cheerio; il wcag-mapper include lo snippet nel testo Problemi al posto del solo tag elemento
  • Screenshot per ogni errore (tutte le modalità) — Evidence Layer: dopo ogni valutazione tecnica web, un modulo fire-and-forget (src/lib/evidence/) cattura in background screenshot degli elementi falliti tramite Playwright e li carica su MinIO; disponibili per la revisione visiva in tutte le modalità (non solo Gemini)
  • Galleria immagini per revisione alt text — Evidence Layer cattura screenshot individuali di ogni <img> per il criterio 1.1.1; l'UI (ComponenteClient e DettaglioClient) mostra griglia con badge colorati — rosso (alt vuoto), arancione (alt generico), verde (alt presente) — per verifica visiva rapida; retrocompatibile con il vecchio formato string[]

v1.16.0

Corretto

  • TraversaliPanel — "0 pagine" per problemi trasversali — la colonna SQL affected_count ora viene restituita con alias "affectedCount" (camelCase); il frontend leggeva la chiave camelCase ma la query restituiva snake_case, mostrando sempre 0
  • Suggerimenti del linguista — JSON grezzo a videoparseAiSuggestions gestisce ora anche paragraphSuggestions formattato come array JSON [...] oltre agli oggetti {...}; in precedenza la stringa veniva stampata letteralmente invece di essere decodificata come lista di elementi
  • IBM Equal Access — falso positivo html_lang_exists — aggiunto filtro post-scan: se il raw HTML contiene un attributo lang o xml:lang valido su <html>, la regola viene soppressa prima del raggruppamento; il motore IBM in certi contesti Playwright segnalava come mancante un attributo già presente
  • Matrice cross-browser — colonna WebKit mancante — introdotto effectiveBrowsers (useMemo): se la configurazione del round non contiene almeno 2 browser, i nomi vengono estratti direttamente dai JSON browserResults dei risultati, normalizzando i suffissi _desktop/_mobile/_tablet
  • Motore statico — etichetta rigabuildSnippet ora emette [Riga N] invece di [Linea N], allineandosi al parser del frontend che cerca questa forma per renderizzare il badge numerico
  • Checker lingua — xml:lang XHTML — il controllo ora usa xml:lang come fallback quando lang è assente; evitava falsi positivi su pagine XHTML con <html xml:lang="it">
  • Checker link — nome accessibile tramite title — l'attributo title è ora riconosciuto come fonte valida del nome accessibile di un link, riducendo i falsi positivi "Link senza nome accessibile"
  • Checker immagini — attributi ARIA e title<img>, <input type="image"> e <area> ora accettano aria-label, aria-labelledby e title come alternative valide all'attributo alt
  • Parser bullet point — output Gemini — la regex in formatTextAsList include ora il carattere (tipico di Gemini) evitando la duplicazione del punto elenco nell'HTML renderizzato

Aggiunto

  • Simulatore dislessia — confronto fianco a fianco — quando il simulatore è attivo, la sezione mostra due colonne affiancate: testo originale (leggibile, typography system-ui) e testo simulato (distorto con font graziato, giustificazione e stress visivo Irlen); il valutatore può confrontare direttamente le due esperienze senza perdere il contesto del testo reale
  • Campo note nella valutazione manuale — aggiunto campo <textarea> facoltativo per le note del valutatore sia nella modalità Wizard che nella modalità Lista di ComponenteClient; il valore è incluso nel salvataggio tramite PUT /api/results/[id]
  • Istruzioni di preservazione HTML nei prompt AI — aggiunta istruzione esplicita a Claude (Anthropic) e Gemini affinché non alterino né rimuovano attributi HTML originali (href, title, alt, ecc.) negli snippet estratti
  • Stato iniziale auto-calcolato in TraversaliPanel — all'apertura di un problema trasversale privo di status, il valore viene pre-calcolato come lo stato più frequente tra i affected_results correlati

v1.15.0

Aggiunto

  • Endpoint reset-statusPOST /api/valutazioni/[id]/reset-status reimposta a idle i componenti bloccati in stato running o queued; accessibile ai ruoli admin e auditor
  • Pulsante "Sblocca analisi bloccate" — voce nel menu Azioni visibile solo quando esistono componenti bloccati e l'utente non è RTD; mostra spinner durante l'operazione e contatore dei componenti sbloccati al completamento
  • Rilevamento automatico problemi trasversali al mount — se al caricamento della pagina risultano ≥ 2 componenti già valutati ma nessun problema trasversale rilevato, la detection viene avviata automaticamente (gestisce ricaricamento pagina, valutazioni singole e ripresa da Inngest)
  • Trigger detection dopo evaluateAll — al completamento del ciclo "Valuta tutto" viene sempre eseguita la detection dei problemi trasversali

Corretto

  • Fingerprinting trasversale per risultati AI/IBM — i risultati privi di source_code (motori AI e IBM) ora usano i primi 120 caratteri del campo problems come chiave di confronto strutturale; in precedenza venivano scartati silenziosamente
  • Consolidamento chiamate di detection — il POST /api/cross-section-issues è ora centralizzato nella funzione triggerCrossSectionDetection, eliminando duplicazioni di codice nel client

v1.14.0

Corretto

  • VisualComparisonTool — viewport responsivi — normalizzazione dei suffissi _desktop / _mobile / _tablet nelle chiavi browser prima della ricerca in BROWSER_LABELS; evita crash quando il rendering responsivo produce chiavi come chromium_desktop
  • Seed WCAG criteri — aggiornamento bloccato — sostituito ON CONFLICT DO NOTHING con upsert completo; tutti i campi incluso methodology_it ora vengono aggiornati sui record esistenti ad ogni avvio
  • Motore leggibilità — fusione parole — aggiunta spaziatura tra elementi block-level prima dell'estrazione del testo con .text(); previene la concatenazione errata di parole da paragrafi adiacenti (es. "HelloWorld" invece di "Hello World")
  • QualitaClient — perdita campi suggerimenti AI — rimosso il blocco di estrazione regex di emergenza in parseAiSuggestions; il fallback ora preserva il JSON originale intatto, evitando la perdita di contextSentence e altri campi
  • Pipeline tecnica — posizione errori senza numero riga — abilitato sourceCodeLocationInfo: true in cheerio.load; ogni elemento ha ora .sourceCodeLocation.startLine disponibile
  • static-checks.ts — snippet troncati senza riferimento riga — introdotto helper buildSnippet() che prepone [Linea N] quando disponibile e porta il limite da 100–150 a 700 caratteri; sostituiti tutti i pattern di troncamento nel file
  • cross-section-issues GET — criterionCode mancante — aggiunto alias AS "criterionCode" nella SELECT e csi.criterion_code nella clausola GROUP BY

v1.13.0

Corretto

  • "Valuta tutto" — errori silenziosi — il loop evaluateAll ora controlla res.ok; se l'API restituisce un errore HTTP (rate-limit 429, timeout 504, 500) l'eccezione viene catturata, conteggiata in failed e loggata in console; il ciclo prosegue sulle pagine successive
  • "Valuta tutto" — aggiornamento non incrementalefetchData() invocata dopo ogni singola valutazione riuscita: la tabella si aggiorna in tempo reale pagina per pagina senza attendere il completamento dell'intero ciclo
  • "Valuta tutto" — filtro URL stringente — rimosso il vincolo && c.url dal filtro iniziale; i componenti web senza URL vengono conteggiati come saltati nel riepilogo finale invece di essere ignorati silenziosamente

Aggiunto

  • Progress bar "Valuta tutto" — banner animato con barra di avanzamento e contatori live (ok / errori) visibile durante il ciclo di valutazione massiva
  • Contatore progressivo nel pulsante — il pulsante "Valuta tutto" mostra N/totale e il numero di errori correnti durante il ciclo
  • Alert finale dettagliato con dismissione — il messaggio di completamento riporta separatamente pagine analizzate, errori e pagine saltate (URL mancante); l'alert è chiudibile con pulsante ✕
  • Delay anti rate-limit — pausa di 700 ms tra richieste consecutive per prevenire errori 429 dai modelli LLM

v1.12.0

Aggiunto

  • Contestualizzazione AI per tipologia ente (P2-03) — nome ente e tipologia dominio iniettati nel system prompt di Claude durante la valutazione web e PDF; recupero automatico tramite join con tabelle entities e domains; parametro opzionale backward-compatible su tutta la chain (evaluateWithAi, evaluatePdfWithAi, phase handlers)
  • Endpoint /api/health (P2-05) — health check strutturato con ping paralleli a DB (SELECT 1), veraPDF (/api/profiles) e renderer (/health); risponde 200 ok se DB attivo, 503 degraded se DB ko; timeout 3s sui servizi esterni

Corretto

  • Endpoint probe veraPDF in /api/health — allineato a /api/profiles coerente con verapdf-engine/index.ts (era /api/v1/info)

v1.11.0

Aggiunto

  • Renderer service microservizio (P1-01) — Playwright isolato in un servizio Express dedicato con immagine Docker playwright-jammy; a11y-app delega il rendering via HTTP; SSRF guard su URL con blocklist hostname e range IPv6
  • Pipeline di valutazione modulare (P1-02) — web-evaluation.ts suddiviso in tre moduli di fase indipendenti per migliore manutenibilità e testabilità
  • Dashboard progetto (P2-01) — nuova tab "Dashboard" nel dettaglio progetto con health score complessivo, radar chart principi WCAG, trend storico di conformità e top criteri falliti
  • API /api/projects/[id]/dashboard — endpoint analytics: health score, trend conformità, principi WCAG, top failing criteria
  • Feedback loop automatico esperto → KB (P2-02) — ogni salvataggio di una correzione di status chiama learnFromSingleResult e aggiorna immediatamente knowledge_entries senza attendere la consolidazione manuale
  • Badge "KB aggiornata" — indicatore visivo nell'UI di valutazione che conferma l'aggiornamento automatico della Knowledge Base dopo una correzione
  • KB Insights panel (P3-03) — pannello statistiche nella pagina Knowledge Base: top criteri corretti, trend di crescita KB, distribuzione confidence, heatmap criterio × content_type
  • API /api/knowledge/insights — metriche aggregate: top criteria per frequenza, trend crescita, distribuzione confidence, heatmap
  • Cache KB in-process — cache con TTL 5 min per getKnowledgeForPrompt; invalidata automaticamente dopo consolidazione e dopo ogni correzione singola
  • Suite di test Vitest — framework di test aggiunto con smoke test per technique engine, KB cache e KB overrides (65 test)
  • Batch SQL in applyEvaluations — inserimenti raggruppati: da N query a 3 statement per valutazione, miglioramento prestazioni significativo

Corretto

  • Guard URL malformati in learnFromSingleResult — gestione eccezioni per URL non validi nella determinazione dello scope di apprendimento
  • SSRF guard renderer service — validazione URL e blocklist hostname (inclusi IPv6 loopback e link-local) prima di delegare al renderer service
  • Health score denominator — calcolo del punteggio di conformità nel dashboard reso consistente tra API e UI
  • Trend SQL e bucket ordering KB Insights — query corrette per crescita storica e ordinamento distribuzione confidence
  • scope="col" su intestazioni tabella KB Insights — fix accessibilità su table header nel pannello KB
  • 404 handling e logging in PUT /api/results/[id] — risposta 404 corretta se il risultato non esiste; log di errore aggiunto
  • Validazione risposta HTTP in saveResult — previene fallimenti silenziosi quando l'API restituisce status non-OK
  • Ordinamento filtri in pagina Valutazioni — uso di localeCompare('it') per ordinamento alfabetico deterministico e localizzato nei menu Progetto, Valutatore ed Ente (fix S2871)

v1.10.0

Aggiunto

  • Resume automatico polling al ricaricamento pagina — Se l'utente ricarica la valutazione mentre Inngest sta ancora elaborando, il client rileva i componenti in stato running/queued e riprende automaticamente il monitoraggio senza ri-triggerare la valutazione
  • Label di fase nel progresso valutazione — Il polling mostra la fase corrente in linguaggio naturale: "Fase tecnica in corso…", "Analisi Claude in corso…", "Analisi Gemini Vision in corso…"
  • Colonna eval_phase nel DB — Persiste la fase corrente della pipeline (technical | claude | visual) durante l'esecuzione Inngest; azzerata automaticamente al completamento o al fallimento
  • Badge "Divergenza rilevata" — Indicatore arancione sui criteri con risultati discordanti tra browser; bordo card arancione per distinguere le divergenze cross-browser dagli esiti "Non superato"
  • Nuove sezioni guida metodologica — "Architettura Pipeline (v1.9.0)", "Bonifica PDF Assistita (AI)", "Analisi Cross-Browser e Divergenze" e "Acquisizione Snippet e Stati Dinamici" nella pagina /help-valutazione; badge tecnologia Atomic Pipeline, PDF Remediation e Cross-browser nell'intestazione
  • evalPhase nell'endpoint /api/components/[id]/eval-status — Il polling FE riceve la fase corrente e aggiorna il messaggio di progresso in tempo reale

Modificato

  • Timeout polling valutazione: safety timeout esteso da 3 min a 30 min; il polling si interrompe correttamente anche su stato inatteso (es. idle dopo un reset manuale)
  • Fase route usa metodologia del roundhandleWebEvaluation riceve la metodologia associata al round specifico per decidere se eseguire la fase claude/visual, evitando conflitti con le impostazioni globali modificate dopo l'avvio della valutazione
  • Prompt AI — risposta JSON pura: l'istruzione finale specifica esplicitamente di iniziare con [ senza blocchi markdown; il parser tryRepairJson gestisce ora risposte troncate con : pendente e virgola finale
  • Report Allegato 2 AgID: formato cambiato da PDF a DOCX; il pulsante "Dichiarazione di Accessibilità" rinominato in "Guida alla compilazione (PDF)" per maggiore chiarezza
  • Styling panel componente: colore sky per il pannello "Log di Esecuzione"; colore ambra per il pannello "Matrice Cross-Browser"; messaggio AXTree vuoto arricchito con descrizione della funzione
  • Tabella componenti valutazione: aggiunto overflow-x-auto per scroll orizzontale su viewport stretti

Corretto

  • Creazione progetto per PM: ruolo pm ora autorizzato su POST /api/projects (in precedenza bloccato a 403); matrice permessi UI in /ruoli aggiornata con la riga Creazione Progetto
  • Consumi responsive: tab tipo con flex-wrap per evitare overflow su mobile; griglia KPI a colonna singola su mobile (grid-cols-1 sm:grid-cols-2)
  • KB sidebar responsive: layout flex-col lg:flex-row con sidebar filtri full-width su mobile

v1.9.0

Aggiunto

  • Pipeline valutazione a fasi atomiche (Inngest) — La funzione evaluationPipeline è ora suddivisa in tre step indipendenti (technical-eval, claude-eval, visual-eval); ogni fase ha il proprio timeout di 10 minuti e retry separato; risolve i timeout su valutazioni complesse in modalità tecnica-claude-gemini
  • Phase API per /api/evaluate — Il parametro opzionale phase (technical | claude | visual) permette l'esecuzione parziale dei motori; fase claude fa fetch HTML statico + esegue solo Claude; fase visual renderizza per screenshot + Gemini Vision + snippet; fase technical esegue tutti i motori non-AI e salva i risultati di base
  • Concorrenza globale valutazione — Limite di 2 valutazioni simultanee sull'intera istanza (global-evaluation-lock) invece che per singolo round; protegge RAM/CPU dalla saturazione da istanze browser headless parallele
  • Helper saveCrossBrowserMatrix — Logica di salvataggio matrice cross-browser estratta come funzione riutilizzabile; chiamata sia dalla fase tecnica che dalla pipeline completa

Modificato

  • maxDuration /api/evaluate: aumentato da 300s a 600s (10 minuti) per supportare le fasi più lunghe
  • Timeout snippet capture: page.goto() aumentato a 30s; scrollIntoViewIfNeeded con timeout 5s; page.screenshot() con timeout 8s su tutti i punti di cattura (snippet, focus, hover); page.evaluate(delay) sostituito con page.waitForTimeout() (API Playwright nativa)
  • Fase claude/visual su PDF: le fasi dedicate ritornano skipped=true immediatamente (non applicabili a documenti PDF)

v1.8.0

Aggiunto

  • Gemini Vision multi-immagine — Cattura snippet screenshot a livello di elemento (selettore CSS → ritaglio Puppeteer) e invio contestuale a Gemini Vision; modalità chirurgica con analisi multi-immagine quando sono presenti snippet, modalità classica in fallback automatico
  • Modalità valutazione Wizard — Navigazione guidata per criteri WCAG raggruppati per categoria Accessibility Insights (Perceivable, Operable, Understandable, Robust); toggle Lista/Wizard nella toolbar; profilo utente determina la vista predefinita
  • Test cross-browser — Infrastructure — Colonna browser_results (JSON) in valutazione_results e ax_tree_snapshots in evaluation_snapshots; cattura AXTree via page.accessibility.snapshot() per ogni engine; endpoint /api/ax-tree-snapshot; motore diff AXTree per confronto accessibilità tra browser
  • AI Divergence Expert — Analisi automatica delle divergenze cross-browser tramite Claude; identifica criteri con esiti discordanti tra engines e produce raccomandazioni per l'auditor
  • Componente ApiKeyField riutilizzabile — Gestione unificata chiavi API con show/reveal/copy/generate; integrato su tutti i tab Impostazioni
  • Tab Notifiche in Impostazioni — Configurazione email (Resend) spostata in tab dedicato con link a template e matrice eventi; layout Quick links rimosso in favore di integrazione nel tab
  • Parametro ?reveal=true in Settings API — Recupero valore reale di chiavi mascherate su richiesta esplicita; readability_ai_api_key e gemini_evaluation_api_key aggiunte a SENSITIVE_KEYS
  • Visualizzatori cross-browser UIBrowserMatrix (griglia engine × criteri con icone stato) e AXTreeVisualizer (albero accessibilità interattivo) come componenti standalone

Modificato

  • Problemi trasversali — UI: header card con numero progressivo Problema #N e formato integrato 1.1.1 — Nome criterio; badge numerici con testo scuro text-amber-950 su sfondo giallo per contrasto WCAG; label occorrenze cambiata in Coinvolge N pagine; titoli sezione e modale in sentence case
  • Chatbot sidebar — UI: allineamento textarea/pulsante invio corretto (items-center); icona invio aggiornata a paper airplane standard
  • TraversaliPanel: interfaccia IssueCard semplificata rimuovendo la prop index ridondante; numerazione inline calcolata via indexOf

v1.7.0

Aggiunto

  • Problemi trasversali — Gestione issue a livello template con propagazione ai componenti; API con analisi similarità e pannello UI interattivo per creazione, conferma ed eliminazione
  • Matrice eventi notifiche — Nuova pagina /impostazioni/notifiche/matrice con visualizzazione tabellare: quali ruoli ricevono notifiche per ogni transizione del workflow e su quale canale
  • Tracciamento autore Knowledge Base — Campo created_by sulle entry KB con visualizzazione in tabella e badge AI/Manuale
  • Warning soglia confidenza KB — Indicatore visivo per entry con confidenza sotto soglia e contatore occorrenze
  • Log esecuzione per criterio — Campo criterion_code nella tabella execution_logs; pannello log espandibile per singolo criterio nella scheda componente
  • Guida metodologica WCAG — Sezione inline nella pagina /help-valutazione con istruzioni di valutazione in italiano per tutti i criteri WCAG 2.2
  • Campo methodology nei criteri WCAG — Aggiunto al DB e script di popolamento da dataset WCAG 2.2
  • Supporto app mobile — Tipo progetto mobile con gestione URL multipli, configurazione piattaforma e store nel form creazione progetto

Modificato

  • Permessi ruoli PM e Delegato aggiornati su navigazione, gestione progetti e route protette
  • Card criteri nel dettaglio valutazione: espandibili con ricerca KB integrata e log di esecuzione per criterio
  • Docker Compose aggiornato a stack multi-servizio con configurazione ambiente migliorata

Corretto

  • Ripristino node_modules e rimozione cache .next obsoleta che causava 21 errori TypeScript

v1.6.0

Aggiunto

  • Sistema notifiche — NotificationBell nella TopBar con contatore non lette e pagina /notifiche
  • NotificationDispatcher — Servizio con matrice eventi: notifiche automatiche ad ogni transizione di stato del workflow (submit, assign, complete, request-revision, publish)
  • Template email admin — UI per la gestione dei template email con endpoint CRON per pulizia notifiche vecchie
  • Campo tecnologie assistive — Aggiunto al form feedback pubblico con persistenza DB e invio email

Corretto

  • Fix query unreadCount e hardening POST email-templates
  • Rimosso .catch() irraggiungibile su Promise.allSettled
  • Toast errore fetch in NotificheImpostazioniClient
  • Fix permessi file DOCX templates: root-owned con chmod 555 (SonarQube docker:S6504)

v1.5.0

Aggiunto

  • Workflow stati valutazioni — Ciclo completo a 6 stati: bozzain_attesa_assegnazioneassegnatacompletatarichiesta_revisionepubblicata
  • Endpoint API workflowsubmit, assign, complete, request-revision, publish per ogni transizione di stato
  • RevisionModal — Componente per RTD per richiedere revisione con note opzionali all'auditor
  • Dichiarazioni AGID — Calcolo automatico stato di conformità dalla valutazione collegata
  • Changelog e Cookie Policy — Footer globale con link a pagine informative
  • Log esecuzione — Visualizzatore log raggruppati per sessione con stile terminale
  • Note AI in sola lettura — Visibili durante la valutazione manuale per supporto contestuale

Modificato

  • Badge stato valutazione aggiornato per tutti i nuovi stati del workflow
  • Bottoni avvio valutazione nascosti quando la valutazione è già completata
  • Ottimizzazione criteri AI: valutati solo quelli non risolvibili staticamente

Corretto

  • Ruolo RTD: RLS dashboard, sincronizzazione entità, modal dettagli log, visibilità consolida
  • Parsing JSON da AI: gestione robusta di risposte troncate o malformate

v1.4.0

Aggiunto

  • Knowledge Base chatbot — Indicizzazione documenti e ricerca semantica RAG
  • Screenshot visibili — Archiviazione MinIO con URL firmati per accesso sicuro
  • Export report AGID Allegato 2 — Generazione documento Word strutturato
  • Confronto storico — Visualizzazione delta tra round di valutazione successivi

Modificato

  • Navbar valutazione: unificazione toolbar e pulizia sezione audit
  • Sorting e unificazione tabelle valutazioni

v1.3.0

Aggiunto

  • Motore WCAG Techniques — 56 criteri con 3 modalità: static / rendered / AI
  • IBM Equal Access — Integrazione checker su pagina renderizzata via Puppeteer
  • RenderedContext — Raccolta dati Puppeteer: focus styles, dimensioni target, link styles
  • veraPDF sidecar — Analisi PDF/UA-1 via servizio REST Docker

Modificato

  • Pipeline valutazione web: rendering JS opzionale per siti con blocco crawler
  • Prompt AI: injection della Knowledge Base per apprendimento continuo

v1.2.0

Aggiunto

  • Knowledge Base — Apprendimento automatico dalle correzioni degli esperti
  • Consolidazione — Endpoint e UI per acquisire le correzioni post-round
  • Confidence score — Ponderazione regole KB in base alle occorrenze (min(1.0, 0.5 + 0.1×n))
  • Ruolo RTD — Accesso area dedicata con dashboard dichiarazioni AGID

Corretto

  • Sincronizzazione entità RTD: mapping automatico ente → dichiarazioni

v1.1.0

Aggiunto

  • Autenticazione NextAuth — Sessioni sicure con ruoli (admin, auditor, viewer, rtd)
  • Gestione utenti — Inviti via email, gestione ruoli da pannello admin
  • Multi-progetto — Organizzazione audit per progetto e round
  • Export Excel — Report risultati in formato xlsx

v1.0.0

Prima release

  • Motore di analisi statica HTML (Cheerio) per ~20 criteri WCAG 2.2 AA
  • Valutazione AI con Claude (claude-opus-4-6) su criteri non automatizzabili
  • Motore PDF con pdf-parse per analisi struttura documenti
  • Dashboard risultati con filtri per criterio, stato e priorità
  • UI in italiano, stack Next.js 15 + React 19 + PostgreSQL + Tailwind CSS