← Novità

v0.22-dev

2026-07-20 → 2026-07-26 · 63 voce/i di changelog

Sprint 7: tre KO — la cerimonia dei super si muove, il gatto magnetico fa «pouf», l'insegna del gattile parla inglese2026-07-26

  • [feat] SU-158 (KO) — la cerimonia dei super ora si muove come il level-up. Ingresso «a lancio sul tavolo» copiato da LevelUpScreen con i valori esatti di SU-111 (0.32s, stagger 0.09, rotazione extra 16°, TRANS_BACK/EASE_OUT) invece di ritararli: le carte arrivano da sotto invece di comparire di scatto. Input bloccato durante il volo (_entering), sia da tastiera/pad sia da tap — senza, si becca una scelta accidentale a mezz'aria. Coriandoli: tre sparate invece di una, sfasate a 0 / 0.18 / 0.36s — centro, alto-sinistra, alto-destra, con direzione e spread diversi per le diagonali. Il colore resta pescato per singola particella da color_initial_ramp: usare color_ramp è la cicatrice di SU-133 (mappa la vita della particella e fa uscire tutti i coriandoli dello stesso colore, KO già dato una volta). Le sparate ritardate sono guardate da is_open e gli emettitori liberati in _close(): niente botto a cerimonia già chiusa, niente nodi orfani. Brillio da 10 a 16 scintille e ciclo dimezzato, come chiesto. SuperCeremony.gd. Commit e15b7a0.
  • [fix] SU-151 (KO) — col GATTO MAGNETICO il gatto si sposta davvero. La causa: il ramo magnetico saltava del tutto la memoria dei «punti bruciati» introdotta il giorno prima da SU-157 e prendeva semplicemente il candidato più vicino al barbone — cioè quasi sempre il punto di raccolta stesso. Ecco perché sembrava che il gatto «tornasse» dove l'avevi preso. Ora anche il ramo magnetico passa dai punti bruciati, con soglia dedicata: 80px di spostamento minimo, ~1/4 dell'altezza inquadrata e oltre una volta e mezza il passo fra due spawn point contigui — si vede a occhio che si è mosso. Scartato il riuso dei 140px del ramo «fuori vista»: è più largo del raggio a vista e avrebbe reso i due requisiti incompatibili. «A vista» è definito come 0.42 × il lato MINORE del riquadro visibile, non la diagonale: agli angoli si vede più lontano, ma entro quel raggio il gatto è a schermo in qualunque direzione. World.gd. Commit 290afb3.
  • [fix] SU-151 — il «pouf» è la firma della carta, non della geometria (difetto trovato in collaudo, prima che arrivasse a Ivan). L'effetto stava in _spawn_cat_at(), che è la funzione comune a tutti gli spawn, gated solo su «il gatto è inquadrato». Ma lo spawn iniziale tiene i gatti a ≥150px dal barbone mentre il mezzo riquadro visibile è 205×153: la fascia fra 150 e 205px cadeva dentro, quindi all'avvio di ogni partita alcuni degli 8 gatti iniziali comparivano con la nuvoletta magica, senza nessuna carta — svuotando di significato proprio l'effetto che doveva firmare il potere. Ora il pouf richiede l'evento (flag alzato solo quando il ramo magnetico ha davvero scelto il punto) e tiene la geometria solo come condizione aggiuntiva, per non disegnare fuori schermo; il default false lascia muti spawn iniziale, refill e ramo client senza toccarne i call site. La texture 2×2 delle particelle è creata una volta sola e appesa a World (non static, così si libera con la scena invece di campare fino a fine processo): resources still in use at exit è passato da 2 a 1, e l'uno che resta è pre-esistente — verificato rimettendo World.gd pre-SU-151 e rieseguendo. L'effetto è tutto a primitive, nessun asset nuovo. Commit 6f67077.
  • [change] SU-151 — il pouf costa ZERO byte di rete. _cl_cat_spawned resta id + pos com'era: nessun flag in più sul tetto EOS di 1170 byte. Limite dichiarato: in MP il pouf lo vede solo l'host — coerente col fatto che la carta letta è la sua. Emerso di riflesso un difetto pre-esistente da valutare a parte: se è un *client* ad avere GATTO MAGNETICO, oggi non gli funziona affatto, perché la carta consultata per lo spawn è sempre quella dell'host.
  • [feat] SU-141 (KO) — l'insegna del gattile in due versioni (in attesa di approvazione), dopo il KO «se sono scritte le metterei sempre in inglese, il V2 è perfetto». Non rigenerato con Codex, modificato con PIL: Ivan ha chiesto la v2 «IDENTICA» e una rigenerazione avrebbe rifatto tetto, gatti ed edera, cioè un terzo disegno da riapprovare. Prova numerica: 0 pixel diversi dalla v2 fuori dal rettangolo dell'insegna, 96×124 invariati, alpha binario. Testo CATS e non «CAT SHELTER»: il cartello è largo 39px e 11 lettere sarebbero diventate una riga grigia. Il primo tentativo di insegna vuota lasciava i fantasmi delle lettere (ombre e contorni sopravvissuti al riempimento per riga): rifatto ricostruendo la tavola dalle sole colonne mai coperte dal testo, con misura di controllo della deviazione dal legno pulito (4.9 → 1.25). sprites_raw/BUILDINGS/temp/, anteprima TMP/su141_insegna_confronto.png.
  • [test] Il provino della cerimonia ora esercita anche i coriandoli. Il collaudo ha girato tre run (110s, 300s, 2000s) senza mai far aprire la cerimonia dei super — serve un potenziamento a livello 9, evento raro: coriandoli e ingresso non erano mai stati eseguiti davvero, e le proprietà di CPUParticles2D si assegnano a runtime, dove il compile-check non arriva. Un nome sbagliato sarebbe uscito solo in partita. shot_super.gd ora accetta un frame di volo e chiama a mano _spawn_confetti_triple(): esito, nessun errore a runtime, coriandoli multicolore, sparate laterali in diagonale. Provini in TMP/screenshots_claude/su158_ko2_{dopo,volo,coriandoli}.png. Commit d5bf5e5 esteso in 9eb5547.
  • [docs] La regola «le scritte negli asset vanno in inglese» è stata promossa a convenzione di progetto (00_CONTESTO_PROGETTO.md), con la distinzione che conta: testi UI e commenti restano in italiano, il testo *cotto dentro il pixel* va in inglese perché non è localizzabile senza rigenerare l'arte. Aggiunta anche la regola operativa: per cambiare una scritta su arte già approvata si modifica il PNG, non si rigenera.
  • [docs] I quattro agenti in .claude/agents/ hanno ora la regola sui processi in background. In una sola sessione tre agenti hanno chiuso il turno «in attesa» di run nohup/Monitor che non notificano mai, costringendo ad altrettanti resume manuali: la regola era in ORCHESTRAZIONE.md ma non nelle definizioni degli agenti, che è dove serve. Corretto anche un riferimento ormai sbagliato nel collaudatore (il binario Godot Linux ARM64 vale solo in sandbox Cowork; su questo Mac si usa /Applications/Godot.app) e aggiunto il promemoria che i path di check_files.sh vanno relativi a files/homeless_city/.
  • [test] Collaudo di fine onda: compile-check 63 script / 22 scene, 0 falliti. Run bot 110s più due lunghe (300s e 2000s): 0 SCRIPT ERROR, orfani 0 in tutti i campionamenti, gatti stabili a 8. Verificato staticamente che i nodi nuovi della cerimonia sono MOUSE_FILTER_IGNORE e che la selezione della carta resta raggiungibile. Non verificabili qui: il pouf a video e tutto il multiplayer. Dettagli in TESTLOG.md.

Sprint 6: i messaggi non coprono più l'HUD, i gatti non tornano dove li hai presi, le carte super si leggono2026-07-26

  • [change] SU-162 — i messaggi piccoli non esistono più come sistema separato. Il gioco aveva due pile parallele: i toast di _queue_notification (fame, sonno, «Entrato: …») e le big notification. Ora tutto confluisce nel formato massimizzato, come chiesto da Ivan. EventBus.notify() resta come API — la chiamano DebugPanel e altri file — cambia solo l'implementazione: rimosse _create_notif, _free_notif, _reposition_notifs, la lista _active_notifs e le costanti MAX_NOTIF/NOTIF_* salvo NOTIF_LIFE. Scartata l'alternativa «tenere i toast e ridimensionarli»: avrebbe raddoppiato la geometria da mantenere e SU-161 sarebbe andato scritto due volte. HUD.gd. Commit 69f49aa.
  • [fix] SU-161 — nessun messaggio finisce più sopra l'HUD, e il font scende solo a chi serve. La non-sovrapposizione è geometrica, non a costanti: si calcola un «corridoio libero» dai Rect2 reali dei nodi HUD visibili (pannello stat, etichette in alto a destra, indicatori gatto/vino, bottoni touch) e lo si interseca con la fascia verticale del singolo messaggio. Estende SU-145 invece di reinventarlo. Scartata l'idea di far partire la pila sotto *tutto* l'HUD superiore: il pannello stat è alto 276px e i messaggi sarebbero finiti a metà schermo. Il rimpicciolimento del font è per singola label (38→16 a passi di 2, misurando il testo ripulito dai tag BBCode e contando le [img] con la larghezza dichiarata), poi autowrap fino a 3 righe. La pila impila sul fondo reale dei messaggi attivi, non a slot fissi, perché ora ognuno può avere font e righe diverse. HUD.gd. Commit 69f49aa.
  • [change] SU-164 — via il nome del distretto in basso, con un effetto collaterale che va detto. La label rimossa (DistrictLabel, tolta anche da HUD.tscn) non mostrava solo il nome: mostrava "NOME [reputazione]", ed era l'unico punto a schermo che mostrasse la reputazione del distretto — informazione di gioco, non decorazione. Il calcolo resta vivo in _district_rep_label ma ora non si vede da nessuna parte: decisione lasciata a Ivan, nessuna nuova collocazione inventata. Il messaggio in alto «Entrato: …» resta (il ticket parla della scritta in basso) e con SU-162 è diventato massimizzato: se stona è una riga da cambiare. HUD.gd, HUD.tscn. Commit 69f49aa.
  • [fix] SU-165 — la mappa non si riapre più per sbaglio. Cooldown ~0,5s sulla riapertura, tenuto distinto dalla guardia anti-doppio-toggle di SU-134 (sono due cose diverse: quella copre la stessa finestra di input, questo copre il mezzo secondo dopo la chiusura). Coperti entrambi gli ingressi, tasto e bottone touch; la chiusura resta sempre istantanea, altrimenti la mappa si sarebbe potuta bloccare aperta. HUD.gd. Commit 69f49aa.
  • [fix] SU-157 — i gatti non ricompaiono più dove li hai raccolti, e stavolta la causa è quella giusta. SU-151 e SU-152 avevano irrobustito la soglia di distanza e non era bastato («capita a volte»). Il motivo: _pick_hidden_cat_spawn() pesca da un pool fisso di punti e misurava la distanza dalla posizione attuale dei barboni — il punto dove avevi appena raccolto restava nel pool, quindi bastava allontanarsi perché ridiventasse un candidato «perfettamente lontano». L'«a volte» era soltanto lo shuffle del pool. Buco secondario: il fallback accettava qualunque punto, incluso quello appena liberato. Ora c'è memoria dei punti di raccolta (coda host/SP-only, TTL 60s, raggio 140px): i punti bruciati sono saltati a ogni livello di rilassamento e il fallback ripiega sul più lontano non bruciato. Il punto si annota nel frame in cui il gatto raccolto è ancora in tree — l'unico istante in cui l'host lo conosce, e copre anche la raccolta di un client. La coda non entra in nessun RPC (zero byte sul tetto EOS 1170) e non tocca l'RNG: lo spawn iniziale seedato resta identico. Limiti dichiarati: oltre 60s un punto torna candidato (voluto), e lo spawn iniziale usa ancora solo il guard di 150px dal player — non può riprodurre il bug, non è stato toccato per non allargare il fix. World.gd. Commit aff2a5c.
  • [change] SU-163 — il seed non si stampa più a schermo, resta solo sul log come [World] Seed mondo: … (il TestBot lo cattura). world_seed, GameState.run_seed e la sincronizzazione MP non sono stati toccati. World.gd. Commit aff2a5c.
  • [fix] SU-158 — le carte super finalmente si leggono, e ci sono voluti due giri. Erano rimaste al layout pre-SU-73/SU-85: titolo appiccicato in alto e tagliato dalla cornice, icona piazzata a occhio e in un caso fuori dalla finestra (il berretto di AMNESIA usciva del tutto). Portati da LevelUpScreen — copiandone valori e formule invece di ritararli — misura 200×278, _icon_window_rect() e blocco testi centrato tra finestra-icona e fondo carta. La scelta dell'icona non è stata toccata (hi-res, atlante super, caso speciale scoreggia_atomica): cambia solo come viene posizionata. Secondo giro, trovato col provino PNG: «AMNESIA COLLETTIVA» si leggeva «NESIA COLLETTIV» — e la causa non era la larghezza della carta, il titolo ci stava dentro, ma la fascia visibile tra due carte accavallate del ventaglio (≈128px su 200). L'a-capo è calcolato a mano sul font reale contro quella fascia, così il VBoxContainer continua a centrare il blocco; se una parola non entra nemmeno da sola scende il font solo di quella carta. Brillio (esperimento chiesto da Ivan): scintille quadrate sul perimetro, coordinate intere, nessun blur — doveva sembrare pixel art; portate da 3×3 a 4×4 con bordo scuro perché a 3×3 erano invisibili e l'esperimento non sarebbe stato giudicabile. Tutte MOUSE_FILTER_IGNORE per non rubare il tap. Residuo noto: sulle carte non selezionate il sottotitolo «SUPERPOTERE · liv. 10» è ancora tagliato a sinistra — testo identico su tutte le carte, nessuna informazione persa. SuperCeremony.gd. Commit 35b6e10 + 1e4ae3c.
  • [test] Due strumenti nuovi che tolgono di mezzo interi giri di KO: scripts/tools/shot_super.gd e shot_hud_notif.gd, gemelli di shot_cards.gd. Aprono solo la schermata interessata, le sparano addosso il caso difficile (tre super con nomi di lunghezza diversa; un messaggio corto, uno lunghissimo e uno medio) e catturano dal viewport, quindi girano su questo Mac senza il permesso «Registrazione schermo» che manca. Sono serviti subito: il confronto prima/dopo ha mostrato il difetto dei titoli, che il solo compile-check non vede. Provini in TMP/screenshots_claude/su158_super_{prima,dopo}.png e su161_messaggi.png.
  • [feat] SU-155 — 4 ciuffi d'erba per il marciapiede (in attesa di approvazione). PixelLab, 32×32, alpha binario, palette campionata da wang_sidewalk_grass.png. Nota onesta: non sono equivalentia e d sono fili d'erba veri, b si porta dietro una zolla di terra marrone che su un marciapiede può stonare, c è un cespuglio tondo e non un ciuffo. Risposta alla nota del ticket: nel tileset SU-117 l'erba è una texture Wang continua, non ci sono ciuffi isolati estraibili come decal → niente doppioni. sprites_raw/WORLD/temp/, anteprima TMP/su155_erba_preview.png.
  • [feat] SU-159 — icone lampadina e tromba (in attesa di approvazione). Codex per i master, ridimensionamento a 48/32 in PIL (crop del bounding box, LANCZOS, soglia alpha binaria) invece di rigenerare. Leggibilità a 32px verificata sulla simulazione della notifica reale: la lampadina resta nettissima, la tromba è più affollata ma la sagoma si riconosce. sprites_raw/UI/temp/, anteprima TMP/su159_icone_preview.png.
  • [feat] SU-147 (KO) — marmotta rigenerata, e consegnata in DUE versioni (in attesa di approvazione). Il KO di Ivan («falla simile a quella allegata») allegava una marmotta a figura intera, mentre il testo del ticket chiede un muso: contraddizione reale, non risolta a indovinare. Consegnate entrambe nella stessa palette. Leggibilità a 32px: il muso vince nettamente — la figura intera resta riconoscibile come animaletto seduto ma perde l'espressione comica, che è metà del senso della notifica. Il riferimento di Ivan è arte di terzi firmata «TJPECK»: usato solo come guida di stile, le immagini sono originali e senza firme. sprites_raw/UI/temp/, anteprima TMP/su147_marmotta_v2_preview.png.
  • [docs] 6 ticket dello sprint non erano lavorabili e sono stati annotati invece che forzati: SU-83 (aspetta SU-153, che non è nemmeno nello sprint), SU-120 (aspetta SU-118), SU-142 (aspetta SU-141), SU-150 (aspetta SU-147), SU-156 (aspetta SU-155), SU-160 (aspetta SU-159). Tutti bloccati dalla stessa regola: le implementazioni non partono finché la generazione non è Fatto, cioè approvata da Ivan.

