Tre giorni, dal 10 al 12 agosto 2026. Questo file racconta l'ordine in cui ho lavorato, come ho usato l'AI, con quali controlli, e i limiti del metodo.
La ricerca normativa è venuta prima di tutto, su tre fronti separati: il prelievo sul lavoratore, il costo per il datore, le leve a fiscalità agevolata. Ogni fronte ha prodotto un documento con le tabelle parametriche per anno, le formule in pseudocodice, lo stato di verifica riga per riga e una sezione su quello che non era stato confermato.
Poi ho guardato come sono fatti i calcolatori che già esistono online. La traccia chiedeva un calcolatore, e quel passaggio mi ha fatto scegliere di costruire prima il corpo di regole e poi le viste che lo interrogano, invece di scrivere la matematica dentro una pagina. Il riposizionamento è nel secondo commit del progetto.
Poi il rulebook, cioè il modello dati. Poi una fase dedicata a rileggere le fonti primarie sul percorso critico. Poi i casi golden, scritti prima del motore. Poi il motore, le viste, l'interfaccia, i sei moduli, e questi documenti.
Trentanove casi attesi, ricavati dalle fonti passo per passo lungo la catena, prima che esistesse una riga del motore. Un test scritto dopo il codice, guardando cosa il codice produce, verifica il codice contro sé stesso. Scriverli prima è il modo per avere un termine di paragone indipendente.
Chi li ha scritti, e come li ho verificati. I casi li ha prodotti un agente, con un mandato solo: derivare i valori attesi dal rulebook e dai testi normativi, senza scrivere nemmeno una versione provvisoria del motore e senza prendere un numero dal confronto di mercato. Ogni caso porta la derivazione passo per passo con i parametri citati, la provenienza normativa e la tolleranza.
Poi ho rifatto il conto io. Ho ricalcolato il caso base 2026 a RAL 30.000 partendo dal rulebook e senza guardare la derivazione dell'agente: tornano tutte e dieci le voci al centesimo, dai 2.757,00 di contributi ai 1.673,25 di netto mensile. Stessa cosa sulla coppia del gradino a 15.000 e su quella della soglia di Milano. In due punti il mio conto divergeva di un centesimo, e aveva ragione l'agente. Ho poi verificato che nei 39 casi le componenti dichiarate sommino al netto dichiarato, e che il netto mensile sia quello annuo diviso le mensilità: zero incoerenze.
Un ultimo controllo è arrivato dopo, quando il motore esisteva. Ho calcolato dal rulebook un caso assente dai golden, RAL 45.000 nel 2026, e l'ho confrontato con quello che produce il motore: nove voci su nove al centesimo. Serve a escludere l'ipotesi che il motore sia stato piegato sui casi attesi invece che sulle norme.
Scriverli prima ha avuto un secondo effetto, che non avevo previsto. Per ricavare il netto di una RAL bisogna decidere dove arrotondare, se il ragguaglio ai giorni si applica a questa detrazione o a quella, se la percentuale del cuneo si calcola sulla RAL o sul reddito di lavoro dipendente. Le convenzioni di calcolo del progetto sono nate lì, per necessità, e stanno nel rulebook perché il motore e i casi attesi dovevano usare le stesse.
Prima di scrivere il motore ho raccolto il netto di tre calcolatori affermati su cinque RAL, con URL e data, in test/confronto-mercato.md. Non sono verità normativa. Servivano come sistema d'allarme: se il motore si fosse allontanato da tutto il mercato, o avevo ragione e potevo dimostrarlo con le norme, o avevo un errore e lo trovavo prima della consegna.
Alla fine tre scarti hanno superato l'uno per cento, e per tutti e tre c'è una spiegazione normativa. Il più grosso, 1.160 euro a RAL 35.000, viene da un calcolatore che applica ancora l'esonero contributivo del 2024, abrogato dal 2025 e sostituito da due istituti diversi. Un altro viene da un calcolatore che applica la percentuale del cuneo alla RAL lorda invece che al reddito di lavoro dipendente, e la differenza fra le due letture vale 88 euro.
L'ordine conta: raccolti i numeri dopo aver scritto il motore, avrei avuto davanti la scelta se aggiustare il motore per avvicinarlo al mercato.
Dopo aver compilato i tre anni ho dedicato una fase a rileggere le fonti primarie delle voci che stanno dentro il conto del netto. Sembrava ridondante: il validatore era già verde, ogni parametro aveva già la sua fonte.
Ha trovato cinque errori di contenuto.
- Mancava la maggiorazione di 65 euro dell'art. 13 comma 1.1 TUIR, dovuta fra 25.000 e 35.000 euro di reddito complessivo. Cade dentro il caso base.
- La banda al 4,8 per cento della somma non imponibile aveva un tetto proprio a 20.000 euro che il testo di legge non pone.
- Il regime agevolato attribuito alla Lombardia appartiene al Friuli Venezia Giulia.
- Il trattamento integrativo sotto i 15.000 euro era dato per spettante senza verifica di capienza.
- Il contributo per i fondi interprofessionali risultava compreso nel NASpI invece che additivo.
Nessuno dei cinque era visibile al validatore, che controlla se ogni numero ha una fonte e non se la fonte dice quel numero. È la differenza fra una verifica di forma e una di contenuto, e la seconda va fatta leggendo.
Sul percorso di accesso alle fonti: Normattiva e la pagina ELI della Gazzetta sono illeggibili da programma, perché la pagina è un guscio JavaScript, e i PDF dei supplementi ordinari sono scansioni senza layer testo. La fase si era arenata lì. La strada che l'ha sbloccata è gazzettaufficiale.it, che espone il testo in HTML statico articolo per articolo. Chi lo ha trovato lavorando sull'art. 13 lo ha passato agli altri fronti, che avevano rinunciato sul PDF scansionato. Da quel momento i testi di legge sono stati letti parola per parola.
Ho costruito questo progetto con modelli linguistici.
Il thread principale ha fatto l'orchestratore e non l'esecutore. Ogni lettura voluminosa, ogni ricerca su un fronte, ogni scrittura di un modulo è passata da un agente separato con un mandato solo. Un mandato che conteneva una "e" fra due obiettivi diversi veniva spezzato in due. Gli agenti scrivevano su disco e restituivano al massimo quaranta righe: cosa avevano prodotto, dove, le decisioni non ovvie, i punti aperti. Mai il contenuto integrale.
La scelta del modello ha seguito una regola sola: il modello più forte decide la forma, gli altri la riempiono. Lo schema del rulebook e le decisioni di modellazione del dominio sono venute dal modello più capace. La ricerca, il motore, l'interfaccia e i test dal modello intermedio.
Sei agenti in parallelo, un bersaglio ciascuno, hanno fatto la verifica delle fonti primarie. È il posto dove il parallelismo ha reso di più, perché sei letture indipendenti dello stesso corpus non si contaminano a vicenda.
Un agente che scrive un modulo e poi scrive il test di quel modulo produce un test che conferma il modulo. Ho adottato quattro controlli, e li ho eseguiti io.
Rilanciare i banchi. Ogni cancello di fase si verifica con un'esecuzione mia, mai sulla parola di un agente. Oggi il comando è uno solo, node test/tutti.js, e sono undici banchi.
Ricalcolare a mano almeno un numero. Per la curva delle aliquote: il rulebook dichiara per la banda fino a 28.000 un termine lineare con moltiplicatore 1.190 e divisore 13.000, cioè 0,091538 di detrazione persa per ogni euro di reddito. Cento euro di RAL fanno 90,81 euro di reddito, e 90,81 per 0,091538 fa 8,31, che è quello che il modulo attribuisce alla detrazione dell'art. 13. Per il costo azienda: le sette componenti datoriali dichiarate singolarmente sommano al 26,90 per cento con la quota CIGS, contro il 29,58 dell'aggregato, e i 2,68 punti di differenza sono malattia e maternità, che il rulebook porta a valore nullo come voci singole. Quel conto ha trovato il punto più debole del costo azienda, che ora è dichiarato in pagina.
Provare mutazioni deliberate. Prima di chiudere un modulo rompo il codice apposta e guardo se il banco se ne accorge. È il controllo che ha trovato più problemi.
Aprire la pagina. Ogni modulo è stato provato da file://, con la console aperta e le richieste di rete sotto controllo. Due difetti sono usciti solo lì, e nessun banco li avrebbe trovati. Il registro delle assunzioni stampava il passo di arrotondamento di un centesimo di euro come "1,00 %", perché la formattazione dell'audit trail legge ogni numero sotto l'unità come una percentuale, e nella stessa colonna del registro convivono aliquote e importi. E a 375 pixel la pagina scorreva in orizzontale, per le chiavi del rulebook citate dentro i testi, parole singole lunghe cinquanta caratteri dentro un contenitore flex.
Le elenco perché una mutazione che sopravvive indica un test che non verificava quello che doveva.
Sulla curva delle aliquote. Ho tolto l'accorciamento della finestra di misura della marginale, che serve a non attraversare un gradino. Il banco ha ricalcolato la marginale con la stessa finestra sbagliata e l'ha trovata coerente con sé stessa, cioè verificava un numero contro un numero ottenuto allo stesso modo. L'ho sostituito con un controllo su una proprietà: nessuna finestra di misura può contenere un gradino. Ora la mutazione muore.
Sul registro delle assunzioni. Due mutazioni sono passate, ed erano lo stesso buco. Attribuire ogni convenzione al primo punto della catena, e attribuire ogni parametro non applicato al primo punto: nessun controllo verificava l'aggancio alla catena, quindi un'attribuzione plausibile e sbagliata passava indisturbata. Il numero resta giusto e la spiegazione diventa falsa, che per un prodotto costruito sulla provenienza è il caso peggiore. Ho aggiunto un blocco che ricalcola l'attribuzione dalla fonte e la confronta.
Sulle leve a fiscalità agevolata. Nessuna delle dieci mutazioni è passata. Una però ha rivelato codice morto: un filtro sui duplicati era una seconda difesa contro un caso già coperto da un filtro a valle, quindi toglierlo non cambiava niente, e l'ho tolto.
C'è anche un controllo che ho scritto io e che sbagliava. Per dimostrare che il modulo delle leve non calcola, la prima stesura del banco cercava operatori aritmetici nel sorgente. Inciampava sulla somma di un conteggio e dichiarava colpevole il codice giusto. L'ho sostituito con un controllo che percorre l'output e pretende che ogni numero compaia identico dentro il nodo del rulebook da cui dice di venire.
C'è un problema che nasce dal vincolo di consegnare un file solo, senza build: i rulebook, i casi golden e i dieci moduli vivono dentro index.html come copie incollate. Una copia si allontana dall'originale in silenzio. Basta correggere src/motore.js e dimenticare l'incollatura, e da quel momento i banchi certificano un motore che la pagina non usa più.
test/run-pagina.js chiude quella possibilità. Riapplica la trasformazione da modulo Node a funzione autoinvocata e pretende che il risultato compaia dentro la pagina parola per parola, commenti inclusi. Poi confronta i dati incorporati con i file, esegue i 39 casi golden dentro e fuori dalla pagina, e verifica che ogni modulo produca lo stesso identico oggetto nei due ambienti.
Quando l'ho scritto ha trovato subito una cosa: le quattro incollature della fase precedente erano state fatte con sed e differivano dalle successive per due righe vuote. Nessun effetto sul calcolo, ma il controllo esatto non poteva esistere finché le regole di incollatura erano due.
Le fonti secondarie. Duecentoventotto parametri su 408 stanno a "fonte primaria citata da secondarie concordanti", che non è la stessa cosa di aver letto il testo. Riguarda soprattutto i valori annuali pubblicati per circolare: il massimale contributivo, la prima fascia di retribuzione pensionabile, i minimali di retribuzione imponibile. Per quei valori la circolare INPS è la fonte operativa che tutti usano, e la lettura del testo di legge darebbe la regola senza dare il numero dell'anno.
Quello che la verifica delle fonti primarie non ha chiuso. Settantanove parametri restano non confermati. Sul percorso critico ne resta uno di origine normativa: la banda della detrazione dell'art. 13 sopra i 50.000 euro, che il motore tocca solo sopra quella soglia. Le convenzioni di calcolo restano il gruppo più esposto, e sono decisioni di prodotto che nessuna fonte fissa.
L'aliquota datoriale aggregata. Due punti e sessantotto di aliquota non hanno una fonte per voce. Il prodotto la espone come campo modificabile invece di nasconderla nel codice, che riduce il problema senza risolverlo.
Il confronto con il mercato usa tre fonti, e una è debole. Talent.com resta sistematicamente sotto le altre due, fra il 10 e il 17 per cento, e il file di raccolta lo dichiara fonte debole per il caso italiano 2026 prima ancora che il motore esistesse. Il confronto vero è contro le due fonti italiane.
Il prototipo è stato provato su un browser solo, basato su Chromium, aperto da file:// a due larghezze, 1280 e 375 pixel. Non ho una matrice di compatibilità.
Il rulebook della prima stesura aveva cinque errori di contenuto che nessun controllo automatico poteva vedere. La verifica delle fonti primarie è arrivata come fase separata dopo. Farei quella lettura mentre compilo il rulebook, e accetterei che la compilazione richieda il triplo del tempo.
E scriverei prima il controllo sulla pagina. Per due fasi ho fatto le incollature con uno script usa e getta, senza modo di dimostrare che la pagina eseguisse davvero il codice del repository.