C’è una differenza piuttosto importante tra un agente che legge una modifica e scrive “qui potrebbe esserci un bug” e un sistema che produce un test, lo esegue e mostra esattamente dove il comportamento cambia. Il primo offre un’ipotesi. Il secondo mette sul tavolo qualcosa che un programmatore può riprodurre, contestare e correggere. Con tutta la velocità che stiamo regalando alla generazione di codice, è una differenza che vale la pena difendere.
Il 29 ottobre 2026 Meta Engineering ha raccontato il funzionamento in produzione di Catching JiTTests, un sistema che usa modelli linguistici per generare test destinati a intercettare problemi prima che le modifiche arrivino nel codice principale. Non è interessante perché un’altra grande azienda ha aggiunto l’AI alla pipeline. È interessante perché sposta la domanda: non “il modello pensa che questo codice sia sbagliato?”, ma “quale comportamento osservabile dimostra che potrebbe esserlo?”.
Un test che deve fallire non è un test scritto male
Siamo abituati a considerare verde il risultato desiderabile: scriviamo un test che passa e lo conserviamo per intercettare regressioni future. È il modello classico dei test di protezione, o hardening tests. I catching tests di Meta perseguono invece un obiettivo diverso: vengono generati in prossimità di una modifica e cercano di fallire proprio sulla versione proposta, idealmente passando sulla versione precedente. Non devono necessariamente diventare parte permanente della suite.
Il confronto tra revisione di partenza e revisione modificata è il cuore della prova. Un test che fallisce soltanto sulla nuova versione segnala una differenza; non dimostra automaticamente che la differenza sia un errore. Se il requisito è cambiato intenzionalmente, quel fallimento potrebbe essere corretto. È qui che il problema diventa più serio del semplice “fai scrivere qualche unit test a un LLM”.
Nel paper tecnico Just-in-Time Catching Test Generation at Meta, gli autori distinguono esplicitamente il catching dall’hardening e analizzano 22.126 test generati. Nella valutazione descritta, i metodi consapevoli della modifica producono più candidati utili rispetto alle strategie di confronto. Ma un candidato che fallisce resta un candidato: bisogna capire se ha individuato un difetto oppure un cambiamento legittimo.
Due modi di cercare un difetto: sospettare il diff oppure capirne l’intenzione
L’architettura raccontata da Meta usa due percorsi complementari. Il primo, chiamato dodgy diff, parte da una provocazione metodologica: trattiamo la modifica come se fosse difettosa e cerchiamo test capaci di distinguere il suo comportamento da quello del codice precedente. Non serve che il modello capisca perfettamente cosa voleva fare l’autore. Serve produrre esperimenti che rendano visibile la differenza.
Il secondo percorso è intent-aware. Il modello legge codice, titolo e descrizione della modifica, prova a ricostruirne l’intenzione, ipotizza come quella intenzione potrebbe essere tradita da errori plausibili e genera mutazioni e test per cercarli. È più semantico, ma porta con sé un rischio preciso: se l’intenzione ricostruita è sbagliata, anche il test può risultare convincente per il motivo sbagliato.
Questa combinazione ha senso perché i due percorsi sbagliano in modi diversi. Uno privilegia la differenza osservabile, l’altro la coerenza con lo scopo dichiarato. Nessuno dei due, da solo, risolve il problema dell’oracolo: chi stabilisce quale comportamento fosse davvero richiesto?
Il collo di bottiglia non è generare test. È non sommergere gli sviluppatori
Quando un sistema genera test su larga scala, aumentare il numero di fallimenti non è necessariamente un successo. Se ogni modifica scatena dieci segnalazioni inconsistenti, abbiamo soltanto trasferito il costo dal computer al tempo delle persone. Una pipeline che rallenta il merge con falsi allarmi può diventare meno affidabile proprio perché gli sviluppatori smettono di fidarsi dei suoi avvisi.
Meta affronta il problema combinando un ensemble di modelli usati come LLM-as-Judge con RubFake, un valutatore a regole deterministiche. I modelli analizzano test, tracce di esecuzione, differenze di codice e intenzione ricostruita; le regole introducono controlli più verificabili. I risultati vengono ordinati prima di coinvolgere un ingegnere. È una distinzione architetturale fondamentale: il modello può contribuire alla selezione, ma il suo voto non è la prova che un bug esista.
L’AI può proporre il sospetto. Il test deve produrre l’evidenza. E qualcuno deve ancora decidere se quel comportamento era consentito.
I numeri sono interessanti. Il modo in cui li leggiamo lo è di più
Secondo il resoconto pubblicato da Meta, 589 ingegneri, pari al 64% dei destinatari contattati, hanno interagito con Catching JiTTests. Le segnalazioni valutate dagli ingegneri avrebbero raggiunto un tasso del 60% di veri positivi. Nel primo semestre 2026, sempre secondo Meta, il sistema ha contribuito a individuare 74 bug gravi relativi alla privacy prima dell’integrazione del codice; l’azienda riferisce inoltre una diminuzione del 20% delle privacy SEV nello stesso periodo.
Sono dati importanti, ma vanno letti correttamente. I 74 casi sono problemi intercettati prima del merge, non 74 incidenti di produzione. Il 60% è riferito al processo di segnalazione e coinvolgimento descritto da Meta, non è una precisione garantita su ogni repository. E il calo del 20% non dimostra, da solo, che l’intera riduzione dipenda da Catching JiTTests: per stabilirlo servirebbe isolare altri cambiamenti organizzativi, tecnici e di misurazione.
Anche il paper di gennaio e il resoconto di ottobre raccontano fasi differenti del percorso. Nel primo, su 41 segnalazioni inviate agli ingegneri, otto furono confermate come veri positivi, quattro delle quali avrebbero potuto causare problemi gravi. Non sono numeri da sommare ai 74 come se descrivessero lo stesso esperimento. Sono evidenze di contesti e momenti distinti, utili a capire l’evoluzione del sistema.
Human-on-the-loop: meno clic manuali, non meno responsabilità
Meta usa l’espressione human-on-the-loop per descrivere una supervisione in cui le persone definiscono criteri e controllano gli esiti in forma aggregata, intervenendo sui casi selezionati invece di revisionare ogni test generato. Non significa lasciare la macchina senza controllo. Significa decidere dove impiegare l’attenzione umana e quali soglie rendono una segnalazione abbastanza credibile da interrompere il lavoro.
Questo passaggio mi sembra più utile della solita contrapposizione fra sviluppo manuale e sviluppo agentico. Un sistema serio ha bisogno di confini: quali modifiche meritano un’analisi costosa, quali segnali possono bloccare una pipeline, quali casi richiedono un responsabile, quali errori si possono tollerare. Senza queste decisioni, l’automazione non elimina il lavoro: lo rende più opaco.
È un tema che attraversa anche il rapporto tra codice prodotto dagli agenti e software realmente consegnato. Misurare quante righe scrive un modello dice pochissimo sulla qualità di ciò che arriva in esercizio. Misurare quali errori sono stati intercettati, con quali evidenze e a quale costo operativo, comincia invece a raccontare un sistema.
Come portare questa idea in una pipeline normale
Non serve replicare l’infrastruttura di Meta per applicarne il principio. Anzi, sarebbe un errore copiare una soluzione industriale senza il suo contesto. In un progetto Laravel, in un plugin WordPress o in un servizio che elabora ordini, si può partire da una versione molto più sobria:
- Identificare i diff rischiosi. Autenticazione, pagamenti, autorizzazioni, migrazioni dati e contratti API meritano test mirati prima di modifiche puramente cosmetiche.
- Costruire una prova riproducibile. Il test deve indicare input, stato iniziale, comportamento atteso e comportamento osservato, possibilmente confrontando prima e dopo la modifica.
- Separare segnale e verdetto. Un fallimento generato dall’AI entra in triage: non diventa automaticamente un blocco definitivo né una vulnerabilità confermata.
- Misurare il rumore. Registrare quanti avvisi sono stati accettati, scartati, riprodotti e risolti, insieme al tempo sottratto alle persone.
- Conservare il controllo umano sui criteri. Le regole che autorizzano un merge, una deroga o una modifica critica devono essere comprensibili e verificabili.
Per esempio, un agente potrebbe proporre un test che mostra come un utente senza autorizzazione riesca a leggere un ordine dopo una modifica al middleware. Il valore non sarebbe il commento “potenziale problema di sicurezza”, ma il test che prepara due identità, esegue la richiesta e confronta il risultato. Se la prova non è riproducibile o la policy permette esplicitamente quel comportamento, la segnalazione va rivalutata. Il lavoro utile è nel contratto, non nell’aggettivo usato dall’AI.
Anche qui la prudenza conta: eseguire codice generato da un modello richiede un ambiente isolato, dati di test e limiti sulle operazioni consentite. Un test automatico non dovrebbe avere la possibilità di alterare dati reali per dimostrare che una modifica è sbagliata.
La prossima metrica dell’AI nello sviluppo non è la velocità di scrittura
Il punto più interessante di Catching JiTTests non è che Meta abbia trovato un modo per usare altri LLM dopo la generazione del codice. È che ha costruito una catena in cui ipotesi, esecuzione, filtraggio e decisione sono passaggi distinti. Non perfetti, non automaticamente trasferibili, ma osservabili.
Se continuiamo a valutare gli agenti soltanto da quanto velocemente producono file, finiremo per celebrare sistemi che spostano il costo nella revisione, nel debugging e negli incidenti. Un agente che scrive codice può essere utile. Un sistema che sa dimostrare quando quel codice viola un comportamento atteso è molto più vicino a ciò che serve davvero per metterlo in produzione. E, come ho già osservato parlando di orchestrazione e contratti fra agenti, il controllo non nasce dal numero di modelli che facciamo collaborare: nasce dai confini che rendiamo verificabili.
Domande frequenti
Che cosa sono i Catching JiTTests di Meta?
Sono test generati in prossimità di una modifica al codice per cercare differenze di comportamento potenzialmente difettose prima del merge. A differenza dei test di protezione permanenti, possono essere creati per un singolo diff e non conservati nella suite.
Un test generato dall'AI che fallisce dimostra sempre un bug?
No. Il fallimento segnala un comportamento da verificare, ma potrebbe riflettere una modifica intenzionale, un ambiente instabile o un’ipotesi errata sul requisito. Servono riproducibilità, confronto con la versione precedente e triage.
Che cosa fanno LLM-as-Judge e RubFake?
Aiutano a selezionare le segnalazioni promettenti: un insieme di modelli valuta codice, tracce e contesto; RubFake aggiunge controlli basati su regole deterministiche. Non sostituiscono l’esecuzione del test né il giudizio sul requisito.
Che cosa significa human-on-the-loop nello sviluppo software?
Significa che le persone definiscono criteri, soglie e regole di intervento, monitorando i risultati nel complesso e verificando i casi selezionati, invece di revisionare manualmente ogni output generato dall’AI.