Sprint 5: la metropolitana si vede davvero, il suolo a TileMap, le torri dei distretti2026-07-25

  • [fix] SU-123 (KO) — la metropolitana non compariva mai a chi ha il tutorial attivo. Il gate verso la schermata stava solo nel ramo di _on_start_pressed() con Settings.show_tutorial = false: le voci «NO, VAI AL GIOCO» e «NON MOSTRARE PIÙ» della domanda tutorial chiamavano _start_game(GAME_SCENE) diretto, saltando la metropolitana per intero — e siccome show_tutorial è il default di un giocatore nuovo, la schermata era di fatto irraggiungibile. Ora c'è un gate unico _goto_metro_or_start() usato da tutti gli avvii non-tutorial, che applica la regola chiesta da Ivan: ≥2 quartieri sbloccati → compare la metropolitana; solo il Centro → parte dritto (zero attrito per chi inizia, criterio originale del ticket). Tolto anche il _can_input = false prematuro da quelle due voci: lo spegne solo chi avvia davvero la partita, altrimenti la metropolitana sarebbe nata con l'input morto. «SÌ, FAI IL TUTORIAL» invariato. Il ritorno indietro non è stato toccato: show_screen()/go_back() usano già uno stack vero, quindi «← INDIETRO» torna da sé al menu o alla domanda tutorial. Verificato che F1 funziona già dal menu principale (DebugPanel è autoload con PROCESS_MODE_ALWAYS): è da lì che Ivan sblocca i quartieri per vederla. MainMenu.gd. Commit 4fadd06.
  • [feat] SU-119 — il suolo può diventare un TileMapLayer con i tileset Wang approvati (SU-117), ma nasce SPENTO. Nuovo TerrenoTileMap.gd: fa da converter Wang→TileSet (16 tile × 4 catene, terrain set in TERRAIN_MODE_MATCH_CORNERS, quindi il tileset è anche dipingibile a mano dall'editor) e da pittore del suolo. Scelta di merito: scartato set_cells_terrain_connect perché con celle da 32px e isolati da 96 l'autotiling di Godot genera inevitabilmente celle con angoli asfalto + erba, accostamento per cui non esiste catena Wang → tile di ripiego a caso. Si dipinge invece il campo di VERTICI rientrando parchi e piazze di una cella: l'accostamento vietato diventa impossibile per costruzione (0 ripieghi su 2601 celle, zero randf(), deterministico dal seme). Tinta di distretto via TileData.modulate per tile, così sui tile di transizione i due colori si mescolano in proporzione agli angoli accesi e la cucitura non stacca. generate() 28 ms contro 94 ms dell'ibrido, 140 nodi contro 187. TutorialWorld migrato allo stesso layer. WorldGenerator.gd, TerrenoTileMap.gd (nuovo), TutorialWorld.gd, DebugPanel.gd, assets/sprites/world/tilesets/. Commit ea72a54.
  • [change] SU-119 — default SPENTO, e il motivo è visivo, non tecnico. Il confronto a video dice che così com'è il TileMap perde su due superfici su tre. Sulla strada asfalto e marciapiede hanno luminanza quasi uguale (66 contro 116 nei materiali SU-117, piazza 73) e sparisce il cordolo in cemento: non si legge più dove finisce la carreggiata, che in un top-down è leggibilità di gioco, non gusto. Dentro il parco spariscono i sentieri e i cespugli di park.png e si vede il motivo ripetuto a griglia. Vince — e nettamente — solo sul bordo dell'erba, dove il taglio rettangolare secco era il difetto storico. Accenderlo di default avrebbe significato consegnare una città peggiore di quella approvata al GATE SU-60 la mattina stessa. Resta quindi l'ibrido, non toccato di una riga, e il TileMap si accende da F1 → TERRENO WANG → «TileMap». Terza via consigliata per il seguito: TileMap per erba e piazza dentro l'isolato, piastre ibride per strada e marciapiede — il codice è già commutabile, è un follow-up piccolo.
  • [feat] SU-118 (KO) — 7 TORRI, una per distretto (in attesa di approvazione). Il KO di Ivan diceva «le generazioni vanno bene» e toglieva il tetto dei ~160px («quelli alti coprono gli edifici dietro»): i 18 edifici già approvati non sono stati toccati, si è generata la taglia che mancava. Larghezza 96 (entrano negli slot esistenti senza inventare larghezze nuove), altezze reali 211-252px: downtown 96×252 · industrial 96×245 · rich 96×238 · commercial 96×231 · nightlife 96×228 · slums 96×216 · residential 96×211. Codex, 7 chiamate in parallelo con la w96 approvata dello stesso distretto come riferimento -i, 4 retry in tutto, nessun asset scartato. sprites_raw/WORLD/temp/objects/ + manifest in append (25 asset), preview skyline e per distretto in TMP/. Nota onesta: le torri sono slanciate 1:2.5 e i piani si ripetono regolari — se in gioco risulteranno monotone la correzione è un secondo giro sui soli piani, non una rigenerazione.
  • [docs] La parte «di piazzamento» del KO SU-118 è stata girata su SU-120, dove è lavoro vero. Ivan aveva scritto nel ticket di *generazione* una regola che riguarda il *generatore*: tradotta in 5 regole operative (candidatura solo nei super-blocchi 3×3 · test di occlusione sul «cappello» dello sprite proiettato a nord contro edifici, entry point e consumabili · esclusione di quel rettangolo dagli spawn gatti, altrimenti si generano gatti invisibili · determinismo dal seme per MP · z-order per base). Il filtro sui 3×3 e il test di occlusione insieme rendono superfluo scegliere a priori fra le due opzioni che Ivan proponeva.
  • [test] Collaudo di fine onda: compile-check totale 61 script / 22 scene, 0 falliti. Il controllo che contava — col TileMap spento l'ibrido è tornato identico — verificato pixel-per-pixel contro gli screenshot di riferimento (seme 424242, stessi 3 punti): asfalto, sampietrini, cordolo e park.png identici. TileMap acceso: 0 SCRIPT ERROR, npcs/cats invariati, mem.orphans=0, fps ~145. Tutorial OK in entrambe le modalità. SU-123 verificato per analisi statica di tutti i rami ma non interattivamente: screencapture fallisce per permesso «Registrazione schermo» assente. Dettagli in TESTLOG.md.

SU-82 (KO): il Quaderno diventa leggibile — inchiostro scuro su carta2026-07-25

  • [fix] Il Quaderno non si leggeva. Causa: la palette era tutta CHIARA (corpo #f2f2fa, descrizioni #a9a9b4, titoli gialli, ombra nera) — ereditata dalle schermate a fondo scuro — mentre il pannello è il cartone chiaro (CardboardPanel). Le descrizioni sparivano letteralmente nel fondo. Ora è un quaderno vero: inchiostro scuro su carta, con la gerarchia data dal TONO e non dalla luminosità — corpo COL_INK bruno scuro, descrizioni COL_SUB bruno medio, intestazioni COL_HEAD rosso-bruno da timbro, accento COL_ACCENT per i superpoteri battezzati, linguette scure (selezionata quasi nera + ). L'ombra nera è diventata un filo di luce (COL_SHADOW): sotto un testo scuro su carta chiara l'ombra scura impastava.
  • [change] Via l'emoji dal titolo (richiesta di Ivan): resta solo «IL QUADERNO», un filo più grande.
  • [fix] Le descrizioni lunghe non sbordano più. Erano indentate con spazi, quindi la riga che andava a capo ripartiva dal margine e la frase sembrava uscire dal pannello (si vedeva sull'impresa «battezza tutto quello che c'è da battezzare…»). Ora usano [indent] BBCode: anche il capoverso resta allineato. Aggiunto line_separation e più respiro sotto l'area scorrevole, dove l'ultima riga restava tranciata a filo del suggerimento.
  • [test] Nuovo strumento scripts/tools/shot_quaderno.gd (stesso pattern di shot_cards.gd): apre solo il Quaderno, sceglie la sezione e salva il PNG catturando dal viewport, senza il permesso macOS «Registrazione schermo». Provini delle tre sezioni in TMP/screenshots_claude/su82_quaderno_*.png. check_files OK.

Sprint 4: feedback a icone, scorregge col conto, gatti nascosti, coriandoli veri2026-07-25

  • [fix] SU-133 (KO) — coriandoli finalmente multicolore. Il colore stava su color_ramp, che in CPUParticles2D mappa la VITA della particella: a ogni istante i coriandoli erano tutti della stessa tinta e cambiavano insieme, da cui l'effetto monocromatico che Ivan vedeva. Ora la tinta si pesca per singola particella da color_initial_ramp con 9 colori a interpolazione CONSTANT (rosso, arancio, giallo, verde, ciano, blu, viola, rosa, bianco); color_ramp resta solo per la dissolvenza finale. Traiettoria centro → ventaglio → caduta veloce invariata. LevelUpScreen._spawn_confetti. Commit c0255f2.
  • [fix] SU-145 — le notifiche grosse non stanno più addosso alla barra di livello. Erano ancorate a una frazione fissa dello schermo (BIG_NOTIF_Y_OFFSET = -0.42): a 720p la prima riga partiva a ~25px mentre la barra XP finisce a ~32px. Ora la pila parte sotto il fondo reale della barra XP + 18px (BIG_NOTIF_GAP_XP), safe-area inclusa, con fallback sulla stessa quota calcolata dalle costanti se la barra non è ancora dimensionata (così non salta mai sul notch). Tempi, logica e tetto BIG_NOTIF_MAX = 3 invariati. HUD.gd::_create_big_notif. Commit c0255f2.
  • [feat] SU-144 — bidoni, fontana e panchina parlano per icone, non per messaggi. Player.spawn_coin_fx generalizzata in spawn_stat_fx(icona, testo, colore, tint, size_mul) — la firma pubblica di spawn_coin_fx NON cambia, quindi NPC/ModularNPC/MoneyCoin/World restano identici; sopra di essa spawn_bin_food_fx, spawn_bin_sock_fx, spawn_fountain_fx, spawn_bench_fx. Icone riusate dal progetto (shower.png, sleep.png, le stesse dell'HUD per quelle stat): zero asset nuovi. Colori letti dalle costanti PB_COL_* di HUD.gd via preload, non ricopiati. Il messaggio «fontana ghiacciata» resta in alto: è un rifiuto, non un recupero. Economia dei recuperi non toccata; nessun RPC nuovo. Player.gd, Interactable.gd. Commit ab74d3b.
  • [feat] SU-146 — la scorreggia ha un costo sociale. −5 igiene a colpo (gate run_active, tutorial intatto); finestra scorrevole di 10s su timestamp, al 5° colpo igiene azzerata + «OOOOPS!!! LA MARMOTTA È USCITA DALLA TANA» e finestra svuotata (niente azzeramento doppio a raffica). Nuova GameState.sporca(amount), simmetrica di wash() con clamp [0,100] (la firma di wash non è stata toccata). Immunità della SCORREGGIA ATOMICA verificata nel codice: il super non instrada mai da _do_fart() (passa da super_show_fx), quindi non è servito modificare SuperPower.gd. Icona marmotta a placeholder emoji finché SU-147 non è approvata (aggancio vero in SU-150). Player.gd, GameState.gd. Commit ab74d3b.
  • [fix] SU-151/SU-152 (duplicati) — i gatti di rimpiazzo non ricompaiono più a vista. Causa vera: CAT_HIDE_DIST era fissa a 520px, cioè sotto la mezza diagonale del viewport su schermi larghi — il rimpiazzo poteva cadere dentro l'inquadratura, e questo spiega il «capita a volte» dei ticket (dipendeva da aspect ratio e zoom, non dal caso). Ora la soglia è max(780px, mezza diagonale reale del viewport/zoom) e la ricerca rilassa progressivamente il vincolo in 12 tentativi prima del fallback: mai loop infinito, mai senza gatti. Gattopoli non è rotta: soglia al 60% (ravvicinata ma non azzerata) riusando il mult gatti_respawn esistente. Spawn ravvicinati solo con GATTO MAGNETICO. Host-authoritative, nessun RPC nuovo. World.gd::_pick_hidden_cat_spawn. Commit f5863d7.
  • [change] SU-148 — il multiplayer diventa solo ONLINE. Il menu MP perde «unisciti a IP locale» e guadagna CERCA PARTITA; la schermata degli ottetti IP non è più registrata né costruita, ma funzioni e ramo input restano nel codice annotati «solo harness» perché run_mp.sh headless ne ha bisogno. Nuovo gate _mp_require_online() su quick/host/browse/codice. Rimosso il fallback SU-70 (EOS fallito → lobby ENet locale, decisione esplicita di Ivan): ora esce «L'ONLINE FA I CAPRICCI — RIPROVA TRA UN PO'» e si ferma. OSPITA nasce pubblica; codice sessione in evidenza in lobby (righe slot 0.072→0.062 per fargli posto). MainMenu.gd, NetworkManager.gd. Commit 8892efd.
  • [fix] SU-143 — navigazione coerente nei menu con un campo. In codice sessione e nome MP: ↑/↓ tra le voci, ←/→ dentro il campo, memoria del cursore per rientrare dove si era. La regressione SU-123 sospettata sugli indici della lobby MP è stata verificata a vista e non esiste (host 0=QUARTIERE 1=AVVIA 2=PUBBLICA 3=BACK, guest 0=PRONTO 1=BACK, coerenti in move/activate/refresh/tap). Trade-off segnalato a Ivan: sul pad A ora fa girare il carattere invece di avanzare, quindi il codice a 6 caratteri col solo pad è più lento. MainMenu.gd. Commit 8892efd.
  • [feat] SU-149 — CERCA PARTITA. Nuova schermata mp_browse: lista lobby pubbliche con nome host, giocatori n/max, barre ping, RIAGGIORNA e Indietro, navigazione pad/tastiera/touch, lobby piene non selezionabili. EOSBridge toccato solo su create_lobby/_search (attributi host e fuso; login, handshake, trasporto e join non sfiorati). Nuove browse_lobbies()/join_public_lobby()/_first_joinable() — bonus: neanche la partita rapida sbatte più contro lobby piene. Ping: EOS non espone l'RTT prima del join e il plugin non ha API di regione (verificato) → stima onesta a 3 fasce dal fuso orario dell'host, barre grigie quando il dato manca, legenda che dichiara che è una stima; le soglie in ms restano pronte per il giorno in cui arrivi un ping vero. Commit 8892efd.
  • [feat] SU-118 — 18 edifici a proporzioni diverse per 6 distretti (in attesa di approvazione): stretto/standard/largo per residential, commercial, nightlife, slums, industrial, rich, con le palette del brief. Downtown NON rigenerato (le tre taglie del pilota SU-60 sono già approvate). Prospettiva verificata su tutti: piano del tetto dall'alto + facciata. Nota onesta: gli «stretti» sono 36-43px invece di 48 esatti perché Codex li ha disegnati ~1:4 e il vincolo duro è l'altezza ~160px (oltre coprono la strada) — si è preferito rispettare il tetto piuttosto che consegnare edifici che tagliano la carreggiata. 18 generazioni, 0 retry, lanciate in parallelo a lotti di 6: è ciò che ha reso il ticket fattibile in una sessione, dopo che il tentativo sequenziale si era arenato. sprites_raw/WORLD/temp/objects/ + manifest, preview per distretto e skyline in TMP/.
  • [feat] SU-117 — 4 catene Wang 32×32 del terreno (in attesa di approvazione): asphalt↔sidewalk, sidewalk↔grass, grass↔dirt, sidewalk↔plaza. Il primo giro è stato bocciato in casa: transizioni ancora a gradini di 90° tra campiture piatte, cioè il «look squadrato» che il ticket voleva eliminare — la metrica usata misurava le cuciture, non la morbidezza. Il secondo giro l'ha risolto: blend bilineare sui 4 bit d'angolo (combacia lungo ogni lato condiviso) deformato da un campo di displacement periodico + dithering di confine, fascia di mescolanza misurata 8.9px, e grana vera aggiunta a erba e terra. Asfalto senza strisce direzionali (riusa lo swatch SU-60 approvato). Solo 2 chiamate a Codex per gli swatch, il resto composto in PIL — Codex non produce autotile Wang affidabili, come già concluso dal pilota SU-60. Nota: la catena asphalt↔sidewalk è in parte ridondante con l'ibrido runtime già in gioco da SU-60; il valore nuovo sono le altre tre.
  • [feat] SU-147 — icona marmotta generata (in attesa di approvazione): muso marrone con espressione colpevole, verificata la leggibilità a 32px sulla simulazione della notifica reale. sprites_raw/UI/temp/su147_marmotta_{32,48}.png, anteprima TMP/su147_marmotta_preview.png.
  • [feat] SU-141 — gattile rigenerato con Codex (in attesa di approvazione), dopo il KO «fa pena, va rigenerato con codex». Al QC visivo la prima versione Codex è risultata quasi frontale, mentre tutti gli edifici del gioco mostrano il piano del tetto dall'alto: un altro KO annunciato. Fatto un giro in più → v2 con la prospettiva di gioco (tetto piatto con parapetto, 5 gatti che dormono visibili dall'alto, insegna «GATTILE» verificata, gatto alla finestra, ciotole, edera), 96×124 px. Entrambe in sprites_raw/BUILDINGS/temp/, confronto a 4 pannelli con un edificio vero come metro in TMP/su141_confronto.png.
  • [docs] SU-83 sbloccato con una coppia di ticket e una decisione di architettura. Analisi del sistema sprite del giocatore: il gatto in braccio è disegnato dentro lo sheet (player_cat_sheet.png), come ubriaco e fantasma — quindi 8 skin × 4 stati = 32 sheet, e ogni prop futuro (la lanterna) ne aggiungerebbe altri 8. Scoperta chiave: ModularNPC._add_accessory_overlay()/_sync_accessory_frames() è un sistema di overlay già scritto e funzionante (Sprite2D figlio sulla stessa griglia 5×5, sincronizzato via frame_changed), con la cartella assets/sprites/npc/accessories/ vuota — motore pronto, mai acceso. Proposto il modello a tre livelli (CORPO 1 sheet per skin · PROP 1 sheet condiviso per oggetto · STATO come tinta/effetto, senza sheet): da crescita moltiplicativa a additiva. Nuovi ticket SU-153 (generazione 8 skin, blocca SU-83) e SU-154 (sistema a livelli).

Workflow: /sprint e /ko partono direttamente su Opus 5 come architetto2026-07-25

  • [change] I comandi /sprint e /ko ora girano SEMPRE su Opus 5 (frontmatter model: opus in .claude/commands/sprint.md e ko.md; per /ko stesso protocollo con lotti più piccoli, KO integrale nel brief e screenshot di verifica sui KO di layout): Opus assume il ruolo di architetto-orchestratore — scompone in lotti a file disgiunti, delega in parallelo a dev-sonnet (o a builder architetto-opus per i lotti profondi, a sua valutazione) e chiude lui commit/CHANGELOG/Jira. Nota tecnica: i subagenti non possono spawnare altri agenti, quindi l'architetto dev'essere il primo ponte della sessione — il frontmatter model è il modo per garantirlo.
  • [change] ORCHESTRAZIONE.md, sezione «Opus come primo ponte» riscritta: superata la vecchia regola «Opus non delega ad architetto-opus» — la parallelizzazione e la resilienza valgono più del cold-start. Aggiunta la regola della capsula di contesto costruita UNA volta per sprint e riusata in testa a ogni brief (ticket integrali inclusi): gli agenti non toccano mai Jira né i doc di progetto. Nota «Chi orchestra» anche in WORKFLOW/02_SPRINT.md.

SU-60 GATE (iterazioni live con Ivan): pelle originale + cordolo basso + marciapiedi larghi2026-07-25

  • [change] La pelle del terreno torna quella ORIGINALE (feedback Ivan: «prima erano così e mi piaceva lo stile» — la grana Codex a periodo 32px sembrava meno dettagliata). La piastra Wang ora si compone in gioco: fondo street.png allineato al mondo, lastre pedestrian.png a dimensione nativa 96px ritagliate dalla MASCHERA delle transizioni (blit_rect_mask), e sopra un velo cordolo semitrasparente (luci/ombre) che lascia vedere la grana vera. Dall'atlas AI restano solo maschera e velo (su60_wang_mask.png + su60_wang_curb.png, generati con PIL dalla struttura PixelLab v2); il fondo strade è tornato TEX_STREET puro.
  • [change] Cordolo basso (Ivan: «più alto della v2 piatta, meno della v1»): lato sud spigolo luce + faccia pietra 2px + ombra di contatto; fili di luce/ombra sui lati; occlusione a nord.
  • [change] Marciapiedi che sbordano dagli isolati (Ivan: «non esistono più i marciapiedi»): WANG_SIDEWALK_PAD=40 — la cucitura cade ~16px dentro il bordo piastra, col pad 10 il marciapiede pieno finiva a filo palazzo; ora sborda di ~24px e tra due piastre resta un canale stradale di ~48px.
  • [feat] Manopole del terreno nel pannello F1 (sezione «TERRENO WANG», valgono dalla prossima run): ON/OFF, sbordo piastra, rialzo prospettico, tono strada, scala e scurità della pietra marciapiede, larghezza cordolo, luminosità cemento, raggio angoli. Per renderle vive, maschera e velo cordolo ora si generano a runtime dalla geometria (WorldGenerator._build_wang_atlases: bordo a 16px, archi, erosione per la fascia cemento) — niente più PNG fissi in dev_pilota; class_name WorldGenerator + manopole come static var. Iterazioni della sessione col GATE di Ivan: cordolo in cemento chiaro (reference foto), pietra marciapiede dimezzata e più scura della strada, via il giunto interno.
  • [change] Stato FINALE congelato dal GATE di Ivan (default di codice = sua taratura): strada scurita (tono −0.30) · marciapiede = lastre pedestrian originali (×1.0) · cordolo cemento 2px a ×1.6 sul punto medio, sfumato a dithering verso le lastre, ombre e faccia solo a sud · sbordo 34 · rialzo 3 · angoli 10. Manopole tonali/dimensionali (Strada±/Scala/Luce±) nascoste dal pannello F1 ma vive nel codice (si riattivano scommentando una riga); la manopola Scala resta il selettore superficie: 0.5 = i sampietrini disegnati con Codex (pedestrian_stones.png, nuovo asset, 3 generazioni per averlo organico) tenuti in gioco per usi futuri (es. per-quartiere in SU-117).
  • [test] check_files OK e smoke Centro PASS a ogni giro (solo i 2 rumori noti). Tutto dietro wang_enabled (false = look storico, zero residui — anche dal pannello F1).

SU-60 GATE: terreno Wang ibrido montato NEL GIOCO, con interruttore2026-07-25

  • [feat] L'asfalto e i marciapiedi della città usano il tileset ibrido (struttura PixelLab + pelle Codex): ogni isolato ha la sua piastra con angoli arrotondati e cucitura scura verso l'asfalto, composta a misura esatta via Image.blit_rect (un solo Sprite2D per piastra, crop sulle bande per le misure non multiple di 32). Fondo strade = cella "tutto asfalto" tileata. WorldGenerator.gd: flag GATE_WANG_TERRENO (true) + _make_walk_plate/_wang_ready/_wang_flat_tex + tabella WANG_CELL dal metadata PixelLab; i riempimenti pedonali interni ridondanti sono saltati col flag acceso (coprirebbero le transizioni). Revert in un secondo: GATE_WANG_TERRENO = falsestreet.png/pedestrian.png intatti su disco e percorso storico preservato. Compatibile con la palette terreno per-quartiere (SU-140, modulate applicato alla piastra). Solo visuale: MP invariato (nessun RPC), vale anche nel tutorial (stesso generatore).
  • [fix] Notifiche HUD, secondo giro: il fix del mattino barattava l'errore del tween con un erase di oggetto liberato su TypedArray — ora _free_notif/_free_big_notif erasano e liberano SOLO se l'istanza è valida (se è già stata liberata dal tetto, il pop_front l'aveva già tolta dalla lista).
  • [test] check_files OK su WorldGenerator e HUD; smoke run Centro col bot: PASS, generazione ok con le piastre ibride, unici errori i 2 rumori noti (NavigationServer al primo frame, resources at exit). Da provare in editor: Play → città con le transizioni; giro quartieri (neve/arso/smog modulano anche le piastre); revert flag se non convince.

Sprint 3, onda 1: quartieri peculiari, ragnatela carte, Quaderno, pilota Codex2026-07-25

  • [fix] SU-136 — i gatti raccolti ora scompaiono davvero. La causa non era il refill: SU-127 aveva innestato _use_gattile() DENTRO la coda di _use_cat() in Interactable.gd, rubandole consumo di rete, refill e queue_free — così il gatto restava in strada E il gattile si autodistruggeva dopo una consegna. Coda restituita, gattile persistente (cooldown 30s), e World._ensure_cat_count ora ignora i gatti già in coda di cancellazione (il rimpiazzo contava il morente e non spawnava). Commit 950972d.
  • [feat] SU-138 — ogni quartiere ha il suo layout. Sezione layout nel QuartiereDef (LAYOUT_DEFAULTS = valori storici del generatore: Centro invariato bit-per-bit a parità di seed, sequenza rng intatta): Gattopoli verde e panchine, Fumarola compatta senza parchi e piena di bidoni, Collina ariosa, Mercato di piazze, Brina stretta e spoglia, Solleone parchi e fontane, Nottefonda fitta di palazzoni. WorldGenerator._load_quartiere_layout/_decide_footprints/_scatter_interactables.
  • [feat] SU-139 — nemici di casa. Schema WeakRef self-limiting (come la ronda): a GATTOPOLI c'è sempre una gattara in giro anche di giorno; a FUMAROLA uno spazzino presidia i bidoni — entro 110px li blocca col meccanismo del nastro (SU-115) e rovistare viene rifiutato con battuta. Nuovo mult ronda_chance (Nottefonda 1.3, Brina 0.8). DistrictSpawner._home_enemy_needed, ModularNPC._update_cleaner (regge quartieri senza parchi).
  • [feat] SU-140 — atmosfera per quartiere. Tinte leggere (alpha 0.09-0.20: Brina azzurrino, Solleone dorato, Fumarola smog, Collina appena dorata) miscelate in World._update_day_night SOTTO giorno/notte e overlay ondate (_blend_tints, gate run_active → tutorial intatto); palette terreno terreno {strade, marciapiedi, erba} (neve a Brina, erba arsa a Solleone, sporco a Fumarola) come modulate in WorldGenerator._build_road_surface. Centro esattamente com'era.
  • [feat] SU-80 — la ragnatela di sblocchi delle carte. Pool iniziale 6+3 (stomaco_ferro, sonno_leggero, pelle_cuoio, carisma, kazoo, suola + ombrello, spirito_patata, gatto_magnetico); le altre 7 si aprono coi contatori vita (MetaProgress.CARD_UNLOCK_RULES: 3 arresti, carisma lv5 in run, 25 gatti, 30 bidoni, giorno 3, 3 furti subiti, 10 panchine diverse) e il ventaglio non le pesca MAI da chiuse. Battesimo dei super registrato con nome e data (via super_baptized); impresa LEGGENDA DI STRADA (premio D7 da decidere con Ivan). Nuovo segnale player_robbed_by_junkie cablato nei due punti di furto (SP + client MP). F1 → «Sblocca carte». Notifica di sblocco IMMEDIATA stile «NUOVA FERMATA» (il ticket diceva "a fine run": scelta da confermare). Commit 3147250.
  • [feat] SU-82 — IL QUADERNO. Nuova voce di menu → overlay a tre sezioni: CARTE (livello massimo mai raggiunto, super battezzati, «???» + indizio comico per le chiuse), IMPRESE (fatte/da fare, quartieri compresi), STATISTICHE DI VITA. Navigazione pad/tastiera/touch + Indietro; regge un meta.cfg vergine; salvataggio throttlato retrocompatibile. Quaderno.tscn/gd nuovi, MainMenu solo additivo (+ pannello menu un filo più in alto per far stare 7 voci a 720p).
  • [fix] SU-133 (KO) — coriandoli «sparati dai tubi». Partono dal CENTRO dello schermo, salgono a ventaglio (spread 40°, esplosione unica) e ricadono rapidi (gravità 2300, vita 1.8s): prima uscivano dal bordo basso e cadevano lenti. LevelUpScreen._spawn_confetti. Commit 5a66f0a.
  • [feat] SU-141 — sprite GATTILE generato (in attesa di approvazione). PixelLab create_map_object 96×96 top-down, 1 generazione: casetta coi gatti sul tetto, insegna col muso, ciotole. In sprites_raw/BUILDINGS/temp/su141_gattile_96.png — il Fatto lo mette Ivan; SU-142 (implementazione) resta bloccato fino ad allora.
  • [feat] SU-60 — pilota Codex per la grafica del mondo (GATE di Ivan). Scena isolata scenes/dev/PilotaCodex.tscn: 3 edifici downtown nuovi a proporzioni ESATTE 48/96/144 (0 retry) accanto agli attuali, + tileset Wang asfalto↔marciapiede 4×4 (2 tentativi + pulizia PIL). Scoperta chiave: Codex non sa produrre un vero autotile a 16 celle — per SU-117 valutare PixelLab create_topdown_tileset o editing a valle; sugli EDIFICI (SU-118) è invece affidabilissimo. 5 generazioni totali, nessun asset di gioco sostituito. Screenshot in TMP/screenshots_claude/su60_confronto.png. Commit d8e9f73. Addendum (richiesta di Ivan): provato PixelLab create_topdown_tileset sullo stesso soggetto → autotile 4×4 vero al primo colpo (celle rispettate, cordolo pulito su bordi e angoli, 1 generazione): per il terreno vince PixelLab, confronto in sprites_raw/WORLD/temp/su60_wang_confronto_codex_vs_pixellab.png. Su nota di Ivan (marciapiede troppo alto: era il transition_size 0.25 letto come dislivello) rigenerata la v2 PIATTA — giunzione a filo, asfalto grigio caldo: su60_pixellab_wang_flat.png (confronto v1/v2 in su60_wang_pixellab_v1cordolo_vs_v2piatta.png). Secondo KO di Ivan (texture PixelLab piatte e povere di palette rispetto a Codex) → chiusa con la via IBRIDA deterministica: struttura Wang PixelLab come maschera + ri-texturizzazione PIL pixel-per-pixel con le texture Codex vere (su60_wang_hybrid_codex.png, confronto triplo in su60_wang_codex_vs_hybrid_vs_v2.png) — grana e palette identiche a Codex, autotile pulito, zero generazioni: è la ricetta ripetibile per SU-117. Montaggio in game per il GATE (ok di massima di Ivan all'idea): modalità --ingame della scena pilota — incrocio con 4 isolati, tile Wang scelti dagli angoli (tabella dal metadata PixelLab), scatti a zoom 2.5 in TMP/screenshots_claude/su60_ingame_confronto.png.
  • [fix] HUD: le notifiche non esplodono più oltre il tetto. Bug pre-esistente scovato dal collaudo: con >3 big-notification ravvicinate il queue_free immediato della più vecchia lasciava il tween con un bind all'oggetto morto → Cannot convert argument 1 e label mai rimossa dalla lista (_free_notif/_free_big_notif, parametro ora non tipizzato + guardia). Le notifiche immediate di SU-80 lo rendevano più facile da innescare.
  • [docs] SU-83 personaggi selezionabili: BLOCCATO, non lavorato — le 8 skin barbone non esistono negli asset (una sola skin player; il restyle personaggi P1 fu bocciato al GATE F1). Proposta sul ticket: coppia generazione (ChatGPT/Codex) → implementazione. Gate rimasti chiusi: SU-117/118/119/120 (aspettano SU-60 Fatto), SU-142 (aspetta SU-141 Fatto).
  • [test] Collaudo onda 1 (dettagli in TESTLOG): tutto PASS. Compile 0 falliti · run_quartieri.sh 8/8 (fontana garantita a Fumarola senza parchi, gattile piazzato) · run survive 900s su meta VERGINE: gating carte corretto (5/7 chiuse mai pescate; sesto_senso e topo_bidone sbloccati LEGITTIMAMENTE in corsa con 16 arresti e 47 bidoni), 0 SCRIPT ERROR, 0 orfani, Centro sempre {downtown: 37} su 90 dump. Scoperta harness: su macOS user:// segue HOME → i run della stessa sessione condividono meta.cfg (il primo giro era contaminato, rifatto isolato). Da provare su device: giro sui quartieri (layout/tinte/terreno/nemici di casa), raccolta gatti e gattile, ventaglio con pool ridotto su salvataggio nuovo, IL QUADERNO su telefono, coriandoli, menu a 720p; MP host+client stessa mappa (qui non testabile).

SU-137: quartieri come livelli, una mappa = un'identità2026-07-25

  • [change] Via il patchwork di distretti dentro la mappa: ogni quartiere-livello indossa UN solo distretto. Decisione di Ivan: il mosaico 3×3 di zone (SU-121) non piaceva, la mappa uniforme di prima era più bella — l'identità visiva vive nei QUARTIERI della metropolitana, non in zone interne. Il QuartiereDef ha ora un campo distretto unico al posto del mix: il CENTRO è di nuovo TUTTO downtown (bit-per-bit la città pre-SU-121: stessi edifici, stesso pool NPC, nessun banner di zona) e ogni stazione veste per intero una tavolozza — Mercato=commercial · Gattopoli=park (il pool con le gattare) · Solleone=residential · Brina=slums · Fumarola=industrial · Collina=rich · Nottefonda=nightlife. Quartieri.gd (accessor distretto() al posto di mix()), WorldGenerator.gd (rimossi partizionamento 3×3/spread/shuffle; _assign_districts riempie la griglia col distretto unico e crea UNA DistrictZone a mappa intera), World.gd (current_district fissato al distretto del quartiere prima di generate() su ogni peer → il banner «Entrato: …» non scatta più). I distretti restano come tavolozza dati: Districts.gd, pool NPC e sprite per-distretto INVARIATI, come pure metropolitana, sblocchi-imprese e gimmick.
  • [change] La ronda bulli copre anche "nightlife" (DistrictSpawner.NIGHT_GANG_DISTRICTS): NOTTEFONDA la riceveva dalle zone slums del vecchio mix, ora è il suo distretto unico — con always_night la ronda gira h24 come da scheda quartiere. Effetto collaterale voluto: anche BRINA (slums) può incontrarla di notte.
  • [fix] run_quartieri.sh: GATTOPOLI mancava dalla lista default (8 stazioni in ORDER, 7 nello script).
  • [docs] QUARTIERI_DESIGN.md: nota di revisione in testa — il «modello a due piani» (§2-§4) è superato. Nuovi ticket W1 in Sprint 3 per le peculiarità per-quartiere: SU-138 (layout mappa dal QuartiereDef), SU-139 (nemici di casa: gattara di Gattopoli, spazzini di Fumarola), SU-140 (atmosfera: tint + palette terreno), SU-141/142 (sprite GATTILE, coppia generazione→implementazione).
  • [test] check_files 4/4 OK. run_quartieri.sh sull'intera linea (8 stazioni, gattopoli inclusa): 8/8 PASS, ogni mappa genera con UN solo distretto (centro={downtown:34} = regressione Centro confermata; mercato=commercial, gattopoli=park, solleone=residential, brina=slums, fumarola=industrial, collina=rich, nottefonda=nightlife), gimmick osservabili tutti verdi, 0 SCRIPT ERROR (solo il rumore noto NavigationServer al primo frame + leak all'uscita). Da provare su device: Centro uniforme senza banner di zona; identità visiva degli altri quartieri; MP host+client stessa mappa (non verificabile su questo Mac, hang noto host_game).

Batch bug/polish: SU-69/70/98/99/133/134/1352026-07-24

  • [fix] SU-98 — via lo spam Lambda capture ... was freed nei run lunghi. La causa non era solo l'audio zuffa gatti (come da diagnosi del ticket): erano quattro sorgenti, tutte lambda che catturano un nodo/oggetto liberabile prima che il timer/tween scatti. Sistemate tutte convertendole a metodo BOUND / metodo nominato (Godot toglie da sé la connessione quando il target è distrutto): audio zuffa gatti (NPC.gd, PoliceOfficer.gda.queue_free), despawn del van di beneficenza e fulmini (World.gdvan.queue_free, _lightning_flash_settle/_play_thunder_delayed), e — la dominante che il ticket aveva mancato — i tween di rimozione delle notifiche (HUD.gd, _free_notif/_free_big_notif via .bind(lbl)): scattano di continuo, quindi generavano errori a raffica. Verifica con la repro del ticket (run_sp.sh 2000 survive --bot-timescale … --bot-pick focalizzata --bot-stat-floor …) su run intera (~30'): 0 occorrenze (2 run), 0 SCRIPT ERROR. Audio/FX invariati in gioco.
  • [fix] SU-134 — il tasto mappa non "chiude e riapre" più. Il toggle è letto in polling (_process) e la stessa azione può arrivare da più sorgenti (tasto fisico, diamante VirtualControls su "B", bottone-icona HUD): una singola pressione poteva commutare due volte. Aggiunto un debounce (MAP_TOGGLE_GUARD_MS=220, _map_toggle_allowed) applicato a entrambi i punti di toggle → una sola commutazione per pressione. HUD.gd.
  • [fix] SU-135 — nella selezione lettere il tasto azione rimappato conferma, non sostituisce. Rimossa la scrittura diretta delle lettere da tastiera in NameEntry.gd: con i tasti rimappabili (es. "interact" su una lettera) la digitazione diretta sostituiva la lettera evidenziata invece di confermarla. Ora le lettere si scelgono solo con ↑/↓ e si conferma col tasto azione (via is_action_pressed, che rispetta il remapping); resta Backspace = indietro.
  • [fix] SU-99 — barra XP nascosta nel tutorial. La barra XP compatta dell'HUD (condiviso città/tutorial) restava visibile ma inerte fuori dalla run: ora è gated su GameState.run_active come il countdown della retata (HUD._update_run_timer).
  • [fix] SU-69 — via le due scene orfane della modalità arena. Cancellate scenes/ui/RunEndScreen.tscn e scenes/entities/RunPlayer.tscn (referenziavano script cancellati in v0.22): sparisce il rumore di parse error a ogni caricamento/run headless (verificato: 0 occorrenze). Il commento obsoleto in RunManager.gd era già stato tolto; nessuno le istanziava.
  • [feat] SU-133 — coriandoli colorati all'arrivo delle carte. Al level-up, all'apertura del ventaglio, CPUParticles2D one-shot spara coriandoli vivaci da sotto lo schermo che salgono e ricadono. Puramente scenografico: non cattura input, non blocca/ritarda il ventaglio, si auto-libera. LevelUpScreen._spawn_confetti.
  • [fix] SU-70 — ospitare MP ripiega su rete locale se l'online non parte. Se EOSBridge.setup() fallisce (login/credenziali EOS ko), host_game non lascia più l'utente senza partita: ripiega su una lobby ENet locale avvisando «ONLINE NON DISPONIBILE, PARTITA IN RETE LOCALE» (NetworkManager._host_game_eos). Ripiego solo per l'HOST; per «unisciti»/«partita rapida» resta l'errore (decisione aperta sul ticket). Compile-check ok; MP non testabile su questo Mac (hang host_game) → da provare su device.
  • [test] check_files: tutti i file OK, 0 falliti. Smoke run SP (~30' col bot): 0 errori, 0 Lambda capture, coriandoli al level-up, distretti/quartieri invariati.

SU-131: collaudo headless dei quartieri (TestBot + run_quartieri.sh)2026-07-24

  • [test] TestBot valida ogni quartiere da terminale. Il dump [BOT] ha una sezione quartiere (id/nome, blocchi per distretto da WorldGenerator.get_district_block_counts(), verifica del gimmick osservabile) + una riga [BOT] quartiere=<id> ... PASS/FAIL per il grep. Verifiche: nottefonda→is_night() vero a mezzogiorno; solleone/brina→tipo ondata REALE (nuovo hook su EventBus.weather_wave_started, così si osserva il filtro cold/heat invece di bypassarlo come farebbe --bot-wave-after) vs Quartieri.wave_kind(); fumarola→conteggio NPC vs World._effective_npc_target(); mercato→prezzo variato tra due ore (stessa formula hash, in sola lettura); collina→mult("wanted")>1; centro→blocchi>0. TestBot resta inerte senza --bot.
  • [test] tools/autotest/run_quartieri.sh: gira in sequenza tutti i Quartieri.all_ids() (scenario survive + --bot-stat-floor 40, timescale alto), stampa PASS/FAIL per quartiere. Gancio MP pronto (MP_CHECK=1), non eseguito di default. README.md aggiornato.
  • [test] Esito: check_files TestBot.gd FALLITI: 0; run_quartieri.sh sui 7 quartieri → 7/7 PASS, 0 SCRIPT ERROR (solo il rumore atteso ObjectDB leaked at exit). Esito in TESTLOG.md. MP (host+client stessa mappa) non verificato — host_game() si blocca su questo Mac (hang noto): gancio pronto, da riprovare su device. Implementato da dev-sonnet su brief chiuso.

SU-132: le imprese aprono le stazioni (sblocchi quartieri)2026-07-24

  • [feat] I quartieri si sbloccano giocando — «le imprese sbloccano, le lattine comprano». Ogni stazione ha la sua impresa (contatore a vita ≥ soglia, MetaProgress.UNLOCK_RULES): IL MERCATO = compra da 3 negozi diversi in una run · GATTOPOLI = 50 gatti a segno · SOLLEONE/BRINA = 3 ondate di caldo/freddo superate al riparo · FUMAROLA = 60 bidoni rovistati · LA COLLINA = reputazione «Amato» (≥60) in un distretto · NOTTEFONDA = sopravvivi alla prima GRANDE RETATA (run al 30'). Sblocchi locali per giocatore anche in MP; notifica «🚇 NUOVA FERMATA: <nome>!» al momento dello sblocco. Il Centro è sempre aperto.
  • [feat] Contatori a vita cablati sugli eventi (MetaProgress.note_and_check / note_shop_purchase): gatti a segno (CatProjectile), bidoni rovistati e acquisti-negozio per tipo (Interactable), ondate superate al riparo e reputazione «Amato» e retata raggiunta (World, via weather_wave_ended/reputation_changed/raid_started). Reset dei contatori di-run a inizio partita (GameState.reset_run_stateMetaProgress.reset_run). Persistenza user://meta.cfg.
  • [feat] DebugPanel: «Sblocca tutti» (apre tutte le stazioni per collaudo/gioco).
  • [test] check_files 6/6 OK. Validazione end-to-end: run SP accelerato (timescale 150) fino alla Grande Retata (elapsed 1824s > 30') → meta.cfg scritto con retate_sopravvissute: 1 e unlocked.nottefonda: true (impresa → stazione aperta), bidoni_rovistati: 33 (contatore vivo), 0 errori. Da provare su device: sbloccare una stazione giocando e vedere la notifica + la fermata attiva in metropolitana. NB architetturale: MetaProgress è il substrato minimo — SU-79 (valuta LATTINE + ragnatela carte, ticket a parte NON in questo sprint) lo estenderà; qui niente lattine.

SU-127: quartiere GATTOPOLI (la città dei gatti) + GATTILE2026-07-24

  • [feat] GATTOPOLI: i gatti hanno vinto. Config: gatti raccoglibili ×2 (World._effective_cat_target, la città mantiene 16 gatti invece di 8, sia spawn iniziale sia refill), gatti a segno valgono doppio in XP e conteggio punteggio (CatProjectile._note_hit_scored scala con gatti_valore). Mix residential+park (parchi e panchine abbondanti).
  • [feat] GATTILE (versione base, SU-26 arricchirà). Nuovo BlockKind.GATTILE + Interactable.Type.GATTILE: edificio speciale garantito nel quartiere (edifici_garantiti: ["GATTILE"]), placeholder = edificio residenziale + insegna finché non arriva lo sprite dedicato (flusso sprite, due ticket). Consegnando il gatto in braccio (has_cat) si ottengono XP + bonus e si azzera has_cat; incrementa un contatore gatti_consegnati in MetaProgress (aggancio futuro). Host-authoritative via il pattern Interactable esistente.
  • [test] check_files 5/5 OK; smoke run SP --bot-quartiere gattopoli: mix park 22/residential 8/downtown 7, cats 16 (×2 confermato), GATTILE generato senza errori, 0 crash. Da provare su device: gatti ovunque, lancio a raffica che rende doppio, consegna al gattile. Nota follow-up: gattara «di casa» come boss ricorrente anche di giorno (il mix park porta già le gattare dal pool, ma lo spawn-boss dedicato su DistrictSpawner è un aggancio successivo) e sprite dedicato del gattile.

SU-128 + SU-129: quartieri LA COLLINA (ricchi) e FUMAROLA (industriale)2026-07-24

  • [feat] LA COLLINA — i ricchi, decoro spietato. Config: elemosina ×2, prezzi +50%, bidoni ×2 resa (tutti via gli hook economici già esistenti), polizia +50% (World._effective_police_count, pattuglie iniziali più dense), wanted +50% (HUD._q_wanted_mult sui due punti di accumulo — misdemeanor e busking: così anche rovistare nei bidoni alza il wanted più in fretta, «IL DECORO!»), e si parte «Sospettato» con reputazione iniziale −30 in tutti i distretti (GameState.reset_run_state legge Quartieri.reputazione_start()). Mix rich+downtown.
  • [feat] FUMAROLA — economia da bidone pura. Config: densità passanti −50% (_effective_npc_target), elemosina/busking −40% (poco pubblico), bidoni +50% resa e cooldown dimezzato (via gli hook bidoni). Ronda bulli notturna già attiva (industrial è in NIGHT_GANG_DISTRICTS). Mix industrial+slums.
  • [test] check_files 4/4 OK; smoke run SP: COLLINA mix rich 26/downtown 11 (NPC ~49, polizia densa), FUMAROLA mix slums/industrial (NPC 27 = densità −50%), 0 errori. Da provare su device: a Collina l'elemosina rende oro ma il wanted schizza e rovistare è un affronto, prezzi alti, parti sospettato; a Fumarola strade vuote e vita da bidoni. Nota: spazzini a guardia dei bidoni (Fumarola), smog/tint e testi ondata a tema = follow-up (il cuore economico + desolazione + ronda notturna è consegnato); tint anche per Collina = follow-up condiviso.

SU-123: LA METROPOLITANA (selezione quartiere pre-run)2026-07-24

  • [feat] Schermata METROPOLITANA pre-run. Nuova schermata additiva in MainMenu.gd (_build_metro_screen + famiglia _metro_*): una linea con una fermata per ogni Quartieri.all_ids(); ←/→ o tap cambiano la scheda quartiere (nome, sottotitolo comico, record personale MetaProgress.get_best se sbloccata, «LAVORI IN CORSO» + indizio comico Quartieri.indizio se bloccata); tasto azione / secondo tap conferma e avvia (Quartieri.set_current/selected_id/save() + _start_game). Da INIZIA PARTITA (fuori dal tutorial) si passa di qui; con solo il Centro sbloccato il primo tasto parte dritto (zero attrito). Preselezione dall'ultimo quartiere giocato. Tutto placeholder con gli StyleBox attuali (re-skin cartone = U1).
  • [feat] MP: il quartiere lo sceglie l'host in lobby, selezionabile solo se TUTTI i peer l'hanno sbloccato (motivo comico se no). I client dichiarano i propri sblocchi al join con una RPC dedicata (_srv_declare_unlocks, unico RPC nuovo dell'epic), l'host li salva in players[pid]["unlocked"]; auto-ripiego su Centro se la scelta smette di valere per tutti. NetworkManager.gd (dichiarazione sblocchi, minima e separata).
  • [test] check_files 2/2 OK (MainMenu + NetworkManager, insieme alla propagazione quartiere_id di SU-122). Implementato dall'agente dev-sonnet su brief chiuso. Da provare su device: SP — INIZIA PARTITA → metropolitana → parte col quartiere scelto (con i quartieri SU-124/125/126/130 già selezionabili se sbloccati via DebugPanel «sblocca tutti»); MP — voce QUARTIERE in lobby navigabile solo dall'host, propagazione sblocchi al join. Regressione da verificare a vista: il layout della lobby MP è stato ridisegnato (righe spostate per fare posto a QUARTIERE) e gli indici di navigazione host sono slittati di 1.

SU-125 + SU-126: quartieri BRINA (gelo) e SOLLEONE (calura)2026-07-24

  • [feat] Filtro meteo per quartiere (impianto condiviso, riuso completo del sistema ondate). WeatherSystem._pick_wave_kind ora, se il quartiere lo chiede, restringe le ondate a un solo tipo: BRINA = solo FREDDO, SOLLEONE = solo CALDO (niente pioggia né l'altro tipo). _schedule_next_wave accorcia l'intervallo con meteo.freq_mult (+50% per entrambi). Host-authoritative come oggi, nessun RPC nuovo. meteo: {wave_kind, freq_mult} nel QuartiereDef.
  • [feat] Decay all'aperto a tema. GameState._decay_stats: quando NON sei al riparo il quartiere accelera il decay di una stat — BRINA energia −15%, SOLLEONE igiene −15% («sudi come un ghiacciolo al sole»). Al riparo (is_sheltered) nessun malus. Mults decay_fame/energia/igiene nel QuartiereDef.
  • [feat] BRINA — fontane GHIACCIATE: con flag fontane_ghiacciate le fontane restano spente (sprite off via il percorso SU-114/115 in _process) e inutilizzabili («l'acqua si è licenziata»). Mix residential+industrial+slums.
  • [feat] SOLLEONE — fontane SALVAVITA e gelataio: flag fontane_super → igiene doppia (+50) e 60s senza malus caldo (GameState.heat_relief_t, azzera il decay igiene all'aperto finché dura); gelato_super → il gelato dà +70 fame, +15 igiene e 30s di tregua; ICE_CREAM garantito (gelataio sempre presente). Mix commercial+rich+park.
  • [test] check_files 4/4 OK; smoke run SP: BRINA mix industrial 18/residential 11/slums 6, SOLLEONE mix commercial 18/rich 7/park 5, 0 errori. Da provare su device: a Brina solo ondate di gelo, energia cala più in fretta all'aperto, fontane ghiacciate; a Solleone solo calura, igiene cala all'aperto, fontane e gelato che rinfrescano. Nota comune ai quartieri: il TINT atmosferico (azzurrino Brina / caldo Solleone) NON è ancora applicato — l'accessor Quartieri.tint() c'è ma il wiring nello shader WorldTint (SU-16) è un follow-up condiviso da fare con cura per non rompere il ciclo giorno/notte.

SU-124: quartiere NOTTEFONDA (sempre notte)2026-07-24

  • [feat] NOTTEFONDA: il sole ha dato le dimissioni. Config con flag always_night: a run attiva GameState.is_night() e DistrictSpawner.is_game_night() ritornano sempre true e il cielo (night_factor in World) resta fisso notturno — ma l'orologio e i 3 giorni scorrono uguale (la retata al 30' arriva identica: cambia il cielo, non il capolinea). Conseguenze a cascata: pool NPC notturni (nightlife_night) + ronda bulli senza finestra oraria (gratis, usano già is_game_night), e il meteo non pesca mai ondate di CALDO (il _pick_wave_kind fa cold quando è notte). Gate su run_active → il tutorial resta invariato.
  • [feat] Economia a tema: busking +25%, elemosina −20%, dormitorio −25% (numeri tarabili). Nuovi hook economici generici riusabili: moltiplicatore elemosina/busking del quartiere applicato ai 4 punti-paga di ModularNPC (SP + host MP: _give_money, busk_donate, net_resolve_beg, net_busk_donate), e moltiplicatore riposo sul dormitorio (Interactable._use_shelter). Mix distretti: nightlife + slums dominanti.
  • [test] check_files 6/6 OK; smoke run SP --bot-quartiere nottefonda: mix nightlife 7 / slums 25 / downtown 8, 0 errori. Da provare su device: notte perenne col cielo scuro anche a mezzogiorno, neon, ronda bulli a ogni ora, busking più ricco, dormitorio meno pieno; MP host/client identici. Nota: verifica "is_night true a mezzogiorno" nel dump = SU-131.

SU-130: quartiere IL MERCATO + substrato MetaProgress2026-07-24

  • [feat] IL MERCATO, primo quartiere della linea (valida l'architettura QuartiereDef). Config in Quartieri.gd: mix distretti commercial dominante + downtown, densità passanti +50%, prezzi ballerini (i negozi variano prezzo a ogni ora di gioco, deterministico dal run_seed → in MP tutti pagano uguale), bidoni gourmet (resa +40%), 3 camioncini garantiti (HOT_DOG+ICE_CREAM+LIQUOR via edifici_garantiti). Hook generici riusabili dagli altri quartieri: densità NPC (World._effective_npc_target, applicata a spawn iniziale E respawn), prezzi (Interactable._quartiere_price_mult, con wobble orario da seed), resa/cooldown bidoni (Interactable, _q_mult). GameState.run_seed (copiato da World dopo generate) come base per le variazioni per-run condivise in MP.
  • [feat] MetaProgress.gd (nuovo autoload, substrato minimo). Sblocchi quartiere (is_unlocked/unlock/unlock_all, il Centro è sempre aperto), contatori a vita e best-score per quartiere, persistenza user://meta.cfg (pattern Settings). NB: NON è SU-79 (valuta LATTINE + ragnatela carte, ticket a parte fuori sprint): è il minimo per far funzionare metropolitana (SU-123) e sblocchi (SU-132); SU-79 lo estenderà. Sblocchi locali per giocatore anche in MP.
  • [test] check_files 4/4 OK; smoke run SP --bot-quartiere mercato: mix corretto (commercial 23 / downtown 17), NPC 72 (densità +50% attiva), 0 errori. Da provare su device: folla più fitta, prezzi che cambiano d'ora in ora, i 3 camioncini sempre presenti, bidoni più generosi. Nota: cartellino prezzo dinamico sul prompt = polish successivo (come già oggi il prompt mostra il prezzo base mentre il tier scala il caricato).

SU-122: QuartiereDef, l'architettura dei livelli-quartiere2026-07-24

  • [feat] Quartieri.gd (nuovo autoload): la config per livello. Un quartiere è una run standalone con gimmick fisso, mix di distretti suo e nome scherzoso, definito da una entry-dati (nome, sottotitolo, mix distretti, flags gimmick, mults, edifici_garantiti, meteo freq/filtro ondate, tint, impresa_sblocco). Il CENTRO è la config NEUTRA: giocando il Centro il gioco è quello di sempre (default di ogni campo = comportamento attuale → regressione). AGGIUNGERE un quartiere = una entry + una riga in ORDER (SU-124..130). Accessor pronti per i ticket-quartiere: mult(), flag(), mix(), guaranteed_blocks(), tint(), wave_kind(), weather_freq_mult(). Selezione persistita (user://quartieri.cfg, pattern Settings).
  • [feat] La selezione arriva a Main.tscn SENZA cambiare scena. World._ready legge Quartieri.current e passa al WorldGenerator il mix distretti (aggancio SU-121) e i blocchi speciali garantiti prima di generate(). current_id è impostato a monte: in SP da metropolitana/DebugPanel/TestBot, in MP dall'RPC host. WorldGenerator (_guaranteed_extra, _blockkind_from_name, reserve extra in _promote_special_footprints).
  • [feat] MP: quartiere_id viaggia col session_seed nell'handshake. NetworkManager.start_game invia il quartiere scelto dall'host in _cl_game_starting(seed_val, quartiere_id) (id corto, ben sotto il limite pacchetto EOS 1170 byte); su tutti i peer (host incluso, call_local) fissa Quartieri.current PRIMA del cambio scena → host e client generano lo stesso quartiere. Nessun altro RPC.
  • [feat] TestBot --bot-quartiere <id> forza il quartiere della run (default centro; predisposizione per SU-131). DebugPanel: voce «QUARTIERE (prossima run)» che cicla il quartiere al volo.
  • [test] check_files 6/6 OK, 0 falliti. Smoke run SP --bot-quartiere centro: flag riconosciuto, generazione ok (8 distretti attivi), 0 errori runtime → regressione Centro confermata. Da provare su device: nulla di visibile finché non arrivano i quartieri a tema (SU-124..130) e la metropolitana (SU-123); questo ticket è l'impianto.

SU-121: distretti finalmente accesi nella città2026-07-24

  • [feat] I distretti sono attivi: la città non è più tutta «Centro». Prima DistrictZone non si registrava mai nel gruppo district_zones (il «filo staccato») e l'unica zona in Main.tscn copriva l'intera mappa 1632² → _detect_district_for_rect ricadeva sempre su downtown. Ora il generatore partiziona la griglia 8×8 in una matrice 3×3 di regioni rettangolari contigue e assegna un distretto a ciascuna (la centrale, dove spawna il player, è sempre downtown), creando una DistrictZone per regione deterministica dal seed: in MP host e client vedono gli stessi distretti senza RPC. Conseguenza a cascata (zero wiring extra): GameState.current_district cambia davvero camminando → pool NPC, generosità elemosina, reputazione e sprite edifici per zona (rich/industrial/nightlife/slums… mai visti prima) si accendono da soli. WorldGenerator.gd (_assign_districts, _spawn_district_zone, _region_bounds, _district_pool_for_regions, _seeded_shuffle), DistrictZone.gd (add_to_group), scenes/world/Main.tscn (rimossa la DowntownZone 1632²).
  • [feat] Banner comico all'ingresso in un distretto. EventBus.district_entered (già emesso, mai ascoltato con zone vere) ora fa scattare un big_notify col nome IT della zona; locale a ogni player (no RPC), solo a run attiva (nel tutorial la mappa resta forzata downtown). World.gd (_on_district_entered).
  • [feat] Tabella unica dei distretti (Districts.gd, nuovo autoload): fonte di verità singola per elenco canonico (8 id), nomi display IT e chiave sprite edifici — «un solo posto dove aggiungere un distretto». GameState.get_district_display_name ora delega qui.
  • [change] Chiavi distretto riallineate. GameState.reputation passa da 4 a tutti gli 8 distretti (prima rich/commercial/industrial/nightlife non registravano mai reputazione); aggiunti il pool NPC e il modifier commercial in NPCDatabase (aveva sprite edifici ma nessun pool → fallback su downtown). I park (senza set edifici proprio) pescano dai residenziali via Districts.building_key.
  • [feat] Aggancio TestBot/collaudo: WorldGenerator espone district_block_counts / get_district_block_counts() e district_at_cell(), e stampa il conteggio blocchi per distretto (dump quartieri, SU-131).
  • [test] Compile-check headless SÌ su questo Mac (l'harness tools/autotest/ usa /Applications/Godot.app, non il binario Linux): check_files.sh 5/5 OK, 0 falliti. Smoke run SP (bot, seed casuale): generazione ok, log district blocks: {rich 7, nightlife 2, residential 2, park 5, commercial 3, downtown 6, slums 3, industrial 6} → tutti gli 8 distretti attivi, nessun errore runtime. Da provare su device: camminando cambia zona (banner) e si vedono edifici diversi; MP host/client stessa mappa.

Volume del jingle di level-up abbassato2026-07-24

  • [change] La fanfara del ventaglio (levelup.wav) suona più bassa (-8 dB). Si sente a ogni level-up, quindi conviene tenerla poco invadente: _play_sfx ora accetta un parametro opzionale volume_db (default 0.0, così il "timbro" della carta card_pick.wav resta invariato) che imposta _sfx.volume_db prima del play(), e la chiamata di apertura ventaglio passa -8.0. scripts/ui/LevelUpScreen.gd (_play_sfx, _open_ventaglio).
  • [test] Compile-check headless NON eseguibile su questo Mac (in tools/godot/ solo il binario Linux): verifica statica di sintassi/indentazione (tab) delle due modifiche. Da provare su device: al level-up il jingle si sente più basso, il suono di scelta carta invariato.

Menu principale: «SEGNALA BUG O IDEA» apre il modulo beta2026-07-24

  • [feat] Nuova voce «SEGNALA BUG O IDEA» nel menu principale. In coda alle voci esistenti, apre col browser di sistema il Google Form del feedback beta (OS.shell_open, primo uso nel progetto). Aggiunte la costante FEEDBACK_URL (https://forms.gle/bQPwQvpUgKNGnLqx9) e il case "report_bug" in _activate_item(); la voce è una Label come le altre, quindi tap, tastiera e pad funzionano già senza codice extra e il pannello si auto-dimensiona su MENU_ITEMS.size(). Nessuna modifica al .tscn.
  • [test] Compile-check headless NON eseguibile su questo Mac (in tools/godot/ c'è solo il binario linux.arm64): verificata a mano l'indentazione a TAB delle due modifiche e la coerenza del match. Da provare su device: la voce compare in fondo al menu e apre il modulo nel browser (Mac/Windows/iOS).

Sprite bottiglia del tossico e panchine col nastro segnaletico (SU-112/115)2026-07-24

  • [feat] SU-112 (KO) — la bottiglia del tossico ha il suo sprite. KO Ivan «genera anche lo sprite bottiglia con Codex»: fatto, e alla scelta di Ivan («usiamo bottiglia Codex») lo sprite è stato importato in gioco al posto del placeholder. La bottiglia (vetro verde, tappo, etichetta) è ricavata dal sorgente Codex sprites_raw/WORLD/temp/bottiglia_tossico.png (1254² trasparente, rif. wine.png), rifilata al contenuto e ridotta a 8×28 con LANCZOS → assets/sprites/bottlefly.png (import lossless, no mipmaps, fix_alpha_border, filtro NEAREST via codice come catfly). BottleProjectile.gd ora monta uno Sprite2D con la texture (via il consueto pattern di CatProjectile) invece del Polygon2D marrone; volo, spin, colpo e sync MP invariati. Screenshot di review: TMP/screenshots_claude/su112_bottiglia.png.
  • [feat] SU-115 — le panchine diventano «inutilizzabili» quando lo spazzino è nel parco. Completa il feedback visivo del blocco già esistente (SU-109/«VERNICE FRESCA»): finché lo spazzino presidia il parco le sue panchine mostrano lo sprite col nastro segnaletico giallo/nero, e tornano normali quando il blocco scade. Riusa il percorso di swap della fontana (SU-114): in Interactable._process lo stato «deve stare off» ora include Type.BENCH col blocco spazzino, ma con un distinguo — la panchina mostra la texture solo per il blocco dello spazzino (want_texture), mentre per il cooldown normale d'uso resta il grigio desaturato di sempre (non è «in pulizia», l'hai solo appena usata); fontana e altri interactable invariati per costruzione. WorldGenerator assegna area.texture_disabled = TEX_BENCH_BLOCKED al ramo BENCH. MP «gratis» come per la fontana (net_cleaner_block è generico su net_id): lo swap si vede anche sui client senza RPC nuove. scripts/world/Interactable.gd (_process, _enter_cooldown_visual), scripts/world/WorldGenerator.gd.
  • [change] SU-115 — sprite panchina bloccata: nastro sovrapposto alla panchina reale, non la variante SU-113. Discrepanza trovata: le varianti approvate in SU-113 sono generate da sprites_raw/bench.png (fondo magenta, prospettiva iso diversa), che NON è la panchina in gioco (assets/sprites/world/bench.png, altro modello/angolo) — importarle avrebbe fatto cambiare modello alla panchina quando bloccata (swap non 1:1, effetto «morphing»). Seguendo il pattern già usato dal team (correzioni geometriche con PIL sull'arte esistente, nessuna arte rigenerata), il nastro è stato composto in modo deterministico direttamente sul bench.png in giocoassets/sprites/world/bench_blocked.png (40×28, X di nastro giallo/nero clippata sulla sagoma): stessa identica panchina, swap 1:1 perfetto. Confronto: TMP/screenshots_claude/su115_panchina_normale_vs_bloccata.png. Se preferisci una delle 4 varianti Codex, andranno rigenerate dalla panchina in-gioco corretta (ticket di generazione a parte).
  • [test] Compile-check headless non eseguibile su questo Mac (nessun binario Godot in tools/godot/, solo il Linux): verifica statica di sintassi/indentazione (tab) e della logica di swap fatta a mano; i nuovi PNG hanno il .png.import (Godot li reimporta all'apertura — occhio alla cache .godot/imported/ gitignored, vedi giro SU-85). Da provare su device: (SU-112) tossico che lancia la bottiglia col nuovo sprite, SP + MP host/client; (SU-115) panchina col nastro mentre lo spazzino è nel parco e ritorno a normale quando se ne va, SP + MP client, e che dopo un semplice riposo la panchina resti grigia (non «nastrata»).

KO sprite: bottiglia e panchine rigenerate anche con PixelLab, per confronto (SU-112/113)2026-07-24

  • [assets] SU-112 (KO) — sprite bottiglia del tossico anche con PixelLab. Richiesta di Ivan «genera anche con codex + pixelab per prova»: accanto alla versione Codex (bottiglia_tossico.png) ora c'è la PixelLab sprites_raw/WORLD/temp/bottiglia_tossico_pixellab.png (map_object basic, view side, 72×168, trasparente). Nessun import in gioco: resta il placeholder finché Ivan non sceglie quale sprite usare. Meccanica (commit 64dab64) invariata.
  • [assets] SU-113 (KO) — varianti panchina rigenerate con PixelLab. «Riprovato a farle generare» con PixelLab (ora connesso in CLI): standard + in pulizia / nastri / sporca / nastri fitti, tutte in sprites_raw/WORLD/temp/*_pixellab.png (map_object basic, view high top-down, 160×120, trasparenti, single-color outline + medium shading per stare nello stile del gioco). Accanto restano le Codex omonime. Il Fatto (approvazione) lo mette Ivan e sblocca SU-115.
  • [assets] Foglio di confronto sprites_raw/WORLD/temp/_CONFRONTO_codex_vs_pixellab.png: Codex vs PixelLab affiancati per bottiglia + 5 panchine, per la scelta di Ivan.
  • [note] PixelLab ora funziona da Claude Code (CLI). L'MCP, prima assente in CLI (scope errato), è connesso: get_balance OK (sub attivo, 1784 generazioni). Le parti «PixelLab» dei KO SU-112/113, prima non eseguibili in CLI, sono state fatte qui. Nessun file del progetto Godot toccato; sprite solo in temp/ (non committati, raw/LFS).

Sprint 2: carte lanciate sul tavolo, tossico che ubriaca, super a scelta, barra XP allineata (SU-111/112/77/107)2026-07-24

  • [feat] SU-111 — le carte del level-up entrano «lanciate sul tavolo». All'apertura del ventaglio le 3 carte non appaiono più di colpo: partono da sotto il bordo inferiore dello schermo (stessa X del target) e volano alle posizioni finali con TRANS_BACK/EASE_OUT (piccolo overshoot d'atterraggio), ruotate un filo oltre l'angolo del ventaglio (verso alternato per indice) e con ingresso SFALSATO (ENTER_STAGGER 0.09s per carta). Durante il volo (~0.5s) selezione/conferma sono disabilitate (_entering) e si riabilitano quando l'ultima carta atterra; vale anche alla riapertura dopo la carta dorata. Layout finale del ventaglio invariato. scripts/ui/LevelUpScreen.gd (_start_entrance, _animate_card_enter, _layout_fan(animate,entering)).
  • [fix] SU-111 — via lo spam di ERROR sul tween delle carte. card.get_meta("_su85_tween", null) stampava The object does not have any 'metà values with the key '_su85_tween' su ogni carta a ogni level-up (in Godot 4.6 il default null non fa da fallback): guardato con has_meta (comportamento identico, niente più stampa). Corretto anche il gemello preesistente e silente in _animate_card_to (SU-85). LevelUpScreen.gd:413,441.
  • [feat] SU-112 — il TOSSICO lancia bottiglie e ti ubriaca. arch_junkie, oltre a borseggiare (invariato), a media distanza (50-200px, ricarica 5s) lancia bottiglie col nuovo proiettile BottleProjectile (gemello di CatProjectile): a segno NON dà vita/energia/fame ma conta come un drink (GameState.consume_drink(), 2 colpi → ubriaco con gli effetti drunk esistenti) + battuta comica. Host-authoritative con RPC nuove e isolate net_bottle_thrown/net_bottle_hit_player (schema gatto/gattara): il colpo applica UN solo consume_drink() sul peer colpito, mai duplicato sull'host. Grafica: placeholder vetro-marrone (Polygon2D), asset dedicato da fare. scripts/npc/ModularNPC.gd (_junkie_throw_bottle_at), scripts/world/World.gd, nuovi scenes/entities/BottleProjectile.tscn + scripts/entities/BottleProjectile.gd.
  • [change] SU-77 (KO 3° giro) — il super si SCEGLIE tra 3 carte. KO Ivan «come si selezionano i superpoteri?»: la cerimonia del battesimo offriva solo il perk maturato. Ora _open_ceremony() costruisce 3 opzioni — il/i maturato/i garantito/i + riempimento a caso dalle chiavi di SUPERS (esclusi ATOMICA, l'equipaggiato e i duplicati) — e il giocatore sceglie quale battezzare (frecce/joypad o TAP; in MP resta la 4ª carta SCOREGGIA ATOMICA). Titolo «✨ SCEGLI IL TUO SUPERPOTERE ✨», notify di maturazione «…per SCEGLIERE il tuo superpotere». Slot invariato (1 super/run), baptize() ed effetti/attivazione intatti; randomizzazione locale (overlay personale, anche in MP). scripts/systems/SuperPower.gd, scripts/ui/SuperCeremony.gd.
  • [fix] SU-107 (KO) — la barra XP non ha più lo scalino pieno/vuoto. KO Ivan «discrepanza tra l'altezza non ricaricata e quella già accumulata»: cornice (Panel 24px) e riempimento (ProgressBar 16px con inset) erano due geometrie scollegate. Rifatta come la StatBar del tema: un unico ProgressBar con background (cornice cartone panel_cardboard.png) e fill (bar_fill.png giallo) sullo STESSO nodo → il fill vive nel canale del background, pieno e vuoto condividono altezza per costruzione, zero scarto. Rimossa la costante XP_BAR_FILL_INSET; look cartone, posizione top/safe-area e label «LV» invariati. scripts/ui/HUD.gd (_setup_progression).
  • [fix] SU-107 (KO 3° giro) — il riempimento giallo non sporge più dalla cornice. KO Ivan «ora è centrata ma la parte gialla è ancora più alta della barra»: il fill di un ProgressBar Godot lo disegna a TUTTA l'altezza del controllo — e per giunta il minimo del ProgressBar è ~l'altezza del font (~21px) — quindi il giallo copriva il bordo della cornice e sporgeva rispetto al canale vuoto. Come le barre stat (che infatti NON usano il fill del ProgressBar ma celle disegnate a mano), la barra è ora una cornice bar_frame (NinePatchRect statica, margini 6/5) + un ColorRect giallo incassato ESATTAMENTE nel canale interno (208×14 a offset 6,5) la cui larghezza = progresso: il giallo sta dentro il bordo per costruzione e pieno/vuoto hanno la stessa altezza. Verificato pixel-a-pixel con screenshot dal viewport (nuovo scripts/tools/shot_xpbar.gd). scripts/ui/HUD.gd (_setup_progression, _refresh_xp_bar).
  • [feat] SU-114 — la FONTANA è spenta quando il netturbino è nel parco. Come già le panchine, lo spazzino (arch_cleaner) blocca anche la fontana del suo parco: sprite fountain_off al posto dello zampillo (riusa cooldown_changed/set_off_state) e, se provi a usarla, «🧹 L'ACQUA È CHIUSA! Lo spazzino sta lucidando i rubinetti.» senza alcun effetto (niente igiene/reputazione/XP/misdemeanor); quando lo spazzino se ne va la fontana riparte da sola (entro CLEANER_BLOCK_REFRESH ~1.6s). Lo stato «spenta» combina cooldown post-uso E blocco spazzino, così nessuno dei due riaccende l'acqua mentre l'altro è attivo. MP «gratis»: net_id è già assegnato a tutti gli interactable e net_cleaner_block è generico, quindi il cambio si vede anche sui client senza RPC nuove. scripts/world/Interactable.gd (_process, _use), scripts/npc/ModularNPC.gd (_update_cleaner, _park_fountains).
  • [test] Collaudo Onda 1: compile 52 script + 21 scene, 0 falliti (inclusa la nuova scena bottiglia). Run bot survive (1500, speed 8): 0 crash, 0 SCRIPT ERROR, orphans=0; regressione tween SU-111 trovata al run e corretta. Review statica MP di SU-112: simmetria host/client corretta (un colpo = un consume_drink). Ventaglio catturato dal viewport (shot_cards.gd), layout OK. Da provare su device: animazione d'ingresso carte, cerimonia con 3 super a scelta, tossico che lancia bottiglie + ubriacatura (SP + MP host/client), barra XP a occhio.

Il mondo oltre il livello: design quartieri/metropolitana e backlog W12026-07-24

  • [docs] QUARTIERI_DESIGN.md — brainstorming completo dell'espansione mondo (richiesta di Ivan): modello a due piani (DISTRETTI dentro la mappa / QUARTIERI-livello a tema), le 7 stazioni della linea (Il Mercato, Gattopoli, Solleone, Brina, Fumarola, La Collina, Nottefonda — i primi due da SU-25), metropolitana come selezione pre-run, sblocchi a imprese («le imprese sbloccano, le lattine comprano»), collaudo TestBot. Scoperta chiave dal codice: i distretti esistono nei dati (pool NPC, modificatori, reputazione, edifici per 7 zone) ma NESSUNA zona si registra nel gruppo district_zones_detect_district_for_rect ritorna sempre «downtown» e la mappa è di fatto un unico Centro. Decisioni prese con Ivan: epic dedicato, roster v1 a 7 quartieri, in MP il quartiere richiede lo sblocco a TUTTI i peer (regola endless).
  • [docs] Jira: nuovo epic SU-116 «W1 — Quartieri e metropolitana» + 12 ticket in backlog: SU-121 (accendere i distretti), SU-122 (QuartiereDef/architettura), SU-123 (metropolitana), SU-124…SU-130 (i 7 quartieri), SU-131 (collaudo bot), SU-132 (sblocchi). Refactoring grafico del Centro sotto P1/SU-6: SU-60 rifinito come PILOTA PixelLab (terreno+edifici, GATE di stile), poi SU-117→SU-119 (tileset Wang → terreno a TileMap) e SU-118→SU-120 (edifici multi-proporzione → slot a larghezza variabile). Aggiornate le liste epic in SU-9 e WORKFLOW/01_TICKET.md; commenti di collegamento su SU-25 (origine, assorbita), SU-19 (→ Brina) e SU-26 (→ Gattopoli).

Settimo giro KO: icone carte ad alta risoluzione, il tossico smette di rimpicciolirsi (SU-85/109)2026-07-23

  • [feat] SU-85 — le icone delle carte passano all'ALTA RISOLUZIONE. KO Ivan: «il topo non è minimamente riconoscibile». Le carte grandi (200×278) montavano il foglio perk_icons.png 16×16 ingrandito ×4 — 4,6 pixel schermo per texel, illeggibile. Ora ogni id ha il suo PNG singolo da 128² in assets/ui/perk_hi/ (16 perk) e assets/ui/super_hi/ (10 super), ricavati dai sorgenti 256px già approvati con chroma-key magenta + ritaglio + LANCZOS: nessuna arte rigenerata. LevelUpScreen e SuperCeremony provano prima il singolo e ripiegano sul foglio se manca; filtro LINEARE sull'alta risoluzione (il NEAREST serve a INGRANDIRE i 16px, qui si rimpicciolisce) e icona portata dai 64px fissi al 92% della finestra-cartone (~76px). Lo slot HUD resta sul foglio 16×16, dove è nitido.
  • [fix] SU-85 — il «color oro seppia» non era codice. Nel ventaglio non esiste alcun modulate/shader sull'icona: il foglio monocromo era semplicemente quello vecchio. Confermato decodificando i pixel — perk_icons.png prima di dec12f3 aveva 6 colori tutti oro/seppia, alla HEAD del branch ne ha 1450. «L'ho vista a colori una volta sola» = una sola prova fatta su una build del branch; tutte le altre su dev, dove il foglio nuovo non è mai arrivato.
  • [fix] SU-109 — il tossico non si rimpicciolisce più guardando a N/E/W. Misurato sui fogli: nelle righe E e N (e SE su v03) il corpo partiva 4-6px più in basso a parità di piedi, cioè ~15% più basso che in S; la W è la E specchiata, quindi il difetto si vedeva in 3 direzioni su 5. arch_junkie_male_v01 (10 frame) e _v03 (15 frame) rinormalizzati all'altezza della riga S, ancorati ai piedi e ricentrati, più la rimozione dei pixel-fantasma staccati in cima (residui di ritaglio). Correzione geometrica con PIL sull'arte esistente: stessa palette, stessi 160×160, .tres e regioni invariati. v02 e drunk erano già a posto.
  • [feat] scripts/tools/shot_cards.gd — provino PNG del ventaglio senza giocare: apre il solo LevelUpScreen con carte vere e cattura dal viewport, quindi senza il permesso macOS «Registrazione schermo» che aveva bloccato il giro precedente. Uso: godot --path . -s res://scripts/tools/shot_cards.gd -- <file.png> [golden].
  • [docs] Nota di processo, causa dei KO 1-3 di SU-109. Triangolo rosso e abbattimento della gattara *erano già implementati* nei commit 100b041/6f89955, ma sul branch sprint-su85-su109 mai mergiato su dev: sul codice di dev la gattara è tuttora solo stordibile e il triangolo non esiste proprio. I KO «non vedo il triangolino» e «non riesco a eliminarla» descrivono esattamente il comportamento di dev. Il branch va portato su dev prima della prossima prova.
  • [fix] Trappola trovata al merge: la cache di import di Godot resta indietro. Subito dopo il fast-forward su dev le carte mostravano ANCORA le icone vecchie seppia: .godot/imported/ è gitignored, quindi un checkout che riceve asset nuovi o sostituiti non ha i loro .ctex finché non passa un import — e ResourceLoader.exists() su un PNG non ancora importato torna false, facendo scattare il fallback sul foglio 16×16. Risolto con un giro di godot --headless --editor sul checkout (22 texture importate) e riverificato a schermo. È la spiegazione più probabile di parecchi «non vedo la modifica»: se un asset sembra vecchio, prima di rifarlo si controlla .godot/imported/.
  • [change] Merge del branch sprint-su85-su109 su dev (fast-forward, 10 commit): tutto il lavoro dei giri KO 5-6-7 è ora sul branch dove Ivan prova davvero. Committate anche le tre modifiche locali che stavano ferme nel checkout: NOVE VITE che rimette in piedi al 50% invece che al 15%, il nuovo levelup.wav e il ri-salvataggio di arch_raid_male_v01_frames.tres.
  • [test] Compile completo su dev dopo il merge: 51 script + 20 scene, 0 falliti. Compile mirato 3/3 OK (LevelUpScreen, SuperCeremony, shot_cards). Verifica visiva con screenshot del ventaglio, carte normali e carta dorata: icone a colori e nitide, topo nel bidone riconoscibile, trombetta al posto del kazoo. Sprite del tossico ricontrollati a occhio e a misura (tutte le direzioni ora occupano i 32px pieni). Da provare su device: ventaglio e cerimonia del battesimo, tossico che cammina nelle 5 direzioni, e — dopo il merge su dev — triangolo rosso e gatto sulla gattara.

Sesto giro KO: perk a colori IN GIOCO, triangolo di minaccia, carte col tasto azione (SU-85/109/110)2026-07-23

  • [feat] SU-85 — le 16 icone perk A COLORI sono IN GIOCO. Foglio assets/ui/perk_icons.png sostituito (64×64, 4×4 di 16px: stesso path e stessi indici, zero modifiche di codice) con riduzione LANCZOS ad alpha PREMOLTIPLICATO dai sorgenti 256px approvati — NEAREST scartato dopo confronto (aliasing e pixel sporchi: i sorgenti non sono pixel-art nativa; la prima LANCZOS «naive» scuriva i bordi mescolando l'RGB nero dei pixel trasparenti, risolto premoltiplicando). Come da KO: l'icona del VIRTUOSO DEL KAZOO è ora una TROMBETTA giocattolo (rigenerata con codex/ChatGPT sul riferimento della trombetta del super CONCERTONE). Sorgenti singoli archiviati in sprites_raw/UI/ («dovessi mai cambiarne una sola»), temp ripulita, copia per revisione in TMP/perk_icons_claude/.
  • [feat] SU-109 (KO 2): triangolo rosso di minaccia sui nemici. Sopra spazzino, gattara, bulli e tossico lampeggia LO STESSO triangolo rosso dell'inseguimento della polizia (identica geometria a gradini Polygon2D, colore (0.95,0.10,0.10) e cadenza 0.25s on/off), SEMPRE acceso finché il nemico è operativo: creato in apply_archetype, quindi visibile anche sui puppet MP senza RPC nuovi; si spegne durante la zuffa di abbattimento (host via _enemy_defeated, puppet quando la reazione replicata nasconde lo sprite).
  • [change] SU-110: le carte si scelgono col tasto AZIONE. Nel ventaglio la conferma della carta selezionata passa da Invio (ui_accept) al tasto azione del gioco (interact: E su tastiera, bottone «A» dei controlli touch); frecce/dpad per navigare e doppio tap sulla carta invariati. L'auto-pick del bot non passa dall'input: run automatiche invariate.
  • [test] Compile mirato 2/2 OK (LevelUpScreen, ModularNPC) + boot e run bot ~10s puliti dal worktree col foglio nuovo (preload ok, solo rumore noto). Screenshot in-game NON producibile da questa sessione (screencapture: «could not create image from display», manca il permesso Screen Recording al processo) — verifica visiva su device; per i prossimi giri: permesso al terminale o ticket per un flag --bot-screenshot. Da provare su device: icone a colori (e trombetta) sulle carte, triangolo rosso sui 4 nemici (anche da client MP), conferma carte con E/bottone azione e Invio muto.

Quinto giro KO: i nemici si abbattono, le sedici perk a colori (SU-109/85)2026-07-23

  • [feat] SU-109 (KO): TUTTI i nemici si ABBATTONO. Spazzino, gattara, bulli (capo E gregari) e tossico cadono col gatto in faccia O coi superpoteri che colpiscono gli NPC (RUTTO SISMICO via stun; AURA MEFITICA/SCATTO via fuga → nuovo override super_flee()): percorso unico _defeat_enemy() in ModularNPC — nuvola di zuffa ~2.5s (ENEMY_DEFEAT_BRAWL_SEC, tarabile), battuta di sconfitta comica NUOVA per gattara/bulli/tossico (lo spazzino le aveva), poi SPARISCONO. Effetti coerenti: panchine del parco di nuovo usabili, orbita di gatti spenta, gregari via col capo (ronda rigenerabile), borseggi finiti. I civili restano invariati (zuffa e rilocazione, niente despawn).
  • [change] SU-109: niente respawn a orologeria. Rimossi il rientro fisso a 120s dello spazzino e DistrictSpawner.schedule_cleaner_respawn/spawn_cleaner_at: un nemico abbattuto rientra SOLO quando il giro naturale dello spawner decide di rispawnarlo (pool pick_archetype_for + regole della ronda). MP host-authoritative SENZA RPC nuovi: zuffa replicata sui puppet col canale del gatto esistente, despawn propagato dall'host via _cl_npc_despawn. Rischio noto: micro-flicker del puppet remoto a fine zuffa (stesso pattern SU-13), mitigabile abbassando ENEMY_DEFEAT_BRAWL_SEC.
  • [feat] SU-85 (KO): le 16 icone perk rifatte A COLORI, in attesa di OK. Le «vecchie icone dorate» sulle carte sono il foglio monocromo perk_icons.png delle carte NORMALI (la CARTA DORATA usa già il foglio super a colori): rigenerate tutte e 16 (10 power-up + 6 occasione) con ChatGPT/codex reference-first — stile del set super approvato, soggetto dalla cella del vecchio foglio, chroma-key e ricentratura deterministica PIL. Deliverable in sprites_raw/UI/temp/ (16 singoli 256px + foglio 4×4 + preview 16/32px) e copia in TMP/perk_icons_claude/; import in gioco SOLO dopo l'OK di Ivan. Più deboli a 16px: PELLE DI CUOIO e SESTO SENSO.
  • [test] Compile 50 script + 20 scene, 0 falliti. Run bot survive a 8×: morte precoce (fame/stanchezza a ~2' di run) sia col diff sia sul codice BASE a parità di seed (run differenziale) → artefatto della velocità 8× del bot, NON regressione; rami nemici non esercitati dal bot (popolazione NPC stabile a 49 in tutte le run). Da provare su device: F1 → SPAWN NEMICI → gatto e super su ciascuno dei 4 (zuffa → sparizione, niente ricomparsa immediata), panchine libere dopo lo spazzino, MP a 2 device, preview delle icone perk.

SU-109: i nemici hanno una personalità — guardiano, cacciatrice, esattori e borseggiatore2026-07-23

  • [feat] SPAZZINO, il guardiano dei parchi. Pattuglia SOLO il suo parco (waypoint dentro il park_rect, migra al più vicino se spawna altrove) e finché è vivo TUTTE le panchine di QUEL parco sono inutilizzabili («VERNICE FRESCA!»); un gatto in faccia lo elimina (speech comica) e il parco si libera — rientra dopo 120s (DistrictSpawner.schedule_cleaner_respawn).
  • [feat] GATTARA, la cacciatrice orbitale. Via l'attrazione dei gatti veri (tornano liberi e raccoglibili): ora le orbitano attorno 5 sprite del gatto volante (visibili anche sui puppet MP); INSEGUE il barbone per la mappa e da media distanza gli lancia gatti (CatProjectile.from_npc) — ogni gatto a segno: −5$ con banconote volanti. La sborsettata da contatto resta come difesa ravvicinata.
  • [feat] BULLI, gli esattori. La ronda notturna non pattuglia più: INSEGUE il barbone (78 px/s, poco sotto di lui); al contatto rapina TUTTI i soldi + metà della fame residua, poi si dilegua soddisfatta con sfottò — niente drenaggi ripetuti. Sostituito lo spintone SU-88 con la rapina (gang_try_rob_puppets/_cl_gang_rob_me).
  • [feat] TOSSICO, il borseggiatore. arch_junkie smette di essere una comparsa: cerca il barbone (−10$ a colpo, ricarica 20s) e borseggia gli NPC che incontra — il derubato protesta con una delle 6 frasi comiche nuove («Il mio portafoglio! Cioè, la mia graffetta!», «M'ha sfilato pure i bottoni della giacca!»…) e resta A SECCO 30 secondi: elemosina e busking da lui non rendono nulla (gate _robbed_t su _give_money/net_resolve_beg/busk_donate/net_busk_donate).
  • [feat] MP host-authoritative: nemici solo su host, effetti sui barboni remoti via relay scalari nuovi in World (junkie_try_steal_puppets, net_catlady_hit_player, net_cleaner_block + rapina di cui sopra); tutorial escluso (gate run_active). Numeri tarabili nelle const in testa ai file.
  • [test] Collaudo: compile 50+20 a 0 falliti (×2); run breve pulito; run INTERO fino a retata: zero errori, economia SANA (21 pescate, 773 XP — sopra i riferimenti dei giri precedenti: il gate dei derubati non strozza l'elemosina). Follow-up dichiarati: micro-stun sul colpo della gattara, replica visiva del suo gatto sui client, speech del derubato solo host. Da provare su device: F1 → SPAWN NEMICI per tutti e quattro i percorsi + MP a 2 device.

Quarto giro: le icone super APPROVATE entrano in gioco, spawn debug dei nemici, barra XP in cartone (SU-85/73/103/106/107)2026-07-23

  • [feat] SU-85 CHIUSO — le 10 icone super sono IN GIOCO. Foglio assets/ui/super_icons.png (5×2 di 16×16, chroma-key + riduzione dai sorgenti 256px) cablato ovunque il super mostra la faccia: slot HUD (equipaggiato E glow "maturo"), cerimonia del battesimo, CARTA DORATA nel ventaglio; le carte normali restano sulle perk. SCOREGGIA ATOMICA (fuori foglio) tiene il fallback perk. I 10 sorgenti singoli sono archiviati in sprites_raw/UI/ (LFS, «dovessi mai cambiarne una sola»), temp ripulita.
  • [fix] SU-73 (KO 4°): margine laterale di 22px sul blocco testi della carta — il testo non arriva più a filo del bordo.
  • [fix] SU-103 (KO 2°): la luce era finita "a bordo schermo": la posizione canvas del player veniva passata a shader che lavorano in pixel FINESTRA — su retina/fullscreen i due spazi differiscono di ~2-3× (in headless 1:1 coincidono, per questo il collaudo non lo vedeva). Ora la posizione passa per la final transform in tutti e tre i punti (update + 2 fallback di setup).
  • [feat] SU-106: DebugPanel → nuova sezione «SPAWN NEMICI»: Gattara, Spazzino, Ronda bulli, Tossico spawnano vicino al player ignorando distretto/orario/pool (DistrictSpawner.debug_spawn_archetype, additivo). La ronda forza le 22:00 se è giorno (altrimenti si autodistruggerebbe al frame dopo) e rispetta il cap di 1 gruppo; host-only con avviso da client MP.
  • [feat] SU-107: barra XP 220×24 (era 160×12) vestita in cartone con gli asset esistenti: cornice panel_cardboard.png (texture_margin 4px) + riempimento bar_fill.png tinto giallo, etichetta LV a font 14. Posizione e safe-area invariate.
  • [test] Compile mirato 7/7 OK + smoke di boot pulito (preload del foglio nuovo verificato a runtime); import Godot in place senza errori. Da provare su device: icone a 16px in gioco, luce su schermo vero (retina), i 4 bottoni di spawn, barra XP su iPhone col notch.

Terzo giro KO: testi carta centrati, niente scherzi sotto il ventaglio, luce che segue, classifica a 5 (SU-73/102/103/104/105 + SU-85 icone)2026-07-23

  • [fix] SU-73 (KO 3°): titolo, livello ed effetto della carta ora sono un blocco unico centrato verticalmente tra la finestra-icona e la zona pallini (VBox adattivo: coi titoli a 1 o 2 righe si ricentra da solo; le carte «una tantum» senza pallini centrano su tutta la fascia). Via l'effetto "titolo incollato al quadrato" dello screenshot 2.
  • [fix] SU-102: con ventaglio o cerimonia aperti, pausa e mappa da tastiera sono bloccate — aprire la mappa sopra le carte e richiuderla toglieva la pausa e lasciava il gioco vivo sotto (barbone che camminava, busk, gatti). I bottoni touch erano già coperti dal dimmer (layer 60 sopra l'HUD a 10). In MP nulla cambia (lì la pausa non esiste).
  • [fix] SU-103: il cerchio-luce notturno segue il barbone anche coi bordi mappa: la causa era la camera clampata (limit_*) col cerchio calcolato a centro schermo; ora la uniform light_center (posizione canvas del player, aggiornata ogni frame) corregge ENTRAMBI gli shader della notte (vignette + tinta mondo — stessa feature, stesso bug in coppia).
  • [fix] SU-104: il DebugPanel scrolla — contenuto in ScrollContainer verticale (rotella + drag), altezza adattiva al viewport anche su resize; ora si arriva oltre "NPC SYSTEM" fino in fondo.
  • [change] SU-105: classifica locale a 5 posti (MAX_ENTRIES 10→5: niente più "settimo posto" col name entry); il ka-ching suona SOLO alla fine per Grande Retata (al posto del trombone, delay 0.3s) — i game over normali tengono il trombone e basta.
  • [change] SU-85 (KO icone): le 10 icone ricentrate geometricamente nei loro quadrati (bbox del disegno → centro; gatto e trombetta erano i più fuori asse, fino a 54px) SENZA ridisegnare l'arte già approvata; foglio, anteprime e file singoli aggiornati in sprites_raw/UI/temp/, in attesa dell'ok.
  • [test] Collaudo: compile 50+20 a 0 falliti; morte "onesta" per fame senza kaching e senza errori; run intera fino a cattura (30:00+3s) con ventaglio aperto 18 volte pulito — 18 pescate, 480 XP: curva 5/1.16/cap25 stabile in fascia al terzo run consecutivo. Da provare su device: resa del blocco testi, pausa/mappa bloccate sotto le carte, luce al bordo mappa di notte, scroll F1, classifica a 5, kaching solo a retata.

I nemici hanno la loro faccia: spazzino, gattara, bulli e Squadra Sgombero in gioco (SU-91/93/95/97)2026-07-23

  • [feat] Import dei 12 sheet approvati da Ivan (import_people_sprites.py --only cleaner,catlady,bully,raid): 24 file nuovi in assets/sprites/npc/bodies/ — spazzino male v01 arancio/v02 verde + drunk PROCIONE, gattara female v01 viola/v02 verdone + drunk GATTO, bulli male v01 capo/v02/v03 gregari + drunk BULLDOG, squadra sgombero male v01 visiera giù/v02 su. Manifest varianti rigenerato; discovery verificata (bully M:3, catlady F:2, cleaner M:2, tutti col drunk).
  • [change] NPCDatabase: arch_cleaner e arch_catlady mollano i placeholder operaio/nonna e puntano agli sprite dedicati (gattara: drunk_animal goat→cat; tolto acc_handbag dai required — la borsetta ormai è disegnata nel body e il codice non legge mai quell'accessorio). Voce NUOVA arch_bully (body_big, 3 varianti contigue, drunk bulldog, generosity/money a zero). La ronda notturna passa da arch_punk ad arch_bully (NIGHT_GANG_ARCH_ID in DistrictSpawner + ModularNPC): il terzetto ora ha bomber, canotte e catenine sue.
  • [fix] La Squadra Sgombero ha la sua divisa (SU-97) — e una scoperta: PoliceOfficer._apply_gender_variant() (ereditata) sovrascriveva i frames della scena col poliziotto normale — era il motivo della vecchia tinta rossa. Ora RaidOfficer._apply_raid_look() imposta SEMPRE arch_raid_male_v01 o v02 (50/50, roll nello stesso punto della sequenza → look coerente sui puppet MP via look_seed) e aggiorna _normal_frames; tinta rossa rimossa. RaidPolice.tscn → frames dedicati.
  • [test] Collaudo: compile 50+20 0 falliti; run intero fino a cattura (30:00+4s, 4 raider): zero fallback a civilian, zero errori script, frames retata ok. Da provare su device: spazzino/gattara di giorno, ronda di notte (slums/industrial, roll raro), retata con entrambe le visiere, MP 2 istanze per il look identico dei raider.

Ventaglio col titolo sotto l'icona, icone singole con TROMBETTA, suoni veri della progressione (SU-73/85/86)2026-07-23

  • [fix] SU-73 (KO): il titolo della carta va SOTTO la finestra-icona («sopra c'è poco spazio»): ordine carta ora finestra/icona → titolo → livello → effetto → pallini. Compile ok; resa da giudicare a video.
  • [feat] SU-85 (KO icone): l'icona del CONCERTONE passa dal kazoo alla TROMBETTA (tromba giocattolo dorata con note, generata a parte in stile col set — il kazoo restava confondibile con l'icona del perk VIRTUOSO DEL KAZOO); le 10 icone ora vivono anche come file singoli sprites_raw/UI/temp/super_icon_<id>.png («dovessi mai cambiarne una sola»), foglio e anteprime 16/32px aggiornati con la trombetta. In attesa dell'ok finale per l'import in gioco.
  • [feat] SU-86: i 4 suoni generati da Ivan sono IN GIOCOlevelup.wav, card_pick.wav, super_baptism.wav, kaching.wav copiati da Sounds_raw/ ad assets/sounds/ (+ import Godot): gli hook già cablati li agganciano da soli, i fallback champagne/coin spariscono. Nel run di collaudo fanfara e timbro suonati 20 volte senza errori; battesimo e ka-ching verificati solo all'import (il bot non battezza mai — da orecchio su device).
  • [test] Collaudo del giro: run intero pulito, 20 level-up (annotazione: curva 5/1.16/cap25 stabile in fascia), orphans=0. .import dei 16 asset nuovi generati in place.

SU-78: curva XP ritarata sui dati — 18 pescate a run2026-07-23

  • [change] XPSystem.gd: BASE 4→5, GROWTH 1.12→1.16, cap addolcimento 20→25. Quattro giri di misura col bot iperattivo a run intera (stessa config del 07-22): 4/1.12→38 pescate · 4/1.18→25 · 5/1.18→14 · 5/1.16 cap 20→22 · finale 5/1.16 cap 25→18 (456 XP), dentro il target 15-20. Dettaglio run in TESTLOG.
  • [change] Due scoperte messe a verbale in PROGRESSION_DESIGN.md §4: l'XP retroagisce coi livelli (CARISMA alto → più elemosine riuscite → più eventi XP → varianza grande tra run, la fascia si centra in proiezione non in singola run) e il cap a 20 era un gradino, non un addolcimento (il codice passa a 1.06^(lv-1): fabbisogno da ~84 a ~15 XP/livello, ~3 pescate regalate a fine run) — spostato a 25, dove la prosa endless del design già lo collocava; lo sconto resta per l'endless R3.
  • [test] Zero regressioni nei 4 run (tier 630/1200/1621, warning 1711, retata 1801, «LA CITTÀ HA VINTO» sempre puntuali; zero errori script sui file modificati oggi). Il super non si è mai battezzato da solo nei 4 giri (focalizzata si è fermata a liv. 6-8): coerente con la curva più dura, da tenere d'occhio al playtest.

KO sprint: ventaglio ridisegnato, super a pressione prolungata, musica continua (SU-77/85/86/100)2026-07-23

  • [fix] Ventaglio (SU-85, KO layout). Carte da 150×200 a 200×278 (proporzione che tiene QUADRATA la finestra-icona del template 96×128, misurata al pixel: rect 31,22 lato 34, mappata via NinePatch), titolo interamente SOPRA la finestra (font 15, ancorato in basso), icona 64×64 centrata nella finestra, livello/effetto/pallini ridistribuiti sotto. Animazione di selezione: tween 0.16s (QUAD/EASE_OUT) su posizione/scala/rotazione, la carta selezionata passa DAVANTI subito e scivola in primo piano — niente più scatto secco.
  • [feat] Super a pressione prolungata (SU-77, KO attivazione). SUPER_HOLD_SEC 0.45s tarabile: tenere premuto Q/pad/bottone touch "S" riempie la barra dello slot in giallo («TIENI PREMUTO…»), al colmo il super parte (notify/speech invariati); rilascio anticipato annulla in silenzio, super non pronto avvisa subito come prima. Hold agganciato a reset/battesimo (niente residui), try_activate/DebugPanel intatti, input solo locale (zero rete).
  • [fix] La musica non si ferma più al ventaglio (SU-100) — né alla cerimonia del battesimo, che aveva lo stesso identico difetto: il nodo Music del World va in PROCESS_MODE_ALWAYS durante la pausa SP e torna pausabile a scelta fatta/riapertura-dorata/chiusura (pattern già collaudato della mappa). In MP nulla cambia (pausa assente).
  • [docs] Prompt ElevenLabs per i 4 suoni mancanti (SU-86, KO). levelup.wav, card_pick.wav, super_baptism.wav, kaching.wav: prompt pronti da incollare, nel commento del ticket e annotati nel codice accanto agli hook (che restano cablati coi fallback attuali).
  • [test] Collaudo: compile 50 script + 20 scene 0 falliti, smoke SP pulito, zero regressioni nei 4 run bot della giornata. Da provare su device: hold 0.45 (tastiera e touch), resa visiva del ventaglio nuovo, musica a orecchio su ventaglio e cerimonia.

Sprite nemici e icone super rigenerati sul KO: reference prima di tutto (SU-90/92/94/96 + SU-85 icone)2026-07-23

  • [feat] 12 sheet 5×5 rigenerati in sprites_raw/PEOPLE/temp/ (LFS, non committati): spazzino v1 arancio hi-vis/v2 verde/vdrunk PROCIONE (scopa VERTICALE a lato, non copre più le gambe), gattara v1 viola/v2 verdone/vdrunk GATTO con orecchie fuori dal foulard, bulli capo-bomber/canotta bianca/canotta a righe+rasato/vdrunk BULLDOG inglese, squadra sgombero visiera giù/su (vestito-casco-manganello del giro KO mantenuti come chiesto, solo ridisegnati). QC visivo passato su tutti.
  • [change] Protocollo nuovo «reference prima di tutto» (annotato in NPC_AI_PROMPTS.md Sez. 0): a ChatGPT/Codex si allega come prima immagine uno sheet esistente del gioco (esempi scelti da Ivan in EXAMPLES/) come legge di stile — lo STYLE ANCHOR testuale da solo produceva proporzioni sbagliate. Righe confermate S/N/E/SW/NE; ciclo colonne ridefinito da Ivan: fermo / passo / fermo / altro passo / fermo. Varianti con la v1 fresca allegata (identità cell-by-cell).
  • [feat] Icone super A COLORI (SU-85 KO): foglio 5×2 rigenerato in sprites_raw/UI/temp/super_icons.png nello stile delle perk esistenti (contorno scuro, colori saturi: rutto-onda, berretto da notte, nube mefitica, comizio, kazoo, gatto in volo, scarpa alata, bidone d'oro, cappello-?, radar) + anteprime 16/32px per giudicare la resa piccola. Import al posto delle placeholder dopo l'ok di Ivan.
  • Nota di pipeline: codex exec col prompt via stdin (l'opzione -i variadica inghiottiva il prompt) e sandbox workspace-write su sprites_raw/ (un PNG strandato in ~/.codex/generated_images recuperato a mano); dettagli in memoria di progetto.

Collaudo dello sprint progressione: 8/8 PASS2026-07-22

  • [test] Collaudo completo su dev, tutto verde (dettaglio in TESTLOG): compile 50 script + 20 scene, FALLITI 0 · smoke SP pulito · percorso R1 riconfermato sullo stato committato (tier a 630/1201/1621, warning 28:30, retata 30:00, «LA CITTÀ HA VINTO» — e stavolta ANCHE un superpotere battezzato via carta dorata, 34 level-up) · cadenza onesta ~6 level-up a morte ~150s (variance di mondo normale) · MP ENet 2 istanze: timer di run sincronizzato entro 1s sul client, level-up del client SENZA pausa dell'host · gate tutorial verificati (RunManager/XPSystem/SuperPower spenti fuori run; nemici nuovi esclusi strutturalmente dal TutorialWorld) · TestBot inerte senza --bot.
  • [test] Nota ambiente MP headless: su questo Mac host_game() preferisce EOS (credenziali reali) e resta appeso su await eb.setup() — hang già noto a TESTLOG 2026-07-21; il giro ENet si fa rinominando le credenziali SOLO nella copia di test disposable (repo mai toccato).
  • [docs] Due minori PRE-esistenti trovati e messi a backlog: SU-98 spam «Lambda capture freed» ×99 nei run lunghi (audio posizionale zuffa gatti su NPC despawnati, NPC.gd:552/PoliceOfficer.gd:771, nessun crash — promosso in visibilità dalla popolazione R1) e SU-99 barra XP visibile ma inerte nel tutorial (HUD.tscn condiviso).

SU-78: il TestBot gioca la progressione, prima run intera validata2026-07-22

  • [feat] Strategia di pesca del bot (--bot-pick focalizzata|generalista): «focalizzata» ripesca sempre lo stesso power-up quando offerto (lock-on verificato a runtime: ~21% dei pick sul bersaglio, il resto diluito dal fallback prima-carta), «generalista» prima carta. LevelUpScreen/SuperCeremony: solo hook additivi bot-only, MP umano invariato (prima carta a 12s).
  • [feat] Scenario survive (nuovo, wander/idle intatti): con fame bassa cerca cibo (preferenza a livelli: soup-van gratis prima del bidone al 30%), con energia bassa panchina/rifugio, nei periodi calmi mendica proattivamente vicino ai passanti; priorità fame/energia "appiccicosa" sulla stat più critica (fix di un bug trovato in corsa: l'energia arrivava a 0 inosservata). Costanti tarabili in testa a TestBot.gd, niente pathfinding (steering + stuck-timeout).
  • [feat] --bot-stat-floor N: clamp di fame/energia/igiene lato bot (GameState.gd NON toccato) — serve ai collaudi di PERCORSO, non di cadenza. Dump [BOT] arricchito: blocco prog (level-up, XP totale, power-up coi livelli, super battezzato sì/no e via cosa, death_reason/t). Unità chiarita nell'header: t = secondi DI GIOCO (reali ≈ t/timescale).
  • [test] Prima run intera validata (survive --bot-stat-floor 30 --bot-pick focalizzata, timescale 10): tier 0→1→2→3 a 629/1200/1621 (target 600/1200/1620 ✓), warning a 1711 (28:30 ✓), retata a 1801 ✓, morte «LA CITTÀ HA VINTO» a t=1833 ✓ — il percorso R1 completo funziona. 38 level-up, 696 XP, sonno_leggero a liv. 8 (a un pelo dal battesimo, mai osservato dal vivo). Senza floor il bot muore onestamente a t≈150 (fame/stanchezza) con 4-7 level-up: la sopravvivenza del bot resta il tappo, non la curva.
  • [change] Cadenza FUORI target — nota di ritaratura per Ivan (NON applicata): 38 pescate a run intera contro il target 15-20 (quasi 2×). Proposta dai dati: XP_GROWTH 1.12→1.16-1.18 oppure BASE_XP_TO_LEVEL 4→6, poi rimisurare con la stessa run. Cautela: 38 è un tetto ottimistico (il bot mendica senza sosta nei periodi calmi), un giocatore vero pesca meno — decidere col playtest.
  • Nota harness: run_sp.sh va lanciato con bash (niente bit +x, preesistente). Comandi di collaudo raccomandati annotati nel report di lotto.

SU-85: asset grafici della progressione in temp, in attesa dell'ok di Ivan2026-07-22

  • [feat] Generati con Codex in sprites_raw/UI/temp/ (raw, non committati): card_gold_front.png 768×1024 + card_gold_back.png 96×128 (la CARTA DORATA della cerimonia, fronte e retro dedicato), super_icons.png 80×32 (griglia 5×2: le 10 icone 16×16 dei superpoteri — GATTLING e AURA MEFITICA le più deboli del set, candidate a rigenerata su KO), super_slot_frame.png 132×20 (cornice slot HUD: finestra icona + recesso barra), notebook_bg.png 128×128 (pagina Quaderno a quadretti con scotch; dimensioni provvisorie, la schermata Quaderno è R3). card_back.png era già stato generato prima dell'interruzione (QC profondo in TESTLOG).
  • [change] Riusi invece di rigenerare (verificati nel codice): card_levelup.png 96×128 di U1 già in uso da LevelUpScreen/SuperCeremony; perk_icons.png di U1 contiene GIÀ le 16 icone di power-up e carte occasione con gli stessi nomi; bar_fill.png come riempimento tintabile della barra slot. Patch margin della dorata a 12 (valore reale hardcoded in LevelUpScreen/SuperCeremony; il 14 di UI_AI_PROMPTS.md è una discrepanza preesistente del doc).
  • Flusso approvazione: Ivan guarda i PNG in temp → OK = si importano al posto dei placeholder (follow-up); KO con commento = si rigenera. Nota di processo: al primo giro codex exec ha modificato di sua iniziativa CHANGELOG/TESTLOG — ripristinati subito (diff pulito) e aggiunto ai prompt successivi il vincolo esplicito «non toccare altri file, niente git».

R2b: superpoteri attivi, cerimonia del battesimo e sfx (SU-75/76/77, SU-22, SU-86)2026-07-22

  • [feat] SuperPower (SU-75). Nuovo scripts/systems/SuperPower.gd: il pattern del busking (durata+cooldown+barra visibile) generalizzato nello SLOT SUPERPOTERE dell'HUD — cornice + barra di ricarica stile cartone in safe-area, azione input NUOVA super (Q / joypad 10) e bottone touch "S" in VirtualControls (compare solo a super battezzato). Il busking resta il super "di serie" di tutti, gratis dal minuto 1, e NON occupa lo slot; PowerUpSystem.super_slots è un array (il 2° slot arriverà con DOPPIA IDENTITÀ in R3). Assorbe SU-24 col default di design D5-D6: niente busking equipaggiabile, lo slot è dei superpoteri.
  • [feat] La cerimonia del battesimo (SU-76). Al liv. 9 il power-up è "maturo": glow dorato pulsante sullo slot + «✨ MATURO — AL RIPARO!»; al prossimo riparo o dormita si apre la CERIMONIA (SuperCeremony.tscn: carta dorata gigante, il barbone medita) e il super si battezza nello slot. Paracadute: sotto i 5' dalla retata la CARTA DORATA entra direttamente nel ventaglio — il super non si perde mai. Il liv. 10 non consuma pescate (_reopen_after_golden); con più maturi si sceglie chi battezzare; MP: overlay solo personale, mondo che continua, auto-conferma 12s (bot 0.6s). DebugPanel: «matura super».
  • [feat] I 10 superpoteri attivi (SU-77). Tabella unica SUPERS con numeri e ricariche tarabili (RUTTO SISMICO 75s, PISOLINO LAMPO 90s, AURA MEFITICA 90s, COMIZIO IN PIAZZA 90s, CONCERTONE, GATTLING 120s, SCATTO DEL CENTOMETRISTA 60s, APRITI SESAMO 120s, AMNESIA COLLETTIVA 150s, RADAR DI QUARTIERE 90s), big_notify e speech comiche per ognuno. La retata se ne infischia di AMNESIA COLLETTIVA e delle aure: i raid_officers sono esclusi ovunque, nessun super la annulla. MP host-authoritative: replica visiva/audio col pattern gatto/scoreggia/busking, RPC scalari ben sotto il limite EOS 1170.
  • [feat] SCOREGGIA ATOMICA (SU-22). L'11° superpotere, jolly SOLO MP (in SP non ha bersagli e non appare): alla cerimonia si può battezzare al posto del proprio super; al rilascio ogni giocatore nel raggio perde il 20% dei soldi, accreditati al lanciatore (World.net_super_atomica_host_atomica, host-authoritative come il fart-slow), nuvola di gas su tutti gli schermi, ricarica lunga 150s. L'idea del playtest del 15/07 è in gioco.
  • [feat] Sfx della progressione (SU-86). Fanfara level-up all'apertura del ventaglio, "timbro" alla scelta della carta, fanfara del battesimo alla cerimonia, sfx d'attivazione per ciascun super (riuso: gas→fart, CONCERTONE→busking, GATTLING→lancio gatto, PISOLINO→sbadiglio, RADAR→sirena, APRITI SESAMO→moneta), "ka-ching" a fine run (+1.2s per non accavallarsi al trombone del game over). Bus Master, niente bus nuovi, suonano anche in pausa SP. ASSET MANCANTI (hook pronti con fallback attivo): assets/sounds/levelup.wav, card_pick.wav, super_baptism.wav, kaching.wav — quando arrivano in Sounds_raw/ si sostituiscono.
  • [test] check_files.sh 16/16 OK al primo giro. Da provare su device: catena maturo→glow→cerimonia→attivazione (tasto Q / bottone S), paracadute carta dorata sotto i 5', MP 2 istanze con SCOREGGIA ATOMICA e auto-conferma 12s, retata che ignora AMNESIA.

Sprite nemici generati: 12 sheet in temp, in attesa dell'ok di Ivan (SU-90/92/94/96)2026-07-22

  • [feat] Generati con ChatGPT via Codex CLI i 12 sheet 5×5 (1254×1254, magenta) in sprites_raw/PEOPLE/temp/ (LFS, non committati): spazzino comunale v1 hi-vis/v2 verde municipale/vdrunk PROCIONE (SU-90), gattara v1 viola/v2 verde bottiglia/vdrunk GATTO (SU-92), bulli capo-bomber/gregario/gregario a righe/vdrunk BULLDOG (SU-94), squadra sgombero visiera giù/su senza drunk (SU-96). QC visivo superato al primo colpo su tutti; trucco nuovo di pipeline: le varianti passano a codex exec -i la v1 come riferimento → zero drift di posa/palette tra varianti.
  • [docs] NPC_AI_PROMPTS.md +375 righe: sezioni archetipo nuove 2.20 arch_catlady, 2.21 arch_bully, 2.22 arch_raid (struttura A-F identica alle esistenti), override varianti 5.21-5.23, ID mnemonici e tabella animali drunk aggiornati. Lo spazzino resta su BUILDINGS_AI_PROMPTS.md §8.6 (composto col protocollo NPC).
  • Nota per la review: la borsetta della gattara legge più come sacca rigonfia che borsetta rigida — se non piace si rigenera su KO. Flusso: Fatto sui ticket di generazione = approvazione di Ivan → si sbloccano le implementazioni SU-91/93/95/97 (import pipeline + NPCDatabase), che restano ferme fino ad allora.

R2a: XP, ventaglio di carte e pool power-up a livelli (SU-72/73/74)2026-07-22

  • [feat] PowerUpSystem (SU-72). Nuovo autoload scripts/systems/PowerUpSystem.gd: pool ed effetti a LIVELLI 1-9 (levels, get_mult(key) unica porta, is_mature(id) al 9), appoggiato a XPSystem ritarato (BASE 5→4, growth 1.20→1.12, cap 1.06 oltre il liv. 20). Fonti XP cablate nei punti veri × moltiplicatore tier (×1.0/1.25/1.5/2.0): elemosina +2, busk-tick +1, bidone +2, dormita +3, lavata +2, gatto a segno +3, ondata superata +5, alba +10 — "la strada indurisce, ma insegna". Tutorial: niente XP (gate run_active). MP: tutto locale per giocatore, zero rete. DebugPanel: sezione PROGRESSIONE con +50 XP / power-up +1 / reset.
  • [feat] Il VENTAGLIO (SU-73). LevelUpScreen riscritta: 3 carte sovrapposte (−10°/0°/+10°, overlap 25%), la carta evidenziata si sfila in primo piano (×1.15); navigazione ←/→ o tap, conferma con A/Invio o SECONDO tap (mai selezione al primo tap su touch); ogni carta mostra nome in pennarello, icona, effetto liv. X→Y e pallini livello. SP in pausa come oggi; MP senza pausa con auto-pick della prima carta a 12s e timer visibile. Bottoni reroll/veto predisposti e nascosti (arrivano con la Baracca R3). Col bot la pesca è automatica: una run --bot non si blocca mai. Barra XP compatta nell'HUD (additiva, safe-area).
  • [feat] Pool v1: 10+6 (SU-74). MAZZO A a livelli: STOMACO DI FERRO, SONNO LEGGERO, PELLE DI CUOIO, CARISMA DA STRADA, VIRTUOSO DEL KAZOO, BRACCIO DA LANCIATORE, SUOLA DI GOMMA, TOPO DA BIDONE, FACCIA DA BRAVO RAGAZZO, SESTO SENSO (polizia in mappa, raggio crescente via MapOverlay). MAZZO B occasione: NOVE VITE (revive al 15% UNA volta — MAI contro la retata, gate su RunManager; assorbe l'idea di SU-23), OMBRELLO RITROVATO, SPIRITO DI PATATA, OCCHIO AI FURTI, GATTO MAGNETICO, COPERTA DI CARTONE. Pesca: 3 carte distinte non al cap, occasioni a peso ridotto. Tutto muore con reset_run_state().
  • [feat] Predisposto per il lotto superpoteri: super_slots array, segnali powerup_leveled/powerup_matured su EventBus (aggancio cerimonia liv. 10). Icone: riuso di card_levelup.png e perk_icons.png di U1 come placeholder (asset dedicati in SU-85).
  • [test] check_files.sh 16/16 OK al primo giro. Nota MP dichiarata: i bonus resa elemosina/busking del client remoto sono calcolati sul suo peer (pattern esistente), parità fine da verificare in collaudo. Da provare su device: ventaglio touch su iPhone (secondo tap), build focalizzata verso il liv. 9, SESTO SENSO, NOVE VITE (salva dal collasso, NON dalla retata).

R1: la run da 30 minuti con la GRANDE RETATA finale (SU-71)2026-07-22

  • [feat] Run a tempo (R1.1). RunManager.gd riconvertito dal prototipo arena alla run città: 30 minuti reali = 3 giorni (l'orologio a 2.4 min/sec c'era già da SU-17), fasi none→warning(28:30)→active, segnali raid_warning/raid_started. Avvio da World._ready() con gate run_active (tutorial e menu esclusi). HUD: countdown mm:ss sotto l'orologio che al 30' diventa RETATA! +Xs. Il collasso stats prima del 30' resta il game over di sempre.
  • [feat] Escalation (R1.2). TIER_THRESHOLDS → [0/600/1200/1620] e get_multipliers() in DifficultyManager.gd: più polizia (police_extra in World), ondate meteo più fitte (WeatherSystem), elemosina più avara, prezzi negozi col moltiplicatore tier e cooldown bidoni (hook in Interactable.gd: _tier_price() sui 4 negozi + bidoni ×2 durante lo sciopero). Eventi comici all'alba (host→relay MP): giorno 2 SCIOPERO DEI NETTURBINI, giorno 3 VISITA DEL SINDACO (più polizia, meno spiccioli).
  • [feat] GRANDE RETATA (R1.3). Nuovi RaidOfficer.gd + RaidPolice.tscn (variante di PoliceOfficer, tinta rossa): chase ineluttabile sul barbone più vicino a ~1.35× la velocità player, ignora wanted, niente arresto-cooldown; il gatto la stordisce 0.5s per pura comicità. Spawn dai bordi: 4 + 2 ogni 20s, cap 30. Cattura = fine run con motivo retata e bonus secondi_extra × 10 (impresa "Resistenza alla retata" in ScoreSystem). Pannello: "LA CITTÀ HA VINTO — SEI DURATO 30:00 + X".
  • [feat] MP host-authoritative. Timer sincronizzato ai client a 1 Hz (_cl_run_sync), retata spawnata solo dall'host sul canale NPC esistente (nuovo kind raid), cattura dei client via net_raid_capture_player → flusso spettatore invariato; la run condivisa finisce quando sono presi tutti. Applicato anche l'hook della ronda bulli (SU-88): gang_try_shove_puppets/_cl_gang_shove_me in World.gd — lo spintone con multa ora arriva anche ai giocatori remoti.
  • [feat] DebugPanel/TestBot. F1: "forza retata ora", "salta a minuto X", vista moltiplicatori tier. TestBot: flag --bot-timescale N + dump run/diff/raiders per il collaudo.
  • [test] check_files.sh 14 file OK (11 lotto R1 + 3 hook orchestratore). Quirk noto: la run parte alle 08:00 e il giorno rolla a mezzanotte → gli eventi alba cadono a ~6:40/16:40/26:40. Da collaudare: run intera con timescale (tier→warning→retata→cattura→pannello), MP 2 istanze, tutorial pulito. Nota tecnica: RunEndScreen.tscn referenzia un .gd inesistente (dead code arena pre-esistente, non toccato).

Nemici del barbone: gattara, ronda bulli e barbone rivale2026-07-22

  • [feat] GATTARA (SU-87). Nuovo archetipo arch_catlady in NPCDatabase.gd (per ora placeholder sulla nonna con palette dedicata e borsetta; lo sprite vero arriva con SU-92/93), spawn nel distretto park (peso 8), 95% femmina. In ModularNPC.gd: attira i gatti entro ~130px (gravitano in orbita attorno a lei e NON sono raccoglibili finché è vicina, tornano liberi quando si allontana); se le lanci un gatto ti insegue ~5s brandendo la borsetta, "sborsettata" con stordimento comico 1s al contatto, raffiche extra ignorate (niente loop di stun). Speech comiche in italiano, mai nel tutorial.
  • [feat] RONDA BULLI (SU-88). Di notte (22-06) in slums/industrial può spawnare un terzetto: leader + 2 gregari puramente visivi in offset (niente AI elaborata), placeholder punk in attesa di SU-94/95. Contatto = "scorta" fuori zona con spintone 220px, −10% soldi con le banconote volanti dell'arresto (SU-58), NESSUN arresto e wanted fermo; cooldown 20s, despawn automatico all'alba. Max 1 gruppo vivo.
  • [feat] BARBONE RIVALE (SU-89). arch_homeless_rival smette di essere una comparsa: si piazza negli angoli buoni (max 2 in mappa, tetto in DistrictSpawner.gd), dimezza la resa di elemosina e busking del player entro ~150px (vale anche per i peer remoti via net_resolve_beg/net_busk_donate), mette in cooldown i bidoni che rovista, sfotte ("questo angolo è mio dal '98"). Un gatto in faccia lo fa sloggiare (riusa la rilocazione esistente). Zero asset nuovi.
  • [test] check_files.sh OK al primo giro su NPCDatabase/ModularNPC/DistrictSpawner. MP: logica solo dove l'NPC è vero (puppet inerti); resta da cablare in World.gd il relay dello spintone-ronda ai peer remoti (hook net_gang_shove_player proposto, si applica col lotto R1) — da provare su device: gattara al parco, ronda di notte, rivale vicino a un angolo di elemosina.

Ticket sprite nemici: 4 coppie generazione→approvazione→implementazione2026-07-22

  • [docs] Creati SU-90…SU-97 sotto P1 (SU-6): coppie di ticket sprite per spazzino comunale (90/91), gattara (92/93), bulli della ronda (94/95) e Squadra Sgombero della retata (96/97). Nuova regola di flusso dettata da Ivan: la generazione ChatGPT deposita i PNG SOLO in sprites_raw/PEOPLE/temp/ (cartella creata) e il ticket di generazione lo segna Fatto solo lui — quel Fatto è l'approvazione; il ticket di implementazione (import con import_people_sprites.pybodies/ → NPCDatabase) è vincolato con link Jira «is blocked by» e non si lavora finché il gemello non è Fatto.
  • [docs] Ricognizione roster nemici a monte dei ticket: lo spazzino gira col placeholder dell'operaio (dichiarato in NPCDatabase.gd, prompt dedicato già pronto in BUILDINGS_AI_PROMPTS.md §8.6); tossico e barbone rivale hanno già set completi (il rivale 4 varianti + drunk: nessun ticket sprite); gattara/bulli/squadra richiedono anche la nuova sezione archetipo in NPC_AI_PROMPTS.md (arch_catlady, arch_bully, arch_raid — è nei criteri dei ticket di generazione). Aggiornati SU-87/SU-88: il punto sprite ora punta alle coppie, il comportamento procede col placeholder senza aspettarle.

Backlog Jira della progressione: 19 ticket da PROGRESSION_DESIGN.md2026-07-22

  • [docs] Creati SU-71…SU-89 in backlog a partire da PROGRESSION_DESIGN.md (SU-68), assumendo i default D1-D10 del §7 (Ivan non ha ancora risposto riga per riga: se qualche decisione cambia, si aggiornano i ticket). Nessuna epic nuova: la progressione era già coperta da R2 (SU-2) e R3 (SU-3). Distribuzione: SU-71 run 30'+retata sotto R1 (prerequisito, non aveva nessun ticket); SU-72…78 il binario in-run sotto R2 (PowerUpSystem a livelli, ventaglio, pool 10+6, pattern superpotere, cerimonia+carta dorata, i 10 super, validazione TestBot); SU-79…84 il binario per-sempre sotto R3 (MetaProgress/lattine, ragnatela sblocchi, Baracca, Quaderno, personaggi, endless); SU-85/86 asset grafici e sfx sotto U1/U2.
  • [docs] Nemici del barbone (sotto U2): SU-87 GATTARA e SU-88 RONDA BULLI dal brief U2.2, più SU-89 BARBONE RIVALE attivo (proposta nuova: arch_homeless_rival esiste in NPCDatabase ma è solo una comparsa). Verificato nel codice che tossico (arch_junkie, borseggio 1-3$) e spazzino comunale (arch_cleaner) esistono già: niente ticket per loro, il contatore "derubato dal tossico" per la ragnatela sta dentro SU-79.
  • Nota per la board: SU-75 assorbe SU-24, SU-74 (NOVE VITE) assorbe SU-23 — segnalato a Ivan nel commento su SU-68 per l'eventuale chiusura come duplicati; SU-22 (Scorreggia atomica) candidata a 11° superpotere futuro.

SU-65: calzino a 32×32, e la causa vera dell'impastato2026-07-21

  • [feat] sock.png rigenerato e portato da 16×16 a 32×32. Cercando «più risoluzione» è saltata fuori la ragione per cui si vedeva male: la notifica lo disegna a 24 px ([img=24] in Interactable.gd), quindi un sorgente da 16 veniva ingrandito 1,5×. Ora si riduce, e si vede nitido. Posa scelta da Ivan al secondo giro: calzino di profilo, silhouette a «L» (gambale verticale, piede orizzontale, tallone nell'angolo), stesse caratteristiche di prima — vecchio, sporco, bucato, tallone consumato. Sorgente ad alta risoluzione archiviata in sprites_raw/sock.png (LFS, non committata).
  • [fix] Player._spawn_item_fx() ha un parametro size_mul. L'effetto «oggetto che vola» disegna lo sprite alla dimensione NATIVA della texture: col sock raddoppiato sarebbe raddoppiato anche a video. spawn_bin_sock_fx() passa 0.5 e l'effetto resta identico a prima. Serve a chiunque alzi la risoluzione di un asset FX in futuro.
  • Nuovo giro di generazione asset: il calzino è stato generato con ChatGPT via Codex CLI (codex exec) su sfondo magenta e ripulito con il chroma-key già in casa (flood-fill strict dai bordi + pulizia frangia loose, le funzioni di import_chatgpt_sprites.py). Nota per i prompt futuri: Codex dichiara dimensioni e magenta esatti che poi non rispetta (ha detto «256×256, angoli #FF00FF», ha prodotto 1254×1254 con angoli (232,18,234)) — regge solo perché il chroma-key lavora a distanza e non a colore esatto.
  • [feat] banknote.png rigenerata: da 18×11 a 36×20. Sono le banconote che volano via durante l'arresto (SU-58): erano troppo poco definite. Arte nuova ma nello stesso spirito (verde, cornice, simbolo centrale), con in più piega, angoli decorati e ombreggiatura; generata con l'originale allegata come riferimento. spawn_arrest_money_fx() disegna gli sprite alla dimensione nativa, quindi le sole banconote vanno a scala 0.5 — le monete (coin.png, invariata) restano a 1. Sorgente in sprites_raw/banknote.png (LFS, non committata).
  • [fix] hotdog.png 16×16 → 32×32 e caticon.png 20×20 → 40×40, disegno IDENTICO. Anche loro venivano ingranditi nelle notifiche a 24 px. Qui però l'arte non doveva cambiare, quindi niente rigenerazione: ingrandimento 2× nearest (ogni pixel diventa un quadrato 2×2), verificato riducendo e confrontando pixel per pixel con gli originali. Ora le notifiche riducono invece di ingrandire. spawn_food_fx()/spawn_bin_food_fx() passano size_mul 0.5; caticon non ha richiesto compensazioni (sta in TextureRect a dimensione fissa).
  • Non toccato: moneybag.png è già 1254×1254 per un'icona HUD da 22 px — problema opposto (sorgente enorme), da valutare a parte.

Sprint: comandi, rifugio, audio, export2026-07-21

  • [feat] SU-67 — Comandi in un posto solo. Opzioni aveva già (da SU-50) una schermata che fonde lista e riassegnazione leggendo i tasti reali dall'InputMap; la voce «COMANDI» del menu principale era invece una lista separata con tasti hardcoded, che dopo un remap continuava a mostrare i default. Rimossa quella schermata e tutto il codice diventato morto con lei (ACTIONS, BTN_PATHS, _load_btn_textures(), classe _BtnIcon, loop icone in _refresh_labels()): −200 righe in MainMenu.gd. La voce di Opzioni ora si chiama «COMANDI».
  • [feat] SU-61 — Via l'azione «dormi sul posto» (si dorme su panchine e al rifugio). L'input era già disattivato in Player.gd: completata la pulizia — _try_sleep(), la voce in Settings.REBINDABLE_ACTIONS e nei default tasti (Z), «DORMI» da REBIND_ACTION_NAMES, l'azione sleep dall'InputMap in project.godot, "sleep" da TestBot.ACTIONS. Intatti is_sleeping, sleep_started/ended, sfx_bench_sleep e i punteggi: panchina e rifugio funzionano come prima.
  • [feat] SU-63 — Voce «← INDIETRO» in tutti i menu con navigazione. Su touch non c'era modo di tornare indietro (niente ESC né tasto B). La voce è ora l'ultima dell'elenco dentro il riquadro, tappabile e navigabile da tastiera/pad, in 10 schermate: punteggi, opzioni, comandi, note di rilascio, domanda tutorial e le 5 multiplayer (home, unisciti, lobby, nome, codice). ESC/B restano scorciatoie equivalenti: tutte le voci passano dallo stesso _request_back(), quindi leave()/cancel_search() del NetworkManager continuano a scattare e nessuna sessione resta appesa; in mp_home il caso «back» è gestito PRIMA delle guardie su stato, così si esce anche mentre una ricerca partita è in corso. Non aggiunta dove non ha senso: menu principale, menu pausa (RIPRENDI è già equivalente), game over. Effetto collaterale utile: nella lobby MP il guest non poteva navigare affatto (unica voce PRONTO sempre selezionata) — ora host e guest hanno entrambi una navigazione vera.
  • [fix] SU-62 — Timer del rifugio in minuti/secondi veri (single player). Il countdown sul cartellone mostrava l'orario di GIOCO mancante alle 19:00, che scendeva accelerato e non diceva niente a chi guarda. Ora i minuti di gioco si convertono in secondi reali dividendo per GameState.GAME_MINUTES_PER_SECOND: usato il rifugio l'orologio salta alle 07:00 → 12 h di gioco → 720/2.4 = 300 s → «05:00» reali. Il ramo gira solo in SP (in MP il gate orario è disattivato), multiplayer invariato.
  • [fix] SU-66 — Equalizzato il volume di tutti i suoni. Misura EBU R128 con ffmpeg su tutti i suoni referenziati: si andava da −31,4 LUFS (bench.wav, quasi inudibile) a −7,7 (cat_1s.wav). Riportati con guadagno costante (nessuna compressione, dinamica invariata) a −16 LUFS gli SFX e −18 la musica (main, main2, tutorial), tetto di picco −1 dBFS; shelter.wav ha richiesto un limiter per salire di 3,7 dB. Non toccati i 9 file audio non referenziati da codice o scene.
  • [feat] SU-64 — Export iOS+macOS e flag debug condiviso. Nuovo files/homeless_city/system_config.cfg: file INI editabile a mano, punto unico per le variabili di sistema. DebugPanel.gd lo legge in _ready() e il pannello F1 ora richiede DEBUG_TOOLS_ENABLED and OS.is_debug_build() and debug=true. Nuovo tools/release/export_builds.sh <debug|release> [ios|macos|all]: scrive il flag e lancia gli export dei preset iOS/macOS con Godot headless. Il valore committato è debug=true (in editor il pannello serve) e dopo un export release lo script lo ripristina, così non finisce a false in un commit per sbaglio.
  • [chore] tools/autotest/common.sh: $SU_TMP ora è sovrascrivibile — serve per far girare due agenti builder in parallelo su copie di lavoro separate senza che l'rsync dell'uno cancelli i file dell'altro.
  • Non lavorato: SU-65 (pickup a risoluzione più alta) — richiede PixelLab, disponibile solo su Cowork. Emerso che sock.png è 16×16 e non ha sorgente in sprites_raw/: va rigenerato, non ri-esportato.

Autotest: compile-check riparato su Mac2026-07-21

Primo run_check.sh lanciato da Claude Code sul Mac: non partiva (binario Godot Linux della sandbox) e, una volta partito, si piantava per sempre.

  • [fix] tools/autotest/common.sh: su macOS il binario Godot si prende da /Applications/Godot.app/Contents/MacOS/Godot; su Linux/sandbox resta la ricerca in tools/godot/. Niente più cannot execute binary fileGODOT= da passare a mano.
  • [fix] scripts/tools/check_scripts.gd: lo script salta sé stesso nel giro dei .gd — ricaricarsi con CACHE_MODE_IGNORE mentre gira rompe la VM GDScript (Internal script error! Opcode: 31) e lasciava il processo headless appeso a vuoto (visto su Godot 4.6.2 macOS).
  • [fix] scripts/tools/check_scripts.gd: reload() che torna ERR_ALREADY_IN_USE non è più un fallimento — è il caso normale degli autoload, già istanziati come singleton: 17 falsi «COMPILE FAIL» in meno. Il codice d'errore ora compare nel messaggio.

Setup CLI: troubleshooting primo avvio2026-07-21

  • [docs] WORKFLOW/05_SETUP_CLI.md: aggiunta la sezione «Se claude non parte» — caso reale del primo setup di Ivan: ~/.local/bin fuori dal PATH + bash che ricorda il percorso della vecchia install npm (fix: riga PATH in ~/.bash_profile + hash -r; pulizia opzionale del residuo in .nvm). Corretta anche la nota shell per l'export GODOT: ~/.bash_profile (la shell del Mac è bash), non ~/.zshrc.
  • [docs] 05_SETUP_CLI.md + cheat sheet PDF: in Claude Code 2.1.216 il wizard /agents è stato RIMOSSO — il roster in .claude/agents/ si carica da solo; la verifica del passo 3 ora è chiedere in sessione «quali subagenti hai a disposizione?». Aggiornato anche il riquadro setup del PDF.

Prontezza ticket: via l'etichetta claude-ready, fa fede lo Sprint2026-07-21

Regola nuova di Ivan: un ticket è da fare se sta nello Sprint attivo in stato «Da fare» — ce li mette lui, KO compresi. Niente più etichetta di prontezza.

  • [docs] WORKFLOW/README.md + 01_TICKET.md + 02_SPRINT.md: selezione = trascinare nello Sprint (KO compresi); perimetro sprint = JQL sprint IN openSprints() AND status = "Da fare"; frase «Fai lo sprint» al posto di «fai i claude-ready»; «In revisione» = in attesa di Ivan, intoccabili; un Da-fare già lavorato È un KO da rifare secondo l'ultimo commento di Ivan.
  • [docs] ORCHESTRAZIONE.md (sezione Jira) aggiornata con la stessa regola; SU-9 «📌 LEGGIMI» riscritto su Jira (etichette attive solo mp/device, flusso in 5 passi con rientro KO, claude-ready dichiarata ritirata).
  • [feat] Slash command aggiornati: /sprint lavora tutti i «Da fare» dello sprint attivo, /ko filtra i soli KO, /triage non decide più la prontezza.
  • [docs] WORKFLOW_CHEAT_SHEET.pdf rigenerato (righe Selezione / Sviluppo / Test device / Rilavorazione).

Workflow v2: tutto su Claude, riparto Cowork/CLI + setup Claude Code2026-07-21

Deciso da Ivan (abbonamento Claude Max): Codex esce dal ciclo; sviluppo e release si lanciano da Claude Code (CLI) sul Mac, Cowork resta il ponte per task sidebar, memoria di progetto e asset PixelLab. Il triage schedulato delle 9:00 è sospeso: si fa a comando quando si inseriscono ticket (spesso i task vengono già lavorati in giornata).

  • [docs] WORKFLOW/ riscritta col riparto Cowork/CLI. README: sezione «Due postazioni, un solo Claude» + colonna Dove nel cheat sheet; 01_TICKET.md: triage a comando («Fai il triage Jira» / /triage), schedulato sospeso; 02_SPRINT.md: sprint da CLI di default, git push origin dev aggiunto alla chiusura sprint; 03_COLLAUDO.md: sezione «Su Mac (CLI)» con GODOT= (i vincoli sandbox valgono solo su Cowork); 04_RELEASE.md: da CLI il giro git lo esegue Claude un passo alla volta con conferma di Ivan, da Cowork resta «prepara e basta».
  • [docs] Nuovo WORKFLOW/05_SETUP_CLI.md (una tantum): installazione Claude Code, login col piano Max, verifica roster con /agents, Jira via claude mcp add --transport http atlassian https://mcp.atlassian.com/v1/mcp/authv2 + /mcp (OAuth), export GODOT= per l'harness su Mac, permessi consigliati (conferme attive su push/merge/tag), prova generale in 3 passi.
  • [feat] Slash command in .claude/commands/: /sprint, /release, /triage, /ko — ognuno punta al file WORKFLOW/ della fase e ne applica le regole.
  • [docs] CLAUDE.md: regola release riformulata (merge su main/tag/push MAI di propria iniziativa, solo in fase release da CLI con ok esplicito) + nota che le istruzioni valgono identiche su Cowork e CLI.
  • [docs] WORKFLOW_CHEAT_SHEET.pdf rigenerato (v2): colonna Dove, triage a comando, giro git «lo esegue Claude da CLI», riquadro setup CLI in 5 punti.

Distribuzione build: dmg → iCloud e zip Windows → Google Drive in automatico2026-07-21

Ivan copiava il dmg a mano nella cartella iCloud condivisa coi tester macOS; per i tester Windows serviva un canale equivalente. Scelto Google Drive (cartella condivisa con le email designate, download dal browser, niente client richiesto); beta chiusa su Steam scartata per ora perché anche il Playtest richiede un'app registrata con i 100$ di Steam Direct.

  • [feat] tools/release/make_dmg.sh: publish automatico su iCloud. Dopo hdiutil verify, il dmg viene sovrascritto nella cartella condivisa (env SU_DIST_MAC, oppure DIST_MAC_DEFAULT nello script) con copia nascosta .tmp + rename atomico: iCloud non parte mai a sincronizzare un file a metà e gli invitati vedono il dmg nuovo in un colpo solo. Cartella assente o non configurata → avviso, la build non fallisce.
  • [feat] Nuovo tools/release/make_winzip.sh — gemello Windows: zippa la cartella export (exe+pck+dll dentro una cartella col nome del gioco, junk macOS escluso, verifica unzip -t) e la pubblica nella sottocartella «StreetUniversityWIN» di My Drive, auto-rilevando Google Drive for Desktop in ~/Library/CloudStorage/GoogleDrive-* (override SU_DIST_WIN). Stesso giro atomico .tmp+rename; senza Drive installato avvisa e lascia lo zip in locale.
  • [docs] WORKFLOW/04_RELEASE.md: export anche Windows (stesso include_filter SU-57 su TUTTI i preset, cartella export dedicata), nuovo passo 5 per lo zip, publish automatici documentati, promemoria SmartScreen per i tester.

Design progressione: superpoteri, power-up 1-10 e sblocchi globali (SU-68)2026-07-21

Brainstorming richiesto dal ticket SU-68: come si ottengono i superpoteri, cosa si sblocca in una run e cosa per sempre. Solo design, nessun codice toccato.

  • [docs] Nuovo PROGRESSION_DESIGN.md (root). Due binari: IN RUN — XP dalle attività → ventaglio 3 carte (cadenza target 15-20 pescate/run, XP che sale col tier), 10 power-up a livelli 1-9 + 6 carte occasione (tutti i 16 perk del brief R2 riciclati), al liv. 10 il SUPERPOTERE: abilità attiva con barra di ricarica sul pattern del busking, battezzata con la cerimonia al riparo (paracadute "carta dorata" sotto i 5 minuti finali). FUORI RUN — regola "le imprese sbloccano, le lattine comprano": ragnatela di sblocchi stile VS (pool iniziale parziale, condizioni comiche sui contatori esistenti), Quaderno/codex, personaggi dalle skin P1 (v1 solo estetica), Baracca R3 estesa con VETO DEL BARBONE e DOPPIA IDENTITÀ (2° slot super). In coda: numeri di partenza (curva XP 4/1.12), impatto sui brief R2/R3 con slicing R2a/R2b/R3 e le 10 decisioni finali per Ivan con default raccomandati.

Guida operativa del ciclo: cartella WORKFLOW/ + cheat sheet PDF2026-07-20

Ivan ha chiesto una mappa chiara di tutti i passaggi (ticket → sviluppo → release) con le frasi e i comandi di ogni fase, per non perdere più pezzi nelle cuciture tra le fasi.

  • [docs] Nuova cartella WORKFLOW/README.md (mappa del ciclo + cheat sheet delle frasi da dire a Claude) + 01_TICKET.md, 02_SPRINT.md, 03_COLLAUDO.md, 04_RELEASE.md. Principio: checklist sottili che PUNTANO alle fonti (ORCHESTRAZIONE.md, script, SU-9) senza duplicarle; a inizio fase Claude legge solo il file di quella fase.
  • [docs] Processo release aggiornato: da ora, su «prepara la release», Claude scrive anche la sezione in-game di release_notes_it.txt e il bump di config/version (a Ivan restano revisione + blocco git). Codificata anche la chiusura sprint: commit per lotto, CHANGELOG/TESTLOG, REPORT_LOTTI.md azzerato, lista «da provare su device».
  • [docs] WORKFLOW_CHEAT_SHEET.pdf (root): riassunto stampabile in 1 pagina — ciclo, frasi, blocco git, regole d'oro.
  • [fix] ORCHESTRAZIONE.md: il ticket-guida delle convenzioni Jira è SU-9 («📌 LEGGIMI», label guida), non SU-6 (che è l'epic P1); aggiunto il puntatore a WORKFLOW/. CLAUDE.md e AGENTS.md: nuova regola «fase richiesta → leggi prima il file WORKFLOW/ di quella fase».

Note di rilascio in-game: sezione v0.22 + guardia nel prepara-release2026-07-20

Ivan ha notato che il gioco è a v0.22 ma la schermata NOTE DI RILASCIO (SU-57) era ferma a v0.21: il tag v0.22 è partito senza aggiornare il file letto in gioco.

  • [docs] assets/release_notes_it.txt: aggiunta la sezione v0.22 in linguaggio da giocatore (12 punti dal delta v0.21→v0.22: restyle cartone U1, icone stat, notte visibile, giornata da 10', banconote che volano all'arresto, sprite calzino, rebinding tastiera, pausa touch, fantasmino spettatore MP, stato "Attendere...", voce NOTE DI RILASCIO, pensionamento arena). Le novità post-tag (v0.22-dev: cerchio-luce notte, sprite ghost, matchmaking, portachiavi macOS) restano per la sezione della prossima release.
  • [docs] Regola fissata da Ivan: le note in-game sono CUMULATIVE. Le sezioni delle versioni vecchie restano sempre nel txt, sotto la più recente — non si rimuovono mai (eventuale potatura solo su decisione futura esplicita). Avviso 1b e piano comandi del prepara-release lo esplicitano («aggiungila IN CIMA, senza toccare le sezioni vecchie»).
  • [feat] tools/release/prepare_release.sh: guardia sulle note in-game (passo 1b). Calcola il core del tag proposto (es. v0.23) e, se release_notes_it.txt non ha quella sezione, stampa un avviso ⚠ in console e in testa a RELEASE_NOTES_DRAFT.md; il piano comandi ora ricorda anche sezione in-game + bump di config/version in project.godot. Così la prossima release non parte più silenziosamente con le note in-game vecchie. Verifica: bash -n ok, guard testata (v0.22 presente → nessun avviso; v0.23 assente → avviso; v0.2 non fa falso match su v0.22).

Online: niente più richiesta portachiavi all'avvio su macOS (SU-53)2026-07-20

Il prompt «Godot vuole utilizzare i dati riservati in "com.epicgames.sdk.connect.access_token"» compariva a ogni avvio perché il warm-up online (SU-27) faceva subito il login EOS Device ID, e su macOS il token vive nel portachiavi.

  • [fix] Warm-up online disattivato su macOS. NetworkManager.warm_up_online(): early-return se OS.get_name()=="macOS" — il login EOS parte on-demand (ospita/unisciti/partita rapida fanno già setup() da soli), quindi il prompt del portachiavi può comparire solo entrando in multiplayer, mai all'avvio. Altre piattaforme invariate. Costo: primo «PARTITA RAPIDA» su Mac senza lista pre-fetchata (qualche secondo in più).
  • [docs] EOS_SETUP.md § «macOS: richiesta portachiavi all'avvio»: perché appare, perché NON è auto-concedibile (modello di sicurezza del portachiavi, nessun entitlement lo evita), e come farla sparire del tutto — password + «Sempre» una volta per l'editor; per le build esportate Codesign Identity stabile nel preset macOS (con identity vuota la firma ad-hoc rende ogni export un'app "nuova" e il permesso riparte da zero).
  • [test] Compile-check NetworkManager.gd in sandbox; su Mac da verificare: avvio → nessun prompt; primo host/unisciti → prompt una tantum → «Sempre» → mai più.

Fantasmino spettatore: sprite dedicato in gioco (SU-31)2026-07-20

Lo spritesheet generato (arch_player_ghost_v1.png) ora è importato e collegato: il fantasma usa la sua grafica invece del barbone normale tinto.

  • [feat] Sprite ghost importato e cablato. player_ghost_sheet.png (160×160, 5×5) + player_ghost_frames.tres generati con la pipeline esistente (import_people_sprites.py, ora riconosce arch_player_ghost*). In Player.gd: caricato _frames_ghost; in _apply_ghost_visuals() (fantasma locale + puppet degli altri) swap a player_ghost_frames con modulate translucido bianco (i colori spettrali li dà lo sprite); fallback al barbone normale + GHOST_TINT se l'asset manca. Le animazioni combaciano con le altre (walk/idle per 5 direzioni) → il ciclo di galleggiamento gira come «walk».
  • [test] Headless: --import del nuovo sheet OK; SP OK (il player carica _frames_ghost senza errori); MP host+client — il client collassato passa a spectating=true e host+puppet applicano lo sprite ghost senza alcun errore di sprite_frames/has_animation/load. Resa visiva da vedere a occhio su device.

Sprint 1 Jira: fix KO SU-16 / SU-54 / SU-552026-07-20

Ripresi dai commenti KO di Ivan, non affrontati nel primo giro (li avevo mancati non leggendo i commenti dei ticket).

  • [feat] Notte: cerchio di luce «giorno» attorno al barbone (SU-16). Sostituito l'alone additivo morbido (bocciato) con un cerchio a stacco netto e circonferenza pixelata: dentro il raggio la tinta notturna sparisce e resta un filo di caldo giallognolo (sembra giorno), fuori resta notte. Due shader in World.gd — su WorldTint (z=10) e vignette (z=11) — «bucano» lo stesso cerchio, centrato sul player (camera 1:1). Raggio regolabile in autonomia: @export var night_light_radius (px) + night_light_pixel (grana del bordo). Rimosso il vecchio _night_glow.
  • [fix] Online: via ogni «(EOS)» dai testi a schermo (SU-55). MainMenu.gd, NetworkManager.gd (7 messaggi di stato) ed EOSBridge.status_text()/errori: «ONLINE ATTIVO (EOS)» → «ONLINE ATTIVO», «EOS NON DISPONIBILE» → «ONLINE NON DISPONIBILE», ecc. Nessun riferimento al motore online a video (in futuro potrebbe non essere EOS). Solo stringhe, logica invariata.
  • [fix] Matchmaking: una partita iniziata esce dalla ricerca (SU-54). NetworkManager.start_game(): all'avvio l'host rende la lobby EOS non-pubblica (EOSBridge.set_lobby_public(false)), così search_public() restituisce solo lobby ancora in attesa; se non ce ne sono, _quick_match_eos ne apre una nuova (modello di Ivan: si crea una lobby a cui gli altri si uniscono finché non parte, e così via). Il gate _srv_register resta come rete di sicurezza. Percorso EOS: non validabile in sandbox (solo ENet).
  • [test] Headless: SP OK (npcs 49, orphans 0, nessun errore script/shader), MP ENet host+client state=IN_GAME/players=2/npcs 49 (la modifica a start_game non tocca il percorso ENet). Resa notturna e testi UI da validare a occhio su device; SU-54 da confermare live su EOS/3 device.

Fantasmino spettatore: spritesheet definitivo (SU-31)2026-07-20

  • [feat] Creato arch_player_ghost_v1.png. Nuovo raw in sprites_raw/PEOPLE/: 25 pose S/N/E/SE/NE con ciclo di galleggiamento a 5 frame, stesso barbone stanco e barbuto del player ma con felpa, palette azzurro-spettrale e coda da genio al posto completo di gambe e scarpe. Asset generato dal riferimento barbone.png; nessun codice o scena è stato collegato in questa sessione.
  • [test] Contratto d'import verificato pixel per pixel. PNG RGB opaco 1254×1254, sfondo esterno esclusivamente #FF00FF, 10 colori totali (chiave + outline + palette dichiarata), 25 celle logiche 250×250 senza overflow, ultimi 4 px destri/inferiori interamente magenta, nessun testo/linea/cornice. La pipeline esistente rileva correttamente 5 isole di righe e 5 di colonne ed estrae tutti i 25 frame; dettaglio in TESTLOG.md.

Sprint 1 Jira: collaudo ticket In corso + fix export note di rilascio (SU-57)2026-07-20

Verifica dei 5 ticket "In corso" (SU-16/31/54/55/57) già implementati nel commit v0.22; un difetto d'export trovato e corretto.

  • [fix] Note di rilascio ora incluse nell'export (SU-57). export_presets.cfg (preset iOS + macOS): include_filter da "eos_credentials.cfg" a "eos_credentials.cfg,assets/release_notes_it.txt". Senza, Godot non impacchetta il .txt sciolto (export_filter="all_resources" copre solo le risorse importate) e la schermata «Note di rilascio» mostrava il placeholder nei build reali, pur funzionando in editor/sandbox. NB: export_presets.cfg è gitignored (path device-specifici, come eos_credentials.cfg): il fix è applicato in locale sulla macchina di Ivan, non entra in git → da riapplicare su un checkout pulito, oppure in futuro rendere le note una risorsa esportabile (.tres) per non dipendere dall'include_filter.
  • [test] Collaudo headless su v0.22. SP OK (npcs=49, orphans=0, stat/orologio avanzano). MP: SU-31 fantasmino confermato — il client collassato passa a spectating=true con gameover_panel=false e l'host prosegue (l'anomalia del 2026-07-19 era pre-fix, risolta dal guard players.size()>1 in _net_last_alive_is_me()). SU-54 verificato a livello codice (_srv_register nega «PARTITA GIÀ INIZIATA» fuori da IN_LOBBY, discovery LAN spento, client scarta host pieni) — conferma live EOS/3-device in sospeso. SU-16 (resa notturna) e SU-55 (testo «Attendere...») da validare a occhio su device. Dettagli in TESTLOG.md.