Igiene dati: niente AI senza dati puliti

Retry con successore, dedupe deterministica, matching per regola e ricevute per riga: l'igiene dati di Accordo prima di ogni AI, con fatti e limiti.

In breve. Prima di ogni intelligenza, Accordo mette igiene: retry che aprono un successore invece di resuscitare la riga morta, dedupe deterministica per chiave, matching che decide sempre allo stesso modo, ricevute per ogni riga importata. La tesi che ne ricavo, ed è interpretazione mia: l'igiene dati non è pulire i dati, è dare a ogni dato una semantica di fallimento e una provenienza — perché un modello eredita le bugie del magazzino che lo nutre. Pubblicato il 6 ottobre 2026.

Il retry che apriva la riga morta

Il caso da cui parto l'ho visto durante il dogfooding: un import falliva, l'utente riprovava, e il retry veniva reindirizzato alla stessa azione fallita. Non una nuova richiesta: la vecchia, già morta. Per riaccodare serviva un UPDATE manuale di un operatore.

Il bug non era nel codice che confrontava le chiavi. Era nel contratto: nessuno aveva deciso cosa significa ripetere una richiesta fallita. La PR #90 di accordo-platform scrive il contratto esplicito: le righe vive o riuscite si ripetono come sé stesse; le fallite aprono un successore con una chiave derivata, e la storia resta collegata; le cancellate restano un replay, perché una cancellazione è una decisione; molti retry insieme convergono sullo stesso successore. Verificato su PostgreSQL 16 reale, incluse corse concorrenti 10x10. Il racconto completo è nel retry che riceveva la riga morta, con i numeri dal corpo della PR.

La regola che ne ho ricavato vale per tutto l'articolo: prima di scrivere il controllo sulle chiavi, scrivi la tabella degli stati. Se una cella è vuota, il sistema la riempirà da solo, di solito nel modo peggiore.

Dedupe per chiave, matching per regola

Lo stesso principio governa i duplicati. I segnali comportamentali dei lead si registrano con chiavi deterministiche: un segnale duplicato è un 409 stabile, non un secondo contributo al punteggio. Il duplicato non viene "pulito dopo": non nasce proprio, perché la chiave lo riconosce prima della scrittura.

Il matching tra record segue la stessa strada: deterministico, stessa decisione a parità di dati. Due import dello stesso file convergono invece di divergere. E dove i dati sono ambigui — quale persona appartiene a quale azienda — il collegamento canonico lo decide un umano, non un punteggio di similarità. Ne ho scritto dal lato dei registri nell'articolo sul customer hub: la fondazione ha import bounded, ricevute per riga, idempotenza, matching e identità logica proprio per questo.

Ricevute per riga, impronte per run

L'ultimo strato è la tracciabilità. Ogni riga importata ha la sua ricevuta: cosa è entrato, cosa no, perché. Non un semaforo unico su migliaia di righe, ma un verdetto per riga, così puoi riprovare solo ciò che serve senza duplicare ciò che c'è già.

Lo stesso vale per i punteggi: ogni run di scoring registra l'impronta degli input che ha letto, così il punteggio storico si rilegge settimane dopo con i dati di allora, anche se il lead è cambiato. L'ho descritto nella pipeline che si muove da sola: lo scoring spiegabile non è una qualità del modello, è una proprietà della registrazione. Ricevute e impronte sono la stessa idea applicata a due oggetti diversi: mai un numero senza la sua provenienza.

Perché senza questo l'AI mente meglio

Qui sta la tesi. Un modello sopra dati sporchi non dà risposte sporche: dà risposte pulitissime e sbagliate, con la stessa sicurezza di quelle giuste. Il duplicato diventa un segnale doppio, il retry resuscitato diventa storia riscritta, il match probabilistico diventa un'identità che nessuno ha deciso. E ogni strato sopra — scoring, routing, proposte — eredita la bugia amplificandola.

Per questo l'igiene viene prima dell'intelligenza, non dopo: dedupe per chiave, matching per regola, retry con successore, ricevute per riga, collegamenti canonici umani. Non è pulizia, è contratto. La tesi completa sull'autonomia che ne deriva è nel pillar sull'autonomia sotto controllo.

Fatti e limiti, separati

Fatti: PR #90 con contratto esplicito per righe live, succeeded, failed, cancelled e retry concorrenti, verificato su PostgreSQL 16 con corse 10x10; PR #108 con chiusura esausti solo da operatore e token di deploy rifiutati; segnali lead con dedupe deterministica per chiave; matching deterministico con collegamenti canonici umani; ricevute per riga sugli import; impronta degli input per ogni run di scoring.

Limiti: 10x10 prova le corse provate, non tutte le corse possibili; la suite verde dice che i test passano, non che il contratto sia completo; la fondazione customer completa ha la PR aperta e non mergiata; Interazioni non esiste; la marketing automation non esegue niente. Un contratto scritto e verificato non misura quanto regga in produzione: misura che esiste e gira.

Domande frequenti

Cosa succede se rinvio una richiesta fallita?

Dipende dal contratto. In Accordo una riga fallita apre un successore con una chiave derivata e la storia resta collegata; una riuscita o ancora viva viene restituita com'è; una cancellata resta un replay, perché cancellare è una decisione.

Perché i duplicati non si puliscono dopo?

Perché pulire dopo significa aver già deciso con dati doppi. Con chiavi deterministiche il duplicato non nasce: viene riconosciuto prima della scrittura e risponde 409 stabile, senza secondo contributo.

Chi decide i collegamenti ambigui tra record?

Un umano. Il matching deterministico decide i casi chiari sempre allo stesso modo; dove i dati sono ambigui, il collegamento canonico è una decisione di una persona, non l'output di un punteggio di similarità.

Perché l'AI ha bisogno di dati puliti prima, non dopo?

Perché eredita gli errori del magazzino amplificandoli: duplicati che pesano doppio, retry che riscrivono la storia, identità mai decise. Sopra dati sporchi il modello non sbaglia in modo visibile: sbaglia con sicurezza.