Come è fatto
Uno sviluppatore, un assistente di programmazione basato sull’IA e molte regole verificate dalla macchina.
Di Nick
Prison Life lo scrivo io insieme a Claude Code (l’agente di programmazione di Anthropic). Io decido che cos’è il gioco e quali strade prendiamo; l’assistente fa gran parte della digitazione. Poiché nessuno rivede il codice a parte me e un agente IA di revisione, mi affido all’automazione: le regole sono imposte da controlli automatici e dalla build, non dalle buone intenzioni.
Delega
La sessione principale di Claude Code pianifica il lavoro e tiene il task tracker, il registro scritto delle scelte di design e la cronologia delle modifiche. Non scrive codice: affida ogni modifica, anche minima, a un agente IA specializzato. Ognuno ha una propria definizione scritta che ne fissa il ruolo e il modello.
| Ruolo | Livello di modello | Compito |
|---|---|---|
| Architettura | Opus | modello dei dati, tick, thread, pathfinding, decisioni |
| Codice di simulazione | Opus | sistemi di simulazione, IA dei personaggi, cicli critici |
| Prestazioni | Opus | profilazione, regressioni del benchmark |
| Revisione (sola lettura) | Opus | rivede un diff; non può modificare file |
| Client e strumenti | Sonnet | client Godot, interfaccia, strumenti |
| Test | Sonnet | test a partire da criteri di accettazione |
| Dati dei contenuti | Sonnet | definizioni JSON a partire da uno schema |
| Ricerca, esecuzione dei controlli | Haiku | ricerca nel codice; esecuzione dei controlli e riassunto degli errori |
Il lavoro difficile va al modello più forte, quello di routine ai più economici. Se un agente IA più economico fallisce i controlli due volte, il compito sale di un livello; se fallisce due volte anche il livello più alto, si ferma e chiede a me.
Hook che dicono di no
Gli hook di Claude Code sono script che girano attorno alle azioni dell’assistente. I miei impongono tre regole:
- Non si finisce sul rosso. Quando una sessione o un agente IA prova a fermarsi dopo aver modificato il codice, un hook esegue il controllo rapido (build più i test veloci). Se fallisce, l’arresto viene rifiutato.
- La sessione principale non può modificare il codice. Un hook rifiuta le scritture su sorgenti, test, contenuti e strumenti provenienti dalla sessione principale.
- Il revisore è in sola lettura. I suoi strumenti di modifica sono rimossi e un hook rifiuta i comandi che cambiano file o la cronologia del progetto.
Proteggono dagli errori, non da un aggiramento deliberato: un trucco di shell ben determinato può aggirarli, e uno degli hook vede un controllo rosso in un agente IA ma non può trattenerlo (l’hook di arresto della sessione principale lo intercetta comunque). Preferisco dirlo chiaramente.
Decisioni e controlli per iscritto
- Ogni scelta non banale è messa per iscritto. Compiti, tappe e decisioni di design sono conservati come testo semplice accanto al codice, in un task tracker. Quando scegliamo tra opzioni che riguardano più di un compito, la scelta viene annotata con il suo contesto e le sue conseguenze.
- I controlli girano sulla mia macchina. Nessuna CI nel cloud. Uno script locale ha quattro modalità:
fast,test,benchefull. Script e hook sono PowerShell 7 sia su Windows sia su macOS. - Controlli a ogni modifica. L’automazione locale rifiuta una modifica descritta o formattata male. Per le modifiche al codice esegue anche il controllo rapido; le modifiche che toccano solo appunti o il sito saltano la build.
- I file di riferimento sono protetti. Gli hash di determinismo fissati, i file di salvataggio di riferimento e la baseline del benchmark cambiano solo con la mia approvazione esplicita, mai in silenzio.
- Il progetto stesso è la fonte di verità. Uno strumento di memoria locale indicizza il progetto e le conversazioni passate per la ricerca, ma tutto ciò che conta è anche un compito, una decisione registrata o un documento.
Il nucleo deterministico
La simulazione vive in una semplice libreria .NET senza riferimenti a Godot; il client Godot si limita a leggerne lo stato e a inviare comandi. Il nucleo segue regole fisse: il mondo cambia solo tramite comandi, il tempo è misurato in tick interi, la casualità proviene solo dai generatori con seed del mondo. Lo stesso seed e lo stesso registro dei comandi devono dare lo stesso mondo. Queste regole sono verificate dal compilatore e dai test, non solo dalla revisione; vedi il devlog #1 per capire come, e il devlog #2 per il mondo, i salvataggi e i replay.
- I comandi sono l’unica via d’ingresso. Ognuno ha un identificatore di tipo stabile e una codifica binaria, e ogni comando viene registrato con il suo risultato, compresi quelli rifiutati.
- Il tick ha tre fasi in ordine fisso. L’ordine dei sistemi è definito in un solo punto del codice, e cambiarlo cambia tutti gli hash.
- La casualità usa generatori propri (SplitMix64 e xoshiro256**). I flussi con nome derivano dal seed del mondo e sono conservati nello stato del mondo. Un generatore con chiave e senza stato, guidato da un dominio, una chiave e il tick, serve il lavoro indipendente dall’ordine.
- L’hash dello stato è un hash a 64 bit sensibile all’ordine per i controlli di determinismo. Non è crittografico.
- Il mondo è una griglia di tessere da 1×1 m su livelli discreti; muri, porte e pavimenti cambiano solo con comandi di costruzione.
- Salvataggi e replay condividono un unico contenitore di file verificato. Un replay è il seed più il registro dei comandi, con hash di controllo lungo il percorso, e viene verificato passo per passo in riproduzione.
- I benchmark provengono da un runner di scenari senza interfaccia, con una baseline per macchina e una soglia di zero allocazioni per tick.
L’obiettivo di progetto è fino a 1.000 detenuti e dipendenti a 20 tick al secondo. È un obiettivo: non ci sono ancora personaggi, quindi il benchmark runner esiste ma nulla è stato misurato a quella scala.