← Novità

Prima della numerazione delle versioni

2026-05-20 → 2026-09-08 · 58 voce/i di changelog

La fiammata del fachiro torna quella grossa, e nessuna delle altre cinque pose si sposta di un pixel2026-09-08

Ivan: «il fachiro nel busking ha perso la fiamma grossa, è tagliata, mettila senza però rimpicciolire o ritagliare altre parti, la proporzione è giusta ora». Aveva ragione su tutto: la fiammata c'era, e si era persa due giri fa.

  • 📌 Dove si era persa. Nel primo giro di generazione (TMP/su_skin_firebreather/_giro1/) la posa 4 aveva una fiammata piena, alta 373 px contro i 293 del corpo. In SU-864 quella striscia aveva un'altra posa rotta (una cella con due uomini), e il ritocco ha rigenerato le due pose di fuoco: sono tornate con una fiammella corta dalla bocca. In SU-865 la striscia è stata rigenerata di nuovo per il taglio della posa 3, e la fiammella è rimasta tale. Nessuno dei due giri l'ha guardata: erano ticket su altri difetti.
  • [fix] Ripresa l'arte del primo giro, non rigenerata. La fiammata di _giro1 è lo stesso personaggio (bandana, canottiera, toppe, piedi nudi) disegnato nella stessa sessione. Registrata sul corpo di oggi cercando la scala che massimizza la sovrapposizione del 55% basso della figura, dove la fiamma non arriva: scala 1,020, IoU 0,964. Rigenerare avrebbe rimesso in gioco il personaggio, che è quello approvato.
  • [fix] Il raw ricomposto restituisce l'alone eroso. maschera_arte() erode 2 px di contorno; incollando il riquadro della maschera già erosa l'erosione si applica due volte e la figura perde 2E px (misurato: 288 → 284, l'1,4%). Il riquadro si allarga di EROSIONE px prima di copiare, e i vicini si cancellano dilatati della stessa quantità. Con la correzione le cinque pose intatte tornano 287, 288, 287, 287, 289 come prima, al pixel.
  • [feat] --persona-da-pose in tools/monta_skin.py: la persona si misura solo sulle pose di cui ci si fida. ⚠️ La fiammata esce dalla bocca — è attaccata alla testa — e nel suo punto più largo è larga quanto i fianchi: né la prova della componente staccata né quella del restringimento del collo la vedono, e in quella posa la persona viene misurata 373 px invece di 288. Siccome la scala della striscia è una sola, quella posa da sola avrebbe rimpicciolito del 21% tutte e sei — l'esatto contrario di quel che Ivan ha chiesto. Nessuna regola automatica la separa, ed è stato provato: la mediana con scarto del 15% boccia le pose a terra del breaker (max/mediana 1,34, sue vere) e cambierebbe il borseggiatore (1,17); «la riga più larga sta nella metà bassa» scatta anche su punk_m e rapper_m, che allargano le braccia (quota 0,20 e 0,21 contro lo 0,27 della fiammata). Si dichiara, e si dichiara per pose e non in pixel, così regge anche se il raw viene rigenerato a un'altra risoluzione: PERSONA_DA="firebreather:0,1,2,3,4" in tools/rimonta_skin.sh.
  • Cambia un solo file di gioco. player_skin_firebreather_busk.png passa da 192×32 (cella 32×32) a 204×43 (cella 34×43): la cella si alza per la fiammata e la persona resta a 32 px. Le altre cinque pose sono identiche al pixel — stesso ritaglio, stesso numero di pixel accesi (381, 394, 412, 393, 395) — e gli altri cinque PNG della skin (quattro fogli e il colpo) sono byte identici. La fiammata sta tutta dentro la cella (2 px di margine sopra) e il fondo della striscia resta ancorato ai piedi (Player._ancora_busk_strip() usa l'altezza della texture, quindi la cella cresce solo verso l'alto). Sonda tools/autotest/probe_su863_roster.sh: 17 skin, nessun problema; provino in gioco tools/autotest/shot_su863_roster.sh: 15 skin, zero errori. Confronto per Ivan in TMP/su866/CONFRONTO_IVAN_fachiro.png, raw di partenza in TMP/su_skin_firebreather/arch_player_firebreather_busk_prima_su866.png.

Le stelline erano la taglia, i musicisti erano la posa, e due pose del busking non erano mai state disegnate intere2026-09-08

Secondo collaudo di Ivan sulle quindici skin, sei osservazioni. Due erano lo stesso difetto, una era una misura ingannata da uno spruzzo d'acqua, due erano arte mai disegnata e una era una riga sbagliata nel raw. Nessuna era dove sembrava.

  • [fix] «La testa non è proporzionata come il barbone standard, sono corpi più piccoli» e «nessuno deve avere le stelline sopra lo sprite statico» sono LA STESSA COSA. Sopra la testa di chi le prende il generatore disegna due o tre stelline gialle, e monta_colpo() le buttava tenendo solo la componente connessa maggiore — che funziona finché restano staccate. Quelle che toccano il cappello o la mano fanno corpo unico con la figura: allungano il riquadro verso l'alto, e siccome la cella scala per farci stare tutto, rimpiccioliscono la persona. Nel colpito della barbona erano quattro, e il corpo occupava 29 righe su 32 invece di 32. Ora via_le_stelline() le toglie prima di scegliere la componente, e le riconosce da tre prove insieme: il giallo (253, 211, 58), la stazza, e soprattutto cosa c'è oltre il loro contorno nero — una stellina sta nel vuoto, un bottone dorato della divisa dei musicisti ha intorno la giacca. ⚠️ Senza la terza prova ne spariscono sette su oneman_f, che sono i bottoni, e la figura rimpicciolisce invece di crescere.
  • [fix] Il colpo si monta in una cella 36×36, non 32×32. Il riquadro è solo tela: la posa a stella disegnata da Astra è più larga di quella compatta disegnata a mano per il barbone base, e dentro 32 px la persona veniva fuori al 80% dell'area del riferimento (mediana 436 px contro 545). A 36 la mediana è 551 px, il 101%, e la barbona sta a 543 contro 545. Non tocca nessun .tres: il colpo è una texture semplice, non una regione di atlante, e l'AnimatedSprite2D la centra da sé.
  • [fix] La pagliaccia era rimpicciolita da uno spruzzo d'acqua — e non in un frame solo, in tutti e otto. altezza_persona() prendeva la riga spessa più alta del disegno, e lo spruzzo sopra la testa è largo il 33% della riga più larga: passava la soglia del 20% e dava la persona alta 288 px invece di 258, cioè scalava il 10% più piccolo l'intero ciclo. Ora si sale dalla riga più larga (corpo di sicuro) e ci si ferma al primo restringimento, che è il collo. Partire dai piedi non va: le dita del breaker a terra sono sottili e il conto si fermava a 1 px. Risultato: la cella della pagliaccia passa da 33 a 36 px di altezza e lo spruzzo ci sta sopra la testa — «deve fare come il giocoliere, che non si riduce ma aumenta in altezza». Il giocoliere non si muove di un pixel (persona 249, cella 44), e nessuna delle altre tredici cambia.
  • [feat] tools/su865_tagli.py — trova le figure troncate di netto nel raw. Il segno è la colonna estrema della figura: in un disegno sano tocca poche righe (la punta di una mano), in un taglio è piena quasi quanto la figura è alta. Passati tutti i 91 raw delle quindici skin: tre figure tagliate, tutte e tre viste da Ivan — clown_m busking pose 3 e 4 (colonna piena al 100% e al 99%, tagliate a sinistra) e firebreather posa 3 (99%, tagliata a destra). Nient'altro, in nessuno degli altri 88.
  • [feat] Le due strisce del busking rigenerate con Astra (tools/sprite/su865_busk_tagliati.sh, due giri in parallelo, stessa tela del raw vecchio: 1544×264 e 1218×339). Stesso personaggio, stessa sequenza, stesse posizioni; le pose troncate tornano figure intere — il cane di palloncini del pagliaccio con testa, orecchie, zampe e coda, il mangiafuoco con tutte e due le spalle. Rimisurato con tools/su865_tagli.py: zero tagli. La cella del pagliaccio si allarga a 34 px per non comprimere il palloncino. Raw di partenza salvati accanto ai nuovi come *_prima_su865.png.
  • [fix] I due musicisti avevano le due diagonali invertite, ma solo nei fogli variante. Nei raw di gatto, sbornia e colpo di calore di oneman_m e oneman_f la riga 3 (che dovrebbe essere sud-ovest, di faccia) tiene la posa di spalle e la riga 4 quella di faccia; i fogli base sono giusti. ⚠️ Si scambia la DESTINAZIONE, non l'etichetta: nel raw il verso è già giusto in entrambe le righe — la 3 è disegnata verso sinistra e va specchiata, la 4 è già verso destra — ed è solo la posa a essere invertita. Scambiando le etichette si porta dietro anche lo specchio, e misurando da che lato sta la faccia il valore passava da +0,19 a −0,18: i due musicisti camminavano a rovescio. Fatto giusto, tutte e tre le varianti tornano con la faccia nel se e le spalle nel ne, verso a destra come la riga est.
  • [feat] tools/su865_diagonali.py — dice quali fogli hanno le diagonali scambiate. ⚠️ La sagoma non lo sa dire: sui due musicisti la cassa è così grande che le due diagonali hanno silhouette quasi identiche (IoU 0,826 contro 0,736, dentro il rumore) e il confronto ne pescava una su sei. Il segno che tiene è la testa — di faccia si vede la pelle, di spalle i capelli — confrontata con le righe s e n dello stesso foglio, che fra loro non possono essere scambiate. Così separa pulito su tutte le altre quattordici skin (se positivo, ne negativo, sempre) e pesca cinque dei sei fogli; il sesto, l'ubriaco di oneman_m, è un pareggio (+0,080 contro +0,074) perché da ubriaco ha gli occhi chiusi, ed è stato letto a occhio sul raw.
  • [fix] files/homeless_city/scripts/tools/probe_su863_roster.gd — il contratto della striscia era quello di prima di SU-864. Pretendeva «alta 32 px e larga esattamente hframes×32» e bocciava 15 skin su 17 con celle perfettamente legittime, che si alzano per far posto ai birilli e allo spruzzo. Ora chiede quel che conta davvero: la larghezza si divide per hframes, e nessuna delle due misure scende sotto i 32 px del cammino.
  • [fix] ⚠️ Tredici raw dell'archivio LFS erano rimasti all'arte di prima delle correzioni del giro precedente. Trovati confrontando byte a byte sprites_raw/PEOPLE/ con le cartelle di lavorazione: i dodici fogli dei due musicisti e la base della punk erano fermi al 7/9, mentre l'arte in gioco veniva dai file dell'8/9 — cioè l'archivio conteneva ancora l'uomo-orchestra coi piatti, che la voce (94) aveva tolto. Il colpo dei due era perfino di dimensione diversa (512 px invece di 1254), segno che a rigenerarlo era stato un giro successivo. Allineati. È esattamente il caso per cui vale la regola «i raw seguono i commit»: un tag che si porta dietro quei file restituirebbe il gioco con sorgenti che non corrispondono agli sprite montati.
  • 91 PNG rimontati, 25 cambiano (16 colpi, 3 strisce, 6 fogli dei musicisti); gli altri 66 sono byte identici, che è la prova che le correzioni sono chirurgiche. Verifica: 64 fogli su 64 col corpo da y=0 a y=31; 17 colpi su 17 a una sola componente connessa, cioè niente che galleggi sopra la testa; sonda tools/autotest/probe_su863_roster.sh 17 skin, nessun problema; provino in gioco tools/autotest/shot_su863_roster.sh 15 skin, zero errori, contatto in TMP/su_skin_roster/CONTATTO_ROSTER.png.

Il montaggio non taglia più sulla griglia: teste, piedi e attrezzi tornano interi in tutte e quindici le skin2026-09-08

Collaudo di Ivan sulla generazione combinata: quindici osservazioni, e quasi tutte dicono la stessa cosa con parole diverse — «tagliato lo sprite sulla testa in diagonale nord», «tagliati i piedi in variante sud», «il palloncino tagliato sulla sinistra», «la chitarra sparisce». Non erano quindici difetti: era uno, nel montaggio.

  • [fix] tools/monta_skin.py ritaglia per FIGURA, non per griglia. Ogni cella si tagliava sulla riga esatta della griglia 5×5 del raw, ma il generatore la griglia non la rispetta: misurato sui 60 fogli, la riga «ne» sfora sopra la propria cella in 232 celle su 300 (fino a 34 px su 250) e la riga «s» sfora sotto in 192. Quel che sforava finiva nel riquadro del vicino, dove solo_corpo() lo buttava via perché toccava il bordo — ed ecco le teste mozzate in diagonale nord, i piedi tagliati a sud, il palloncino verde della pagliaccia troncato a sinistra e la fiammata del mangiafuoco tagliata a destra nel busking. Ora le figure si etichettano su tutto il foglio e ognuna va alla cella del proprio baricentro; i pezzi staccati (birilli in volo, spruzzo) vanno al corpo più vicino, non alla cella dove cade il loro baricentro, che per un birillo sopra la testa è quella di sopra. Il conto che rende sicura l'operazione: tutti e 60 i fogli hanno esattamente 25 figure, nessuna fusa col vicino, nessuna cella vuota. Arte che resta fuori dopo il rimontaggio: al massimo lo 0,54% di un foglio (le gocce di sudore più lontane), zero nei fogli base.
  • [fix] Nella striscia del busking la figura si ancora al contatto a terra. Ogni posa era centrata sul proprio riquadro, che si allarga quando il braccio si alza: la cassa sotto i piedi del punk ballava da un frame all'altro — «occorre tenere come riferimento la cassa sotto ai piedi ferma tra uno sprite e l'altro». Ora l'ancora è il centro della fascia bassa del disegno. Misurato lo scarto massimo del contatto a terra fra i frame, prima → dopo: punk_m 3,0 → 0,0 px, mimo 5,0 → 1,0, pagliaccio 4,5 → 1,0, borseggiatore 3,5 → 0,5, rapper 3,5 → 0,5. Il breaker resta a 3,0 e va bene: le sue pose sono a terra, il contatto è tutto il corpo.
  • [fix] Le altezze di cella del busking non si scrivono più a mano: le calcola la persona. ⚠️ Le sette altezze della voce (94) erano tarate sul montaggio che tagliava, e col ritaglio giusto gonfiavano la figura: il mangiafuoco usciva alto 38 px contro i 32 del suo cammino, il mimo 34. Ora tools/monta_skin.py tiene la persona alta 32 come nel cammino e alza la cella per quel che le sta sopra la testa. La persona non è la componente connessa maggiore — i birilli in mano al giocoliere sono attaccati e contarli come corpo lo rimpiccioliva del 20% — ma il primo punto in cui la figura diventa larga: un birillo è sottile, le spalle no. Risultato: corpo a 32 px in tutte e quindici, celle da 32 a 45. Resta a mano solo il punk (42), dove la cassa sta sotto i piedi e nessun conto sulla larghezza la distingue dal corpo. Cade da sé anche il «rimpicciolisci il personaggio» dei punti 9/11/12: uomo-orchestra, donna-orchestra e borseggiatore erano grossi perché tagliati sotto, e la parte rimasta riempiva la cella.
  • [feat] tools/su864_diagnosi_celle.py dice, cella per cella, di quanto un raw sfora la propria casella — è il conto che ha smontato l'ipotesi «l'arte è sbagliata». tools/su864_audit_frame.py cerca i frame in cui sparisce un pezzo del disegno, confrontando ogni frame con la mediana e col consenso della sua riga.
  • Rimontate tutte e quindici, 75 PNG (60 fogli 5×5 + 15 strisce; i colpi non cambiano, byte identici). Verifica: 65 fogli su 65 col corpo da y=0 a y=31 in tutte e 25 le celle. Provino in gioco tools/autotest/shot_su863_roster.sh: 15 skin caricate, zero errori, contatto in TMP/su_skin_roster/CONTATTO_ROSTER.png.
  • [feat] I due difetti di DISEGNO che restavano, rigenerati con Astra (tools/sprite/su864b_gatto_e_chitarra.sh, sei fogli in parallelo). (a) Il gatto dei due pagliacci a sud stava sulla pancia: a 32 px leggeva come una macchia sul cappotto, non come un animale — colpa anche della parrucca, che si prende tanta della cella da schiacciare il busto sotto. Rigenerato tenendolo alto sul petto sotto il mento con testa e orecchie sopra le braccia, come nel riferimento f1 allegato al prompt. (b) Nella riga nord-est della punk la chitarra spariva nei fotogrammi alterni delle varianti gatto, sbornia e colpo di calore, e nel terzo di quella del punk: verificato sul raw, non era un taglio — il foglio base era già stato corretto nel giro precedente, le varianti erano rimaste indietro. Contati i pixel del corpo della chitarra nella riga ne dopo il rimontaggio: punk_f gatto [38, 46, 42, 44, 40], sbornia [36, 41, 35, 43, 39], calore [41, 42, 42, 41, 40], punk_m gatto [28, 30, 26, 29, 29] — nessuno zero in nessuna riga di nessuno dei quattro fogli. Le altre righe reggono il confronto col disegno di prima: stesso personaggio, gatto, bottiglia e guance arrossate al loro posto. Raw di partenza salvati accanto ai nuovi come *_prima_su864b.png.

Le quattordici correzioni del collaudo: il montaggio ne chiude nove, Astra disegna le altre cinque2026-09-08

Ivan, dopo aver visto in partita tutti gli sprite giocabili: quattordici punti, dai colpi «più piccoli perché hanno le stelline» al mimo «completamente sbagliato come movimenti», dai piatti dell'uomo-orchestra «brutti e ambigui» alla barbona che «non suona». Poi, quando il giro precedente aveva consegnato solo lo script e il punk: «punk e punketta hanno la cresta, ma tutte le altre modifiche che ti ho chiesto? dove sono?». Qui ci sono.

  • [feat] Le quindici skin rimontate tutte, 90 PNG, con tools/monta_skin.py e un driver che lo guida. tools/rimonta_skin.sh prende i raw dalle dieci cartelle di lavorazione e rifà per ciascuna i quattro fogli 5×5, il colpo e la striscia del numero; senza argomenti le fa tutte, bash tools/rimonta_skin.sh mime ne fa una. Le altezze di cella diverse da 32 stanno in una tabella dentro il driver, con scritto accanto perché: punk 42 (la cassa sotto i piedi), juggler_f 40 e juggler_m 38 (i birilli sopra la testa), clown_f 36, firebreather 34, mime 34. Verifica su tutti e quindici i fogli: corpo da y=0 a y=31 in tutte e 25 le celle, x fra 5 e 25, cioè dentro il riquadro del barbone base.
  • [fix] I colpi: le stelline fuori dal riquadro, e il corpo cresce del 18%. Il metro è il barbone base, il cui colpo vale 1,23 volte l'area della sua posa ferma. Prima del rimontaggio le quindici skin stavano fra 0,77 e 1,32 (mediana 0,93): il corpo si stringeva per far entrare anche le stelline nel quadrato. Ora stanno fra 0,84 e 1,49 (mediana 1,13), con area opaca che sale da 372→439 (breaker), 383→440 (pagliaccio), 364→448 (mimo), 375→453 (rapper). Quattro restano sotto — mangiafuoco 0,84, borseggiatore 0,87, pagliaccio 0,89, breaker 0,96 — e non è un difetto da correggere: quelle pose sono distese e saturano i 32 px in larghezza, quindi non c'è margine per ingrandirle senza tagliarle o senza allargare la cella del colpo, che vorrebbe rifare le SpriteFrames.
  • [fix] Il mimo era ruotato di due righe. Nel foglio in gioco la riga «est» mostrava la figura di fronte e la riga «sud» la mostrava di profilo: il raw del mimo non seguiva l'ordine s/n/e/sw/ne che import_chatgpt_sprites.py presuppone, e nessuno se n'era accorto perché ogni cella, presa da sola, è un disegno giusto. Rimontato con la rimappatura corretta, le cinque direzioni tornano al loro posto — ed è anche più grande, perché prima non riempiva la cella.
  • [fix] tools/monta_skin.py — UNA sola scala per tutta la striscia del numero, e la cella si allarga invece di comprimere. Ogni cella si scalava per conto suo: la posa a terra del breaker veniva ingrandita fino a riempire i 32 px di larghezza mentre quella in piedi riempiva solo l'altezza, e lo stesso ballerino usciva in due taglie — è il punto 7 del collaudo, «nel busking sembra più grosso del normale». Ora il fattore lo dà la posa più alta e vale per tutte; se la più larga non ci sta, si allarga la cella (hframes divide la larghezza della texture, quindi una cella 38×40 è legittima) invece di schiacciare la figura. È anche il rimedio ai rimpicciolimenti dei punti 9, 11 e 12.
  • [fix] files/homeless_city/scripts/dev/VisorePlayer.gd — il visore mostrava sollevati da terra proprio i personaggi appena corretti. Teneva l'offset fisso sprite.position + (0,-2) di prima di SU-852, mentre Player.gd ancora la striscia col fondo: sui tre con la cella alta gli scatti misuravano 103 px di scarto (punk) e 44 (giocoliera) — un difetto dello strumento che si legge come un difetto dell'arte. Aggiunta _ancora_busk(), copia esatta di Player._ancora_busk_strip(). Rimisurato: 17 skin su 17 con i piedi allineati fra posa normale e busking, scarto 0 px.
  • [feat] Arte nuova di Astra (GPT-6), sei giri. (a) Pagliaccio e mangiafuoco «si sdoppiavano» perché una cella del raw conteneva due personaggi — la gag a due che alla riduzione diventa una macchia: due pose nuove ciascuno col personaggio da solo, clown_m da 7 a 8 celle e firebreather da 5 a 6 (Skins.gd aggiornato). (b) I piatti dell'uomo-orchestra tolti da tutti i fogli di entrambi — base, gatto, sbornia, colpo di calore, colpo — con le gambe ridisegnate sotto: i pixel dorati nella metà bassa scendono da 459 a 268 (maschio) e da 362 a 216 (femmina), il resto sono i galloni della giacca, che restano. (c) La grancassa della donna-orchestra di profilo, prima stretta, ora larga come quella del maschio. (d) La chitarra della punk spariva nei fotogrammi alterni della riga nord-est: contati i pixel del corpo azzurro, [3, 0, 2, 0, 2] → [20, 21, 22, 26, 26], sempre visibile e più grande. (e) La barbona suona: quattro celle con la trombetta, ricalcate su quelle del barbone base, e la riga busk che a SU-852 mancava in Skins.gd — prima ripiegava su «beg» e restava ferma.
  • [nota] La misura che ha raddrizzato l'arte generata: quanto sale il prop sopra la testa. Il primo spruzzo del pagliaccio era +56% dell'altezza del corpo e, entrando nella cella, schiacciava la figura; il modello che Ivan indica — la pagliaccia — sta a +15%. Detto il tetto in percentuale nel prompt, il secondo giro è sceso a +11/+13% — ma il getto era spesso un pixel e a 32 px spariva. Il terzo giro chiedeva «spesso come l'avambraccio, non alto»: è quello montato. La stessa misura ha corretto la fiammata del mangiafuoco (da fuori scala a +3/+4%). tools/innesta_pose_busk.py fa il resto: innesta le pose nuove in una striscia esistente normalizzando sull'altezza del corpo, non su quella del riquadro, altrimenti la posa col prop esce col personaggio più piccolo delle altre — che è il difetto da cui si era partiti.
  • [nota] ⚠️ Il secondo giro sull'uomo-orchestra aveva perso la grancassa. Chiedendo la striscia del busking «senza piatti» con il foglio base come riferimento, Astra ha disegnato le due figure in piedi e senza strumento: un uomo-orchestra senza grancassa visibile è una persona ferma. Rifatto dicendo che la cassa deve sporgere ai due lati del busto, con la vecchia striscia allegata come prova di quanto è grande. Vale in generale: quando si chiede una rimozione, va detto anche cosa deve restare.
  • [nota] Restano fuori: i tredici ritratti in alta risoluzione (punto 14b). Ivan li vuole generati a figura intera come per il barbone e la barbona, non presi dagli sprite di gioco: si fanno dopo che ha approvato l'arte di questo giro, altrimenti si generano ritratti di personaggi che potrebbero cambiare ancora.

Uno script solo per montare le skin, e il punk ritrova la cresta2026-09-08

Ivan, dopo il collaudo che ha bocciato le quindici skin: «fai lo script unico di montaggio e rimonta il punk». Il montaggio era il vero imputato — l'arte nei raw era giusta.

  • [feat] tools/monta_skin.py — dal raw ai fogli di gioco, in un posto solo. Sostituisce i dieci script copiati dentro le cartelle di lavorazione (TMP/su_skin_punk/, TMP/su_skin_clown/ e le altre), dove la stessa riga sbagliata stava in 23 file: if a and r > g+35 and b > g+35: alpha = 0 rendeva trasparente qualunque pixel rosa, viola o fucsia del disegno, ovunque si trovasse, senza guardare il bordo né la dimensione della macchia. Tre correzioni: (1) il fondo si toglie per flood-fill dai bordi più le sacche di magenta pieno racchiuse dal disegno — nessun pixel può sparire per il suo colore; (2) si applica prima l'alfa e poi si riduce, in premoltiplicato, così i pixel di fondo non entrano nel colore e la frangia non nasce (prima il BOX girava col magenta ancora dentro e i bordi viravano al rosa, che la regola del punto 1 poi cancellava); (3) il quadrato di ritaglio si costruisce sul corpo, non sul bbox di tutto: nei fogli del colpo le stelline entravano nel conto e il corpo si stringeva per far entrare anche loro. In più l'ancoraggio: si scala perché il disegno riempia l'altezza della cella e si posa col fondo sull'ultima riga, che è il contratto del barbone base (ogni cella y 0-31, x 6-24). Modi: foglio (5×5 con la rimappatura righe s/n/e/sw/nee/se/s/ne/n, sw specchiata), striscia, colpo, misura.
  • [fix] files/homeless_city/scripts/player/Player.gd — la striscia del numero si ancora col FONDO, non col centro. _ancora_busk_strip() mette l'overlay a y = sprite.position.y + 16 - altezza_texture/2, chiamata alla nascita del nodo e a ogni cambio di skin. Con la cella da 32 restituisce -8 invece del -10 cablato prima: suonando, il personaggio non si alza più di due pixel. E soprattutto una striscia può ora avere celle più alte di 32 — 42, 48 — con la persona alla scala del suo foglio di camminata e lo spazio in più sopra la testa (birilli, spruzzo, fiammata) o sotto i piedi (chi suona su una cassa). L'altezza si legge dalla texture: nessun campo nuovo in Skins.gd.
  • [feat] Il punk e la punk rimontati: dodici asset, e la cresta torna in tutte e cinque le direzioni. Nel raw l'8,8% dei pixel del punk è rosa — la cresta, presente in ogni riga; nel foglio in gioco erano zero, e la testa risultava rasata nelle tre righe di profilo e diagonale. Ora sono 7,6-8,8% per i quattro fogli del maschio (base, gatto, sbornia, colpo di calore) e 1,3-2,4% per quelli della punk, dove il rosa è il manico della chitarra che spariva nella riga nord-est. Piedi a y=31 in tutte e 25 le celle di tutti e otto i fogli, bbox in linea col barbone base. Colpo: corpo da 27-30 px a 32 px pieni, area opaca 380 → 418 px (maschio) e 385 → 453 (femmina), stelline scartate (7 e 9 macchie). Striscia del numero: celle 32×42, la persona torna a 32 px e la cassa sta sotto, dove prima persona + cassa dovevano stare dentro 32 px e la persona restava a ~22.
  • [test] Ancoraggio misurato in partita, non sul foglio: scarto 0,0 px. Sonda nuova files/homeless_city/scripts/tools/probe_su852_ancoraggio.gd (carica Main.tscn, sceglie la skin, avvia il numero): *sprite personaggio y=-8 → fondo a 8,0; striscia 192×42 y=-13 → fondo a 8,0*. Compile-check su Player.gd e sulla sonda: 0 falliti. Guardati anche i sei scatti del busking in partita (TMP/su864_rimontaggio_punk/punk_m_busking_ingame.png) e i sei stati nel visore. NON PROVATO: multiplayer a due peer, le altre tredici skin (che hanno gli stessi difetti e lo stesso rimedio), il colpo su cui il criterio «area ≥ 90% del barbone base» non è raggiungibile: la posa del punk è più larga di quella di m1 e satura la cella in larghezza (32×29), quindi il criterio giusto è il bbox che riempie la cella, non l'area.
  • [nota] ⚠️ La stessa riga sbagliata è anche in una sonda del repo. files/homeless_city/scripts/tools/shot_su_skin_provino.gd cancella per tinta con lo stesso criterio (MAGENTA_MARGIN = 35/255) quando costruisce i fogli dal raw: un provino fatto con quella sonda mostra l'arte rosa già sparita, e chi guarda conclude che il difetto è nel disegno. È il 24º posto dove vive quella regola, e l'unico dentro files/homeless_city/.
  • [nota] ⚠️ Trappola: la sonda misurava la striscia vecchia e diceva OK lo stesso. Sostituito il PNG (32 → 42 px di altezza), il primo giro ha stampato texture 192x32: Godot serviva la texture importata, non il file su disco. Serve Godot --headless --path files/homeless_city --import prima di misurare — e il segnale che manca non è un errore, è un numero plausibile e vecchio.

Un tester Android in piu': Alessio Sereno sui tre elenchi, non solo sul foglio2026-09-08

Ivan porta nome, mail e piattaforma gia' pronti («Alessio sereno aka Ale, Android, Samsung Galaxy S25 Ultra»): il messaggio di reclutamento non serve, si va dritti allo store.

  • [chore] Foglio Tester riga 53 (ID 82), e i due elenchi di Google aggiornati insieme. Nickname *Ale* (e' il saluto dei messaggi), mail in Email e Utente Play Store, Android = Si, Avvisa tester = Si, modello *Samsung Galaxy S25 Ultra* con la fascia (2025, flagship — sopra Honor 10), data invito 08/09. Sugli store: mailing list «Test Interno Street University Android» del canale Alpha 30 → 31, utenti di prova della schermata di consenso OAuth 38 → 39 (55 utenti totali sui 100 del tetto). Gli indirizzi nella mailing list Alpha sono ora 31, sopra i 12 che Play chiede per la produzione — due piu' delle 29 righe del foglio con Android = Si e mail Play compilata: uno scarto che c'era gia' prima di oggi e che nessun passo del giro riconcilia. Backup del foglio in BETATESTING/Beta_Tester_Homeless_City.BACKUP-2026-09-08-pre-sereno.xlsx.
  • [nota] La mail e' passata dal filtro OAuth dopo il reload, e questo dice piu' di quanto sembri. Google rifiuta gli indirizzi che non corrispondono a un account vero, e la console non lo scrive a schermo: la prova che l'aggiunta e' andata a segno e' il contatore che cambia e la voce che ricompare col filtro dopo aver ricaricato la pagina. Chi salta quel passo si accorge del buco solo quando il tester installa la beta e viene respinto al login Google. Messaggio di conferma Play mandato su WhatsApp col testo approvato il 06/08, stato Invitato.

Un visore per i personaggi giocabili, coi cinque stati che in partita capitano a caso2026-09-08

Ivan: «nello scenario dove posso testare tutti i personaggi, compresi quelli giocabili, c'è modo se non ancora implementato di mettere per ogni personaggio (con tasto magari) le varianti ubriaco, insolato, colpito, gatto in mano, busking?» — e subito dopo, la decisione che ha dato la forma al lavoro: «magari creiamo un visore apposta separato VisorePlayer così li differenziamo».

  • [feat] files/homeless_city/scenes/dev/VisorePlayer.tscn — le diciassette skin nei loro sei stati, un tasto per stato. Il visore degli NPC (SU-47) i personaggi giocabili non li vedeva affatto, e non per una dimenticanza: costruisce le sue voci da NPCDatabase, che di arch_player conosce solo player_new, player_cat e player_drunk — i quindici fogli di SU-863 non passano da lì e finivano nell'elenco «non raggiunti dal database». Il visore nuovo legge invece il roster da Skins.all_ids() (17 personaggi) e mostra i sei stati del contratto di una skin: NORMALE, GATTO IN BRACCIO, UBRIACO, INSOLATO, COLPITO, BUSKING — V passa al successivo, 1..6 ci va diretto, Q/E cambiano personaggio, PagSù/PagGiù saltano di cinque, frecce/WASD guidano nelle otto direzioni (nelle due pose senza direzione girano la posa a specchio), Spazio fa il giro automatico, ESC torna al menu. Il punto non è mostrare i fogli: è mostrare quello che si vedrà in partita, quindi gli stati usano gli stessi ripieghi di Player._load_skin_frames() — gatto e sbornia ripiegano sul PROPRIO foglio base, l'insolato prima sulla PROPRIA sbornia (SU-348) — il colpo è l'animazione hit dentro le SpriteFrames attive come in _apply_hit_pose(), e il busking monta la striscia del numero al posto del corpo (Sprite2D con hframes, corpo nascosto sotto: è un corpo alternativo, non un overlay — SU-154). Quando uno stato ripiega, il visore lo scrive in arancione a schermo invece di far finta di niente. Ci si arriva da F6 in editor, da F1 → NPC SYSTEM → «Visore PLAYER» (bloccato in multiplayer come il fratello: cambiare scena chiuderebbe la sessione agli altri peer) o da bash tools/autotest/visore_player.sh. File nuovi: files/homeless_city/scenes/dev/VisorePlayer.tscn, files/homeless_city/scripts/dev/VisorePlayer.gd, files/homeless_city/scripts/tools/probe_visore_player.gd, tools/autotest/visore_player.sh, tools/autotest/probe_visore_player.sh; toccato solo files/homeless_city/scripts/autoload/DebugPanel.gd (un pulsante). VisoreNPC.gd non è stato toccato di una riga, che è esattamente ciò che Ivan ha chiesto separando i due visori.
  • [feat] Censimento del contratto in console, per non sfogliare diciassette personaggi a mano. All'avvio (e da bash tools/autotest/visore_player.sh --censimento, headless, nessuna finestra addosso a chi lavora) il visore stampa una riga per personaggio: base, gatto, ubriaco, insolato, colpo e striscia del numero, ognuno ok o ASSENTE col ripiego che scatterebbe in gioco. Misurato oggi: sedici personaggi col contratto completo, e f1 unica senza striscia del busking — «numero ASSENTE (ripiega su «beg»)», che è la nota già scritta in Skins.gd e non una regressione. Con --scatti salva un PNG per personaggio × stato (102 file in TMP/screenshots_claude/visore_player/) per guardarli tutti insieme.
  • [nota] Una scelta deliberata contro la fedeltà: la striscia del numero qui scorre ordinata. In partita il busking cambia cella a caso ogni 0,25-0,7 s (Player.MUSIC_FLIP_MIN/MAX, insieme al flip). Il visore la fa scorrere in ordine a 6 fps: serve a vedere una per una le celle disegnate — da 4 a 8 secondo la skin — che è l'unico motivo per cui lo strumento esiste. È scritto accanto alla costante, perché è il punto in cui il prossimo penserebbe di aver trovato un bug.
  • [test] Sonda nuova: 17 personaggi × 6 stati × 8 direzioni, zero animazioni mancanti. files/homeless_city/scripts/tools/probe_visore_player.gd (via bash tools/autotest/probe_visore_player.sh, headless) non guarda i disegni — quelli li guarda Ivan — ma controlla che lo strumento dica il vero: roster uguale a quello di Skins (17 = 17), i tasti che fanno quel che dice la riga di aiuto (E, Q, PagGiù, V, 5), ogni combinazione risolta senza MANCANTE, la striscia che scorre davvero e f1 che senza striscia suona con beg. Esito: 0 controlli KO. Compile-check su quattro file: 0 falliti; check_no_scene_comments.sh verde. Guardati anche gli scatti veri di breaker (busking e colpo) e di f1 (ripiego su «beg»). NON PROVATO: i tasti premuti da una tastiera vera (la sonda chiama _input() con eventi sintetici) e la resa a schermo intero.

Astra entra nel roster: i compiti difficili e tutti gli sprite2026-09-08

Ivan, il giorno dopo l'annuncio di OpenAI: «è arrivato chatgpt astra! utilizza quello per i compiti più difficili e per generare qualsiasi tipo di sprite, nella speranza che migliori l'output». Lo vedeva sull'app mobile e non su quella desktop — e la spiegazione è la stessa che teneva Astra fuori dal nostro Codex: è una questione di versione del client, non di piano.

  • [chore] gpt-6-astra cablato: alias corretto, consulti di default, tutti gli sprite. In tools/codex_lotto.py l'alias astra puntava a gpt-5.6-astra, un segnaposto scritto il 04/09 quando il modello non esisteva ancora: il server lo rifiuta (is not supported when using Codex with a ChatGPT account). Lo slug vero è gpt-6-astra — 272K di contesto come gli altri, effort fino a ultra, descritto dal server come *«our most capable model for complex, demanding work»*. Il modo consulto passa ad Astra di default (il consulto è il compito difficile: seconda opinione su una diagnosi, un design, un KO al 2º giro); il builder resta su Sol, con Astra a richiesta (--modello astra) sui sistemi profondi e sui ticket già rientrati, altrimenti la settimanale se ne va in lavori che Sol chiude uguale. Le quindici chiamate di tools/sprite/*.sh passano ora -m "${MODELLO_SPRITE:-gpt-6-astra}": per rigenerare col vecchio modello basta MODELLO_SPRITE=gpt-5.6-sol bash tools/sprite/<script>.sh "$PWD", senza toccare gli script. File: tools/codex_lotto.py, i dieci script di tools/sprite/, tools/sprite/LEGGIMI.md, ORCHESTRAZIONE.md, CLAUDE.md.
  • [nota] ⚠️ Trappola: l'errore accusa la CLI, non il modello, e le due frasi si somigliano. Con la CLI installata (0.144.6) il server rispondeva The 'gpt-6-astra' model requires a newer version of Codex, mentre uno slug davvero inesistente (gpt-6) risponde is not supported when using Codex with a ChatGPT account. Chi legge la prima di fretta conclude «il modello non c'è» e smette di provare: la differenza fra le due frasi è la diagnosi. codex update ha portato la CLI dalla 0.144.6 alla 0.153.4 e Astra ha risposto al primo colpo.
  • [chore] Le memorie di Claude sono ora leggibili da Codex, e il canale è AGENTS.md. Sono ~180 note (380 KB: 95K token, impensabili da incollare a ogni chiamata) e stanno fuori dal repo, in ~/.claude/projects/…/memory/. Misurato l'08/09: Codex quella cartella la legge benissimo anche in sandbox read-only, quindi non serve copiarla — serve indirizzarla. AGENTS.md (da 3.203 a 4.363 byte, +290 token per chiamata) ora dice tre cose: che le note esistono, che MEMORY.md è l'indice e non si legge intero ma si interroga con grep, e che il canale va in una direzione sola — Codex legge, le memorie le scrive Claude dal report. Prova, senza suggerimenti: alla domanda «genero una rapper con la felpa viola su fondo magenta, ci sono rischi?» Astra ha fatto rg -i 'magenta|viola|felpa…' MEMORY.md, ha aperto solo costume-rosa-o-viola-sparisce.md e ha citato la fonte. File: AGENTS.md.
  • [test] Astra alla prova sullo stesso prompt di Sol: vince su tutto tranne il passo, e il passo è ciò che si vede in partita. Rigenerato il foglio del pinguino di SU-801 con il prompt identico a quello del 2º giro (TMP/astra_prova/prova_pinguino_astra.sh, estratto da tools/sprite/su801_806_giro2.sh cambiando solo il path d'uscita), così l'unica variabile è il modello. A favore di Astra: 1750×1250 esatti alla prima; fondo #FF00FF puro, 0,00% di pixel quasi-magenta contro lo 0,02% del raw di Sol — e il fondo sporco è la causa dei costumi mangiati dal ritaglio; soggetto più grande nella cella (riempimento 23-30% contro 14-24%: a 64 px si legge di più); geometria dello scivolo corretta in tutte e cinque le righe e con scarti molto più marcati (riga 2 dy +54 contro +21, riga 5 dx-42 dy+42 contro -36/+16). 📌 Astra ha anche fatto una cosa che Sol non faceva: ha riaperto con PIL l'immagine appena generata per verificarne misura e fondo, e l'ha rifatta — il primo tentativo era 1484×1060 con fondo trasparente. ⚠️ Contro: le due pose di passo sono quasi identiche — pixel diversi fra colonna 2 e colonna 4 4,1-5,4%, contro 6,6-15,0% del raw di Sol e 15,7-28,6% del foglio montato. Il prompt lo chiede a parole («Columns 2 and 4 must be visibly DIFFERENT poses», «col 4 drawn FROM SCRATCH») e a parole non basta: va dettato come vincolo geometrico misurabile, esattamente come si fece per lo spruzzo di neve («nella col 4 il piede in avanti è quello nella metà DESTRA»). Contatto in TMP/astra_prova/confronto_astra_sopra_sol_sotto.png.
  • [nota] Astra è preciso ma non ha le nostre memorie — e si è visto al primo colpo. Il consulto di collaudo (43 s, 65K in / 867 out, +0,0 punti di settimanale) ha risposto con file:riga e ha contato giuste le 17 skin di Skins.SKINS, ma ha dato res://assets/sprites/npc/bodies/ come cartella del frame del colpo, mentre i .tres lo cercano in res://assets/sprites/una cartella sopra, che è proprio la trappola scritta nel changelog del giorno prima. È il motivo per cui il canale delle memorie qui sopra vale più di un modello più bravo.
  • [nota] ⚠️ Trappola più insidiosa: la cache dei modelli può dire il falso, ed è condivisa con l'app. ~/.codex/models_cache.json la scrivono sia la CLI sia ChatGPT.app, e il server elenca i modelli secondo la versione del client che sta chiedendo. Misurato l'08/09 a due minuti di distanza, con lo stesso account: l'app ferma alla 0.145 (build del 18 luglio) riscrive il file senza gpt-6-astra, la CLI 0.153 lo rimette. Quindi python3 tools/codex_lotto.py modelli può giurare che Astra non esista mentre -m gpt-6-astra funziona benissimo — ed è anche il motivo per cui Ivan lo vedeva sul telefono e non sul Mac. Lo script ora stampa da quale client viene la cache e, se un alias non compare, mette *«l'ha riscritta un client più vecchio»* come prima causa da escludere, non più come ultima.

Le quindici skin entrano nel roster, con nomi in otto lingue2026-09-08

Ivan, guardate le schede: «iniziamo ad importarle tutte, poi eventualmente le modifico». Entrano quindi tutte e quindici insieme, senza aspettare l'approvazione una per una: i ticket sprite sono in revisione e non a Fatto, e questa è la decisione che lo scavalca.

  • [feat] SU-863 — quindici skin registrate in Skins.SKINS: 240 asset, 60 .tres, 15 nomi × 8 lingue. Per ognuna i quattro fogli 160×160 (base, gatto in braccio, sbornia, colpo di calore), il frame del colpo e la striscia del numero, copiati direttamente e mai passati da import_people_sprites.py, che ricentra le celle (SU-83). I .tres sono cloni di quelli di f1 per sostituzione del nome: ogni file di f1 contiene esattamente due riferimenti, entrambi negli ext_resource, quindi la sostituzione è completa e non tocca né le regioni né i sedici nomi di animazione. Gli hframes del busking non sono scritti a mano ma letti dalla larghezza della striscia (vanno da 4 a 8, dentro il contratto). Costo 150 come f1 per tutte, che è la proposta del ticket e non un bilanciamento. 📌 Il montaggio non è stato fatto a mano: tools/monta_skin_roster.py copia, clona, genera le voci e le righe di traduzione da una tabella di quindici righe, e ha un --prova che stampa cosa farebbe senza scrivere. Misurato dalla sonda nuova files/homeless_city/scripts/tools/probe_su863_roster.gd: 17 skin caricate, 0 problemi — per ognuna base e tre varianti espongono tutte e sedici le animazioni con texture non nulle, e la striscia è alta 32 px e larga esattamente hframes × 32. Compile-check 0 falliti, audit emoji 0 pittogrammi scoperti, verifica_i18n.py fermo ai 2 punti preesistenti di HUD.gd. I 90 raw 1254×1254 sono archiviati in sprites_raw/PEOPLE/ come quelli di f1. NON PROVATI: il provino visivo delle otto direzioni, la comparsa nel menu (bloccata con «???» e sbloccata dopo l'acquisto), il multiplayer a due peer e la modalità demo. File: files/homeless_city/scripts/autoload/Skins.gd, files/homeless_city/assets/translations/ui_menu.csv, files/homeless_city/assets/sprites/npc/bodies/, tools/monta_skin_roster.py.
  • [nota] ⚠️ Trappola: il compile-check non reimporta, e un .tres che punta a una texture non importata carica lo stesso. Dopo la copia c'erano 80 PNG e 5 soli .import — quelli di f1 — eppure check_files.sh dava «FALLITI: 0» e nessun errore compariva da nessuna parte: le quindici skin sarebbero entrate in partita invisibili. Serve un Godot --headless --path . --import esplicito, e la prova che è servito sta nella sonda, che legge get_frame_texture(...).get_width() invece di fidarsi del caricamento. È la stessa lezione già scritta per gli asset modificati, qui su asset nuovi.
  • [nota] Il frame del colpo non sta in bodies/. f1 tiene player_skin_f1_hit.png in files/homeless_city/assets/sprites/, una cartella sopra i fogli, ed è lì che lo cerca il .tres clonato: metterlo accanto agli altri avrebbe rotto tutti e quattro i .tres di ogni skin, in silenzio e allo stesso modo. Il contratto in testa a Skins.gd dice il nome del file ma non la cartella: la cartella si legge dagli ext_resource di f1.
  • [nota] I quindici nomi sono una proposta, non una decisione. In italiano: BREAKDANCER, PAGLIACCIO, PAGLIACCIA, MANGIAFUOCO, GIOCOLIERE, GIOCOLIERA, MAGO, MIMO, UOMO-ORCHESTRA, DONNA-ORCHESTRA, BORSEGGIATORE, PUNK, PUNKETTA, RAPPER, RAPPER DONNA — tradotti in tutte e otto le lingue, tenuti sotto i 18 caratteri come i due esistenti per non sfondare la riga del menu. Si cambiano in files/homeless_city/assets/translations/ui_menu.csv senza toccare altro, perché Skins.SKINS li nomina per chiave.
  • [test] SU-863 — le quindici viste camminare, nel menu, in rete e in demo. Provino nuovo files/homeless_city/scripts/tools/shot_su863_roster.gd, generalizzato all'id da quello di f1: prende la skin come la carica il gioco, da Skins.SKINS, e non ricostruendo gli SpriteFrames dai PNG di lavoro come fa shot_su_skin_provino.gd — altrimenti non proverebbe il montaggio ma se stesso. Genera Main.tscn una volta sola e cambia skin a caldo invece di rifare il mondo quindici volte. Misurato: 15 skin × 13 scatti (otto direzioni camminate, busking col proprio numero, gatto in braccio, sbornia, colpo di calore, posa del colpo) con 0 SCRIPT ERROR; menu con la skin bloccata (silhouette e «???») e sbloccata, nome più lungo che non sfonda la riga né in italiano (UOMO-ORCHESTRA) né in russo (ЧЕЛОВЕК-ОРКЕСТР); multiplayer a due peer ENet, dove il puppet remoto ha i propri fogli — base, gatto, sbornia, colpo di calore e striscia da 8 — con m1 verde a controprova; demo ferma a ['m1'] col roster a 17; compile-check 3 file, 0 falliti. ⚠️ Il primo giro del contatto complessivo era illeggibile — celle troppo piccole e HUD acceso: rifatto ritagliando un quadrato centrale prima di rimpicciolire. Restano NON PROVATI i due stati sul puppet *forzati davvero in rete* (sono letti dalle risorse che Player.apply_skin() risolve, le stesse che il gioco assegna) e la resa su due telefoni veri. Contatti in TMP/su_skin_roster/. File nuovi: i tre provini in files/homeless_city/scripts/tools/ e quattro wrapper in tools/autotest/.
  • [nota] Due cose incontrate per strada, non toccate. (1) Nessuna delle quindici ha un ritratto dedicato (SU-750): la vetrinetta del menu ripiega sullo sprite di gioco con un push_warning esplicito — è il comportamento già previsto, ma è quello che si vede oggi. (2) Cambiando lingua mentre si è sulla schermata delle skin, MainMenu._ricostruisci_testi() va in SCRIPT ERROR: Trying to assign invalid previously freed instance: a files/homeless_city/scripts/ui/MainMenu.gd:3162 la guardia is_instance_valid(lbl) arriva un'istruzione dopo l'assegnazione var lbl: Label = voce.get("lbl"), quindi non protegge da una label già liberata. È pre-esistente e indipendente dal roster_testi_fissi è il registro di tutto il menu — e vuole un ticket suo.
  • [fix] SU-863 — 45 .tres avevano lo stesso uid di quelli di f1. Clonando per sostituzione del nome si copia anche l'uid dell'intestazione, che è l'indirizzo univoco della risorsa: sedici file — f1 più i quindici cloni — si presentavano a Godot con lo stesso, per ciascuna delle tre varianti. Il difetto non l'ha visto nessuna delle prove del lotto, perché non impedisce il caricamento: è saltato fuori aprendo il progetto nell'editor, che ha riassegnato d'ufficio gli uid dei quindici cloni e ha riscritto 45 file sotto i piedi (Duplicate UID detected … The new file UID was changed automatically). f1 ha tenuto i suoi, quindi nessun riferimento è mai finito sulla risorsa sbagliata: Skins.SKINS nomina i .tres per path, e nessun .tscn cita quegli uid. Misurato dopo: 0 duplicati fra tutti i .tres del progetto, 0 avvisi Duplicate UID a scansione ripetuta, sonda del roster di nuovo a 17 skin, 0 problemi; il diff è di una riga per file, la sola intestazione. 📌 La causa è rimossa in tools/monta_skin_roster.py, che ora toglie la chiave uid dal clone: i .tres base di f1 vivono da sempre senza — è la forma già in uso nel repo, e Godot fa da sé. Nuovo tools/autotest/probe_su863_roster.sh, perché la sonda del roster era l'unica delle quattro senza lanciatore.

Ivan sceglie giro per giro, e le varianti seguono la base scelta2026-09-07

Guardate le dodici basi del giro 2, Ivan ha deciso skin per skin: «breaker e clown li usiamo del giro 1, breather giro 1, juggler giro 2, magician giro 1, mime giro 1, oneman giro 2, pickpocket giro 2, punk giro 1, rapper giro 2». Sei skin tornano al primo giro, quattro personaggi restano al secondo — e siccome tre di loro hanno acquistato la versione femminile, le skin di giro 2 sono sette. La decisione è scritta sugli otto ticket il giorno stesso, perché ribalta il KO precedente su breaker, clown, sputafuoco e mago: quelle quattro restano col viso del barbone, e il clown con l'outfit rattoppato.

  • [asset] SU-856, SU-858, SU-859, SU-862 — 35 varianti rigenerate sulle basi nuove: sette skin complete. Gatto in braccio, sbornia, colpo di calore, posa del colpo e striscia del busking per juggler_m/_f, oneman_m/_f, pickpocket, rapper_m/_f. 📌 I 35 prompt non sono stati riscritti: le varianti del giro 1 non descrivevano il costume da capo — dicevano «identico all'immagine allegata» e allegavano il foglio base della skin — quindi TMP/sprint/scrivi_prompt_varianti_g2.py le deriva cambiando tre cose sole: il foglio allegato, la parentesi che riassume il personaggio e il path di uscita. Il taglio riusa i due utensili già collaudati del giro 1, che sono generici nei path (TMP/su_skin_juggler/su858_build_strip_e_vhit.py per il taglio BOX con alfa binaria, TMP/su_skin_pickpocket/su862_pulisci_frangia_magenta.py per la frangia). Misurato su tutte e 35: 0 pixel magenta residui, alfa solo 0/255, 1 solo componente per cella su tutti i fogli 5×5, altezza del bbox entro 2 px rispetto alla base della propria skin — che è il confronto giusto, perché una variante deve stare in piedi come il personaggio da cui deriva, non come il barbone. Una scheda per skin, dentro la cartella della skin: per esempio TMP/su_skin_oneman/CONTATTO_VAR_oneman_m.png. ⚠️ Da guardare prima di approvare: il busking del borseggiatore non chiude il ciclo (all'ultimo fotogramma la coppola è a terra, al primo è di nuovo in testa: in loop farà uno scatto), e sui due giocolieri il gilet cambia tinta fra una variante e l'altra — a rombi viola nella base, giallo oro in due celle del gatto, grigio-blu nella sbornia.
  • [nota] La palette «teneva» solo perché il costume era monocromo. Il gilet dei giocolieri che balla fra le varianti sembrava una regressione del giro 2; il confronto montato coi fogli del giro 1 dice il contrario: al primo giro il giocoliere era interamente marrone-beige, senza un gilet distinguibile, ed è esattamente ciò che Ivan aveva bocciato («l'outfit facciamolo di un altro colore, per differenziarlo dal barbone originale»). La variazione di tinta è il prezzo di avere un costume colorato, ed è un difetto minore di quello che sostituisce: non è stato speso un giro di rigenerazione, la decisione resta a Ivan sulle schede.
  • [nota] ⚠️ Trappola: i nomi dei file di lavorazione non erano quelli che il gioco carica. Il contratto di una skin sta scritto una volta sola in files/homeless_city/scripts/autoload/Skins.gd:36, e vuole player_skin_<id>_hit.png (32×32) e player_skin_<id>_busk.png (striscia N×32); nelle cartelle di lavoro del giro 1 convivevano invece _hit.png, _vhit.png e _hit_sheet.png con contenuti diversi — il _hit_sheet è un 160×160 di lavorazione — e i nomi non erano uniformi da una skin all'altra. Rinominando in blocco, sei file buoni sono stati sovrascritti dai grossi omonimi. Riparati ritagliandoli di nuovo dai raw con la stessa pipeline, che è anche il modo per renderli uniformi: 90 file su 90 presenti e conformi per tutte e quindici le skin. 📌 La lezione: prima di rinominare in blocco, misurare i due omonimi — «esistono entrambi» non vuol dire «sono lo stesso file».
  • [nota] ⚠️ Trappola: «rapper» è insieme il nome italiano del personaggio e il nome della sua cartella. Nei prompt derivati, la parola con cui il giro 1 chiamava la skin va neutralizzata, perché adesso una cartella ospita due personaggi (maschio e femmina). La sostituzione alla cieca ha colpito anche i path, e dieci generazioni sono finite in una cartella inventata TMP/su_skin_personaggio/ [sic], dove per giunta maschio e femmina si sono sovrascritti a vicenda sugli stessi cinque nomi. Le altre skin si erano salvate solo per fortuna linguistica: giocoliere/juggler, uomo-orchestra/oneman, borseggiatore/pickpocket non collidono. Ora la sostituzione si applica riga per riga, saltando quelle che contengono un path.
  • [nota] Il criterio «un solo pezzo per cella» non vale sul colpo e sul busking. È la misura che al giro precedente aveva scoperto i costumi viola mangiati dalla pulizia del magenta, ma applicata alle due varianti sbagliate dà falsi allarmi: nel colpo le stelline attorno alla testa e nel busking i birilli in aria sono staccati dal corpo di proposito. Ristretta ai soli fogli 5×5.

Le skin cambiano faccia: via le toppe e i cloni del barbone2026-09-07

Ivan ha bocciato in chat le nove skin del giro precedente, skin per skin: «l'outfit ricorda troppo quello del barbone originale», «niente toppe», «viso diverso e capelli diversi», e per l'uomo-orchestra «rifacciamolo da zero». Mimo (SU-853) e punk (SU-855) restano approvati e non sono stati toccati.

  • [asset] SU-854, SU-856…SU-862 — dodici basi rigenerate: costumi e visi staccati dal barbone. ⚠️ La causa del KO stava in due frasi dei prompt del 1º giro, uguali per tutti: «stessa identica persona del barbone di riferimento — stessa palette di base (pelle/tonalità)» e «il resto dell'abbigliamento resta coerente col tono senzatetto: strati consumati, roba rimediata, pantaloni rattoppati, scarpe rotte». Erano nate per tenere le skin intercambiabili, e hanno finito per clonare undici volte la stessa persona. Nel template nuovo del riferimento si copiano soltanto stile pixel art, spessore del contorno, corporatura, altezza da righello, scala e linea di base — mentre viso, incarnato, capigliatura e vestiario sono dichiarati originali, con una riga esplicita: «niente toppe, niente rattoppi, niente stoffa sgualcita, niente scarpe rotte». 📌 I dodici prompt non sono stati riscritti a mano: TMP/sprint/scrivi_prompt_giro2.py li genera da un template unico più una tabella di dodici righe (viso, outfit, tratti distintivi), così la frase che aveva causato il KO sparisce in un punto solo. Tre personaggi acquistano la versione femminilejuggler_m/_f, oneman_m/_f, rapper_m/_f, come già clown e punk — e restano dentro il loro ticket invece di aprirne di nuovi. Misurato sui dodici fogli 160×160: 60 righe su 60 con le 5 isole attese, 0 pixel magenta residui, alfa solo 0/255, 1 solo componente per cella su tutte e 300 le celle. ⚠️ Il criterio «bbox entro 2 px» è stato riformulato sull'altezza, che è a +0 su tutte e 300 le celle: la larghezza ora sfora di 3-8 px ed è attesa, perché i costumi non sono più gli stessi stracci (mago col mantello +6, breaker in tuta −4, donna-orchestra −7). Il vecchio criterio passava proprio perché erano tutti vestiti uguale. Riepilogo per l'occhio di Ivan in TMP/sprint/CONTATTO_G2_TUTTI.png, uno per skin nella cartella della skin, per esempio TMP/su_skin_magician/contatto_g2_magician.png. NON provate: le 60 varianti (gatto in braccio, sbornia, colpo di calore, colpo, striscia del busking), che partono solo dopo l'approvazione delle basi.
  • [nota] Trappola nuova, che vale per ogni sprite futuro: un costume viola o rosa sparisce col fondo. Gli sprite si generano su magenta #FF00FF e il ritaglio toglie i pixel con r > g+35 and b > g+35. Un capo viola, rosa o fucsia soddisfa quel criterio e viene cancellato insieme allo sfondo, senza errori e senza magenta residuo: alla rapper donna con la felpa viola è sparito tutto il busto — restavano testa e pantaloni come due macchie staccate, 25 celle su 25 — e la clown donna con i pois rosa era bucherellata in 23 celle su 25. Si riconosce dal conteggio dei componenti staccati per cella, mai dal magenta residuo, che è zero proprio perché il colore è stato tolto. Rigenerate entrambe con colori sicuri (pois rossi e gonnellino verde; felpa verde acqua) e divieto scritto nel template dei prompt.
  • [nota] Ai giocolieri erano spariti i birilli, e il rimedio è stato dettarne la geometria. Al 1º giro del template nuovo i tre birilli erano diventati due oggettini illeggibili alla cintura — proprio la cosa che a Ivan piaceva. Ridirli «colorati» non serviva: la frase che ha funzionato è geometrica — «alti un TERZO del busto, il collo sporge sopra la cintura, la pancia arriva a metà coscia, corpi a fasce contrastanti» — ed è la stessa lezione già pagata sul pinguino di SU-801, dove «nella direzione della sua riga» non bastava e ha funzionato «la testa nella metà destra della cella». Ora sono tre e leggibili, ma sono usciti giallo/verde/viola invece del blu/arancione/rosso chiesto: non è stato speso un terzo giro per la sfumatura.

Ripresa dopo il congelamento: i camioncini all'80% e i menu senza righe di aiuto2026-09-07

Ripartenza della sessione congelata alle 19:30 per soglia di contesto (250K), non per la finestra d'uso. I due lotti già costruiti e non committati sono stati chiusi con le prove che mancavano; il resto del giro è andato su Codex.

  • [fix] SU-848 — i due camioncini scendono all'80% e l'ombra li segue. Il fattore 0,8 è applicato in un punto solo, sui frame di hot dog e gelati (tela 120×84 → 96×68, riduzione NEAREST come disegna il gioco), prima di posizione, animazione e ombra: così _van_pos_compensato ragiona già sulla misura ridotta e l'ombra nasce dallo stesso frame del visuale, senza un secondo moltiplicatore da tenere allineato. van_z, la quota delle ruote, il lotto, il prompt e il raggio dell'interagibile restano quelli di prima. Misurato dal provino headless: sagome a 0,8023 e 0,8000 del valore precedente (criterio 0,80 ± 0,02), impronta dell'ombra a mezzogiorno 32,54% della bounding box contro il 31,79% di riferimento di SU-796, versi SE alle 08 e NE alle 15 e 17 come chiede il ticket. Il contatto che deve guardare Ivan — i due camioncini prima/dopo alle 08, 15 e 17, stesso seme 796001 e stessa inquadratura — è in TMP/su848_camioncini/contatto_prima_dopo.png. ⚠️ Gli scatti «prima» sono stati rifatti da un worktree sul commit di partenza b991506, perché i primi erano stati presi a builder già in scrittura ed erano di fatto un «dopo». Resta NON PROVATA la resa in partita su device. File: files/homeless_city/scripts/world/WorldGenerator.gd, files/homeless_city/scripts/tools/shot_su796_camioncini.gd.
  • [fix] SU-850 — via la riga «TOCCA UNA VOCE PER SELEZIONARE» e le spiegazioni sotto le voci delle Opzioni. Sparisce tutta la riga di aiuto, in ogni schermata e per ogni input: tenere la sola variante tastiera avrebbe lasciato il desktop diverso dal telefono. _hint_lbl non viene più creata né aggiornata e MENU_HINT_* non è più letta a runtime (le chiavi restano nei CSV, che non costano nulla); _info_lbl sparisce da tutte le pagine delle Opzioni — gioco, grafica, audio, controlli, note e bug, lingua — nei due contesti, menu e partita. Lo spazio liberato resta vuoto di proposito: rimpaginare è un'altra decisione, e il criterio era che la lista non si muovesse. Verificato: sugli scatti a 1024×768 e 844×390 le voci stanno alla stessa altezza di prima (CONTROLLI, DIMENSIONE, D-PAD, COMANDI tutte invariate); provino rilanciato con 0 occorrenze di «Node not found», SCRIPT ERROR o accessi a null; audit emoji 0 pittogrammi scoperti; verifica_i18n.py fermo a 2 punti, entrambi in HUD.gd, fuori dal lotto. Restano intatti il riquadro della scelta modalità, le conferme MENU_OPT_HINT_ON/OFF (che sono notifiche, non spiegazioni) e il pannello F1. Scatti prima/dopo in TMP/su850_menu/. File: files/homeless_city/scripts/ui/MainMenu.gd, files/homeless_city/scripts/ui/OptionsPanel.gd, nuovo provino files/homeless_city/scripts/tools/shot_su850_menu.gd.
  • [asset] SU-853 — il gatto in braccio del mimo diventa rosso come negli altri personaggi. L'unico rilievo di Ivan sul mimo («va bene, ma il gatto in braccio rosso come per gli altri pg») si è lavorato rimappando la palette con PIL, mai rigenerando: il ticket lo impone per i KO su un dettaglio, e rigenerare avrebbe rimesso in gioco un costume già approvato. La pelliccia passa da grigia (74,70,61 / 132,130,122 / 187,184,175) all'arancio-rosso (131,86,35 / 194,125,48 / 237,176,101), che è la media misurata dei due gatti già approvati — quello del barbone base e quello di f1 — con le tre tonalità luce/base/ombra conservate. Misurato: 6.736 pixel cambiati in 15 celle su 25 (righe S, E e SW; N e NE sono di spalle e il gatto non c'è), 0 pixel toccati fuori dalla maschera del gatto, 0 magenta introdotto, bbox opaco invariato su tutte e 25 le celle. ⚠️ Il «0 fuori maschera» non prova da solo che la maschera fosse il gatto — è la trappola di SU-832, dove una maschera aveva preso l'aletta delle tasche invece delle mani: per questo la verifica è passata da un ingrandimento cella per cella (TMP/su_skin_mime/_zoom_gatto.png), dove si vede il gatto arancione a strisce in braccio e il resto del disegno identico. Nessun file di gioco toccato: i PNG restano in TMP/su_skin_mime/, il «Fatto» lo mette Ivan.
  • [fix] SU-814 — il riccone gira come un NPC e carica solo quando lo vedi arrivare (terzo giro). Il KO diceva: «quando spawna deve muoversi in zona come un npc, e una volta che è vicino a te, già in telecamera, deve fermarsi, caricare». Il giro precedente aveva risposto con un ritardo fisso di 4 s, che è un cronometro cieco e non una situazione: via quello, l'ingaggio ora è geometrico — parte solo se il barbone è entro i 260 px con linea libera e entrambi stanno dentro il rettangolo inquadrato. ⚠️ Il primo tentativo di questo giro aveva il rettangolo sbagliato e sarebbe rientrato KO: il builder aveva scelto 844×390 unità mondo, mentre l'area di mondo davvero visibile con lo zoom di default 2,5 è 546×307 su desktop 16:9 e 666×307 su telefono — cioè un rettangolo più grande del 96% in area, con cui il riccone poteva ancora partire da fuori schermo. Corretto a 400×260, che sta dentro entrambe col margine. 📌 Il rettangolo resta una costante identica su tutti i peer e non legge la Camera2D locale: lo zoom è regolabile dal giocatore fra 1,2 e 4,0, quindi leggere il viewport vero farebbe divergere la simulazione fra due peer. Misurato su 5 semi: all'avvio della carica riccone e barbone sono dentro il rettangolo 5 volte su 5, 0 cariche partite fuori, distanza all'ingaggio 128,8-132,5 px, e 90-111 px di pattuglia percorsi prima di puntare (la soglia minima è passata da 1 px a 90 px, un secondo di cammino). Restano verdi arresto 1,017 s, carica 225,0 px/s, scarto laterale di 60 px → 0 vite, nuvola 0,600 s, attese 67,1 / 49,5 / 60,6 s, probe_su540_invarianza.gd. Restano NON PROVATI il multiplayer a due peer, il frame-time con un riccone a schermo e la linea di vista contro un isolato vero (la sonda usa uno stub). File: files/homeless_city/scripts/world/Richman.gd, files/homeless_city/scripts/tools/probe_su814_patrol_delay.gd, files/homeless_city/scripts/tools/probe_su814_riccone.gd.
  • [tool] Un provino delle 8 direzioni che vale per qualunque skin, non solo per il mimo. shot_su_skin_provino.gd prende l'id della skin come argomento, cerca i fogli di gioco 160×160 nella sua cartella di TMP/ e — se trova solo il raw 1254×1254 — se li ricava da sé (5×5 celle, riduzione BOX, alfa binaria dal magenta), poi scatta le otto direzioni camminate, la striscia del busking e i tre stati forzati, montando tre contatti. Serve ai nove ticket sprite: senza, ogni skin avrebbe voluto il suo provino copiato a mano. ⚠️ Due difetti trovati provandolo davvero (il primo giro girava senza morire e produceva immagini inservibili, che è il modo peggiore di sbagliare): costruiva lo SpriteFrames dal raw col magenta invece che dal foglio tagliato, e il personaggio usciva come un quadrato fucsia; e il montaggio dei contatti moriva su blit_rect perché gli scatti del viewport escono in RGB8 mentre la tela è RGBA8 — ora ogni miniatura viene convertita prima del blit. File: files/homeless_city/scripts/tools/shot_su_skin_provino.gd.
  • [asset] SU-854…SU-862 — generate le nove skin rimaste: undici personaggi, 66 fogli, tutti misurati. Il mimo di SU-853 era il capostipite e ha dettato la ricetta agli altri; questo giro l'ha applicata a clown e clown (SU-854), punk e punk (SU-855), uomo-orchestra (SU-856), sputafuoco (SU-857), giocoliere (SU-858), rapper (SU-859), ballerino di breakdance (SU-860), mago (SU-861) e borseggiatore (SU-862). Per ciascuno: quattro fogli 5×5 (base, gatto in braccio, sbornia, colpo di calore), il frame del colpo e la striscia del numero — 66 immagini in tutto, generate solo con Codex come vuole la regola 8, partendo dai prompt del mimo con il solo blocco del costume riscritto. 📌 La pipeline è stata costruita in tre tempi invece che a mano skin per skin: un lotto ha derivato i 66 prompt e gli 11 script di lancio dai sei del mimo; le generazioni sono partite in parallelo, prima gli undici fogli base — guardati uno per uno prima di lasciar partire le 55 varianti, per non sprecarne cinque su un costume sbagliato; poi un lotto di rifinitura per skin ha tagliato, pulito, misurato e montato i contatti. ⚠️ La lezione del KO del mimo è entrata nei prompt: «questi sono gli UNICI tratti distintivi, il copricapo indicato è obbligatorio ed esclusivo» — il mimo era stato bocciato per un cappello a tesa larga al posto del basco e una tracolla inventata. Misure comuni, per ognuno dei fogli: bbox contro il barbone base entro 2 px su tutte e 25 le celle, 5 isole per riga con l'import vero, zero pixel magenta residui, alfa solo 0/255, zero celle con pezzi staccati, riga E col viso a destra verificata sul foglio etichettato e non a occhio, bottiglia della sbornia in tutte le celle, gatto arancione-rosso come negli altri personaggi (la decisione di Ivan sul mimo, propagata a tutti). ⚠️ Un criterio non è soddisfatto e sta scritto sul ticket: sulla sbornia dei due punk il bbox sfora i 2 px in 12 celle su 25 (punk) e 9 su 25 (punk femmina), perché chitarra e bottiglia allargano il profilo; il giocoliere ne ha 3 su 25. Ogni skin è stata poi vista camminare in gioco nelle otto direzioni col provino vero in Main.tscn. I PNG restano tutti in TMP/su_skin_<id>/: nessun file di gioco toccato, il montaggio è di SU-863 e il «Fatto» lo mette Ivan skin per skin.
  • [fix] SU-848 (2° giro) — i camioncini restano all'80% ma con tutti i loro pixel. Ivan ha bocciato il primo giro in giornata: «la dimensione ora va bene ma ridurli così ha portato ad avere meno definizione, rendendoli eccessivamente pixellosi, sistemare con una risoluzione consona come i palazzi adiacenti». ⚠️ Il difetto nasceva da una frase sbagliata del ticket, che diceva «scala del nodo, oppure frame ridotti con NEAREST: a video è lo stesso». Non è lo stesso: ridurre la texture da 120×84 a 96×68 butta via il 36% dei pixel per sempre, mentre scalare il nodo li tiene tutti e li disegna più piccoli. Ora i due AnimatedBuilding ricevono i frame originali del BuildingDatabase e il nodo visuale porta scale = (0.8, 0.8); l'ombra nasce dallo stesso frame originale con la stessa scala, quindi c'è ancora un solo fattore in tutto il sistema. Misurato: sagoma a schermo 86,0 → 68,8 px (hot dog) e 90,0 → 72,0 (gelati), rapporto 0,8000 esatto per entrambi; 10.080 texel sorgente per frame contro i 6.528 del giro precedente, con la texture identica a quella del database (nessun ricampionamento); impronta dell'ombra a mezzogiorno 31,79% della bounding box, cioè il valore di riferimento di SU-796 al centesimo; versi SE/NE/NE alle 08/15/17; quota delle ruote invariata su tutti e 8 i semi (scarto 0,00 px); prompt e trigger identici (hot dog $20, gelato $10, rettangolo 108×84). Confronto a tre — originale, primo tentativo, versione buona — in TMP/su848_camioncini/CONFRONTO_tre_giri.png: le scritte «HOT DOG» e «ICE CREAM» tornano leggibili. 📌 Il builder ha misurato l'allineamento del nodo scalato (fase x 0,00 px, y 0,40 px) senza toccare il filtro NEAREST, perché cambiarlo su un solo oggetto è una decisione di Ivan. File: files/homeless_city/scripts/world/WorldGenerator.gd, files/homeless_city/scripts/tools/probe_su761_camioncini.gd, files/homeless_city/scripts/tools/shot_su796_camioncini.gd.

Sprint serale: la zuffa che non fa più muro, il riccone che si fa vedere, e la skin che viaggia in rete2026-09-07

Giro da CLI su due piani: cinque lotti a Codex sol, quattro builder su Claude, un collaudatore per i provini. Il tasso di rientro del giro precedente, misurato prima di aprire i lotti: 2 su 4 — SU-814 e SU-832 tornate in «Da fare», SU-841 e SU-846 no.

  • [fix] SU-849 — la nuvola della zuffa col gatto non fa più da muro, e non si sposta a spallate. Il difetto stava tutto in una cosa che restava accesa: hit_by_cat() nascondeva lo sprite e accendeva la nuvola per 2,5 s, ma il corpo continuava il suo _physics_process — separazione dai giocatori, panico, rotta e move_and_slide() — quindi la nuvoletta camminava, scartava il barbone e gli faceva da ostacolo. Ora durante _catfight_timer la velocità è zero, i rami di movimento sono saltati e la CollisionShape2D è disabilitata con set_deferred, riabilitata a fine nuvola prima della ricollocazione. Misurato: spostamento della nuvola dopo 2 secondi di spinta 0,000 px su civile e su poliziotto, barbone che esce dall'altra parte, shape.disabled di nuovo false alla fine, sonda del gatto di SU-822 verde con 14 controlli. 📌 Il poliziotto è stato aggiunto al perimetro dal builder, e aveva ragione: PoliceOfficer sovrascrive _physics_process e non passa dal ramo dei civili, quindi senza quelle tre chiamate la metà delle zuffe sarebbe rimasta com'era — e il ticket chiede esplicitamente «vale per civili e poliziotti». ⚠️ Un difetto residuo fermato al cancello, in multiplayer: sul peer remoto la posizione della replica avanza per dead-reckoning con l'ultima velocità ricevuta, quindi la nuvoletta sarebbe scivolata di una decina di pixel finché non arrivava l'aggiornamento successivo dall'host — proprio mentre deve stare ferma. Azzerata la velocità replicata dentro show_puppet_cat_hit(). Resta NON PROVATO il comportamento con due peer veri: la sonda misura la cache locale, non una sessione EOS. File: files/homeless_city/scripts/npc/NPC.gd, files/homeless_city/scripts/npc/PoliceOfficer.gd, nuova sonda files/homeless_city/scripts/tools/probe_su849_catfight_collision.gd.
  • [asset] SU-853 — generati gli sprite del mimo, primo dei dieci personaggi-skin (in attesa che Ivan approvi). Quattro fogli 5×5 (base, gatto in braccio, sbornia, colpo di calore), il frame del colpo e la striscia del numero, tutti in TMP/su_skin_mime/: nessun file di gioco toccato, perché il «Fatto» qui lo mette solo Ivan. Misure sui quattro fogli: bbox contro il barbone base entro i 2 px su tutte e 25 le celle (0 violazioni per foglio), 5 isole per riga riconosciute dall'import vero, riga E col viso a destra verificata sul foglio etichettato e non a occhio, zero magenta residuo dopo la pulizia, bottiglia della sbornia presente in tutte e 25 le celle. 📌 Cinque scoperte che valgono per i nove ticket sprite successivi, ed è il motivo per cui il mimo è stato lavorato da solo: (1) l'ordine delle righe nel raw è S, N, E, SW, NE, non l'ordine di destinazione; (2) il frame del colpo è una posa grande sull'intero canvas, non una griglia; (3) la striscia del busking è una riga di pose frontali, non 5×5; (4) il taglio standard lascia sempre 1-3 px di frangia magenta per cella — ce l'hanno anche gli asset già approvati, 12 px sul foglio del barbone — quindi «zero magenta» richiede sempre un passo di pulizia dopo il taglio, non è un difetto del generatore; (5) il criterio «≤1 px fuori dal prop» sulla sbornia non lo passa nemmeno l'asset in gioco oggi (21 celle su 25, scarti fino a 7 px), quindi il 19 su 25 del mimo è nella norma e non una regressione. ⚠️ Da guardare prima di approvare: a 32 px il gatto in braccio nella riga frontale si confonde un po' con le righe della maglia. File: TMP/su_skin_mime/, nuovo provino files/homeless_city/scripts/tools/shot_su853_mime_provino.gd.
  • [feat] SU-852 — il tasto del busking anima il numero della skin scelta, e la skin viaggia in multiplayer. Due buchi chiusi insieme. Il primo: _music_sprite caricava sempre homelessmusic_sheet.png, quindi anche la barbona, quando suonava, diventava il barbone maschio con la trombetta. Ora ogni voce di SKINS può avere una busk con la sua striscia e i suoi hframes, e senza striscia si vede l'animazione beg dei propri fogli — mai più il foglio del maschio: è la cura per f1 finché non ha la sua. Il secondo: la skin non arrivava agli altri giocatori. Viaggia ora nel registro della lobby come il nome, con una RPC nuova e un _pending_skins sul modello degli sblocchi; nessun byte in più nei pacchetti di gioco. L'host non risolve l'id ricevuto, lo taglia a 16 caratteri: così un peer con una build più nuova può avere una skin che l'host non conosce ma che gli altri sanno disegnare, e il ripiego su m1 lo fa ogni peer a casa sua. ⚠️ Il vincolo che rompe le partite fra versioni: la RPC nuova è l'undicesima e ultima, il diff lo mostra come 10a11, quindi nessuna delle dieci esistenti si è spostata di una posizione. Misurato: con m1 busking identico a oggi (stesso foglio, 4 frame); con f1 la barbona che fa beg; striscia di prova da 6 frame → hframes 6 e frame dentro 0..5; id ignoto → m1 senza errori; due peer ENet con il puppet che ha davvero i fogli di f1 (letti, non guardati); registro con 4 giocatori a 936 byte contro il limite EOS di 1170, cioè +72 byte per il campo nuovo. 📌 Il contratto di una skin è ora scritto in testa a Skins.gd: lo citeranno i dieci ticket sprite. Restano NON PROVATI i due scatti del busking e una partita incrociata con una build precedente, che vuole un secondo eseguibile. File: files/homeless_city/scripts/autoload/Skins.gd, files/homeless_city/scripts/player/Player.gd, files/homeless_city/scripts/autoload/NetworkManager.gd, files/homeless_city/scripts/world/World.gd, tre sonde nuove.
  • [i18n] SU-851 — cinese e russo senza i modi di dire italiani: inventario, pivot in italiano piatto e ritraduzione. Fino a oggi tutte le lingue nascevano dall'italiano com'è, idiomi compresi. Ora c'è un inventario di 137 chiavi in tools/i18n/idiomi.md (per CSV: menu 27, npc 32, meta 23, mondo 22, hud 16, gioco 14, extra 3), un pivot in tools/i18n/it_piatto/ con la versione piana di ognuna, e la ritraduzione di 137 chiavi su 137 in russo e altrettante in cinese fatta a partire dal pivot, non dall'idioma. Dove l'idioma è la battuta — titoli, nomi di carte, giochi di parole: 110 casi su 137 — il traduttore ha scelto un equivalente vivo nella lingua d'arrivo invece della frase piatta, così il tono assurdo resta senza importare modi di dire italiani. Misurato: 1.208 righe non segnate byte-identiche, 0 modifiche alle colonne it/en/fr/es/de/pt, segnaposto e caratteri del font icone identici alla riga italiana su 137/137, controprova a rovescio (ru→it e zh→it) che su 137/137 non riproduce più l'idioma italiano alla lettera. merge_i18n_columns.py ha imparato a sostituire una cella per chiave e colonna lasciando intatto il resto del file, che è il motivo per cui il diff è solo le celle cambiate. Una chiave resta dubbia e vuole un madrelingua. Restano NON PROVATI gli scatti in russo e cinese e l'overflow su dispositivo. File: i sette CSV in files/homeless_city/assets/translations/ (sole colonne ru e zh), tools/merge_i18n_columns.py, tools/i18n/.
  • [fix] SU-832 (3° giro, KO di Ivan coi segni rossi sul contatto) — le mani di fronte e la fronte di profilo prendono finalmente la carnagione scura. Ivan aveva disegnato lui tre cerchi rossi sul contatto e l'aveva risalvato su disco, non su Jira: due sulle mani nella riga frontale e uno sulla fronte in quella di profilo, tutti sulla colonna della variante scura nuova. ⚠️ La causa non era quella che sembrava, e conteneva una regressione mai notata: le finestre delle mani non stavano prendendo le mani, ma l'aletta delle tasche del cappotto — 144 px di tasca scuriti per errore, mentre la mano vera, 9-10 px più in basso, restava chiara. La finestra della fronte semplicemente non copriva la fascia fra capelli e sopracciglio. Corrette entrambe con maschere per posizione più strette, verificate su tutti e cinque i fotogrammi di ciascuna riga; e lo scuro di riferimento ora si ricalcola con apply_dark_skin invece di rileggere il file del giro precedente, che in quelle zone era già «chiaro» e faceva da specchio al proprio errore. Misurato: mani +1.042 px scuriti, tasca del cappotto −970 px riportati esatti al beige, fronte di profilo +755 px; righe non richieste 0 differenze, magenta introdotto 0, bbox della sheet 0 celle su 25 fuori tolleranza. Il contatto annotato da Ivan non è stato toccato: il nuovo è TMP/su832_cappotto/contatto_prima_dopo_g2.png. File: files/homeless_city/assets/sprites/npc/bodies/arch_business_male_v02_dark_sheet.png, sprites_raw/PEOPLE/arch_business_v2_dark.png, tools/su832_cappotto_dark.py.
  • [fix] SU-847 — in metropolitana le monete raccolte saltano sopra la testa, e si vedono davanti al vagone. In banchina le monete sparivano al contatto col solo suono: _raccogli_monete() faceva queue_free(), add_money() e basta, mentre le lattine dello stesso livello saltavano già con l'aiutante _salta_sopra_la_testa. Ora ogni tick con almeno una presa fa saltare l'icona della moneta con la scritta «+$n», stesso tetto di 5 effetti in volo. Il secondo pezzo era lo z: FX_SALTO_Z valeva 10, cioè sotto i treni (300), sotto il barbone e sotto la folla, quindi qualunque salto finiva dietro, lattine comprese; portato a 301 con z assoluto, così il padre non può ripescarlo sotto. La scritta è un parametro opzionale dell'aiutante, quindi le lattine restano identiche a prima. Misurato: z globale dell'icona da 10 a 301 contro i 300 del treno; conto invariato sullo stesso seme (200/200 e 118/59 prima e dopo); una sola chiamata al suono per tick. ⚠️ Una sonda rossa che NON è una regressione: probe_su491_forbice fallisce tre controlli («la folla semina esattamente 200 monete», osservato 0) — ma li fallisce identici sul commit di partenza, verificato lanciandola in una copia di lavoro separata su b991506. È un difetto preesistente, non di questo lotto, e va aperto a parte. Resta NON MISURATO lo scatto in cui l'icona copre il vagone. File: files/homeless_city/scripts/world/BonusRewards.gd, nuova sonda files/homeless_city/scripts/tools/probe_su847.gd.
  • [fix] SU-814 (2° giro, KO di Ivan «compare pochissimo da quando spawna») — il riccone adesso si fa vedere prima di caricare. La causa non era la velocità né lo sprite: in pattuglia non esisteva alcuna soglia minima, quindi se il barbone era già entro i 260 px del raggio di vista al momento della comparsa, la rincorsa partiva al primo _physics_process utile — zero pixel di giro visibile, e per il giocatore il riccone «caricava senza manco iniziare a video». Aggiunta MIN_PATROL_SEC = 4.0: prima di poter puntare qualcuno il riccone gira come un NPC qualunque, e a 90 px/s sono 360 px, più del raggio con cui vede. È una costante fissa e non un tiro di _rng_riccone, quindi resta identica su ogni peer. Misurato su 5 semi: fra comparsa e inizio della carica da 1,0 s e 0,0 px percorsi a 5,0 s e 59-78 px; col barbone fermo a tiro fin dal primo frame non c'è più nessuna carica anticipata. Il resto della macchina a stati è intatto: arresto 1,017 s, carica 225 px/s, scarto laterale di 60 px → 0 colpi, nuvola 0,600 s, linea di vista bloccata → 0 rincorse in 10 s, attese fra un riccone e l'altro 67,1 / 49,5 / 60,6 s. ⚠️ Un difetto della sonda fermato al cancello: la soglia era stata ricopiata a mano nel test, con un commento che chiedeva di ricordarsi di allinearla; una sonda così resta verde sul numero vecchio proprio quando qualcuno cambia la costante. Ora la legge da MIN_PATROL_SEC col get_script_constant_map(). Restano NON PROVATI, come al giro scorso, il multiplayer a due peer e il frame-time con un riccone a schermo. File: files/homeless_city/scripts/world/Richman.gd, files/homeless_city/scripts/tools/probe_su814_riccone.gd, nuova files/homeless_city/scripts/tools/probe_su814_patrol_delay.gd.

Ventinove tester fuori dalla beta, e gli accessi revocati sui tre elenchi2026-09-07

Manutenzione della lista beta chiesta da Ivan in chat, in quattro riprese (Gasverde; Panato e Peyrachia; venticinque nomi in blocco; Alberto Lagna). Il foglio Tester passa da 79 a 50 persone e nasce il foglio Tester rimossi con le 29 schede complete, colonne originali e data di rimozione. Defedele, tolto in mattinata da un'altra sessione, resta fuori dall'archivio perché Ivan lo ha escluso.

  • Accessi revocati davvero, non solo sul foglio, perché un tester tolto dall'Excel continua a ricevere le build finché sta sugli store. TestFlight 27 → 20, utenti di prova della schermata di consenso Google 54 → 38, mailing list Alpha di Play 43 → 30. Restano 30 tester Android, sopra i 12 che Play richiede per la produzione.
  • testflight_tester.py ora sa anche togliere: --rimuovi mail [mail ...] cancella il beta tester (DELETE /v1/betaTesters/{id}, HTTP 204) invece della sola relazione col gruppo, che lo lascerebbe registrato sull'app. Nessuna email parte: la persona se ne accorge solo perché l'app sparisce dal suo TestFlight.
  • ⚠️ delete_rows() di openpyxl non sposta i collegamenti ipertestuali. Al primo tentativo 14 righe si sono ritrovate il «Link WhatsApp» della persona precedente e l'ultimo link è sparito (70 → 68). Si salvano i link in una mappa per nome, si azzerano tutti, si cancella la riga e si riattaccano seguendo il nome. La prova è il numero di telefono che deve comparire dentro l'URL wa.me della stessa riga.
  • ⚠️ Nelle console di Google l'esito di una rimozione non si legge a schermo. Nella schermata di consenso OAuth la riga resta visibile e il contatore fermo anche quando la rimozione è andata a buon fine: l'unica verifica è ricaricare la pagina. Due rimozioni date per fallite erano riuscite, e una data per riuscita non lo era.
  • ⚠️ Nella mailing list di Play le modifiche vivono solo dentro il dialogo. Se si chiude prima di «Salva modifiche» si perde tutto — è successo con otto rimozioni. Si lavora a gruppi di tre e si salva ogni volta. E il pulsante «Elimina mailing list» sta accanto a «Salva modifiche»: un click a coordinate fisse senza guardare la schermata ha aperto la richiesta di cancellare l'intero elenco, annullata in tempo.
  • 📌 Un indirizzo non era un account Google: hnprojects@gmail.com faceva comparire «Account non idonei non aggiunti» a ogni salvataggio della schermata di consenso. Quella persona non avrebbe comunque potuto entrare col login Google.
  • 📌 Scoperto di passaggio: nel gruppo TestFlight c'è un tester con l'app installata che nel foglio non compare affatto, Marco Durand. O è stato aggiunto fuori dal giro, o la sua riga è andata persa.

Il marchio STREET UNIVERSITY è depositato: domanda 302026000153505, classi 9 e 41 (SU-763)2026-09-04

Depositato all'UIBM il 04/09/2026, procedura Fast Track, marchio denominativo a nome di Ivan Bianco persona fisica. Pagati 183 € con PagoPA (135 di tasse + 48 di bollo): esito «Pagamento acquisito correttamente», ricevuta via PEC. Stato della pratica: Presentata.

  • Classe 9: software per giochi per computer (registrati, scaricabili), software applicativo per computer scaricabile, software applicativo scaricabile per ambienti virtuali. Classe 41: servizi di giochi forniti online da una rete informatica, servizi di intrattenimento forniti in ambienti virtuali — la 41 ristretta apposta per stare lontano da «educazione/formazione».
  • 📌 La rappresentazione è solo la scritta, nera su bianco 380×160, senza logo: un denominativo protegge la parola sotto qualsiasi grafica, e mettere il logo lo avrebbe trasformato di fatto in un figurativo — l'errore che ha lasciato il nome libero in UE (SU-607, §10).
  • ⚠️ Il difetto del portale che il 03/09 aveva cancellato la compilazione: il modulo di caricamento del JPEG ha action="" e, aperto fuori dalla sua pop-up, l'invio ricarica la pagina. Aggirato iniettando il file nell'input fileToUpload e lanciando change: nessun ricaricamento, file accettato e verificato a video dal server (380×160).
  • 📌 Altre trappole misurate: i numeri 1-8 dei passi non sono cliccabili (si torna indietro dalla tabella «Passi della procedura»); la spunta «Paga le Imposte di bollo» si azzera passando fra le schede; il modello F24 che il portale genera non va pagato se PagoPA è andato a buon fine.
  • 📅 Due scadenze: pubblicazione entro 7 giorni e poi 3 mesi di opposizioni (l'osservato speciale è la Fondazione Gruppo Abele, SU-607 §10); 04/03/2027 è l'ultimo giorno utile per depositare l'EUTM rivendicando la priorità di oggi.

Esito completo e lezioni operative in OPUS_BRIEFS/DEPOSITO_MARCHIO_UIBM.md.

La grazia sale a 2 s col lampeggio del barbone, e la metà server di SU-576 è deployata (SU-588/576, v0.41)2026-08-26

  • [feat] SU-588 (rilavorazione, deciso in chat da Ivan) — grazia a 2,0 s e LAMPEGGIO per tutta la finestra. Il barbone lampeggia via sprite.self_modulate — stesso canale, stesso ritmo (14 Hz) e stesso interruttore GRAFICA LEGGERA del lampeggio di posa SU-305, che dura 0,5 s: ora un contatore separato (_grace_blink_left) lo prolunga fino a fine grazia, così l'invulnerabilità si VEDE. Niente lampeggio per le cause fuori whitelist (un arresto non promette protezioni che non ha). Sonda estesa alla città vera: 10/10 OK (contabilità A-D come prima, più lampeggio in finestra, bianco stabile a finestra chiusa, arresto senza lampeggio esteso).
    • ⚠️ Trappola di misura nuova, pagata e annotata nella sonda: Color.to_html() clampa i canali sovraespostiHIT_REACT_FLASH (r=1.7) diventa ffffffff, identico al bianco, e il lampeggio sparisce dallo strumento pur essendoci a schermo. Primo giro della sonda KO per questo: si campiona il canale r grezzo.
  • [infra] SU-576 — la metà server è FATTA e collaudata, con gli URL invariati. Da Chrome: il guardrail blocca ancora la *lettura* del sorgente Monaco, ma non la scrittura né gli hash — quindi prima il confronto (SHA-256 del codice spogliato dei commenti, calcolato DENTRO la pagina: telemetria e registro deployati = copie in BETATESTING/, byte per byte), poi l'incollata delle versioni patchate e il redeploy «Nuova versione» sugli STESSI deployment (telemetria → Versione 3, registro → Versione 2; l'ID/URL non è cambiato, verificato a schermo e col doGet).
    • Telemetria: sottocartella ambiente dentro il giorno (AAAA-MM/AAAA-MM-GG/dev|stage|live/), senza campo → stage; i file vecchi restano dove sono. Collaudo end-to-end: 3 POST (dev, live, senza env) → i 3 file sul Drive locale ciascuno nella cartella giusta, poi puliti.
    • Registro nickname: _foglio(env) con migrazione automatica — la tab storica viene rinominata stage da sola alla prima chiamata (il passo a mano del brief §9 non serve più); dev e live nascono copiando l'intestazione. Collaudo: claim in dev risolto solo in dev, claim SENZA env finito in stage (le build 0.40 continuano a scrivere dove scrivono oggi), release puliti.
    • Le copie aggiornate dei due .gs stanno in BETATESTING/ (fuori git come tutta la cartella): sono di nuovo il sorgente fedele del deployato.

La prima analisi vera della telemetria (69 partite), e i quattro fix che ne escono (SU-587/588/589/590, v0.41)2026-08-26

  • [analisi] Letti tutti i file del 25-26/08 su Drive: 69, di cui 65 con run_start (54 run sp dei tester su stage 0.40, 4 tutorial, 7 fumo dev dal Mac, 4 code crash SU-558). Mediana di morte 4,0 min (p25 2,8 / p75 7,9, max 18,2), esiti: 20 stanchezza, 18 fame, 13 «nove vite», 2 ondata. Vite perse per causa: arresto 89, gattara 68, spazzino 33, rivale 30, tossico 22, giullare 18, grandine 5. Nessuno ha mai visto la retata (raid_phase=0 in 63 run chiuse). Carte: in testa stomaco_ferro/calamita (67%), in coda spirito_patata (6,6%), ombrello (8,4%), occhio_furti (10,5%), carisma (11,8%); scelta mediana in 1,9 s; golden mai scelte (0/680). FPS mediani per device: Honor 24, Redmi Note 9 Pro 30, A52s 35, Redmi Note 14 43, il resto 60-120.
  • [fix] SU-588 — Grazia di 1,2 s dopo un colpo ostile (GameState.lose_life(), l'unico collo di bottiglia dei colpi, SP e MP). La telemetria mostrava raffiche impossibili: 3 vite in 0,5 s, run da 9 vite bruciate in 18-47 s, quasi tutte «gattara» — più gattare inseguono insieme (1,8 s di cooldown A TESTA) e il giocatore non aveva nessuna finestra di invulnerabilità. Whitelist {gattara, tossico, spazzino, giullare, rivale, ronda}; la ronda multi-vita passa intera come UN colpo; esclusi arresto, grandine (ritmi propri) e la retata (RAID_LIFE_CAUSE, ineluttabile per progetto — e il suo raffreddamento sta già in RunManager). Provato con sonda nuova probe_su588_grazia (6/6 OK) e regressione probe_retata_vite.sh (TUTTO OK, compresa la controprova che sarebbe fallita filtrando la retata).
  • [fix] SU-587 — env anche DENTRO run_start, e dev sale a 0.41. L'ambiente viaggiava solo nell'involucro della POST (SU-576) e su Drive si perde: dev e stage si distinguevano solo a indizi (modello device, log dei crash). Ora ogni file si dichiara da sé; e col numero di versione diverso dallo store (0.40) anche i file vecchi restano attribuibili. Verificato su run bot fresca: env=dev, ver=0.41.
  • [fix] SU-589 — Telemetria a dieta. Il busking emetteva player_misdemeanor OGNI FRAME: 42.600 righe «busk» su 46.688 misdemeanor nei due giorni (91%). L'emissione non si tocca (il wanted ci si appoggia): RunRecorder ora accumula e scrive UNA riga {"action":"busk","n":K} al giro di stat (10 s), al primo misdemeanor diverso e a fine run. E RewardScale.LOG_SERIES passa a false: la coda crash del S23 (16 KB) conteneva SOLO quelle stampe — crash illeggibile. Verificato: run bot 60 s → 1 riga busk (n=24), zero righe grezze, zero [RewardScale] nel log.
  • [fix] SU-590 — La metro e il bonus ora si leggono nella scatola nera. La lettura ingenua dei dati diceva «metro rotta: giocatori con soldi premono e non parte niente, fermi 100 s». Falso: la corsa vera (percorso hold SU-486) non passava da _use() e non lasciava traccia — le 62 corse riuscite (notifica CAPOLINEA) erano invisibili; gli interact metro_stop «muti» erano ingressi nel bonus dall'arcobaleno della banca, e gli «stuck» da 52-105 s erano il barbone parcheggiato durante il bonus a città congelata. Ora: la partenza vera logga metro_stop (con dmoney=-1 che la distingue dal tornello rifiutato), la porta del bonus logga bonus_door, lo stuck si scarta col bonus attivo. Regressione: probe_collaudo_bancametro.sh ESITO OK.
  • [ticket] SU-591 (aperto, indagine) — il tester su CPH2207 (Adreno 650) non ha mai finito il tutorial: 2 run troncate e coda crash con QueuePresentKHR failed -1000000000 ripetuto. Tester perso finché non si trova la mitigazione.
  • 📌 Il lato server di SU-576 resta da fare insieme (10 min, browser: sezione 9 di OPUS_BRIEFS/SU-526_ambienti_online.md — «Nuova versione», MAI «Nuovo deployment»): finché non c'è, l'ambiente su Drive lo dichiara solo il file stesso.

Il tetto notturno è ~40, confermato due volte; resta il cancello di rilevanza sul LOD (SU-585, v0.40)2026-08-26

  • [fix] SU-585 — Cancello di RILEVANZA sull'ingaggio del LOD (NPC.gd, commit a9c2a0d): lo stato «ingaggiato» tiene il passo pieno solo se l'azione avviene entro 1,5× la soglia lontana dal barbone più vicino — contando anche i puppet remoti, quindi in multiplayer un inseguimento addosso a un giocatore remoto resta a frame pieno per costruzione. Di notte la gang teneva mezza città a pieno regime anche a mezza mappa da tutti.
  • [diag] Provato e rimosso il composito a mezzo refresh (idea di Ivan, implementata con la parità dei frame renderizzati così segue il device: 60→30, 120→60): A-B sul device = zero guadagno — il composito a metà risoluzione non era il collo. E la misura M14 dice che nemmeno la dieta muove la notte DA FERMO: la gang converge sul giocatore, quindi è vicina e il suo pieno regime è gioco, non spreco (il cancello morde in partita vera, sugli inseguitori attardati). Tetto onesto: notte ~40, giorno 50-55 — oltre si va solo toccando il look (aloni accesi dei lampioni/neon ≈ 1,5 ms di overdraw di arte voluta, gang a schermo). Numeri e metodo in TESTLOG; gli A-B fini da 5 s ballano ormai nel rumore termico dell'Honor (±3 fps fra sessioni).

Mattina: la prima cerimonia delle carte senza cratere; la notte oltre i 40 non passa da qui (SU-586/585, v0.40)2026-08-26

  • [fix] SU-586 — Micro-scatti: le risorse della cerimonia carte si scaldano al load, non al primo uso (LevelUpScreen.gd, HUD.gd). La telemetria di un tester (A52s) mostrava un cratere di frame da 399 ms esattamente su card_offered: le 29 icone hi-res delle carte (128×128, ~4 MB in VRAM totali) e gli SFX della cerimonia (mischiata compresa — il calo che Ivan sentiva) venivano caricati al momento. Ora un manifesto COMPILATO li scalda in _ready dietro il caricamento del livello (le cartelle res:// non si elencano a runtime: nell'export i file diventano remap e la lista mente); la scena della LevelUpScreen e MapOverlay.gd passano a preload. Verificato sull'Honor: prima cerimonia forzata a freddo a 54 fps, nessun cratere. Il bidone dorato rientra (apre la stessa cerimonia).
  • [diag] SU-585 — La notte oltre i ~40 NON passa dalle lime: attribuzione chiusa, niente codice. Provate e scartate due strade: (1) luci in coordinate MONDO con upload solo-su-cambiamento — guadagno misurato ≈ zero (39,4 contro 39,8: il collo non erano gli upload) e una regressione visiva su device → revert; (2) pista «canvas sovracampionato ×3,3» — falso allarme da strumento: get_texture().get_size() sulla radice riporta una dimensione fantasma (anche a oversampling spento), mentre la prova vera (composita a 1140 px combaciante pixel-perfetto su device) dice che l'Honor renderizza ai pixel veri. Il muro rimasto è la passata stessa del SubViewport (~3-4 ms anche a metà risoluzione: spegnere la sola vista rende +1,5 fps, il render offscreen continua). Per superare i 40 le opzioni sono di design, non di lima: composita a 30 Hz (rischio «nuoto» delle pozze in panoramica) o ripensare il look notturno — decisione di Ivan, annotata sul ticket.
  • ⚠️ Nota per il giro desktop/iOS futuro: nei provini desktop di oggi le pozze notturne escono sfalsate (ambiente del provino con finestra/DPI diversi dalla notte prima); su Android è tutto pixel-perfetto. Da rivisitare quando si lavorerà la resa desktop — annotato su SU-581.

Terzo giro: via la danger vignette (deciso da Ivan), e il pad touch cotto in un atlas (SU-583, v0.40)2026-08-26

  • [change] SU-583 — La vignetta di pericolo fame/sonno è RIMOSSA del tutto (HUD.gd, deciso da Ivan in chat: la nuvoletta comunica già il pericolo, la vignetta si vedeva pochissimo e costava una passata fullscreen a frame). Resta il lampeggio delle barre a stat ≤10%. Lo shader però NON muore: il suo unico altro utente era il pulse rosso del preavviso retata, che ora ne è il proprietario (RAID_VIGNETTE_SHADER, cache compilata una volta e riscaldata all'avvio — lezione SU-484: una pipeline nuova al preavviso della retata è uno scatto nel momento peggiore).
  • [fix] SU-583 — Gli ottagoni dei tasti e gli anelli dello stick cotti in UN atlas (VirtualControls.gd). Misurato a fette sull'Honor: il pad vettoriale valeva +6,4 fps / 31 draw call / ~750 primitive a frame, e il costo era tutto nelle FORME (le etichette: rumore). Ora al _build_ui le forme si disegnano una volta in un SubViewport, diventano Sprite2D che condividono l'atlas, e il disegno vettoriale resta come ripiego (headless o bake fallito → pad identico a prima). Controprova sul device: spegnere il pad ora vale ~+1 fps (era +6,4), primitive di base da 1186 a 595. Il pallino segue il dito e l'highlight dei tasti modulano le stesse referenze scambiate; il tocco non passa da qui per costruzione (le forme erano già pura resa, SU-316).
  • Base diurna sull'Honor dopo il giro: 53-55 fps tiepido (era ~51 pari condizioni). Bot desktop pulito, zero SCRIPT/SHADER ERROR nei logcat. Da provare a mano: il flash dei tasti alla pressione e il pulse del preavviso retata (meccanicamente preservati, non osservati stanotte).

Secondo giro serale: le carte a 26 fps erano la danger vignette, e la notte sale a 40 (SU-583/581, v0.40)2026-08-26

  • [fix] SU-583 — Le schermate delle carte da 26 a 59 fps: era la vignetta di pericolo dell'HUD (HUD.gd). La DangerOverlay (fame/energia basse) nasceva visible e non si spegneva MAI: un fullscreen con shader rasterizzato a ogni frame anche a intensità zero — cioè quasi sempre, perché a stat sane non disegna nulla. In gioco libero il vsync la assorbiva (−3 fps misurati), ma sul frame carico delle schermate-carta (mondo dietro + velo + pannelli) ribaltava il totale. Ora si accende solo coi FATTORI di pericolo sopra zero (gate sui fattori, non sui pulse: il seno tocca zero a ogni ciclo e sfarfallerebbe). Stessa classe di baco degli overlay meteo (voce 16) — segnalata da Ivan a intuito («può centrare l'HUD?»): sì.
  • [fix] SU-581 — La composita notturna a MEZZA risoluzione: notte da 31 a ~40 fps (World.gd). L'unica passata fullscreen rimasta di notte costava ancora ~13 ms a risoluzione nativa: ora disegna in un SubViewport a metà lato (un quarto dei pixel) e si stira a schermo in NEAREST con blend premoltiplicato — matematicamente la stessa composizione. TUTTA la geometria resta in px di schermo pieno (coord_scale nello shader): celle, pozze, grana e dithering identici per costruzione, l'unica differenza sono texel da 2×2 px veri. Provino notturno dal viewport: pozze, lanterna, neon e vignetta indistinguibili. A composita spenta si spegne anche il render del SubViewport (UPDATE_DISABLED), quindi il giorno sereno non paga nulla.
  • [diag] Numeri della serata sull'Honor (freddo): giorno 55-56 · notte 31-32 → 39-40 con la mezza risoluzione · carte 26 → 59 · zero SHADER ERROR. Legenda misure in TESTLOG, incidenti di percorso compresi (install adb fallito in silenzio che ha fatto rimisurare tre volte il build sbagliato, ring buffer che ruota, run RIPRESA dal salvataggio che inganna i tap).

Sprint prestazioni: la notte dimezzata era LO STESSO male del giorno, e la dieta NPC (SU-581/582/583/584, v0.40)2026-08-25

  • [fix] SU-581 — Le tre passate notturne (tinta, bagliore, vignetta) fuse in UNA (World.gd, NIGHT_COMPOSITE_SHADER). La notte sull'Honor girava a 20,5 fps contro i 51-52 del giorno, e la curva dose-risposta misurata sul device ha inchiodato il perché: ogni ColorRect fullscreen con shader costa 10-15 ms da solo (0 passate = 54 fps · 1 = 30 · 2 = 22,5 · 3-4 = 20,5). La fila mix→add→mix è riprodotta ESATTA in una passata blend_premul_alphaCOLOR.rgb = V·Va + (T·Ta + G)·(1−Va), COLOR.a = 1−(1−Ta)(1−Va) — col ciclo delle 32 luci che gira una volta per pixel invece di due e confronta le distanze al quadrato (sqrt solo dentro la pozza). Notte: 20,5 → 29-38 fps, divario col giorno dimezzato; giorno invariato (50-51); zero SHADER ERROR nel logcat; scatto notturno con tinta, cerchio-lanterna, pozze, neon, finestre e vignetta tutti al loro posto. NightGlow e VignetteOverlay non esistono più come nodi; i loro uniform vivono sul materiale unico (vig_tint, darkness, light_radius/center), e il gate diurno spegne la passata composita quando tinta+buio+notte sono a zero.
    • ⚠️ Tre giri di misura buttati per un baco della sonda: il fix degli overlay (voce 16) riafferma visible a ogni frame, e la sonda — che girava PRIMA di World — spegneva i rettangoli per un frame che World riaccendeva subito. Tutti gli «assolti» notturni di M1 erano falsi. Rimedio: process_priority = 1000 e ri-spegnimento per frame. Lezione annotata anche in TESTLOG.
  • [fix] SU-582 — Dieta della fisica NPC: LOD a cadenza sulla distanza (NPC.gd, ModularNPC.gd, builder architetto-opus). I passanti oltre ~1,6× la mezza diagonale inquadrata girano 1 frame su 3 (delta accumulato: i timer scorrono giusti) e si muovono per integrazione diretta senza move_and_slide (a quella distanza le collisioni non si vedono); vicini, ingaggiati, allarmati, in panico o derubati restano a pieno regime, la polizia non passa di qui per costruzione. Il brief sbagliava le soglie fisse (950 px: mai superate, città compatta) — la sonda del builder l'ha smentito prima di scrivere il codice, e le soglie ora seguono viewport÷zoom (463/362 px a zoom di gioco, 73% dei passanti a dieta; col pinch aperto salgono da sole). Sul device: fisica −2,1 ms, +6,2 fps di giorno; quota NPC da 6,5 a ~4,4 ms (il target ≤3,5 riletto come quota non è ancora centrato — sul ticket). Sonde riusabili committate: scripts/tools/probe_su582_lod.gd + tools/autotest/probe_su582.sh.
  • [diag] SU-583 — Attribuzione dei residui, con numeri: fisica totale diurna 7 ms = NPC ~4,4 + base ~2,6; la coda di upload delle luci vale ~0 di giorno (misurata col flag di salto); il joystick virtuale disegna 762 primitive (~+3 fps se spento: primo candidato del prossimo taglio, prerender su texture); le schermate in PAUSA (carte, giornale) girano a 26 fps con render CPU raddoppiato — anomalia nominata, non ancora spiegata. Il process «alto» su Android resta in parte attesa GPU (il menu a 59 fps segna 20 ms).
  • [test] SU-584 — Warp sbornia + calura convivono: verificato su device, nessun fix necessario. Ondata di caldo forzata + is_drunk pinnato: lo scatto in piena ondata mostra lavata ambrata, stelline da colpo di calore E ondeggiare del warp insieme; a ondata finita la scena torna neutra. I primi due tentativi erano stati mangiati dalle schermate-carta (l'ondata apre la scelta del perk meteo, che PAUSA l'albero — da sapere per i prossimi collaudi via adb).
  • Misure: 4 sessioni A-B-A sull'Honor a telefono raffreddato (metodo e numeri in TESTLOG); build di misura con sonda PerfProbe da TMP/perf/, MAI committata.

RIENTRI ATTESI: SU-581, SU-582, SU-583, SU-584

SU-226 ha una risposta, e non è quella che cercavamo — e da lì nascono SU-227 e SU-2282026-08-03

  • [change] Gli sprite e i suoni approvati entrano in LFS; le temp/ della generazione immagini non ci entreranno mai più. Nel git status c'erano ~96 MB di sprites_raw/**/temp/ — tentativi, scarti, skins_raw/attempt1/, i vari _v2 e _codex — accanto a una manciata di file finiti. La regola nuova (sprites_raw/**/temp/) non decide niente di nuovo: scrive una scelta già presa, perché di 223 file tracciati in sprites_raw/ nemmeno uno stava sotto una temp/. Ma finché non era scritta, quelle cartelle riempivano il git status a ogni giro, ed è esattamente lì che le cose vere si nascondono — è così che il fix del Buttafuori è rimasto sepolto per giorni. Verificata col git check-ignore su tutte e sei le temp/ (compresa sprites_raw/temp/ in cima, che il pattern ** prende comunque) e, dall'altro lato, che gli approvati non vengano ingoiati. Committati i finiti: 13 sheet arch_* in PEOPLE/ (bully v1-v3 + drunk, catlady, cleaner, jester, raid), 10 icone super_icon_* in UI/ — le sorgenti singole da cui nasce l'atlante super_icons.png già in gioco — e 5 .wav in Sounds_raw/. Di questi, card_pick, kaching e super_baptism sono già importati in assets/sounds/: il gioco li suona da tempo e la sorgente non era da nessuna parte. levelup.wav e levelup_OLD.wav invece non sono ancora importati — entrano come archivio, non come materiale in uso. File: .gitignore, nuovi sprites_raw/PEOPLE/arch_* (13), sprites_raw/UI/super_icon_* (10), Sounds_raw/*.wav (5).
  • [fix] Quattro .uid di Godot erano rimasti fuori da git mentre i loro .gd erano dentro. Riguardano buildings_windows.gd, shot_finestre.gd, su199_shot.gd e su206_shot.gd: gli script sono tracciati da tempo, i file d'identità che Godot genera accanto no. Verificato uno per uno che il .gd corrispondente sia davvero ancora tracciato e sul disco — un .uid orfano andrebbe cancellato, non committato, e la potatura dei provini di ieri rendeva la cosa possibile. Non è pedanteria: su un clone fresco Godot li rigenera con valori diversi, e da lì in poi ogni riferimento a quelle risorse punta a un'identità che nessun altro ha. È lo stesso motivo per cui i .uid degli altri script (NPC.gd.uid, ModularNPC.gd.uid…) stanno in git da sempre. File: nuovi buildings_windows.gd.uid, shot_finestre.gd.uid, su199_shot.gd.uid, su206_shot.gd.uid.
  • [docs] KIT_CHATGPT/ entra in git — c'era da cinque giorni sul disco, e in git c'erano solo le regole per ignorarne le immagini. È il caso più curioso emerso facendo ordine nel git status: le righe di .gitignore che escludono esempi_stile/, identita_idle/, generati/, edifici/, celle_riferimento/ e STATO.md erano già committate, con tanto di spiegazione («i .md e gli strumenti si versionano, le immagini no»), ma la cartella che quelle righe governano non è mai entrata. Quindi il repo dichiarava una politica su roba che non conteneva. Adesso ci sono le 8 istruzioni, i 6 strumenti Python e la misura grezza camminata_96_20260729.csv da cui nasce la lista degli sheet da rifare; le immagini restano fuori come previsto, perché sono copie di sprites_raw/ (che sta in LFS) o file rigenerabili, e versionarle significherebbe portarsi dietro ~24 MB di duplicati come blob git normali. Il kit è deliberatamente autosufficiente — si consegna a ChatGPT così com'è, senza esporgli il resto del progetto — e questo spiega l'unico doppione: estrai_colonna_idle.py esiste sia in KIT_CHATGPT/strumenti/ sia in files/homeless_city/tools/, identico byte per byte, e non è un errore: la copia nel kit serve alla sua autosufficienza, quella in tools/ sta insieme agli altri dieci script già tracciati lì. Entrambe committate. In più AGENTS.md prende una deviazione in cima: se la richiesta è generare sprite non si leggono i punti sul ciclo di sviluppo, si va diretti a KIT_CHATGPT/07_ISTRUZIONI_CHATGPT_WORK.md, e in quel ruolo files/homeless_city/ è in sola lettura. Colta l'occasione per correggere il titolo: era ancora «Street University». File: nuovi KIT_CHATGPT/** (.md e strumenti) e files/homeless_city/tools/estrai_colonna_idle.py; AGENTS.md.
  • [docs] Il codice di un tester non si ricalcola mai, nemmeno se sembra sbagliato: la lezione del 31 luglio finisce nero su bianco in tutti e due i posti che la usano. Quel giorno è successo davvero: un codice SU-XXXX-XXXX-XXXX valido è stato scambiato per un MAC address travestito — e la confusione è comprensibile, la forma è identica, dodici cifre esadecimali a gruppi di quattro — quindi «corretto», ricalcolato con un altro sale e pubblicato. Risultato: il legittimo proprietario è rimasto fuori dalla propria beta, senza capire perché. La regola scritta prima diceva solo che il codice «non si inventa» e spiegava cos'*è*; adesso dice cosa non si fa, che è la parte che serve a chi ha il codice sospetto sotto gli occhi: non ricalcolarlo, non dedurlo, non correggerlo. Il motivo è per costruzione, non prudenza: è l'impronta di OS.get_unique_id() con il sale definito in BetaGate.gd, quindi qualunque valore calcolato altrove è un valore che nessun dispositivo produrrà mai. L'unica mossa lecita davanti a un codice strano è farselo rileggere dal tester sulla schermata del Buttafuori; e se proprio si deve verificare, il riferimento è DEVICE_SALT in files/homeless_city/scripts/autoload/BetaGate.gd letto lì, mai un sale copiato in un ticket o in un documento, che può essere invecchiato. Messa in entrambi i punti dove il passo si esegue davvero, perché in uno solo si sarebbe persa. File: .claude/commands/lista-beta.md, WORKFLOW/04_RELEASE.md.
  • [fix] Il Buttafuori mostrava il pannello di cartone anche mentre stava solo controllando, e su risposta veloce era un lampo indistinguibile dalla schermata di blocco. Il codice che lo risolve era sul disco da giorni, mai committato, ed è saltato fuori facendo ordine nel git status: la sua chiave di traduzione BETA_CHECK_ATTESA invece era già in git, entrata di straforo con la riscrittura di ui_menu.csv del commit di SU-222 — quindi su dev c'era una chiave che nessuno usava e il lampo era ancora tutto lì. Ora durante il controllo il pannello non esiste proprio: resta solo il nero, quello da cui il menu fa già il suo fade-in, così un avvio che va liscio sembra un avvio normale. Il cartone compare solo quando il cancello dice davvero di no. Se invece il controllo tarda più di 0,6 s spunta una riga discreta «Un attimo…», perché nessuno pensi che si sia piantato — sotto quella soglia non si vede niente. Due dettagli che sono il vero contenuto del lotto: il timer è un nodo figlio e non un await get_tree().create_timer(...), perché quando il controllo passa BetaGate fa queue_free() di questa schermata e una coroutine in attesa si sveglierebbe su un oggetto già liberato — stessa famiglia di errori di SU-217; e viene creato in _ready() e non in _build_ui(), che invece viene rifatta a ogni cambio di dimensione della finestra e avrebbe accumulato timer duplicati. Il pannello inoltre nasce nascosto, perché anche un solo fotogramma di cartone vuoto sarebbe di nuovo il lampo che stiamo togliendo. Verificato con compile-check: nessun SCRIPT ERROR. File: BetaGateScreen.gd.
  • [docs] Nasce REGISTRAZIONI/: una cartella per call, e i materiali dell'intervista a Michele smettono di stare sparsi in root. Fino a ieri i cinque file dell'intervista del 29 luglio (traccia, trascrizione .md e .srt, riassunto, spunti) stavano nella root del progetto insieme ai design doc, senza niente che dicesse che erano la stessa cosa. Ora ogni registrazione ha la sua cartella AAAA-MM-GG_argomento, e la data davanti tiene l'ordine cronologico gratis. Spostati in REGISTRAZIONI/2026-07-29_intervista_michele_gestione_senzatetto/: erano tutti untracked, quindi nessuna history da preservare, e i 3 link relativi interni al set (il riassunto cita la trascrizione e gli spunti, gli spunti citano la trascrizione) reggono perché i file si sono mossi compatti — verificato che i target siano nella stessa cartella. Aggiunta la call di oggi in REGISTRAZIONI/2026-08-03_brainstorming_citta_personaggi_longevita/. Gli audio stanno nella cartella ma non in git (.gitignore: REGISTRAZIONI/**/*.mp3|m4a|wav), per due motivi che vale la pena aver scritto: sono voci di persone reali che hanno parlato in confidenza — il testo si rilegge e si corregge, l'audio no — e le regole LFS in .gitattributes sono per-cartella (solo sprites_raw/ e Sounds_raw/), quindi un mp3 da 58 MB entrerebbe come blob git normale, per sempre nella history e sopra la soglia di allarme di GitHub. La cosa che il README salva davvero è la ricetta di trascrizione, che il 29 luglio era documentata solo come riga di prosa dentro un header: whisper large-v3-turbo via MLX, in locale sulla GPU, con due trappole in cui si è ricascati oggi — senza arch -arm64 uvx sceglie un Python x86_64 sotto Rosetta e MLX muore con *«incompatible architecture (have 'arm64', need 'x86_64')»*, e il whisper in /usr/local/bin è quello Intel, che gira in emulazione sulla CPU ed è inutilizzabile. File: nuovi REGISTRAZIONI/README.md, REGISTRAZIONI/2026-08-03_.../TRASCRIZIONE_BRAINSTORMING_2026-08-03.md e RIASSUNTO_BRAINSTORMING_2026-08-03.md; .gitignore.
  • [change] SU-228 — GRAFICA LEGGERA sparisce dal menu, ma il codice resta tutto dov'è. Decisione di Ivan dopo averla provata sul telefono: «non vedo sostanziali cambiamenti tra grafica bassa e alta, la toglierei dal menu e terrei sempre grafica alta e vsync — il codice però tienilo per un futuro». Il contrasto è annotato apposta nel codice, perché è la ragione per cui non si butta niente: a strumento la differenza *non* è piccola (frame a 60 fps: 0% senza, ~50% con), ma è il giudizio a occhio a decidere, non il numero. Rimettere la voce costa una riga: MainMenu.MOSTRA_GRAFICA_LEGGERA è l'unico interruttore, e comanda la voce, la sua porta su mobile e il cap di SU-227. Le due trappole erano il vero contenuto del lotto, e nessuna delle due si vede togliendo la voce e basta. (1) Su mobile LIMITE FPS e SCHERMO INTERO non esistono (SU-186), quindi senza GRAFICA LEGGERA la porta GRAFICA avrebbe aperto una stanza vuota: va rinascosta, tornando alla situazione pre-SU-222, e le voci di OPZIONI lì tornano da 11 a 10. (2) E allora gli indici si spostano: con 10 voci l'indice 8 smette di essere GRAFICA e diventa DIMENSIONE TESTO — senza guardia, su mobile toccare DIMENSIONE TESTO avrebbe aperto la schermata GRAFICA, e la riga di aiuto avrebbe mostrato quella sbagliata. Verificato a schermo forzando _is_mobile() (la funzione esiste apposta per questo, lo dice il suo commento): 10 voci, porta assente, indice 8 → DIMENSIONE TESTO con la sua riga di aiuto. Il rischio più serio però non si vede in nessuno screenshot: chi aveva GRAFICA LEGGERA già accesa e salvata — il telefono di prova, e ogni tester che l'abbia provata — sarebbe rimasto in grafica bassa per sempre, senza più un interruttore per uscirne. Non basta smettere di offrire la voce: load_settings() ora ignora il valore salvato, stesso schema con cui SU-186 azzera fps_limit su mobile. Provino dedicato che fabbrica quel settings.cfg e verifica la liberazione. Effetto su SU-227: il cap a 30 fps diventa codice dormiente (non rotto — il suo provino passa ancora 4 casi su 4), perché low_graphics non può più diventare true. File: MainMenu.gd, Settings.gd, ui_menu.csv (la porta GRAFICA ora annuncia due voci e non tre, in 5 lingue), nuovi su228_shot_menu.gd e su228_check_forzatura.gd.
  • [fix] I provini finivano dentro l'APK: TMP/* ora è escluso da tutti e quattro i preset di esportazione. Trovato per caso costruendo una build di prova: pesava 137 MB invece di 126. Gli 11,2 MB in più erano 26 screenshot scattati durante la giornata (TMP/SU228_grafica_desktop.png, TMP/SU227_info_de.png…), impacchettati e spediti agli utenti — TMP/ sta dentro la cartella del progetto e i preset esportano all_resources. È la stessa famiglia del problema che SU-223 aveva combattuto per stare sotto i 120 MiB, e il modo in cui si manifesta è il peggiore: silenzioso e variabile, perché dipende da cosa uno si è lasciato in TMP/ quel giorno. Con l'esclusione la build torna a 126,4 MB. File: export_presets.cfg.
  • [feat] SU-227 — GRAFICA LEGGERA adesso blocca anche il ritmo a 30 fps: un 30 fermo invece di un 45 che singhiozza. Decisione di Ivan durante l'indagine di SU-226, staccata in un ticket suo perché SU-226 è dichiaratamente brainstorming e vieta modifiche permanenti al gioco. Il difetto non era la media, era l'alternanza: con l'interruttore acceso l'Honor 10 non sta *sul* traguardo, sta *a cavallo* — 47,6% dei frame in tempo per i 60 e 50,0% no. Con V-Sync a 60 Hz non ci sono vie di mezzo (16,7 ms o 33,3 ms), quindi il gioco saltella di continuo fra i due, ed è il ritmo che si nota di più; la media ~45 fps suona bene ed è proprio questo a ingannare. Cappando, il 97,6% dei frame sta comodo dentro i 33,3 ms. La regola è che il cap si mette SOLO insieme a GRAFICA LEGGERA, e la misura dice perché: senza, il 33,6% dei frame sfora anche i 33,3 ms — si otterrebbe un 30 a singhiozzo invece di un 45 a singhiozzo, perché a piena risoluzione quel telefono non tiene nessuna frequenza stabile. A interruttore spento quindi non cambia nulla rispetto a oggi. Su desktop la scelta esplicita dell'utente vince: chi ha messo un LIMITE FPS diverso da AUTO non se lo vede sovrascrivere alle spalle, così restano possibili i pixel dimezzati senza cap. Tutta la logica di Engine.max_fps sta in un posto solo (apply_fps_limit), richiamato da apply_low_graphics prima del controllo sulla finestra — di proposito: max_fps non dipende dalla finestra, e metterlo dopo avrebbe perso il cap in silenzio ogni volta che la finestra non c'è ancora (è saltato fuori dal provino, che girava senza finestra). Testi aggiornati in 5 lingue: l'opzione prima prometteva «più fps», adesso promette un ritmo fisso, che è una cosa diversa e va detta. Prezzo dichiarato: a 30 fps l'input si legge la metà delle volte, quindi il joystick virtuale risponde un filo più tardi. Verificato: i 4 casi (leggera ON/OFF × limite AUTO/esplicito) con un provino in-engine, 0 falliti su 4; compile-check 4 file, 0 falliti; provini a schermo del testo nuovo in IT e DE a 1024×768 (il caso più stretto), tre righe dentro il pannello in entrambe. ⚠️ NON provato su device: la percentuale reale di frame fuori budget col cap acceso, il giudizio a occhio e la reattività del joystick restano da vedere sull'Honor 10 — l'export Android di release è bloccato (vedi sotto). File: Settings.gd, MainMenu.gd, ui_menu.csv, nuovi su227_check_cap.gd e su227_shot_info.gd.
  • [docs] SU-226 — misurato: il gioco è limitato dal riempimento dei pixel, non dagli NPC. E la spiegazione di ieri sera era sbagliata. Idea di Ivan: rifare tutte le prove del giorno prima con GRAFICA LEGGERA accesa. Era la mossa giusta, ma per un motivo diverso da quello previsto. Ritirata la conclusione del 2026-08-02 («al muro termico gli A/B sono ciechi»): la vera causa era il V-Sync, non il calore. A 60 Hz un frame o entra in 16,7 ms o costa 33,3 — non ci sono valori intermedi; tutte le prove di ieri giravano a ~33 ms, quindi togliere 2 ms di NPC o di ombre non poteva cambiare un fps, per costruzione. Con GRAFICA LEGGERA ci si mette *sul confine* dei 16,7 ms, l'unico regime in cui un risparmio si vede. Rifatte lì, tutte appaiate con un controllo accanto: togliere 40 NPC su 45 vale +6 punti di frame a 60 fps, ombre dei palazzi zero, i due overlay a schermo intero zero esatto; dimezzare i pixel porta i frame a 60 dallo 0% al ~50%. Il meccanismo è aritmetico: viewport 1024×768 + stretch/mode="canvas_items" + aspect="expand" significa che GRAFICA LEGGERA fa una cosa sola, passare da 2280×1080 = 2,46 Mpixel a ~1621×768 = 1,24 Mpixel — metà pixel esatti. Quindi la strada per SU-226 non è «gestire meglio gli NPC» ma disegnare meno pixel, e SU-222 aveva già fatto il grosso. Due trappole di misura annotate per chi riprende in mano il ticket: la mediana degli fps è inutilizzabile a questo punto di lavoro (salta fra 59 e 29,5 per un punto percentuale — si legge la quota di frame sotto i 18 ms), e la deriva termica vale 9 punti nell'arco di una sessione, cioè più del segnale cercato. Ricaduta sul multigiocatore: siccome il collo di bottiglia è per-dispositivo e non di simulazione, non conta chi fa da host. Seconda domanda di Ivan, «e se cappassimo a 30 o duplicassimo i frame come il frame generator di NVIDIA?»: guardata la coda della distribuzione invece della mediana, un cap a 30 da solo NON reggerebbe (a piena risoluzione il 33,6% dei frame sfora anche i 33,3 ms — sarebbe un 30 a singhiozzo invece di un 45 a singhiozzo), mentre cap a 30 + GRAFICA LEGGERA reggerebbe nel 97,6% ed è la strada concreta per «fluido su un telefono vecchio»; duplicare i frame non fa nulla perché con V-Sync lo fa già il display (stessa immagine per due refresh: cambia il contatore, non il movimento), e la frame generation vera — che *sintetizza* un'immagine intermedia, non la copia — costa quanto disegnare un frame ed è quindi controproducente proprio perché siamo limitati dalla GPU, oltre ad aggiungere ritardo al tocco. Il 97,6% è una previsione dalla distribuzione, non un cap provato dal vivo: su mobile apply_fps_limit() forza Engine.max_fps=0 per scelta di SU-186. Dettaglio completo in TESTLOG.md; nessun file del gioco modificato.
  • [docs] RICOSTRUZIONE_DA_ZERO.md — l'export Android di release non parte più, e il documento adesso lo dice. Trovato provando a costruire varianti per le misure: --export-release fallisce con «Could not find release keystore». Il keystore c'è (~/Library/Application Support/Godot/keystores/), manca il riferimento — export_presets.cfg, tracciato da SU-223 proprio per non essere volatile, non contiene nessuna riga keystore/release, ed è la stessa volatilità vista dal lato opposto. Rimedio senza segreti in git: le variabili d'ambiente GODOT_ANDROID_KEYSTORE_RELEASE_PATH/_USER/_PASSWORD, che imposta Ivan. Aggiunto anche l'avvertimento di non ripiegare su --export-debug per aggirare il problema: template diverso, APK da ~144 MiB invece di ~120, prestazioni non confrontabili.

Dieta token per l'orchestrazione: playbook snellito, check mirato riutilizzabile, harness /tmp per-utente2026-07-17

  • [docs] ORCHESTRAZIONE.md: nuova sezione "Dieta token" (vincolante), dal post-mortem dello Sprint 1 (~1,7M token nei soli 6 subagenti + overhead Jira/fetch dell'orchestratore). Regole: micro-task fatti inline dall'orchestratore (uno spawn costa 60-100k token a freddo), validazione centralizzata (builder → solo check mirato sui propri file, bot e regressioni solo nel collaudatore finale unico), brief "chiusi" senza esplorazione libera del repo, report ≤30 righe anche in append su REPORT_LOTTI.md (gitignored — sopravvive ai limiti di sessione degli agenti), Jira con UNA sola transizione per ticket e commenti ≤6 righe, lotti aggregati per file condivisi (≤4 builder per sprint ~20 ticket), modello minimo che basta. Aggiornato il flusso ticket nella sezione Jira (niente più "In corso" di passaggio).
  • [test] Nuovo tools/autotest/check_files.sh + scripts/tools/check_files.gd: compile-check MIRATO di singoli file, il SOLO check che i builder devono usare. Replica la ricetta che ogni agente dello sprint si era reinventato da zero: compila una copia fresca del sorgente (GDScript.new() + take_over_path) → niente falso "Cannot reload script while instances exist" sugli autoload, niente scansione full-tree (check_scripts.gd resta per l'uso da editor). Scene: load-check senza istanziare. Rumore EOS filtrato. Provato in sandbox: OK su autoload+script+scena, exit 1 su file rotto/mancante.
  • [fix] Harness autotest: path /tmp per-utente (SU_TMP=/tmp/su_<uid>) in common.sh, run_check.sh, run_sp.sh, run_mp.sh al posto dei path fissi (/tmp/su_proj, /tmp/su_*.log): i residui di sessioni sandbox precedenti con uid diverso rompevano rsync/log con "Permission denied" a ogni prima esecuzione. Era l'insidia già nota "usa path freschi", ora risolta alla radice invece che aggirata a mano ogni volta.

Fix EOS nel build macOS: "Cerca partita" non funzionava (SU-15)2026-07-16

  • [fix] Multiplayer online (EOS) morto nell'export macOS: credenziali non impacchettate. Stessa causa del vecchio fix iOS: eos_credentials.cfg non è una risorsa Godot, quindi con include_filter vuoto l'export macOS non lo includeva nel .appEOSBridge.credentials_present() falso → available() falso → il menu resta "solo LAN" e CERCA PARTITA / PARTITA RAPIDA non trovano nulla (dall'editor su Mac funzionava perché il file è lì nel progetto). Aggiunto al preset macOS il filtro Resources → "export non-resource files" = eos_credentials.cfg (include_filter="eos_credentials.cfg"), come già sull'iOS.
  • [fix] Libreria nativa EOS bloccata dalla firma macOS (Library Validation). Il build macOS è code-signed (codesign/codesign=3, hardened runtime); con la Library Validation attiva l'app rifiuta di caricare dylib firmate da un altro team — cioè sia la GDExtension libeosg.macos sia libEOSSDK-Mac-Shipping.dylib di Epic → ClassDB.class_exists("EOSGMultiplayerPeer") falso, EOS non si inizializza. È il caso identico a GodotSteam su Mac. Attivata l'entitlement Codesign → Entitlements → "Disable Library Validation" (codesign/entitlements/disable_library_validation=truecom.apple.security.cs.disable-library-validation). Non tocca EOSBridge né il plugin: solo il preset di export.
  • [docs] Ricordo: export_presets.cfg è gitignored → queste due modifiche vivono solo sulla macchina di export (il Mac di Ivan) e vanno ri-applicate a mano se il preset macOS viene rigenerato (stessa avvertenza del fix iOS). Nessun file tracciato modificato dal fix.
  • [test] Modifica solo di configurazione export; non collaudabile in sandbox (serve macOS + Godot + firma). Da provare sul device: esportare il .dmg, avviare il .app, MULTIGIOCATORE → la riga info deve dire "ONLINE …" (non "solo LAN — credenziali mancanti" né "plugin EOS assente") e CERCA PARTITA/PARTITA RAPIDA devono funzionare come su iPad. Se resta "plugin EOS assente" nonostante il fix firma, incollare gli errori [EOSBridge]/console del .app.

Orchestrazione multi-modello: roster agenti + ORCHESTRAZIONE.md + CLAUDE.md2026-07-16

  • [docs] Roster di 4 agenti delegabili per .claude/agents/ (frontmatter name/description/model): architetto-opus (feature complesse multi-file, stile OPUS_BRIEFS), dev-sonnet (feature scoped 1-4 file da brief), tuttofare-haiku (lavori meccanici: doc, ricerche, rinomine), collaudatore (sonnet: autotest headless e caccia regressioni, senza modificare codice). Tutti rimandano a OPUS_BRIEFS/00_CONTESTO_PROGETTO.md come contesto vincolante, così le convenzioni restano in un posto solo.
  • [docs] Nuovo ORCHESTRAZIONE.md (root): playbook del "primo ponte" — scomposizione in lotti con brief autosufficienti, delega al modello più basso capace (haiku→sonnet→opus), parallelo solo su file disgiunti, ricostruzione + collaudo + changelog a carico dell'orchestratore — con sezione fallback "Opus come primo ponte" se Fable non è disponibile nel piano. Nuovo CLAUDE.md (root) con i puntatori da caricare a inizio sessione (contesto, orchestrazione, brief attivo) e le regole minime (branch dev, changelog, LFS).
  • [docs] Backlog su Jira (tosettiweb.atlassian.net, progetto "Street University" chiave SU): ticket-guida SU-6 (etichette claude-ready/mp/device + template bug/feature), Epic del piano V2 SU-7→12 (R1, R2, R3, U1, U2, P1). Triage automatico schedulato ogni mattina (~9:00): commenta i ticket nuovi con stima/domande/etichette, mai codice. Flusso ticket→brief→agenti documentato nella nuova sezione Jira di ORCHESTRAZIONE.md.

Poliziotto colpito dal gatto: a fine zuffa sparisce e ricompare lontano da tutti i giocatori2026-07-15

  • [change] Il poliziotto stordito dal gatto non si riprende più sul posto (dove ricominciava subito a inseguire il barbone): a fine animazione della zuffa sparisce e ricompare in un punto della mappa fuori vista di TUTTI i giocatori — locale + remoti in multiplayer — con una rotta di pattuglia nuova calcolata dal punto d'arrivo (i vecchi waypoint lo avrebbero fatto tornare dritto verso i player). Nuovo World.pick_police_respawn_point(min_dist): pesca dai punti spawn NPC quelli ad almeno 800px dal giocatore più vicino (oltre mezza diagonale viewport 1024×768 → fuori schermo); se nessuno qualifica (giocatori sparsi ovunque) ripiega sul punto che massimizza la distanza dal giocatore più vicino. In PoliceOfficer._exit_stun_relocate_after_cat_stun: teleport + reset completo (_target_ref azzerato, rotta via get_route_near, nav/stuck invalidati, _slow_timer pulito) + 4s di grazia anti re-aggro (_arrest_cooldown). In MP il respawn è solo host (i puppet non girano l'AI) e i client snappano da soli: _net_puppet_process teletrasporta il puppet oltre i 200px di scarto. Nel tutorial (mappa fissa, TutorialWorld senza il metodo) l'agente resta dov'è come prima — guardia has_method.
  • [test] Compile-check headless mirato (Godot 4.6.2 ARM64, progetto avviato con autoload registrati): OK su World.gd, PoliceOfficer.gd e NPC.gd. Il check full-tree (check_scripts.gd) non completa nella finestra della sandbox di questa sessione — lo copre il run schedulato dell'autotest (TESTLOG). Falliscono come sempre solo gli script EOS (lib nativa assente in sandbox, pre-esistente). Da provare in gioco: colpo di gatto in SP (l'agente ricompare lontano e non torna a caccia), in MP host+client (sparizione della nuvola e snap del puppet), e il passo GATTO vs POLIZIA del tutorial (comportamento invariato).

Playtest Ivan: mappa avversari MP, musica solo-host, fine partita ultimo-vivo, menu pausa/game-over navigabili, scoreggia anti-polizia, lampi temporale, prompt audio2026-07-14

  • [feat] Mappa multiplayer: posizione LIVE degli avversari. MapOverlay disegna un marker per ogni altro barbone della sessione (nuova classe _MpMarkers: rombo colorato per slot + nome). Aggiornati a ogni frame anche a mappa aperta (che mette in pausa il gioco): leggono Player._net_target_pos — il bersaglio di rete che continua ad arrivare via RPC anche con l'albero in pausa — invece della posizione visiva congelata. Solo in sessione MP; saltati i puppet collassati/in dissolvenza.
  • [feat] Opzioni → "MUSICA: ON/OFF" per dispositivo, effetto immediato. Tutta la musica (menu, gioco, tutorial) passa dal nuovo bus audio "Music" (creato a runtime da Settings), che il toggle muta/smuta all'istante via AudioServer.set_bus_mute — non serve riavviare la scena. Persistente in user://settings.cfg (music_enabled, Settings.set_music_enabled/apply_music_enabled). Utile anche in multiplayer locale: i dispositivi vicini mettono OFF per togliere l'eco delle tracce sfasate (l'host resta "cassa"). Sostituisce il precedente mp_music_host_only/voce nel menu MP (rimossi).
  • [feat] Multiplayer: la run finisce quando resta UN solo barbone vivo. Quando tutti gli altri sono collassati, il superstite vince subito (World._net_last_survivor_win) invece di restare da solo in città fino allo scadere del tempo: entra anch'esso nella classifica finale (gli spettatori chiudono la run condivisa) e vede il pannello con titolo "🏆 SEI L'ULTIMO BARBONE IN PIEDI!" (HUD.show_last_survivor_win). Rilevato in World._cl_final_score via NetworkManager.living_ids().
  • [feat] Menu pausa e game over navigabili (touch-friendly). "Premi menu per ricominciare" non funzionava coi comandi touch. Ora entrambe le schermate usano un menu di Button reali (nuova classe HUD._MenuList): voce evidenziata che pulsa, tap diretto su touch, navigazione su/giù (WASD/frecce/D-pad/levetta con isteresi), A/Invio conferma. Pausa: RIPRENDI · [SALTA TUTORIAL] · ESCI, con B/ESC = riprendi. Game over: RICOMINCIA (o RIVINCITA da host MP; solo ESCI per il guest) · ESCI, B non fa nulla. Logica restart estratta in HUD._do_restart_or_rematch() (riusata dal menu e dalla scorciatoia R/Start); il corpo del pannello non mostra più i prompt da tasto.
  • [feat] Se ti insegue la polizia e scoreggi, la rallenti. Contromossa difensiva: una scoreggia nella nuvola (FART_SLOW_RADIUS=150) rallenta al 45% per 2.6s gli agenti che ti stanno inseguendo/indagando/avvisando (PoliceOfficer.apply_fart_slow + _slow_mult, applicato in _do_chase/_do_investigate), con tosse. Nessun effetto se stanno solo pattugliando. Funziona anche in MP: le scoregge dei client raggiungono già gli agenti dell'host via World._srv_misdemeanor.
  • [feat] Temporale: lampi veri + tuono. Lo scaffold c'era ma *scuriva* i bordi; ora un fulmine fa un flash bianco-azzurro a schermo (nuovo overlay in World, doppio tremolio) e un tuono ritardato (World.sfx_thunder, opzionale). In MP l'host decide quando cade e lo trasmette ai client (_cl_lightning) così il lampo è identico su tutti gli schermi.
  • [feat] Prompt ElevenLabs inseriti come commento accanto ai relativi @export: busking/trombetta (Player.sfx_busk, in loop, con variante toy-trumpet), allarmi rifiniti + varianti fame/sonno (HUD), tuono (World.sfx_thunder).
  • [change] Nodi audio dedicati per i suoni prima "export-only", così si assegnano nell'editor come tutti gli altri Sfx* (niente più player creati a runtime): SfxBusk in Player.tscn, SfxThunder in Main.tscn, SfxGameOver/SfxWarnSoft/SfxWarnAlarm/SfxDanger in HUD.tscn (process ALWAYS così suonano anche a gioco in pausa/game over). Gli slot @export restano come override opzionale (se pieni sovrascrivono lo stream del nodo, come per gli altri suoni). Rimosso il player-allarme condiviso: ogni allarme suona ora il proprio nodo (_play_alert prende un AudioStreamPlayer); la fanfara game over non è più legata all'@export ma allo stream del nodo.
  • [fix] Crash Cannot call method 'set_input_as_handled' on a null value uscendo al menu (o ricominciando) dal menu pausa/game over con A/Invio/R. La voce ESCI/RICOMINCIA cambia scena (change_scene_to_file/reload_current_scene) e subito dopo get_viewport() sull'HUD è null. Ora l'input viene marcato *prima* di attivare la voce, con guardia anti-null (HUD._safe_handled()); col tap touch il problema non c'era (passa dal segnale pressed del Button).
  • [fix] Doppio-tap nei menu col tocco (colpiva selezioni e toggle). Su touch un tap genera SIA InputEventScreenTouch SIA un InputEventMouseButton *emulato*: il gestore scattava due volte. Sui toggle tornava com'era (sembrava non rispondere al dito); in navigazione faceva doppio-salto — es. MULTIGIOCATORE su iPhone piccolo saltava dritto a UNISCITI CON CODICE. Nuovo helper MainMenu._is_tap() (accetta il touch, e il click del mouse solo senza touchscreen → un tap = un'azione), applicato a TUTTI i gui_input dei menu: voci menu principale, domanda tutorial, Opzioni e _mp_connect_tap (sistema anche il doppio-incremento di IP/nome MP e il rischio di reset statistiche accidentale in un tocco).
  • [fix] Multiplayer: al force-quit dell'app (es. swipe-up iOS) il barbone restava "impalato" nella partita altrui, senza avviso di disconnessione. ENet nota il peer morto solo dopo un timeout lungo. Nuovo heartbeat: ogni client segnala "sono vivo" 1×/s (NetworkManager._srv_heartbeat); l'host droppa chi tace oltre 30s (PEER_TIMEOUT) → disconnect_peer(force) + pulizia standard (puppet liberato + avviso "ha lasciato la città"). I 30s tollerano un app-switch/background breve (torni prima che scada e resti in partita); una chiusura o sospensione lunga viene ripulita. NetworkManager è già process ALWAYS, quindi l'heartbeat continua anche con mappa/menu in pausa locale.
  • [change] Disconnessi in partita → messaggio + ritorno al menu (invece del vecchio "continui da solo"). Se un client perde l'host o viene cacciato per timeout (es. rientra dopo un background lungo ed è stato rimosso), NetworkManager.kicked_from_game avvisa e l'HUD lo riporta al menu principale dopo 2,4s.
  • [fix] Sfondo/splash del menu ora sempre 100% verticale, centrato orizzontalmente. Prima KEEP_ASPECT_COVERED tagliava in alto/basso sugli schermi larghi (iPhone). Ora MainMenu._fit_bg_to_height() scala l'immagine all'altezza dello schermo e la centra (sborda/croppa solo ai lati), ricalcolato a ogni resize/rotazione. NB: splash.png è 4:3 (1448×1086) → sui telefoni larghi lascia margini ai lati finché non viene allargata lateralmente (immagine da rigenerare ~2.4:1).
  • [fix] Multiplayer: gli agenti "seguivano solo l'host" e non i guest. Reagendo a un misfatto l'agente non impostava _target_ref, quindi _chase_target() ripiegava sempre su _player_ref (il barbone locale = host). Ora PoliceOfficer._on_player_misdemeanor individua il colpevole (il candidato — player locale o puppet remoto — più vicino al punto del misfatto, via _nearest_candidate_to) e indaga/insegue lui. La visione (_check_vision) e l'avviso al bersaglio remoto (net_police_notify → sirena/banner sul suo schermo) già consideravano i guest; ora anche i misfatti. Ogni barbone è trattato come in single player, col proprio wanted (relayato via _srv_wanted).
  • [fix] Multiplayer: gatto lanciato a un agente da un client → sprite della zuffa bloccato e mai animato. Sul client il gatto stordiva il puppet in locale (stun_by_cat), ma il puppet non gira l'AI → _do_stunned non partiva mai (nuvola ferma, agente invisibile per sempre). Ora il client non stordisce il puppet: rilancia solo all'host (net_cat_hit_npc), l'host stordisce l'agente vero e risincronizza lo stato a tutti i peer (net_npc_stun_cl_npc_stunPoliceOfficer.set_puppet_stunned), che animano la nuvola e la tolgono a fine stun (con auto-scadenza se l'RPC di fine si perde).
  • [fix] Multiplayer: si sentiva l'audio della zuffa del gatto "dall'altra parte della città". stun_by_cat gira sull'host anche per i gatti relayati dai client e suonava play_sfx_cat_fight non-posizionale (volume pieno) sul barbone dell'host. Ora la zuffa è audio posizionale: ogni peer riproduce un AudioStreamPlayer2D one-shot sull'agente (host in stun_by_cat, client in set_puppet_stunned, stream via Player.get_cat_fight_stream, max_distance≈550 come il busking) → lo sente chiunque abbia il barbone vicino (lanciatore o di passaggio), attenuato dalla distanza; chi è lontano no. La notifica "Poliziotto distratto" resta al lanciatore (CatProjectile).
  • [test] Compile-check headless (Godot 4.6.2 ARM64) OK su tutti gli script modificati (Player, World, HUD, MapOverlay, PoliceOfficer, CatProjectile, Settings, MainMenu, TutorialWorld, NetworkManager) e sull'intero albero scripts/ (58 file); le 3 scene toccate (Player/Main/HUD) caricano e contengono i nodi audio referenziati dagli @onready. Da provare sul device: toggle MUSICA in Opzioni (tocco + effetto immediato), navigazione menu col dito senza doppio-salto, sfondo pieno su iPhone/iPad, disconnessione al force-quit (30s) e rientro-dopo-espulsione in multiplayer locale. Falliscono solo gli script dell'addon EOS perché la libreria nativa richiede GLIBC 2.38, assente nella sandbox (pre-esistente, non legato a queste modifiche). Da provare sul device: marker mappa in MP, toggle musica con 2 dispositivi vicini, menu coi tasti touch A/B, scoreggia anti-polizia, lampi. Gli asset audio (trombetta/allarmi/tuono) vanno generati su ElevenLabs e assegnati nell'inspector.

Apple TV: verifica fattibilità + APPLE_TV.md + automatismo tools/appletv/export_appletv.sh2026-07-07

  • [docs] Nuovo APPLE_TV.md (root): stato export tvOS a luglio 2026 — Godot 4.6 NON supporta tvOS (base "Apple Embedded" condivisa iOS/visionOS pronta da 4.5, proposal godot-proposals#13532 aperta, branch sperimentale tvos-vibed di migueldeicaza sconsigliato). Il progetto Xcode iPad non è convertibile via script: contiene libgodot compilato solo iphoneos, senza slice appletvos. Blocchi da risolvere al giorno X: piattaforma engine, EOS senza SDK tvOS (MP da escludere con OS.has_feature("tvos")), renderer GL Compatibility assente su tvOS (Metal-only → method mobile), user:// non persistente garantito. Alternative per giocare in TV oggi: AirPlay da iPad (pad sul device) o Moonlight+Sunshine / Steam Link dal Mac.
  • [feat] Nuovo tools/appletv/export_appletv.sh: automatismo "pronto per il giorno X" da lanciare sul Mac. Rileva Godot e i template tvOS installati; se assenti interroga GitHub (esiste platform/tvos nel master? l'ultima release cita tvOS?) e riassume stato + alternative; se presenti aggiunge una tantum il preset tvOS a export_presets.cfg (backup .bak, stesso bundle id/team dell'iOS, export_project_only=true), esporta headless il progetto Xcode in ~/Desktop/streetUniversityTVOS/ e lo apre, con promemoria dei fix EOS/renderer/salvataggi. Env: GODOT_BIN per binario custom, FORCE_TVOS=1 per engine build sperimentali.

OPUS_BRIEFS/P1_RESTYLE_PIXELLAB.md: piano esecutivo per rigenerare TUTTA la pixel art via PixelLab MCP2026-07-07

  • [docs] Nuovo brief OPUS_BRIEFS/P1_RESTYLE_PIXELLAB.md (traccia parallela agli sprint R/U, richiede solo l'MCP PixelLab): rigenerazione completa degli asset con upgrade a 8 direzioni native + walk 8 frame (nuovo sheet 288×256 celle 32×32, importer import_pixellab_sprites.py, addio specchiatura ovest e camminate/direzioni rotte tipo il turista-maiale drunk), 8 skin giocabili del barbone (4 M + 4 F) con drunk e sync multiplayer via NetworkManager + selezione personaggio all'avvio run, rigenerazione dei 18 archetipi NPC con varianti/female/drunk (mappa animali invariata da NPCDatabase) + i 4 legendary mai disegnati, edifici per distretto con stato notte a finestre illuminate (crossfade su GameState.is_night()) e sistema personalizzazione tetti (BuildingDecorator.gd: motore/HVAC, camino, antenna, parabola, serbatoio, panni stesi… deterministici da seed mappa), terreno da texture squadrate a Wang tilesets 32px con transizioni (WorldGenerator v6 su TileMapLayer), prop/icone di gioco, gatto quadruped con stati dance/fight/fly/sleep. Stile "evoluzione moderata" con i raw attuali come sample/reference (style_images dove il tool li supporta), STYLE ANCHOR unico, manifest.json degli id PixelLab, stime budget per fase con GATE di approvazione Ivan, QA (autotest, LFS, MP determinismo). UI/font esclusi (restano in U1). Decisioni fissate con Ivan 2026-07-07; puntatore aggiornato in PIANO_SVILUPPO_V2.md.

OPUS_BRIEFS/: brief autosufficienti per eseguire il piano V2 in chat nuove con Opus2026-07-07

  • [docs] Nuova cartella OPUS_BRIEFS/ con 6 brief pensati per chat fresche di Claude Opus (zero contesto pregresso): 00_CONTESTO_PROGETTO.md (gioco, struttura repo, autoload, convenzioni changelog/MP/tutorial, autotest, guardrail) + un brief per sprint (R1_RUN_30_MINUTI, R2_XP_E_CARTE, R3_META_E_ENDLESS, U1_RESTYLE_UI_CARTONE, U2_AUDIO_E_CONTENUTI). Ogni brief: prompt di avvio copia-incolla per Ivan, spec con anchor reali del codice (costanti/segnali/file verificati), guardrail, criteri di accettazione con comandi di test, decisioni aperte con default, e sezione STATO AVANZAMENTO da appendere a fine sprint per passare il testimone alla chat successiva. Puntatore aggiunto in PIANO_SVILUPPO_V2.md.

PIANO_SVILUPPO_V2.md: roadmap "La città è l'arena" (run 30' stile VS senza combat + restyle UI cartone)2026-07-07

  • [docs] Nuovo PIANO_SVILUPPO_V2.md: piano concordato con Ivan — run a tempo di 30 minuti (3 giorni di gioco) chiusa dalla "Grande Retata" ineluttabile stile Morte di Vampire Survivors; XP dalle attività di strada + carte perk a ogni level-up (riuso di RunManager/XPSystem/LevelUpScreen del prototipo arena); meta-progressione "La Baracca" con valuta LATTINE e sblocco ENDLESS ("Avvocato di strada"); restyle UI in pixel art "cartone, scotch e pennarello" via theme type variations + kit asset da generare (futuro UI_AI_PROMPTS.md). Ordine: R1 run → R2 carte → U1 UI → R3 meta → U2 audio/contenuti. Supera PIANO_SVILUPPO.md (Sprint 1-2 completati; i sospesi audio e nemici tematici confluiscono in U2).

Vestito che salta in aria all'acquisto (negozio vestiti)2026-06-13

  • [feature] 9 sprite clothes_1..9.png (16×16) importati in assets/sprites da sprites_raw/clothes: 3 magliette, 2 jeans, 4 scarpe. Chroma key magenta rimosso → sfondo trasparente, autocrop e resize nearest mantenendo le proporzioni
  • [feature] Player.gd: array _fx_clothes_tex caricato in _ready; nuova spawn_clothes_fx() che pesca una variante random (pick_random) e la fa volare in alto col solito _spawn_item_fx (stessa animazione del panino)
  • [feature] Interactable.gd _use_clothes_store: spawn del vestito random + suono provvisorio dello shelter (play_sfx_shelter) al posto del vecchio play_sfx_wash (placeholder finché non c'è un SFX dedicato)

Freccia verde sopra gli interactable buildings2026-06-12

  • [feature] Interactable.gd: Polygon2D verde triangolare creato a runtime in _ready su tutti i tipi tranne SHELTER e CAT
  • [feature] Bob verticale animato (sin) in _process; freccia nascosta durante il cooldown dell'oggetto
  • [feature] Export arrow_offset_y (default -32) per aggiustare l'altezza per tipi più alti

Manuale libretto A3: versione bianca risparmio inchiostro2026-06-12

  • [docs] MANUALE_GIOCATORE_A3_LIBRETTO_BIANCO.pdf: identico al libretto A3 ma con facciata esterna su sfondo bianco (fogli sottili non si imbarcano, meno inchiostro). Skyline grigio chiaro, testi pixel gialli con contorno navy, codice a barre bordato
  • [docs] build_manuale_pdf_a3.py ora parametrizzato sui temi (scuro/bianco): genera entrambe le versioni in un colpo solo

Manuale: versione libretto A3 + rifiniture v22026-06-12

  • [docs] MANUALE_GIOCATORE_A3_LIBRETTO.pdf: versione da stampare su A3 orizzontale fronte-retro (lato corto) e piegare a metà. Fuori: copertina dalla splash del gioco + retro con gatti volanti sparsi, luna e finto codice a barre. Dentro: le 2 pagine A4 del manuale identiche all'originale
  • [docs] build_manuale_pdf_a3.py: script generatore del libretto (richiede manual.pdf dalla v A4)
  • [docs] Manuale A4 v2: tasti controller (A/X/Y) accanto ai tasti tastiera, muro di 5 passanti per l'elemosina, icone centrate, rifugio "riapre dopo 10 minuti", riga G impostata sul lancio del gatto, barbone ubriaco a fine pagina 2, header con barbone trombettista + gatto che balla

Manuale del giocatore in PDF (2 pagine)2026-06-12

  • [docs] Creato MANUALE_GIOCATORE.pdf nella root: manuale per nuovi giocatori con comandi, barre, cibo/sonno/igiene, soldi, gatto, polizia, sbronza, ondate meteo, game over e punteggio pesato. Grafica con sprite del gioco (sprites_raw) e titoli in pixel-font
  • [docs] Aggiunto build_manuale_pdf.py (script generatore, reportlab+PIL): rieseguirlo per rigenerare il PDF dopo modifiche al gioco. Nota: i path interni puntano alla sandbox Cowork, da adattare se eseguito altrove

Priorità beg su interact: il press non attiva Interactable se c'è un NPC beggable vicino2026-06-12

  • [fix] EventBus.gd: aggiunto flag interact_consumed: bool (resettato ogni frame da Player)
  • [fix] Player._handle_interact(): setta interact_consumed = true quando consuma il press per il beg
  • [fix] Interactable._process(): controlla EventBus.interact_consumed prima di chiamare _use() — se true, salta il frame

Big notifications per cibo, igiene e riposo2026-06-12

  • [feature] Interactable.gd: tutti gli esiti di consumo ora usano EventBus.big_notify invece di notify
  • [feature] Panchina: "💤 Pisolino sulla panchina +30 riposo"
  • [feature] Fontana: "🚿 Lavato alla fontana +25 igiene"
  • [feature] Bidone — cibo: "🥪 Panino trovato nel bidone +25 fame"; monete: "🪙 Trovato $1 nel bidone!"; vuoto: "🪰 Solo mosche..."
  • [feature] Food van: "🌭 Hot dog! +fame massima -$X"
  • [feature] Ice cream van: "🍦 Gelato! +50 fame -$X"
  • [feature] Liquor store: "🍷 Salute! +50 fame -$X" / "🍷 Glug glug... ora sei ubriaco!"
  • [feature] Clothes store: "👕 Vestiti nuovi! +igiene massima -$X"
  • [note] Stato precedente: bench/fountain senza notifica; shop usavano EventBus.notify (testo piccolo in alto); soup_van già usava big_notify (invariato)

Fix shelter zone: ombra attiva solo dentro la pensilina2026-06-12

  • [fix] WorldGenerator.gd _add_bus_stop: ShelterZone ristretta a W-20 × DEPTH-4 (era W+8 × DEPTH+28) così il tint ombra si attiva solo quando il player è effettivamente dentro, non ai lati

Shelter shade: ombra pensilina sullo sprite player2026-06-12

  • [feature] SHELTER_SHADE_COLOR (blu-teal Color(0.55, 0.72, 0.85)) + _was_sheltered in Player.gd
  • [feature] _update_shelter_shade_visual(): tween 0.35s su sprite.modulate all'entrata/uscita da ShelterZone (via GameState.is_sheltered)
  • [feature] _compute_sprite_base_color(): compone shelter shade × drunk color così i due effetti coesistono senza sovrascriversi
  • [refactor] _update_drunk_visual() aggiornato per usare _compute_sprite_base_color() invece di Color.WHITE hardcoded

Come leggere le date: le voci di oggi (2026-06-11) hanno data e ora precise.

Le voci più vecchie sono ricostruite dalle note di progetto: la data (giorno) è

attendibile, l'ora non era registrata e quindi è omessa. Dove un giorno ha avuto

più sessioni, le voci sono in ordine logico ma non cronometrato.

> Formato per le voci future — in cima si aggiunge sempre la voce più recente.

> Schema: ### AAAA-MM-GG — Titolo breve seguito (se nota) da _HH:MM_.

> Sotto, un elenco puntato con: cosa è cambiato, il file toccato tra backtick,

> e (se utile) il perché. Tag [fix], [feature], [tuning], [refactor],

> [asset], [docs] a inizio riga per scansione veloce.

> Esempio: - [tuning] BUSK_COOLDOWN 120s → 90s in \Player.gd\ (troppo punitivo nei playtest).

## 2026 — Giugno

Punteggio pesato per azioni (v3) + pagina Opzioni2026-06-11

_18:17_

  • [feature] Nuovo sistema di punteggio pesato: ogni azione di gioco vale punti, non solo i soldi. Nuovo autoload scripts/autoload/ScoreSystem.gd (registrato in project.godot): pesi in WEIGHTS — gatto vs polizia +150, panchina nuova +40, busking +25, pasto dal cestino +20, dormita/fontana +15, elemosina riuscita +10, drink +10. Componenti live: $1 guadagnato = 2 pt, giorno completato = 500 pt, reputazione positiva = 5 pt/punto. Toast "+N PT" per le azioni ≥40 pt.
  • [tuning] Gatto vs civile, scoreggia e arresto non danno né tolgono punti (pesi commentati in WEIGHTS): l'arresto come malus è da rivalutare più avanti.
  • [feature] Le panchine contano UNA volta ciascuna (instance id univoco per run): esplorare paga, dormire 10 volte sulla stessa no.
  • [refactor] GameState.compute_survival_score() ora delega a ScoreSystem.compute_total() (fallback alla vecchia formula giorni·1000+soldi+rep·10 se l'autoload manca). start_run() azzera i contatori; anche il restart in HUD.gd chiama reset_run().
  • [feature] Nuovi segnali in EventBus.gd: cat_hit_police(pos) (emesso da CatProjectile.gd quando stordisce un agente) e bench_used(bench_id) (emesso da Interactable._use_bench()).
  • [feature] Game over: riga "Imprese:" con le 3 azioni più redditizie della run (_build_gameover_body in scripts/ui/HUD.gd).
  • [feature] Pagina OPZIONI nel menu principale (scripts/ui/MainMenu.gd): nuova voce dopo COMANDI. Per ora un solo tasto "RESETTA STATISTICHE" con doppia conferma (si arma per 3 s, seconda pressione cancella tutti gli high score via HighScore.reset_all(), nuova funzione). Funziona con tastiera (E/Invio), pad (A) e touch/mouse.

Invertite posizioni: nome zona in basso, messaggi in alto2026-06-11

_17:54_

  • [tuning] (esperimento) Scambiate le posizioni a schermo: il DistrictLabel (nome zona + reputazione) passa da top-center a bottom-center in scenes/ui/HUD.tscn (anchor bottom, offset_top -34 / offset_bottom -10). I toast notifica passano da bottom-center a top-center e ora impilano verso il basso: in scripts/ui/HUD.gd _create_notif ancora top, NOTIF_YBASE (-10) → NOTIF_YTOP (34), _reposition_notifs riscritta.

Freccia riparo sempre gialla2026-06-11

_17:48_

  • [tuning] La freccia che indica il riparo durante le ondate è ora sempre gialla (Color(1.0, 0.85, 0.2)), invece di rossa per il caldo / azzurra per il freddo. Serve solo a mostrare DOVE è la pensilina. In _update_shelter_arrow() (scripts/player/Player.gd); ws.wave_kind() non più usata lì.

Busking: una donazione a testa (due col gatto) + lockout2026-06-11

_17:30_

  • [tuning] Durante il busking la gente ora dona una sola volta, due volte se hai un gatto addosso. In scripts/npc/NPC.gd: rimpiazzato BUSK_MAX_DONATIONS con BUSK_MAX_DONATIONS_BASE (1) / BUSK_MAX_DONATIONS_CAT (2) + helper _busk_max_donations() che legge GameState.has_cat.
  • [feature] Quando un NPC esaurisce le donazioni se ne va e resta non-elemosinabile per il solito tempo, come dopo un'elemosina normale. busk_donate() ora ritorna bool (esausto); Player._collect_busk_tips() segna l'NPC in _recently_begged con BEG_COOLDOWN_TIME (8s). Vale anche per i ModularNPC (ereditano).

Fermata a "U capovolta": muri su tre lati2026-06-11

_17:20_

  • [feature] La pensilina ora ha muri solidi (StaticBody2D, collision_layer 1) su retro e due fianchi; il fronte (verso la camera) resta aperto → si entra solo da davanti, apertura ~56px. In _add_bus_stop (scripts/world/WorldGenerator.gd) + nuovo helper _add_local_wall() (muro rettangolare in coordinate locali, figlio del root della fermata). Spessore WALL_T 6px. La ShelterZone invariata copre l'interno.

Busking: muoversi interrompe l'esibizione (con grace iniziale)2026-06-11

_17:16_

  • [tuning] Ripristinata l'uscita dal busking col movimento in scripts/player/Player.gd: ora basta muoversi per smettere (oltre a ripremere il tasto), così durante un inseguimento della polizia si scappa naturalmente. Aggiunta una finestra di protezione BUSK_MOVE_GRACE (0.4s) all'inizio in cui il movimento NON interrompe, per evitare lo stop accidentale appena premuto il tasto. Nuovo _busk_elapsed; alla cancellazione per movimento il movimento è applicato già nello stesso frame. Notifica aggiornata ("... o muoviti per fermarti").

Countdown ondate ridotto e durata dimezzata2026-06-11

_17:05_

  • [tuning] Ondate caldo/freddo: preavviso WAVE_WARNING_LEAD 30s → 20s e finestra di pericolo WAVE_DURATION 10s → 5s in scripts/autoload/WeatherSystem.gd. UI, barra evento e debug derivano dalle costanti, quindi si aggiornano da sole.
  • [docs] Allineati due commenti che citavano "30s" (in WeatherSystem.gd e scripts/autoload/DebugPanel.gd).

Fermata con profondità + niente sovrapposizioni2026-06-11

_17:00_

  • [feature] Ridisegnata la pensilina (_add_bus_stop in scripts/world/WorldGenerator.gd) con profondità: pavimento/pedana a due tonalità (retro in ombra, davanti chiaro), parete di fondo, pali corti dietro e lunghi davanti per la prospettiva, tettoia con bordo frontale e ombra a terra. È un placeholder finché non arriva lo sprite dedicato.
  • [feature] La ShelterZone ora copre tutta la pedana (più margine), così basta entrarci sotto per ripararsi.
  • [fix] Le fermate vengono piazzate per prime e registrate in _bus_stop_spots; panchine e cestini (piazze + marciapiedi) scartano qualsiasi posizione entro BUS_STOP_CLEAR (60px) tramite il nuovo helper _too_close_to_bus_stop(). Niente più bidoni/panchine sopra la fermata.

Barra durata del busking2026-06-11

_16:50_

  • [feature] Durante il busking compare una barretta sopra la testa del barbone che si svuota lungo i 12s dell'esibizione, virando dal giallo al rosso negli ultimi istanti. Due ColorRect creati a runtime in scripts/player/Player.gd (costanti BUSK_BAR_W/H/Y), mostrati in _start_busking, aggiornati in _handle_busking, nascosti in _stop_busking.

Fix playtest (run gate, busking, freccia riparo)2026-06-11

  • [fix] GameState.run_active (false nel menu) blocca decay di stat/tempo/meteo/difficoltà finché non si preme Start. GameState.start_run() chiamato da World._ready() e Arena._ready(); gate anche in DifficultyManager e WeatherSystem._process.
  • [fix] Cartello shelter: controller.z_index = int(rect.end.y) in WorldGenerator._build_shelter → i pedoni dietro l'edificio non coprono più cartello/tetto.
  • [feature] Busking come "superpotere": BUSK_DURATION 12s, BUSK_COOLDOWN 120s (da tarare), mancia ogni 2s via NPC.busk_donate() (prob 52-87% su generosità, $2-6, max 2 donazioni/sessione). Niente più interruzione muovendosi: si ferma solo ripremendo il tasto o a fine durata.
  • [feature] Freccia _shelter_arrow (Polygon2D) in Player.gd che punta al riparo più vicino durante warning/active dell'ondata (rossa per caldo, azzurra per freddo).
  • [feature] HighScore v2: top 10 con nome, qualifies() + add_entry(), migrazione v1. Nuovo scripts/ui/NameEntry.gd (selettore arcade 3 iniziali). MainMenu v2 a schermate con stack (INIZIA PARTITA / HIGH SCORES / COMANDI).
  • [fix] Typo "Barcolli troppo" corretto in Interactable.gd.
  • [docs] SPRINT2_AI_PROMPTS.md creato nella root: prompt ChatGPT (pensilina, clothes store, tossico, spazzino, gattara, bulli, bidone, panchina) + ElevenLabs (allarmi stat, trombetta loop, fail) + checklist.

## 2026 — Maggio

Sprint 1 del PIANO_SVILUPPO + ristrutturazione repo2026-05-31

  • [tuning] Wanted bar: recupero reputazione scalato (1+|rep|/25) indipendente dal boost; REPUTATION_RECOVER_INTERVAL 20s → 6s, WANTED_DECAY_GRACE 30s → 12s in HUD.gd.
  • [tuning] Fontana wash 40 → 25.
  • [feature] Nuovo Interactable.Type.CLOTHES_STORE (costo $40, igiene → 100), spawn via BlockKind.CLOTHES in WorldGenerator (placeholder palazzo + label "VESTITI").
  • [feature] Triangolo rosso (Polygon2D) sopra la polizia in chase, lampeggiante in warn, runtime in PoliceOfficer.gd.
  • [feature] Nuovo segnale EventBus.stat_threshold_crossed(stat, level): GameState emette al crossing 50/25 di fame/energia; HUD fa pulse barra + audio (hook audio in sospeso: sfx_warn_soft/alarm, sfx_danger, sfx_busk).
  • [refactor] Radice git spostata da files/homeless_city/ a livello progetto Homeless Game/; sprites_raw/ + Sounds_raw/ versionati via Git LFS; .gitignore/.gitattributes in radice. Tag v0.4-sprint1.
  • [feature] Sprint 2 (tag v0.5-weather-shelters): ondate in WeatherSystem (preavviso 30s + finestra 10s, −5%/s a tutte le stat se scoperti), GameState.is_sheltered, nuovo ShelterZone.gd, fermate bus + rifugio come ripari, segnali weather_warning/wave_started/wave_ended, pulsanti ondate in DebugPanel.

Allineamento sprite mondo + varietà palazzi + shelter2026-05-30

  • [fix] [asset] Fontana/camion: eliminati drift orizzontale e bleed tra frame; nuova pipeline "fixed-window ancorato" in tools/import_buildings_sprites.py (drift 0px). Fountain anim/off riscalati per avere la vasca alla stessa larghezza renderizzata (swap piena↔vuota senza salto).
  • [fix] [asset] shelter_transition riallineato (6 frame a 0px), shelter_sign ingrandito a 40×20, shelter_timer_bg a 48×18 poi 50×20; buco trasparente interno riempito con pannello LED spento e bordo magenta ricolorato in bezel scuro (niente più magenta visibile). Shelter.tscn ricalibrato (Sign/TimerBg/TimerLabel).
  • [feature] Varietà palazzi: WorldGenerator._build_building riscritto — i superblocchi suddividono il footprint in sotto-celle e ogni cella pesca un palazzo indipendente via pick_building_for(district). Nuovo _place_building_sprite() (Sprite2D ancorato alla base, mai upscale).
  • [asset] Tutti i 19 building_*.png ritagliati al contenuto (dimensioni native varie); backup in outputs/_backup_buildings.

Sistema edifici: scaffolding + asset Fase 12026-05-28

  • [feature] Implementato lo scaffolding edifici (Settimana 1, 37/37 check): nuovi BuildingDatabase.gd (autoload), AnimatedBuilding.gd + scena, ShelterController.gd + Shelter.tscn, tools/import_buildings_sprites.py. Patch a Interactable.gd, WorldGenerator.gd, DebugPanel.gd, project.godot. Il gioco continua a funzionare senza nuovi asset (fallback alle texture esistenti).
  • [asset] Importati 41 PNG (Settimane 2-4): 19 building variants su 7 quartieri, 3 landmark (bank/church/factory), shelter (transition 3 frame + sign 2 frame + timer_bg), fountain (anim 3 + off), vehicles (hotdog 2 frame + icecream 3 frame), props animati (roof_fan/chimney_smoke/manhole_steam), 7 neon, 2 flag.
  • [feature] Manifest statico scripts/autoload/buildings_manifest.gd (fix export iOS, DirAccess non lista res:// su build). Nuovo Interactable.Type.ICE_CREAM_VAN ($10, mezza vita stile vino); _build_hot_dog_block fa 50/50 hot dog vs gelato.

Sistema edifici: design2026-05-27

  • [docs] Progettato il sistema edifici parallelo a quello NPC: BUILDINGS_SYSTEM_DESIGN.md (roadmap 3 fasi), BUILDINGS_AI_PROMPTS.md (prompt ChatGPT con ABSOLUTE RULE anti-label/grid + palette quartieri), BUILDINGS_IMPLEMENTATION.md (codice GDScript completo + patch). Risolve: edifici monotoni, shelter illeggibile, mancanza di feedback "chiuso/quanto manca", mondo statico.

Sistema NPC modulare: design + iterazioni prompt + import 82 sprite2026-05-24

  • [feature] Progettato sistema NPC modulare ("molti NPC con pochi asset"): ModularNPC.gd (extends NPC.gd), autoload NPCDatabase.gd (17 archetipi), DistrictSpawner.gd, shader palette_swap.gdshader (recolor maglia/pantaloni via marker color), 7 district pool pesati. Docs: NPC_SYSTEM_DESIGN.md, NPC_AI_PROMPTS.md, NPC_IMPLEMENTATION.md.
  • [docs] Iterazioni style anchor dei prompt (v2 → v3.3) dopo i test di generazione: ombra dinamica come asset separato, proporzioni "non-chibi", layout righe S/N/E/SE/NE, regole drunk variant (solo testa animale), ABSOLUTE RULE anti-label/grid, orientation cheat sheet E/W, sezione TROUBLESHOOTING con frasi pronte.
  • [feature] [asset] Batch import di 82 sprite (v4, 2026-05-27): nuovo tools/import_people_sprites.py, refactor NPCDatabase multi-variant + gender (discover_variants, pick_variant_for), ModularNPC.apply_archetype() usa le varianti, swap sprite del gatto sul player via GameState.has_cat (property + signal). 83 sheet generati.

Pipeline sprite2026-05-22

  • [asset] Definita la pipeline sprite: source in sprites_raw/ (1254×1254, sfondo magenta, griglia 5×5 o strip 4 frame), processati con tools/import_chatgpt_sprites.py, output assets/sprites/*_sheet.png (32px/cella), SpriteFrames .tres via tools/gen_sprite_frames.py. Aggiunti npcdrunk/policedrunk, homelessmusic/catdance.

Direzione roguelike + Milestone 1 (loop VS-like)2026-05-20

  • [feature] Scelta direzione roguelike stile Vampire Survivors, tono assurdo cartoonesco; le stat fame/energia/igiene diventano soft constraint (debuff, non morte).
  • [feature] Milestone 1 su branch dev: autoload RunManager (timer 15min, fasi calma→boss) e XPSystem; classi base Weapon/BottleWeapon, Projectile, Enemy + varianti, Pickup/CoinPickup, RunPlayer, WaveManager; UI RunHUD / LevelUpScreen / RunEndScreen; Arena.tscn. Layer collision: 1=player, 2=enemy, 4=projectile, 8=pickup, 16=boundaries. Tag locale v0.1-survival-base.
  • [feature] Curva di difficoltà time-based (autoload DifficultyManager, tier 0-3 su 30min), DebugPanel (F1, slider stat/meteo/tier/skip time), big notifications via EventBus.big_notify(). Feedback dal tester Valerio Grosso (fame troppo veloce, notifiche poco visibili, troppe panchine).

RIENTRI ATTESI (messi In revisione il 2026-08-14, sprint notturno): SU-393, SU-406, SU-407, SU-411, SU-412, SU-413, SU-414, SU-415.

ESITO RIENTRI dei giri precedenti, misurato all'apertura di questo: del lotto 13/08 (SU-388, SU-389, SU-392, SU-395, SU-396) nessuno tornato in «Da fare»; del giro serale 14/08 erano invece rientrati KO in giornata SU-393, SU-406 e SU-407 — rilavorati qui.

NON LAVORATI in questo giro, di proposito: SU-409 (il ticket prescrive design live con Ivan), SU-410 (arte già generata, aspetta solo l'occhio di Ivan sul foglio di contatto), SU-381 (fermo: manca la scelta del quartiere per il lampione, proposta nel commento).

RIENTRI ATTESI (messi In revisione il 2026-08-15, giro KO del mattino): SU-393 (3º giro), SU-406, SU-410, SU-412.

ESITO RIENTRI misurato all'apertura di questo giro: dello sprint notturno 14/08 (8 chiavi attese) sono rientrati KO in mattinata SU-393, SU-406 e SU-412 — tasso 3/8; più SU-410, che era fermo sull'occhio di Ivan e ha preso un KO invece del «Fatto». Tutti e 4 rilavorati qui. Non rientrati: SU-407, SU-411, SU-413, SU-414, SU-415.

NON LAVORATI in questo giro, di proposito: SU-409 (il ticket prescrive la sessione di design dal vivo con Ivan) e SU-381 (fermo: manca la scelta di quale quartiere si prende il lampione del parco all'imbrunire — proposta LA COLLINA nel commento del 14/08, senza risposta).

ESITO RIENTRI misurato all'apertura del secondo giro 15/08 (~9:40): delle 4 chiavi del giro del mattino (SU-393 3º giro, SU-406, SU-410, SU-412) nessuna era rientrata in «Da fare» — zero KO al momento del check.

RIENTRI ATTESI (messi In revisione il 2026-08-15, secondo giro): SU-381 (lavorato stavolta: la condizione è caduta e il lampione è andato alla COLLINA come da proposta), SU-426. NON LAVORATO di proposito: SU-409 (aspetta la sessione di design dal vivo con Ivan).

ESITO RIENTRI misurato all'apertura del terzo giro 15/08 (~21:50): delle 2 chiavi del secondo giro (SU-381, SU-426) nessuna è rientrata — 0 su 2. Del giro KO del mattino (SU-393, SU-406, SU-410, SU-412) ne sono invece rientrate 2 su 4: SU-406 e SU-410, entrambi ticket di generazione arte, dove Ivan itera sul risultato visivo. Lettura onesta: il codice regge, l'arte torna indietro — e torna indietro perché è giusto che lo faccia, non perché sia lavorata male.

RIENTRI ATTESI (messi In revisione il 2026-08-15, terzo giro serale): SU-406 (4º giro), SU-410 (3º giro), SU-416, SU-417, SU-418, SU-419, SU-420, SU-421, SU-423, SU-427, SU-428. NON LAVORATI di proposito: SU-409, SU-424 e SU-425 — sono i tre ticket DESIGN che prescrivono progetta-feature e pretendono le risposte di Ivan; su SU-424 e SU-425 è stata comunque fatta e commentata la verifica nel codice che i ticket stessi chiedono. SU-422 resta bloccato dal «Fatto» di Ivan su SU-421.

ESITO RIENTRI misurato all'apertura di questo giro (2026-08-16, notte): delle 11 chiavi messe In revisione il 15/08 nel terzo giro serale (SU-406, SU-410, SU-416, SU-417, SU-418, SU-419, SU-420, SU-421, SU-423, SU-427, SU-428) ne sono rientrate in «Da fare» 4: SU-416, SU-418, SU-423 e SU-427 — tasso 4/11. Le altre sette non sono tornate indietro. Lettura onesta: due dei quattro rientri (SU-423, SU-426) non erano difetti del codice ma la mancanza di una PROVA — il multiplayer locale era dichiarato incollaudabile per ragioni d'ambiente che non esistevano. Gli altri due erano difetti veri di lettura del requisito.

RIENTRI ATTESI (messi In revisione il 2026-08-16, giro notturno): SU-416, SU-418, SU-423, SU-424, SU-425, SU-426, SU-427.

NON LAVORATI in questo giro, di proposito: SU-409 (le sue 6 domande di design sono ancora senza risposta di Ivan: senza quelle si potrebbe solo inventarle) e SU-422 (il ticket stesso si dichiara bloccato finché SU-421, la generazione delle carnagioni, non è «Fatto» — è ancora «In revisione», e il «Fatto» lo mette solo Ivan).

ESITO RIENTRI misurato all'apertura del secondo giro 16/08 (~3:30, notte fonda): delle 7 chiavi del giro notturno (SU-416, SU-418, SU-423, SU-424, SU-425, SU-426, SU-427) ne sono rientrate in «Da fare» 2: SU-418 e SU-424 — tasso 2/7. Promossi a Fatto da Ivan: SU-416, SU-423, SU-427 (più SU-417, dal giro dei KO iPhone). Restano In revisione senza rientrare: SU-425 e SU-426. Lettura onesta: entrambi i rientri sono ticket dove il giro precedente aveva visto il problema e l'aveva lasciato agli atti come domanda aperta invece di chiuderlo — su SU-418 il «se lo vuoi immediato dimmelo», su SU-424 la scorciatoia della guideline 4.8. Non è un difetto di esecuzione, è l'abitudine di consegnare una scelta al posto di una soluzione: quando la risposta prevedibile è «sì, fallo», va fatta.

RIENTRI ATTESI (messi In revisione il 2026-08-16, secondo giro): SU-406 (5º giro), SU-414 (2º giro), SU-418 (3º giro), SU-424 (2º giro), SU-429, SU-430, SU-434, SU-435.

NON LAVORATI in questo giro, di proposito: SU-409 (le 6 domande di design aspettano ancora le risposte di Ivan) e SU-422 (bloccato finché SU-421 non è «Fatto»: è ancora «In revisione», e il «Fatto» lo mette solo lui — motivo commentato sul ticket). SU-431 e SU-432 non sono stati implementati perché dipendono dallo spike SU-429, ma le loro descrizioni sono state riscritte su Jira secondo il KO di SU-424; sono nati da lì SU-436, SU-437 e SU-438.

GLI «IN CORSO» RIMASTI A METÀ, guardati come vuole il perimetro della fase e non solo i «Da fare» — erano tre e due avevano lavoro vero ancora possibile: SU-408 aveva la meccanica in gioco dal 14/08 e aspettava una prova MP che credevamo impossibile: fatta stanotte, resta In corso solo per l'arte di SU-410. SU-378 aveva tre modelli dati da Ivan il 14/08 alle 18:58, dopo il nostro ultimo aggiornamento delle 17:37: due erano già registrati, il terzo no ed è stato censito; resta In corso perché il deliverable è il numero finale e mancano 14 risposte su 34. SU-302 resta fermo, ma il suo blocco si è mosso e gliel'ho scritto: non aspetta più le pavimentazioni (ci sono tutte), aspetta la riga di Ivan su *cosa* non va nei lampioni attuali.

DUE COSE CHE ASPETTANO UNA RISPOSTA DI IVAN, e senza le quali due ticket restano a metà: (1) su SU-429 tre criteri su quattro vivono nel Dev Portal EOS o in un login Epic interattivo — la sonda è scritta e le tre azioni sono elencate nel commento, ma le credenziali le mette sempre lui; (2) su SU-414 il criterio del JSONL su emulatore è BLOCCATO-AMBIENTE dopo tre ipotesi smentite, e la scelta fra device reale e aggancio di sviluppo FORCE_RUN è sua.

ESITO RIENTRI misurato all'apertura di questo giro (2026-08-17, mattina): delle 8 chiavi messe In revisione il 16/08 nel secondo giro (SU-406, SU-414, SU-418, SU-424, SU-429, SU-430, SU-434, SU-435) è rientrata in «Da fare» 1 sola: SU-418 — tasso 1/8, il migliore finora. E quel rientro non era un difetto di esecuzione: è il GDPR che ha cambiato il requisito. Promossi a Fatto da Ivan: SU-406, SU-434, SU-435. Restano In revisione senza rientrare: SU-414, SU-424, SU-429, SU-430.

Lettura onesta, però: il tasso di rientro basso NON significa che il giro precedente fosse buono. Questo sprint ha trovato tre difetti veri in codice che il giro di stanotte aveva dichiarato funzionante — il login Epic che non entrava in EOS Connect, il trasporto del PUID rovesciato (avrebbe cancellato le classifiche a ogni accesso), e la telemetria che non consegnava un solo file. Nessuno dei tre era rientrato come KO, perché nessuno dei tre era provabile da Ivan su device: erano tutti dietro a un «NON MISURATO» che noi stessi avevamo scritto. Il tasso di rientro misura solo ciò che Ivan può vedere.

RIENTRI ATTESI (messi In revisione il 2026-08-17, giro del mattino): SU-413, SU-418 (6º giro), SU-431, SU-432 (3º giro), SU-436, SU-437, SU-441.

NON LAVORATI in questo giro, di proposito: SU-409 (quinta volta — il ticket pretende le risposte di Ivan alle sue sei domande di design, e in autonomia si potrebbero solo inventare: proposto di spostarlo fuori dallo sprint finché non c'è una data) e SU-422 (bloccato finché SU-421 non è «Fatto»: è ancora In revisione, e il «Fatto» lo mette solo lui).

APERTO IN BACKLOG: SU-442 — i quattro simulatori mobile non eseguono il gioco (iOS non installa per un problema di architettura, Android si blocca dopo il menu con QueuePresentKHR failed, riprodotto in isolamento). Finché resta aperto, ogni criterio «provato su iPhone/iPad/telefono/tablet» nasce NON MISURATO — ed è per questo che SU-431 ne porta uno.

TRE COSE CHE ASPETTANO IVAN: (1) l'ultimo passo misurabile di SU-431, bash tools/autotest/probe_su431.sh --trasporto --esegui-trasporto, il cui permesso è stato negato all'agente; (2) i token veri di Apple e Google, che richiedono un gesto umano sul pannello di sistema e un telefono con i servizi Google; (3) riaprire la cartella Box dei loghi EOS per riconfermare la provenienza dell'icona Epic, che non è dimostrabile su disco.

DUE COSE DA RIPULIRE QUANDO VUOLE: sul suo Drive ci sono 4 file di telemetria di prova in StreetU_telemetria/2026-08/, e sulla board SU_SCORE_CENTRO c'è un punteggio di prova (1234 pt, account «ITA_Blackwind») che con aggregazione Max non si abbassa più.

⚠️ UNA COSA DA FARE PRIMA DI RILANCIARE IL GIOCO: nella coda locale ci sono 2 .jsonl da partite vere del 16/08 con consent=true. Le prove sono state fatte con una HOME dedicata per non spedirli a sua insaputa, ma ora che la coda funziona partiranno al prossimo avvio: se non li vuole mandare, vanno tolti da user://telemetria/ prima.

ESITO RIENTRI misurato all'apertura di questo giro (2026-08-17, notte): delle 7 chiavi messe In revisione stamattina (SU-413, SU-418, SU-431, SU-432, SU-436, SU-437, SU-441) è rientrata in «Da fare» nessuna — tasso 0/7. Promossi a Fatto da Ivan: SU-413, SU-418, SU-432, SU-436. SU-431 resta In revisione.

Lettura onesta, però, la stessa di stamattina e vale ancora: il tasso di rientro misura solo ciò che Ivan può vedere. Tre dei cinque ticket di stanotte portano un NON MISURATO che nessun KO potrebbe scoprire, perché sta dietro a un login con token veri o a un device — non dietro a un difetto di codice.

RIENTRI ATTESI (messi In revisione il 2026-08-17, giro notturno): SU-444, SU-445, SU-446, SU-447, SU-448 — cioè lo sprint intero, che era il giro dei nickname dall'inizio alla fine.

GLI «IN CORSO», guardati come vuole il perimetro della fase e non solo i «Da fare»: erano tre e nessuno aveva lavoro tecnico possibile stanotte. SU-378 aspetta risposte di persone (il deliverable è un numero e mancano le risposte dei tester). SU-449 e SU-451 sono stati lavorati poche ore fa nei giri precedenti e i loro blocchi sono già scritti sui ticket: aspettano device e gesti di Ivan, non codice.

⚠️ DUE CONDIZIONI DI RILASCIO CHE NASCONO DA QUESTO GIRO, e che valgono per la release, non per lo sviluppo: (1) SU-445 va rilasciato insieme a SU-449, perché fino a quel momento chi entra con Google o Apple si vede pubblicare il nome legale; (2) prima di rilasciare il gate di SU-447 la lista degli utenti di prova OAuth di Google dev'essere completa, altrimenti chi manca da quella lista non viene solo respinto al login — perde il multiplayer per intero, e il gioco sembra rotto.

📌 DUE MINI-TICKET PROPOSTI, non aperti in autonomia: allineare MainMenu.gd a OnlineLeaderboard.RIGHE_MENU (oggi il menu usa una costante locale a 6 e la board ne dichiara 8: per questo la distinzione degli omonimi usa la finestra da 5 di fine partita); e decidere se browse_lobbies() va gated come gli altri tre ingressi (oggi non lo è, ma non apre né entra in niente e dalla UI un ospite non ci arriva più).

✅ MISURATO SU DEVICE la notte stessa (Honor 10, 2026-08-17 22:54), e cade il NON MISURATO più importante dello sprint: [EOSBridge] LOGIN «google» riuscito — PUID: 0002f6a5… seguito da nome pubblico rifatto dentro EOS per «google». Cioè: il login Google con un token vero completa fino a EOS su un telefono vero, la schermata del nome pubblico compare vuota (nessun «IVAN BIANCO», che era il motivo per cui SU-445 è diventato una condizione di rilascio), e il nickname scelto entra dentro EOS rifacendo la login Connect.

⚠️ LA FIRMA DELL'APK NON È UN DETTAGLIO: il primo export, firmato in debug, è stato rifiutato dall'installazione per firma diversa — e sarebbe stato inutile comunque, perché quella SHA-1 non è registrata in Cloud Console e Google avrebbe respinto il login. La prova vale solo con un export release firmato streetuniversity_release.keystore (SHA-1 2133c059…). Chi rifà questa prova parta da lì.

⚠️ DIFETTO TROVATO DAL LOGCAT, annotato su SU-449: su Android il login Apple non partebad_arguments — La sessione web richiede sia «url» sia «scheme». È lo stesso buco che SU-449 ha chiuso per Google e non per Apple: dove Apple non è «di casa» il login deve passare dalla sessione web con PKCE, e nessuno costruisce url e scheme.

📌 UN BUCO DI OSSERVABILITÀ, non un difetto: il registro dei nickname non stampa niente nel log. Il claim su device è chiaramente riuscito (senza, il nome non sarebbe entrato in EOS), ma da un logcat non si distingue «il registro ha detto ok» da «il registro è stato muto». Al primo nickname che si comporta male su un telefono, questa mancanza costerà un giro.

ESITO RIENTRI misurato all'apertura di questo giro (2026-08-18, pomeriggio): delle 5 chiavi messe In revisione il 17/08 nel giro notturno (SU-444, SU-445, SU-446, SU-447, SU-448 — lo sprint intero dei nickname) è rientrata in «Da fare» nessuna: tasso 0/5, e tutte e cinque promosse a Fatto da Ivan. È il secondo giro di fila a zero rientri.

Lettura onesta, la stessa delle due volte precedenti e vale ancora: il tasso di rientro misura solo ciò che Ivan può vedere. Quelle cinque chiavi portavano un NON MISURATO dietro a un login con token veri o a un device, e nessun KO avrebbe potuto scoprirlo. Questo giro ne aggiunge uno dello stesso tipo (il multiplayer di SU-452 e SU-466, letto e non eseguito).

Vale però la pena notare che stavolta il difetto l'ha trovato una sonda, non Ivan: probe_su363.sh è diventata rossa da sola quando SU-466 ha alzato la soglia della banca sotto il minimo del bidone d'oro. Una regola di design scritta dentro un controllo automatico è l'unica che non dipende da chi guarda.

RIENTRI ATTESI (messi In revisione il 2026-08-18, giro del pomeriggio): SU-452, SU-458, SU-460, SU-463, SU-464.

IN CORSO, dichiarato parziale: SU-466 — fatte le parti 1 (soglia che raddoppia) e 2 (contatore sopra la banca), NON la parte 3 (l'arcobaleno che punta alla fermata della metro), perché le fermate non esistono ancora. Il ticket si chiude nel giro dopo l'approvazione dell'arte.

NON LAVORATI in questo giro, di proposito e per blocco scritto nel ticket stesso: SU-465 («BLOCCATO DAL TICKET DI GENERAZIONE SU-463: non si lavora finché quello non è Fatto — il Fatto di Ivan è l'approvazione dell'immagine»), SU-467 (stessa formula, bloccato da SU-464) e SU-468, che vive dentro la scena bonus di SU-467. L'arte che li sblocca tutti e tre è stata generata oggi ed è in attesa di approvazione: appena Ivan mette Fatto su SU-463 e SU-464, quei tre partono insieme.

⚠️ DUE COSE CHE ASPETTANO IVAN, ed è tutto ciò che serve per sbloccare il resto dello sprint: (1) la scelta del logo della metro fra le tre proposte di SU-463 (consigliato v1, il rombo con la M — è l'unico leggibile a 20×20); (2) la scelta della famiglia di segnali di pericolo fra le tre di SU-464 (consigliati i chevron: sono gli unici che dicono anche da che parte arriva il treno).

⚠️ UNA CONDIZIONE DI RILASCIO, non di sviluppo, notata durante il compile-check: all'avvio OnlineLeaderboard.gd:309 avvisa che il quartiere CENTRO è deviato su SU_TEST_CENTRO — scrive e legge su una board di prova, non sulla classifica vera. Prima del prossimo tag va rimesso BOARD_PROVA_CENTRO = "".

⚠️ UNO STATO DI PASSAGGIO DA NON DIMENTICARE: con la soglia della banca che raddoppia (100 → 200 → 400) ma il premio del bidone d'oro che non scala, dal secondo ciclo in poi il deposito è in perdita. È voluto per il disegno finale — dal secondo giro il premio vero sarà il livello bonus — ma finché SU-467 e SU-468 non esistono, quel buco è aperto nel gioco vero.

📌 IN ATTESA, NON MIO E NON DI QUESTO SPRINT: MUSICA_AI_PROMPTS.md ha 148 righe non committate da una sessione precedente (v1.1, la §12 coi prompt della musica di game over). Sembra finito ma non l'ho committato insieme allo sprint: non è lavoro di questi ticket e la decisione è di Ivan.

RIENTRI ATTESI (secondo giro del 2026-08-18, dopo le risposte di Ivan): SU-465, SU-466, SU-467, SU-468 — cioè la catena intera metro → livello bonus → premio. SU-463 e SU-464 sono già Fatto: l'arte l'ha approvata Ivan in chat (logo v1 col rombo, segnali chevron) e il Fatto l'ho messo io perché mi aveva chiesto di proseguire subito con i ticket che quell'approvazione sbloccava.

⚠️ COME SONO STATE RACCOLTE LE PROVE DI QUESTO SECONDO GIRO, perché cambia come vanno lette: cinque subagenti su sei sono morti per errori di API del server («Server error mid-response» ×2, «529 Overloaded» ×3). Tre erano a lavoro quasi finito e il codice era su disco; per SU-468 l'ultimo è morto senza aver scritto niente. Da lì in poi il lavoro è stato fatto inline dall'orchestratore — sonde, provini, suono e verifiche comprese. È un blocco d'ambiente, non un difetto del lavoro, ma spiega perché i report degli agenti mancano e le prove le firma l'orchestratore.

⚠️ IL RISCHIO APERTO DI QUESTO GIRO, uno solo e dichiarato: in SU-468 il tiro sui livelli e il premio della tabella d'oro aprono due cerimonie, e il ticket chiede che la sequenza sia «guardata davvero». Da headless non si può: serve un playtest a mano di Ivan. Tutto il resto è misurato.

📌 UNA DOMANDA APERTA A IVAN, piccola ma vale un cambio: nella tabella d'oro «livello» è una CARTA che sale di livello (PowerUpSystem), non il LIV dell'HUD (XPSystem). SU-468 dice «XPSystem» ma indica la strada di SU-248, che è quella delle carte: ho riusato quella, come chiedeva il divieto di inventarne una seconda. Se intendeva il livello del giocatore è un cambio piccolo.

RIENTRI ATTESI (messi In revisione il 2026-08-21, Sprint 10): SU-378, SU-449, SU-451, SU-469, SU-470, SU-471, SU-472, SU-473, SU-474, SU-475, SU-476, SU-477, SU-478, SU-479, SU-480, SU-481, SU-482, SU-483, SU-484, SU-485, SU-486, SU-488, SU-489, SU-490, SU-491, SU-492, SU-493, SU-494, SU-495, SU-496, SU-497, SU-498, SU-499, SU-500 — lo sprint INTERO, trentaquattro su trentaquattro. E' il lotto piu' grosso mai messo in revisione in un giorno solo: il tasso di rientro di queste chiavi e' l'unica misura che dira' se la parallelizzazione a otto agenti ha retto o ha solo spostato il lavoro piu' avanti. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

ESITO RIENTRI misurato all'apertura di questo giro (2026-08-21, sera), ed e' la prima volta che il numero dice qualcosa di nuovo: delle 34 chiavi messe In revisione in giornata — lo sprint intero, il lotto piu' grosso mai spedito in un giorno — ne sono rientrate in «Da fare» 6: SU-470, SU-471, SU-484, SU-489, SU-491, SU-492. Tasso 6/34 (18%), contro lo 0/7, 0/5, 0/2 dei giri precedenti. La parallelizzazione a otto agenti ha retto, ma non a costo zero.

⚠️ E il modo in cui sono rientrate conta piu' del numero: NESSUNA delle sei porta un KO scritto. Tutte e sei finivano con «DOMANDA PER IVAN», «TRE DOMANDE in fondo», o «NIENTE IMPLEMENTATO». Non sono ticket sbagliati: sono consegne incomplete, e Ivan non ha commentato perche' non c'era niente da bocciare. E' un modo di rientrare che i giri precedenti non avevano mai prodotto, e nasce direttamente dalla giornata a otto agenti: quando si spediscono 34 ticket in un giorno, cio' che resta indietro non e' il codice — sono le decisioni.

📌 La regola che ne discende, applicata oggi e da riapplicare: un rientro senza KO non si lavora come un KO. Se la domanda aveva un default gia' proposto, si applica il default, lo si scrive sul ticket come decisione tracciata e correggibile, e si chiude — non si blocca il giro aspettando. Se finiva con «niente implementato», vuole il rimedio, non una seconda analisi onesta. Se finiva con un NON PROVATO, il ticket che resta e' quella prova, non la feature. Solo il blocco che dipende davvero da Ivan (un asset, un device, un gusto) resta in «Da fare» — e prima di ripetere la domanda si verifica che il blocco esista ancora: oggi SU-489 e' stato l'unico, e l'mtime del raw ha confermato che il treno nuovo non e' mai arrivato su disco.

RIENTRI ATTESI (messi In revisione il 2026-08-21, giro serale): SU-470, SU-471, SU-484, SU-491, SU-492, SU-502, SU-503, SU-504 — otto chiavi, di cui sei sono secondi giri e due nuove nate dal collaudo di ieri sera. Da contare al prossimo giro, PRIMA di aprire lotti nuovi. ⚠️ Attenzione a come si leggera' questo numero: quattro delle otto portano un NON PROVATO che nessun KO di Ivan potrebbe scoprire, perche' sta dietro a un iPhone (SU-502, SU-484), a un telefono Android con build debug (SU-504), o a due decisioni di economia che sono sue e non nostre (SU-491). Un rientro a zero qui non significherebbe «tutto giusto».

NON LAVORATO, uno solo e con la ragione verificata: SU-489 (il treno della metro). Resta in «Da fare» perche' aspetta una riga di Ivan, non del lavoro: il raw sprites_raw/WORLD/subway_train.png ha mtime 2026-08-20 20:11, cioe' non e' cambiato dopo il giro di ieri — nessun treno nuovo e' arrivato su disco, e il «modificato» in git status e' il falso positivo LFS di sempre. La domanda aperta e' una sola: il treno piu' alto come nel raw, accettando che la rotaia vicina non cada piu' sul tetto?

📌 OTTO TICKET NUOVI NEL BACKLOG, non nello sprint (la selezione e' di Ivan): SU-505 → SU-512, i ticket di implementazione che chiudono i due (DESIGN) SU-470 e SU-471. Sulle sei domande aperte sono stati applicati i default gia' proposti nei documenti, scritti sui ticket come decisioni tracciate. ⚠️ Vincolo scritto dentro i ticket e da non perdere: SU-508 e SU-510 non si cominciano prima di SU-505 — senza nome di riserva, un nome in revisione lascia il giocatore FUORI dal multiplayer, che e' il difetto che quella catena chiude.

RIENTRI ATTESI (messi In revisione il 2026-08-22, Sprint 10, giro del pomeriggio): SU-484, SU-485, SU-490, SU-492, SU-523, SU-524, SU-525, SU-526, SU-527, SU-528, SU-529, SU-530, SU-531, SU-532, SU-533, SU-534, SU-535, SU-536, SU-537, SU-538 — venti chiavi su ventuno in perimetro, di cui quattro erano rientri (SU-484, SU-485, SU-490, SU-492). SU-539 non e' stato lavorato: e' bloccato per iscritto dal ticket di generazione SU-538, e quel Fatto lo mette solo Ivan. Da contare al prossimo giro, PRIMA di aprire lotti nuovi. ⚠️ Attenzione a come si leggera' questo numero: SU-484 porta un NON PROVATO che nessun KO puo' scoprire (la misura su iPad e' rimasta a meta'), e SU-538 e SU-529 non aspettano un collaudo ma un giudizio estetico: un rientro li' e' informazione, non difetto.

ESITO RIENTRI misurato all'apertura di questo giro (2026-08-23): delle 20 chiavi messe In revisione il 22/08 ne sono rientrate in «Da fare» 5 — SU-530, SU-532, SU-533, SU-536, SU-538. Tasso 5/20 (25%), contro il 18% del 21/08 e lo 0% dei giri piu' piccoli.

⚠️ Ma il numero da solo direbbe il falso, e in due direzioni opposte. Da una parte due dei cinque rientri non sono difetti: SU-536 e SU-538 sono tornati indietro con una scelta di Ivan (il percorso /changelog/ invece di /novita/, il tendone pieno invece di quello sottile), cioe' esattamente il tipo di rientro che ci si aspetta da un ticket che aspetta un giudizio e non un collaudo. Dall'altra SU-474 era rientrato il 21/08 ed e' rimasto fuori da DUE giri di fila senza che nessuno lo contasse: non compariva nella riga RIENTRI di ieri perche' quella riga elenca cio' che si spedisce, non cio' che resta indietro. Un KO che nessuno raccoglie non fa rumore, ed e' il modo piu' silenzioso di perdere un ticket.

📌 Cosa ne discende, e vale piu' del tasso: i tre rientri veri (SU-530, SU-532, SU-533) hanno tutti la stessa forma — il codice faceva quello che il ticket diceva, ma non quello che Ivan voleva vedere. SU-530 agganciava le icone al pannello perche' cosi' era prima di SU-339; SU-533 aveva coperto la larghezza e non l'altezza; SU-532 aveva scelto 0,55 s con una motivazione scritta nel codice. Nessuno dei tre era sciatteria: erano tutti misure giuste su una domanda sbagliata. La difesa non e' misurare di piu', e' guardare l'immagine finale prima di consegnare — che e' come sono stati bocciati in casa, oggi, il secondo tentativo di SU-533 e il primo di SU-532.

RIENTRI ATTESI (messi In revisione il 2026-08-23, Sprint 10): SU-474, SU-530, SU-532, SU-533, SU-536, SU-538, SU-539 — sette su sette in perimetro, di cui sei erano rientri e uno solo (SU-539) mai lavorato prima. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

⚠️ Attenzione a come si leggera' questo numero: SU-474 porta un NON PROVATO che nessun KO di Ivan potrebbe scoprire da desktop — la causa e' stata misurata con rete e account veri su macOS, ma i provider su telefono sono Google e Apple e li' non e' stato misurato niente; SU-538 e SU-539 non aspettano un collaudo ma un giudizio estetico, e un rientro li' e' informazione, non difetto; SU-532 e' gia' al secondo KO in giornata (prima la velocita', poi la trasparenza), quindi un terzo rientro su quel ticket vorrebbe dire fermarsi e parlare dell'impianto invece di tentare un quarto aggiustamento.

📌 UN TICKET CHE VALE LA PENA APRIRE, e non l'ho aperto io perche' e' una decisione di Ivan: il fix di SU-474 alza la pompa dell'SDK di EOS al primo uso della classifica. Da li' in poi vale per tutto EOS, ma prima di quel momento qualunque altra chiamata EOS fatta a gioco in pausa — achievement, multiplayer — resta appesa esattamente come restava la classifica. E' lo stesso difetto, in un altro punto, e oggi nessuno lo sta guardando.

RIENTRI ATTESI (messi In revisione il 2026-08-23, Sprint 10, giro del pomeriggio): SU-541, SU-542, SU-543, SU-544, SU-545, SU-546, SU-547, SU-548, SU-549, SU-550, SU-551, SU-552, SU-553 — tredici chiavi, cioe' tutto il perimetro, che a fine giro e' vuoto. Di queste SU-548 e' gia' un rientro (bocciata da Ivan in giornata e rifatta: il cuore-insegna diventato contatore in cifre) e SU-553 e' nata oggi da una segnalazione sua in chat. Da contare al prossimo giro, PRIMA di aprire lotti nuovi. ⚠️ Attenzione a come si leggera' questo numero: cinque portano un NON PROVATO che nessun KO puo' scoprire — la galleria del viaggio in metro di SU-552 (in headless l'animazione e' saltata per costruzione), il tunnel su iPhone vero di SU-545, gli fps dell'alone di SU-543, il login vero coi tre provider di SU-553, e il riascolto delle musiche di SU-546, che e' un orecchio e non una misura. E SU-549 non aspetta un collaudo ma un giudizio estetico: un rientro li' e' informazione, non difetto.

RIENTRI ATTESI (messi In revisione il 2026-08-24, Sprint 10): SU-505, SU-506, SU-507, SU-543, SU-544 — cinque chiavi, cioe' tutto il perimetro, che a fine giro e' vuoto. Di queste SU-543 e SU-544 erano rientri (bocciate da Ivan il 23/08 e rifatte oggi), le altre tre sono nuove. Il tasso di rientro del giro precedente e' stato 2 su 13. Da contare al prossimo giro, PRIMA di aprire lotti nuovi. ⚠️ Attenzione a come si leggera' questo numero: tre delle cinque portano un NON PROVATO che nessun KO di Ivan potrebbe scoprire — il login Epic vero di SU-505/506/507 (qui l'account EOS e' anonimo e il registro e' sempre quello di prova), e gli fps del tunnel su telefono di SU-543. E il collaudo d'insieme e' rimasto a meta': fatto il compile-check completo (471 script, 92 scene, 0 falliti), mai fatta la smoke SP ne' la caccia al muto dopo la rimozione dell'autoplay.

RIENTRI ATTESI (messi In revisione il 2026-08-24, Sprint 10, giro del pomeriggio): SU-513, SU-554, SU-556, SU-557, SU-558, SU-559, SU-560, SU-561, SU-562, SU-563, SU-564, SU-565, SU-569 — tredici chiavi (SU-556 si è aggiunta in serata, quando Ivan ha collegato l'Honor 10), tutte nuove, nessun rientro: il giro precedente ha chiuso a 0 rientri su 5 (SU-505/506/507/543/544 non sono tornati indietro), che è il tasso migliore finora ed è anche il primo giro in cui il perimetro era fatto solo di ticket mai lavorati. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

⚠️ Attenzione a come si leggerà questo numero, perché stavolta la parte cieca è grossa: sei delle dodici portano un NON PROVATO che nessun KO di Ivan potrebbe scoprire, e per la stessa ragione — non c'è un telefono collegato. SU-557 (che su Android il log su file esista davvero in release), SU-558 (che la riga arrivi su Drive: serve l'endpoint vero, e una GET non prova una POST), SU-560 (nessun PUID intero nel logcat di una build di release), SU-562 e SU-554 (il caricamento vero in Play Console e App Store Connect, che vuole browser e credenziali), SU-563 (un crash vero forzato su un device TestFlight: la risposta è documentale, non misurata). E SU-569 non aspetta solo un collaudo ma anche un giudizio: sparisce la vignetta rossa di fame/sonno dalla pagina del giornale, ed è una scelta di resa su cui Ivan può avere un'opinione diversa — un rientro lì è informazione, non difetto.

📌 AGGIORNAMENTO DI SERANTA — il telefono è arrivato. Ivan ha collegato l'Honor 10 alle 17:15 e sei dei NON PROVATO qui sopra sono diventati misure vere (vedi la voce «Le prove sull'Honor 10» e TESTLOG): SU-557, SU-558, SU-556, SU-560 e, in regalo, SU-569 su device. Due di quelle misure hanno bocciato il lavoro del pomeriggio — SU-560 lasciava un PUID intero in logcat stampato dal plugin EOS, e la classifica di SU-561 era inutile sul primo dato vero — ed entrambi sono stati rifatti in giornata. Resta UN SOLO ticket non lavorato: SU-555, che vuole una build installata dal Play Store, non da USB, più 24-48 h di attesa in Console: non è un rinvio per scelta, è l'unica prova che il cavo non può dare.

📌 TRE COSE APERTE CHE NON SONO TICKET, e che si perderebbero: (1) le due informative privacy (street-university-site/privacy/index.html e la gemella in street-university-beta-devices/index.html) sono modificate, non committate e non pubblicate — e portano dentro anche la correzione della contraddizione del box «In breve» («né analytics», «solo in tre casi»), che era falsa da SU-413 e non da questo ticket; (2) la .so di EOS non ha i simboli di debug (tools/android/eosg_16kb/RICETTA.md non usa debug_symbols=yes separate_debug_symbols=yes): serve un ticket suo, senza il quale metà di uno stack trace nativo resta illeggibile anche coi simboli del motore caricati; (3) tools/release/testflight.sh:246 cancella l'.xcarchive a ogni run, quindi non conserviamo l'archivio delle versioni spedite — con uploadSymbols=true al giro normale non serve, servirebbe solo per risimbolicare fuori dall'Organizer.

RIENTRI ATTESI (messi In revisione il 2026-08-24, Sprint 10, giro serale): SU-526, SU-554, SU-555, SU-570 — quattro chiavi, e a fine giro il perimetro dello sprint e' vuoto. Di queste SU-526 e' un rientro (bocciata da Ivan in giornata: voleva tre ambienti, non due) e SU-570 e' nata oggi da una sua segnalazione giocando. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

⚠️ Attenzione a come si leggera' questo numero: SU-554 e' appesa per costruzione — i simboli nativi sono caricati sul bundle 30, ma la prova che funzionino richiede un crash di una build che se li porta dietro, quindi non prima della prossima release; SU-555 e' stata risposta con dati gia' esistenti e non col crash forzato che il ticket descriveva, il che e' piu' forte ma diverso da quanto chiesto; e SU-570 non ha lo scatto in-engine che il suo stesso ticket pretendeva, sostituito dal conteggio per quartiere nei due versi con la ragione scritta sul ticket.

📌 CHIUSI A FATTO IN GIORNATA, su ok di Ivan in chat: SU-513, SU-556, SU-557, SU-558, SU-559, SU-560, SU-561, SU-562, SU-563, SU-564, SU-565, SU-569 — dodici. ⚠️ Tre di questi (SU-569, SU-565, SU-564) sono stati chiusi senza che Ivan li provasse, e portano un cambiamento visibile che potrebbe non piacergli: la vignetta rossa che sparisce dal giornale, gli avvisi spenti nel tunnel, la chiesa unica per quartiere. Un loro rientro sarebbe informazione, non difetto.

📌 E il giro serale ha prodotto due cose che non sono ticket: la privacy policy 1.2 pubblicata sui due repo gemelli, e su App Store Connect il contratto di licenza accettato, lo stato DSA dichiarato «non operatore commerciale» e la riga Crash Data pubblicata. Il perche' e gli inneschi stanno in DISTRIBUZIONE_STORE.md e nel pre-volo di pubblica-store.

RIENTRI ATTESI (messi In revisione il 2026-08-28, Sprint 12): SU-592, SU-608, SU-609, SU-610, SU-611, SU-612, SU-613, SU-614, SU-615, SU-616, SU-617, SU-618, SU-620, SU-621, SU-622, SU-623, SU-624, SU-625, SU-626, SU-627, SU-628, SU-629, SU-630, SU-631, SU-632, SU-633, SU-634, SU-635, SU-636, SU-637, SU-638, SU-639, SU-640, SU-641, SU-642, SU-643, SU-644, SU-645, SU-409 — trentanove chiavi, cioè tutto il perimetro tranne SU-619, che resta in «Da fare» apposta perché manca il dato di partenza e serve una decisione di Ivan. Di queste SU-645 è nata in giornata da una segnalazione di un tester riferita da Ivan in chat, e il perimetro di partenza era zero rientri (il giro del 24/08 serale ha chiuso 0 su 4). Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

⚠️ Attenzione a come si leggerà questo numero, che è il più alto mai messo In revisione in un giorno solo. Tre cose lo rendono meno impressionante di quanto sembri, ed è giusto saperlo:

  1. Sedici dei trentanove sono documenti, non codice: i dodici (DESIGN), più SU-608, SU-636 e le parti di indagine. Il loro «collaudo» è che Ivan li legga, non che il gioco funzioni — e un rientro lì è una scelta diversa, non un difetto.
  2. Tre ticket sono stati chiusi senza cambiare una riga di gioco, perché il requisito era già rispettato (SU-615, SU-614) o perché la premessa era falsa (SU-630, la colonna esisteva già). Quelli non possono rientrare per un bug: solo per un disaccordo sulla diagnosi.
  3. Quasi tutto il codice porta un NON PROVATO che nessun KO può scoprire da solo: niente è stato provato su device né in multiplayer vero. In particolare restano fuori dalla portata di questo giro il suono della SUPER SCOREGGIA (mai generato), gli fps della tempesta sull'Honor (telefono assente), la soglia dei 300 ms del tasto tenuto (mai toccata con un dito), e le finestre reali della transizione in metro (in headless durano zero).

RIENTRI ATTESI (messi In revisione il 2026-08-29, Sprint 12, giro del referto telemetria): SU-646, SU-648, SU-651, SU-652 — quattro chiavi, tutte nuove, nessun rientro nel perimetro di partenza: gli otto ticket di oggi nascono tutti dal referto telemetria 0.40/0.41 e nessuno era mai stato lavorato. ⚠️ Il conto del giro PRECEDENTE non è ancora misurabile: le undici chiavi del giro dei bocciati del 28-29/08 (SU-592, SU-613, SU-614, SU-616, SU-619, SU-621, SU-624, SU-627, SU-628, SU-633, SU-643) sono state messe In revisione poche ore fa e Ivan non le ha ancora provate — vanno contate al prossimo giro, non ora. Restano fuori dalla revisione SU-647, SU-649, SU-650 e SU-653, che aspettano una decisione di Ivan e non del codice. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

RIENTRI ATTESI (messi In revisione il 2026-08-29, Sprint 12, giro completo del referto telemetria): dodici chiavi — SU-646, SU-648, SU-651, SU-652 (il primo giro), SU-647, SU-649, SU-653 (i tre di design, chiusi dopo l'approvazione di Ivan in chat), e SU-650, SU-654, SU-655, SU-656, SU-657 (l'implementazione delle sue decisioni, più il bug del consenso nato dal lavoro su SU-652). Perimetro dello sprint vuoto a fine giro. Nessun rientro nel perimetro di partenza: gli otto ticket iniziali nascevano tutti dal referto telemetria 0.40/0.41 e nessuno era mai stato lavorato; i quattro nuovi sono nati in giornata dalle decisioni di Ivan. ⚠️ Restano da contare al prossimo giro anche le undici chiavi del giro dei bocciati del 28-29/08, che Ivan non ha ancora provato. Da contare PRIMA di aprire lotti nuovi.

RIENTRI ATTESI (messi In revisione il 2026-08-29, Sprint 12, giro dei cinque design): quattordici chiavi — SU-659, SU-660, SU-661, SU-662, SU-663 (punteggio), SU-664, SU-665, SU-667 (metropolitana), SU-669 (IL BRANCO), SU-672, SU-673 (piccioni), SU-675, SU-676 (HUD), SU-677 (grafica leggera). Tutte NUOVE, nessun rientro nel perimetro di partenza: i 19 ticket dello sprint nascevano tutti dai cinque documenti di design del 28-29/08 e nessuno era mai stato lavorato. Il giro precedente ha chiuso 0 rientri su 23 chiavi. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

⚠️ Attenzione a come si leggerà questo numero, perché la parte cieca è grossa e ha una sola causa: non c'è nessun telefono collegato (adb devices vuoto). Ne discende che cinque delle quattordici portano un NON PROVATO che nessun KO di Ivan da desktop potrebbe scoprire: i 30 fps dell'Honor che sono la premessa di SU-677, il costo della scia del piccione d'oro (~210 draw_rect per ridisegnata, 16 volte al secondo), il costo della riemissione del punteggio a ogni moneta (SU-659), il ramo mobile del menu grafica (SU-677), e il multiplayer di SU-662 — dove _announce_enemy_defeat() gira solo su host, quindi i 300 punti del giullare li prende l'host anche se l'ha steso un client.

📌 E sei delle quattordici girano ancora con un SEGNAPOSTO al posto dell'arte: topo, zombie, piccione normale, piccione d'oro e i tre cani. I path finali sono già scritti nel codice e provati per primi, quindi il giorno che gli sprite sono approvati non si tocca una riga — ma l'aspetto non è mai stato giudicato, e un rientro lì sarebbe informazione, non difetto.

📌 Tre ticket portano una decisione aperta, non un collaudo: SU-669 (la carta FISCHIETTO PER CANI non ha effetto passivo ai livelli 1-8 — manopola vera o meno livelli, come si fece per il RADAR), SU-660 (con i soldi in tasca a punteggio, comprare un hot dog ora abbassa il punteggio a schermo: coerente col ticket, ma è la prima cosa che si nota), SU-676 (il suggerimento panchina è una notifica autonoma invece del testo allungato che il design chiedeva, per non far uscire due toast quasi identici).

📌 Quattro ticket restano in «Da fare» e NON è un ritardo: SU-666 aspetta l'Honor per la metà mancante della misura (la metà Mac è fatta: margine 7,2 s); SU-668, SU-670 e SU-674 hanno le varianti generate e aspettano l'approvazione di Ivan prima del montaggio; SU-671 è bloccato da una ragione di licenza — la chiave ElevenLabs non ha il permesso user_read, quindi non si può accertare se l'account sia abbonato, e le licenze degli asset AI seguono la generazione, non il download.

RIENTRI ATTESI (messi In revisione il 2026-08-31, Sprint 12, giro da CLI): diciassette chiavi — SU-611, SU-617, SU-619, SU-620, SU-640, SU-644, SU-646, SU-665, SU-666, SU-670, SU-673, SU-678, SU-681, SU-682, SU-683, SU-684, SU-685. Il perimetro di partenza erano 18 ticket, di cui 5 nuovi (SU-681÷SU-685) e 13 già lavorati. ⚠️ Il tasso di rientro del giro precedente, misurato prima di aprire i lotti: 11 chiavi su 65 = 17% (SU-611, SU-617, SU-619, SU-620, SU-640, SU-644 dal giro dei 39 del 28/08; SU-646 dal giro telemetria; SU-665, SU-668, SU-670, SU-673 dal giro dei cinque design del 29/08). Resta fuori dalla revisione il solo SU-668, che aspetta una decisione di Ivan (la tinta verde sugli zombie basta, o serve l'arte dedicata?). SU-666 è stato chiuso con la metà misurabile senza telefono: i due confronti A-B-A sull'Honor restano a Ivan, come aveva chiesto lui. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

RIENTRI ATTESI (messi In revisione il 2026-09-02, Sprint 13, giro da CLI): ventinove chiavi — SU-421, SU-580, SU-593, SU-594, SU-595, SU-596, SU-597, SU-598, SU-599, SU-601, SU-603, SU-605, SU-607, SU-658, SU-694, SU-705, SU-710, SU-711, SU-712, SU-715, SU-716, SU-717, SU-718, SU-719, SU-720, SU-722, SU-723, SU-725, SU-727. ⚠️ Il tasso di rientro del giro precedente, misurato PRIMA di aprire i lotti: 0 su 17 — nessuna delle diciassette chiavi messe In revisione il 31/08 è tornata in «Da fare». Il perimetro di partenza era di 47 ticket, tutti nuovi, zero bocciati. Di queste ventinove, una sola è un rientro: SU-421, bocciata da Ivan in giornata con una lista puntuale, rilavorata e rimessa In revisione lo stesso giorno. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

⚠️ Come si leggerà questo numero, e cosa lo rende meno impressionante di quanto sembri.

  1. Cinque delle ventinove non sono codice di gioco: SU-725 e la sua coda (i documenti del rilascio in tre tempi e il generatore del cheat sheet), SU-605 (marca temporale), SU-607 (ricerca di anteriorità sul marchio), SU-694 (misura del registro), SU-593 e SU-601 (decisioni scritte). Il loro «collaudo» è che Ivan le legga, e un rientro lì è un disaccordo, non un difetto.
  2. Due sono state chiuse senza cambiare una riga di gioco perché il lavoro era già stato fatto da un altro ticket: SU-594 prima metà (già risolta da SU-704) e SU-597 per 23 schermate su 25 (già risolto da SU-722 poche ore prima). Non possono rientrare per un bug: solo per un disaccordo sulla diagnosi.
  3. Quasi tutto il codice porta un NON PROVATO che nessun KO può scoprire da solo: nessun device collegato, nessun multiplayer vero a due peer. In particolare restano fuori portata il dito su una barra di scorrimento (SU-598), i 64×64 px e la safe area di iPhone (SU-722), il suono delle tre calamità e della sirena (SU-719, SU-603 — vanno *ascoltati*, e nessuna sonda lo può fare), la forma vera di un Oppo (SU-596, simulata a 2400×1080) e la classifica coi nomi su iPhone (SU-705, che si vedrà solo dopo la prossima pubblicazione TestFlight).

📌 TRE COSE CHE ASPETTANO IVAN E NON SONO RITARDI: i tre fogli della barbona di SU-723 e i 68 fogli delle carnagioni di SU-421 vogliono il suo occhio uno per uno prima del montaggio (SU-724, SU-422); e SU-607 chiede una decisione di spesa — 183 € all'UIBM per fissare la data, con la priorità unionista che sposta i 900 € di EUIPO a quando ci saranno ricavi.

📌 E tre cose fatte oggi che non sono ticket: il pacchetto di marche temporali comprato e attivato (le credenziali stanno in ~/.aruba/tsa, fuori dal repo, portate a chmod 600); il progetto Apps Script di prova con 100.008 righe finte, che resta in piedi e permette di rimisurare il registro in pochi minuti; e la prima release marcata davvero, archiviata in PROVE_DATATE/ accanto alla cartella del progetto coi suoi certificati di verifica.

RIENTRI ATTESI (messi In revisione il 2026-09-05, Sprint 14, giro da CLI, sessione delle ombre): due chiavi — SU-736, SU-695. Esito gia' noto alla chiusura: SU-695 Fatto (Ivan, 17:08) e SU-736 rientrato KO alle 17:11 («al pomeriggio a sud-ovest invece che a nord-est, rifare quegli orari»): 1 rientro su 2 in giornata, con rimedio noto in RIPRESA.md. ⚠️ Il tasso di rientro del giro precedente, misurato PRIMA di aprire i lotti: 0 su 29 (le ventinove chiavi del 02/09). ⚠️ Un'altra sessione ha lavorato in parallelo lo stesso giorno (lotto nickname, 16 commit, propri RIENTRI): per il conteggio del prossimo giro sommare le due liste. Ripresa in RIPRESA.md.

RIENTRI ATTESI (messi In revisione il 2026-09-05, Sprint 14, giro serale da CLI): sette chiavi — SU-509, SU-511, SU-736, SU-739, SU-796, SU-798, SU-800. Perimetro di partenza: 13 ticket dello sprint, di cui 3 fuori per decisione di Ivan scritta sul ticket (SU-701 aspetta Godot 4.7, SU-461 backlog, SU-268 aspetta il suo via libera su itch), 3 bocciati (SU-736, SU-739, SU-670) e 7 nuovi. ⚠️ Tasso di rientro del giro precedente, misurato PRIMA di aprire i lotti: 1 su 2 (SU-736 tornato KO in giornata, SU-695 Fatto) sulla sessione delle ombre; l'altra sessione dello stesso giorno aveva le sue 16 chiavi, di cui Ivan non aveva ancora letto nulla. ⚠️ Due delle sette chiusure sono correzioni mie al cancello, non lavoro del builder: SU-739 (il numero scelto non risolveva il KO) e SU-509/511 (due modifiche che avrebbero rotto la registrazione dei nickname in produzione): sono i punti dove il rientro e' piu' probabile. Restano aperti SU-670 (mai aperto) e i due lotti in volo al congelamento (SU-797, SU-799). Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

RIENTRI ATTESI (messi In revisione il 2026-09-06, Sprint 14, giro pomeridiano da CLI): undici chiavi — SU-820, SU-821, SU-822, SU-823, SU-824, SU-825, SU-826, SU-827, SU-828, SU-829, SU-830. Perimetro di partenza: 14 ticket dello sprint, di cui 3 fuori per decisione di Ivan scritta sul ticket (SU-701, SU-461, SU-268) e 11 lavorabili. ⚠️ Tasso di rientro del giro precedente, misurato PRIMA di aprire i lotti: 0 rientri formali — nessuna delle chiavi messe In revisione nel giro del mattino (Brina e Collina, piu' itch/audio/comandi) e' tornata in «Da fare». ⚠️ Ma il conteggio formale qui inganna, e va detto: SU-825 e' nato come bug NUOVO su fogli sprite montati e messi In revisione poche ore prima, dopo che Ivan li ha guardati in partita. Formalmente non e' un rientro, sostanzialmente lo e', ed e' stato lavorato col protocollo dei bocciati. Chi conta al prossimo giro tenga presente che un bug nuovo su lavoro appena consegnato vale quanto un KO. ⚠️ Sei difetti veri sono stati fermati al cancello, non dai builder: il ghiaccio che sarebbe esistito solo dove ci sono gli edifici (SU-828), il gatto che azzuffava anche i pinguini piu' altri tre difetti di posizione del controllo (SU-826), il poliziotto rimesso all'inizio del tutorial (SU-820) e la neve finita dietro tutto il mondo (SU-829). Sono i punti dove il rientro e' piu' probabile. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

RIENTRI ATTESI (messi In revisione il 2026-09-06, Sprint 14, giro serale da CLI): diciassette chiavi — SU-796, SU-800, SU-805, SU-808, SU-826, SU-827, SU-831, SU-832, SU-833, SU-834, SU-835, SU-836, SU-837, SU-838, SU-839, SU-841, SU-842. Perimetro di partenza: 21 ticket dello sprint, di cui 3 fuori per decisione di Ivan scritta sul ticket (SU-701, SU-461, SU-268) e 18 lavorabili; il diciottesimo, SU-840, e' partito per ultimo perche' il ticket stesso lo vuole dopo SU-826. ⚠️ Tasso di rientro del giro precedente, misurato PRIMA di aprire i lotti: 2 su 11 — delle undici chiavi messe In revisione nel giro pomeridiano sono tornate in «Da fare» SU-826 («il pupazzo di neve solo con torcia si scioglie, il gatto non gli fa nulla») e SU-827 («proviamo con 30 a partita»); dal giro serale del 05/09 erano gia' rientrate SU-796 e SU-800. ⚠️ Tre difetti veri sono stati fermati al cancello, non dai builder, e sono i punti dove il rientro e' piu' probabile: la pagina dei record che riservava 188 px allo spazio di un tasto touch mai disegnato sul web (SU-841, secondo giro aperto da me); il raw scuro dell'uomo d'affari che ripararlo avrebbe cambiato 3.264 pixel contro i 36 del difetto (SU-832, fermato); e l'audit dei glifi che al primo giro segnalava 26 falsi positivi in stringhe di log, cioe' sarebbe morto inutilizzato (SU-833, seconda passata). 📌 SU-805 e' In revisione ma NON ha niente di installato: consegna quattro varianti e un contatto, e aspetta che Ivan scelga la lettera. 📌 SU-796 porta un criterio APERTO: la direzione dell'ombra sull'immagine renderizzata non e' stata misurata, perche' tre misure diverse davano segni discordi. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

RIENTRI ATTESI (messi In revisione il 2026-09-06, Sprint 14, giro notturno da CLI): dieci chiavi — SU-687, SU-796, SU-800, SU-805, SU-826, SU-827, SU-832, SU-843, SU-844, SU-845. Perimetro di partenza: 14 ticket dello sprint, di cui 3 fuori per decisione di Ivan già scritta sul ticket (SU-701, SU-461, SU-268) e 11 lavorabili; l'undicesimo, SU-846, resta in «Da fare» di proposito — il difetto non si riproduce su desktop e curare senza averlo visto era vietato dal ticket stesso. ⚠️ Tasso di rientro del giro precedente, misurato PRIMA di aprire i lotti: 7 su 17 — delle diciassette chiavi messe In revisione nel giro serale sono tornate in «Da fare» SU-687, SU-796, SU-800, SU-805, SU-826, SU-827 e SU-832. ⚠️ Tre difetti veri fermati al cancello, non dai builder, e sono i punti dove il rientro è più probabile: il fenicottero cancellato per sempre (SU-826) sotto un commento che lo dichiarava «come gli altri NPC», mentre gli NPC rinascono e ogni nemico di quartiere rientra — con la carta del gatto si sarebbero svuotati tutti i parchi in una partita; la ruota del riccone ridotta a 3 colori distinti contro i 5.157 dell'originale (SU-805, due giri, poi lo scostamento dichiarato dalla decisione di Ivan); e SU-832 che puntava allo sprite sbagliato, cosa che si scopre solo scaricando l'allegato del KO. 📌 Due criteri restano APERTI e vanno guardati da Ivan: la notifica sull'Honor di SU-687 (nessun device collegato, il comando adb è sul ticket) e la scelta fra ruota piena e ruota col cerchione di SU-805. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

RIENTRI ATTESI (messi In revisione il 2026-09-07, Sprint 14, giro notturno da CLI): quattro chiavi — SU-814, SU-832, SU-841, SU-846. Perimetro di partenza: 6 ticket dello sprint, di cui 2 fuori per decisione di Ivan gia' scritta sul ticket (SU-701, che aspetta Godot 4.7, e SU-461, backlog) e 4 lavorabili. ⚠️ Il giro era fatto di soli rientri: zero ticket nuovi. Tasso di rientro misurato PRIMA di aprire i lotti: delle dieci chiavi del giro notturno precedente ne e' tornata 1 (SU-832); SU-841 e SU-814 erano rientrate da lotti anteriori, e SU-846 non era mai stata chiusa. ⚠️ Quattro difetti veri fermati al cancello, non dai builder, e sono i punti dove il rientro e' piu' probabile: (1) il rigeneratore delle carnagioni che con --solo business troncava npc_dark_manifest.gd da 64 a 4 coppie in silenzio, lasciando senza gemello scuro bouncer, bully, catlady, cleaner e delivery — chiuso alla radice nello script; (2) lo stesso comando che riportava 36 pixel magenta sulla sheet v03 e cancellava l'uid da quattro .tres; (3) il riccone riscalato per riga, che lo faceva rimpicciolire del 35% girandosi; (4) il riccone ridotto dalla variante a ruota piena che Ivan aveva bocciato di persona su SU-805. ⚠️ Due errori erano dell'orchestratore, non dei builder, e vanno contati come tali: il brief diceva «58 px di larghezza» misurando un bbox che conteneva un doppione staccato, e un cancello chiedeva «≥250 colori distinti» in una zona che a quella scala ha 224 pixel in tutto — impossibile per definizione. 📌 Due criteri restano APERTI: la resa in partita del riccone (Ivan deve dire la colonna del contatto a quattro) e la prova acustica di SU-846, che e' misurata ma non ascoltata. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

RIENTRI ATTESI (messi In revisione il 2026-09-07, Sprint 14, giro serale da CLI): sette chiavi — SU-814, SU-832, SU-847, SU-849, SU-851, SU-852, SU-853. Perimetro di partenza: 21 ticket dello sprint, di cui 3 fuori per decisione o dipendenza già scritta sul ticket (SU-701 aspetta Godot 4.7, SU-461 backlog, SU-863 vuole SU-852 chiuso e almeno una skin approvata da Ivan) e 18 lavorabili; dei 18 ne sono stati aperti 9 — i nove ticket sprite rimasti (SU-854…SU-862) sono stati tenuti fuori di proposito, perché il mimo era il capostipite che detta la pipeline agli altri. ⚠️ Tasso di rientro del giro precedente, misurato PRIMA di aprire i lotti: 2 su 4 — delle quattro chiavi del giro notturno sono tornate in «Da fare» SU-814 («il riccone compare pochissimo da quando spawna») e SU-832 (i due segni rossi sul contatto), mentre SU-841 e SU-846 sono rimaste dove erano. ⚠️ Quattro difetti veri fermati al cancello, non dai builder, e sono i punti dove il rientro è più probabile: (1) la nuvoletta della zuffa che in multiplayer sarebbe scivolata di una decina di pixel perché la replica avanzava con l'ultima velocità ricevuta (SU-849); (2) la sonda del riccone che ricopiava a mano la soglia dei 4 secondi e sarebbe rimasta verde sul numero vecchio (SU-814); (3) le maschere di SU-832 che prendevano l'aletta delle tasche invece delle mani, cioè una regressione sul cappotto nascosta sotto il KO; (4) il costume del mimo, consegnato ma dichiarato non convincente — cappello a tesa larga al posto del basco. ⚠️ Due errori erano dell'orchestratore: gli scatti «prima» di SU-850 e SU-848 sono stati lanciati dopo i builder e valevano come «dopo», rifatti da un worktree sul commit di partenza; e un cancello su lotto Claude è stato letto senza accorgersi che non vede il report del builder. 📌 Due lotti restano non committati di proposito (SU-850 e SU-848): il codice è fatto e i cancelli passati, ma i loro criteri sono visivi e gli scatti vanno guardati. Ripresa in RIPRESA.md. 📌 probe_su491_forbice è rossa da prima di questo giro (verificato sul commit b991506): vuole un ticket suo. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

RIENTRI ATTESI (messi In revisione il 2026-09-07, Sprint 14, giro notturno da CLI): quindici chiavi — SU-814, SU-832, SU-848, SU-850, SU-853, SU-854, SU-855, SU-856, SU-857, SU-858, SU-859, SU-860, SU-861, SU-862, e il provino generalizzato che le serve tutte. Perimetro di partenza: 17 ticket dello sprint, di cui 2 fuori per decisione o dipendenza già scritta sul ticket (SU-701 aspetta Godot 4.7, SU-461 backlog) e SU-863 ancora bloccato, che vuole almeno una skin approvata da Ivan. ⚠️ Tasso di rientro del giro precedente, misurato PRIMA di aprire i lotti: 3 su 7 — delle sette chiavi del giro serale sono tornate in «Da fare» SU-814 («deve muoversi in zona come un npc, e caricare quando è già in telecamera»), SU-832 (poi commentata «PERFETTO» senza essere transizionata) e SU-853 (il gatto in braccio da fare rosso). ⚠️ Due difetti veri fermati al cancello, non dai builder, e sono i punti dove il rientro è più probabile: (1) il rettangolo d'ingaggio del riccone a 844×390 unità mondo contro i 546×307 davvero visibili — il fix sarebbe rientrato KO identico, perché il riccone poteva ancora caricare da fuori schermo; (2) il provino generalizzato che girava senza errori producendo immagini inservibili, perché costruiva lo sprite dal raw col magenta invece che dal foglio tagliato. 📌 Tre criteri restano dichiaratamente non soddisfatti sui ticket: il bbox della sbornia sfora i 2 px sui due punk (12 e 9 celle su 25), sul ballerino (10 su 25) e sul giocoliere (3 su 25) — è la bottiglia impugnata, e la scelta di non deformare il prop è dichiarata sui ticket. 📌 Le nove skin sono in TMP e non in gioco: il montaggio è di SU-863, che si sblocca quando Ivan approva la prima. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

RIENTRI ATTESI (messi In revisione il 2026-09-08, Sprint 14, giro delle skin da CLI): nove chiavi — SU-853, SU-854, SU-856, SU-857, SU-858, SU-859, SU-860, SU-861, SU-862 (SU-855 era già lì). Non sono un rientro come gli altri: Ivan ha approvato l'arte in chat («ok gli sprites mi sembrano tutti abbastanza buoni ora») dopo il quarto giro di collaudo, e questi ticket erano fermi in «Da fare» col loro KO. Il «Fatto» lo mette lui. ⚠️ Tasso di rientro dei tre giri di collaudo sulle skin: 15 osservazioni il 07/09, 6 l'08/09 mattina, 1 l'08/09 sera — e nessuna delle 22 stava dove sembrava: 15 erano il ritaglio sulla griglia, 2 le stelline attaccate al corpo, 1 uno spruzzo che ingannava la misura, 3 arte mai disegnata intera, 1 una riga scambiata nel raw. Aperto per il seguito: SU-865, i quindici ritratti della selezione personaggio, portato oggi dentro lo Sprint 14 (era «Da fare» ma fuori da ogni sprint, quindi invisibile a /sprint).

RIENTRI ATTESI (messi In revisione il 2026-09-09, Sprint 14, giro notturno da CLI): sei chiavi — SU-852, SU-865, SU-889, SU-891, SU-893, SU-894. Perimetro di partenza: 10 ticket dello sprint, di cui 3 fuori per una dipendenza o una decisione già scritta sul ticket (SU-892 bloccato dall'ascolto di Ivan sui suoni di SU-891; SU-701 rinviato da Ivan il 05/09 — riproposto stanotte perché il blocco «aspetta Godot 4.7» è caduto, e Ivan ha confermato di lasciarlo fermo; SU-461 backlog dichiarato) e 1 aperto in corsa, SU-895, che resta in «Da fare» perché il punto che conta è una decisione di Ivan. ⚠️ Il tasso di rientro del giro precedente NON è misurabile oggi, e dirlo è più utile che scrivere zero: delle 14 chiavi dei due giri del 07-08/09, 12 sono ancora «In revisione» e 2 «Fatto», nessuna tornata in «Da fare» — ma Ivan non ha ancora fatto la prova su device, quindi quello zero è ancora «vero per costruzione», esattamente ciò da cui questa riga dovrebbe difendersi. Da rimisurare al prossimo giro. 📌 Tre cose trovate al cancello, non dai builder, e tutte e tre erano verifiche che guardavano nel posto sbagliato: (1) il criterio di SU-852 «la RPC nuova è l'ultima della lista» — vero sul file, falso sul programma, perché in Godot 4 gli id RPC seguono l'ordine alfabetico del nome (SU-895, _srv_declare_skin prende l'id 5 su 10 e ne fa slittare cinque); (2) il payload della lobby, dove la sicurezza viene dal blocco da 3 voci e non dal registro, mentre due commenti del codice dicevano il contrario e uno sbagliava perfino il conteggio dei blocchi a 4 giocatori; (3) l'effetto ad area della super «IL BRANCO», che nessuna sonda copriva e che in sei partite reali non è mai stato esercitato perché la carta non è stata pescata — su un file cresciuto di 258 righe si sarebbe rotto in silenzio. 📌 La carta dei cani resta provata dalle sonde e non dal gioco: è il primo posto da guardare su device.

RIENTRI ATTESI (messi In revisione il 2026-09-09, Sprint 14, giro del mattino da CLI): diciassette chiavi — SU-866, SU-867, SU-868, SU-869, SU-873, SU-874, SU-875, SU-876, SU-879, SU-880, SU-884, SU-885, SU-886, SU-890, SU-895, SU-896, SU-897. Tre di queste sono nate oggi e chiuse in giornata: SU-896 (il blocco di versione, deciso da Ivan in chat), SU-897 (il bot che scende nel tunnel) e SU-895, che aspettava solo quella decisione. Perimetro di partenza: 42 ticket lavorabili dello sprint (44 meno SU-701 e SU-461, fuori per decisione di Ivan già scritta sul ticket), il più grande di sempre. ⚠️ Tasso di rientro del giro precedente, misurato PRIMA di aprire i lotti: 0 su 6 — nessuna delle sei chiavi del giro notturno (SU-852, SU-865, SU-889, SU-891, SU-893, SU-894) è tornata in «Da fare». Lo sprint non aveva nessun ticket bocciato: 42 su 42 mai lavorati, cinque commenti in tutto e nemmeno uno che fosse un KO.

📌 Ivan ha scelto lui il perimetro, alle 05:52, prima di tornare a dormire: bug e telemetria, la possessione, il tunnel in multiplayer e l'online che si vede — tutte e quattro le aree. Tre decisioni date in chat e scritte subito sui ticket: SU-870 fermo finché non c'è una misura sulla 0.43 con dentro SU-765; SU-895 chiuso con «un blocco in multiplayer per far giocare solo chi ha l'ultima versione», che ha fatto nascere SU-896; SU-868 solo lato server, col client non toccato.

⚠️ Nove difetti veri fermati al cancello e dalla review, non dai builder — sono i punti dove il rientro è più probabile, e quattro di essi sono la stessa famiglia: un'RPC che crede a quello che dichiara chi la manda. (1) In SU-879 un client poteva nascondere il puppet di chiunque e rendersi intoccabile dalla polizia senza mai scendere nel tunnel; (2) in SU-886 l'host validava tutto tranne i 3 secondi di pressione, quindi si possedeva all'istante; (3) in SU-880 l'host crede ancora a «ho pagato» e «sono al giro 64» — non chiuso, dichiarato, e diventato SU-899; (4) l'audio della città tornava udibile nel tunnel perché World riscrive i volumi al frame dopo, e la misura «250 su 250 zittiti» era presa nello stesso fotogramma del muto; (5) un CanvasLayer nato mentre si è sotto restava sopra il tunnel, col vettore vero che era il SpeechCanvas dentro ogni NPC; (6) in SU-876 il segnale che riporta in lobby veniva emesso e nessuno lo ascoltava, quindi TORNA IN LOBBY portava al menu principale; (7) in SU-896 chi veniva respinto leggeva «l'host ha chiuso la lobby» invece del perché — trovato solo dal collaudo a due peer, invisibile al codice; (8) in SU-886 si poteva guidare un NPC fuori dal mondo, lasciandolo fuori dal navmesh; (9) sempre in SU-886, un accesso a ghost.velocity su un Node2D che check_files.sh dava verde.

📌 Tre cose sono cambiate nel modo di lavorare, e conviene ricordarle. (a) Il collaudo a due peer veri adesso si fa: tre lotti avevano dichiarato lo stesso NON PROVATO perché nella sandbox di Codex run_mp.sh ricade in single player — fuori parte, con un worktree e la cache d'importazione copiata, e ha trovato subito un difetto che nessuna sonda vedeva. (b) Il bot sa scendere nel tunnel (SU-897, nato dal buco di SU-879): senza, SU-880, 881, 882 e 883 si sarebbero chiuse tutte e quattro con lo stesso NON PROVATO. (c) I lotti Codex si impiantano e il loro --timeout non li salva — tutti e quattro fermi insieme alle 05:43, vivi a 0% di CPU, 7-9 eventi in due ore, mentre l'API rispondeva in due secondi: serve un guardiano che conti gli eventi.

📌 Quattro ticket nuovi aperti in corsa: SU-896 (il blocco di versione, deciso da Ivan e già chiuso oggi), SU-897 (il bot che scende, già chiuso), SU-898 (la sonda dello scudo metro conta gli arresti in modo non deterministico — 0/10, 2/10, 0/10 sul lotto e 1/10, 5/10 a HEAD: quel numero oggi non può né bocciare né promuovere niente) e SU-899 (la fonte autoritativa dell'economia in multiplayer).

📌 Tre ticket NON aperti di proposito, e non per dimenticanza: SU-870 e SU-871 chiedono decisioni che dipendono da una misura o da un playtest di Ivan su un telefono non-S23; SU-872 vuole una misura A-B-A sui suoi due telefoni con le build appaiate. Tutti e tre commentati sul ticket con cosa serve per sbloccarli. SU-892 resta bloccato dall'ascolto dei suoni di SU-891.

⚠️ Cosa resta più esposto al rientro, detto senza attenuanti: nessuna prova visiva in multiplayer è stata fatta — su questo Mac lo scatto dalla finestra senza fuoco è impedito da App Nap, quindi il velo rosso della possessione, il conto alla rovescia della chiamata e il fantasma sullo schermo dell'altro li vedrà per primo Ivan. E SU-880 va su device sapendo che il suo rilievo critico è aperto. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

RIENTRI ATTESI (messi In revisione il 2026-09-09, Sprint 14, giro del pomeriggio da CLI): quindici chiavi — SU-878, SU-881, SU-882, SU-883, SU-887, SU-888, SU-898, SU-899, SU-900, SU-901, SU-903, SU-904, SU-905, SU-906, SU-908. Perimetro di partenza: 18 ticket, di cui 3 fuori per una dipendenza già scritta sul ticket (SU-907, SU-902 e SU-892 aspettano che Ivan approvi i gemelli di generazione: i due suoni del branco, i quindici fantasmi, i sedici suoni di busking). Lavorati 15 su 15. ⚠️ Tasso di rientro del giro precedente: 0 su 17 — nessuna delle diciassette chiavi del giro del mattino è tornata in «Da fare». Come l'altra volta, però, quello zero è vero per costruzione: Ivan non ha ancora provato su device, e la riga serve proprio a difendersi da questo. Da rimisurare al prossimo giro. ⚠️ Tre lotti su nove sono stati fermati o corretti al cancello, e nessuno dei tre difetti l'aveva visto un builder: (1) SU-887 dichiarato finito con la sonda mai rilanciata — e la sonda diceva HIT_DELTA=0, cioè i 120 punti non arrivavano affatto; sotto ci stavano due difetti veri, il colpo senza ricarica né tiro registrato e i punti accreditati a qualunque perdita di vita, ed è servito il perimetro allargato a ModularNPC.gd per chiuderli (3 giri, l'ultimo su Astra); (2) due righe var arch := … che facevano morire ogni run mentre il compile-check restava verde — trovate dal lotto *accanto*, non da chi le aveva scritte; (3) SU-905, dove il difetto stava nella sonda (misurava l'ombra dell'altro camioncino, perché alcuni semi ne generano due uguali) e le tre ipotesi di rimedio sono cadute una dopo l'altra, l'ultima per algebra. 📌 SU-905 e SU-901 aspettano una tua occhiata, non un fix: tre varianti d'ombra a confronto e quindici fantasmi da approvare. 📌 SU-903 non è attivo finché non pubblichi versione_multiplayer nel devices.json su GitHub: BETATESTING/ è gitignored, quindi la modifica non è nel commit.

RIENTRI ATTESI (messi In revisione il 2026-09-09, Sprint 14, giro serale da CLI): otto chiavi — SU-779, SU-780, SU-784, SU-785, SU-786, SU-791, SU-877, SU-892. Perimetro di partenza: 27 ticket dello sprint (la query paginata di ieri, non più la fetta da 18), di cui 17 fuori e non per dimenticanza: SU-902 aspetta che Ivan approvi i 15 fantasmi di SU-901 (ancora «In revisione», non «Fatto»); SU-870, SU-871, SU-872, SU-781, SU-783 chiedono misure o playtest su device che solo Ivan può fare; SU-790, SU-701, SU-461 sono fermi per decisione scritta sul ticket; SU-792, SU-793, SU-794, SU-795, SU-788, SU-789 sono a valle di ticket chiusi oggi; SU-687 e SU-707 sono i due soli bocciati dello sprint e aspettano entrambi la stessa cosa — l'Honor 10 collegato al Mac, che Ivan ha chiesto esplicitamente di fare insieme. ⚠️ Tasso di rientro dei giri precedenti: ancora non misurabile. Delle 38 chiavi messe In revisione ieri e stamattina, nessuna è tornata in «Da fare» — ma Ivan non ha ancora provato su device, quindi quello zero resta «vero per costruzione», che è esattamente ciò da cui questa riga dovrebbe difendersi. 📌 Tre difetti trovati al cancello, nessuno visto dal builder che li aveva scritti, e tutti e tre della stessa famiglia — una verifica verde su una premessa falsa: (1) SU-786 chiamava get_player_data_storage_interface(), un metodo che nel binding EOS non esiste, ed essendo fail-open non avrebbe scritto niente in silenzio per sempre, con la sonda verde — ora la sonda ha una prova negativa che diventa rossa; (2) SU-791 era solo API senza un call-site: nessuno lo chiamava, quindi la marcatura di fine partita chiesta dal ticket non sarebbe mai avvenuta; (3) SU-779 aveva saltato il punto 5 del ticket, lasciando commenti e una sonda che ricavavano il giro dalla soglia — cioè la premessa che il ticket stesso aveva smontato. 📌 Due cose trovate invece guardando gli scatti, non i report: la testata diceva «PAGINA 2» sopra la terza pagina di SU-877, e nella pagina definitiva i due bottoni fanno scorrere la lista (3 righe su 4 visibili in forma telefono). 📌 Il commit non è stato pushato: git push origin dev aspetta l'ok di Ivan.

RIENTRI ATTESI (messi In revisione il 2026-09-12, Sprint 14, giro del mattino da CLI): cinque chiavi — SU-943, SU-944, SU-945, SU-946, SU-940. Perimetro di partenza: 14 ticket in «Da fare», di cui 9 fuori e non per dimenticanza: SU-872 aspetta il Redmi collegato al Mac; SU-871 e SU-870 sono fermi per decisione di Ivan già scritta sul ticket (prima si rimisura, sulla 0.43 con SU-765 e sulla prossima build da store); SU-783 e SU-781 vogliono il referto della 0.44, che non c'è ancora; SU-795 aspetta che la richiesta a Epic la mandi Ivan («la mandi tu»); SU-790 e SU-461 sono nel backlog per sua decisione; SU-782 sta a valle di SU-779 e SU-780, ancora solo «In revisione» e non «Fatto», e vuole tre cosmetici generati e approvati. Lavorati 5 su 5. ⚠️ Tasso di rientro del giro precedente: 0 su 13 — nessuna delle chiavi dello sprint dell'11/09 sera è tornata in «Da fare»; stavolta quello zero pesa un po' più del solito, perché l'11/09 Ivan ha provato davvero i due telefoni sulla build stage b91322a (collaudo a due peer in TESTLOG). ⚠️ Quattro difetti fermati al cancello o dalla review, nessuno visto dal builder che aveva scritto il codice, e tre su quattro sono verifiche verdi su una premessa falsa: (1) in SU-940 il gate era valutato prima di await eb.setup(), e il rientro silenzioso Epic dentro il setup cambia il PUID dopo — la sonda passava, il difetto restava, ed era una via d'ingresso in più oltre al caso ESCI+riaccesso del ticket; (2) sempre in SU-940 il canale coperto dal builder (join_failed) non è quello che si vede: premendo MULTIPLAYER il menu MP non si apre affatto, e il pannello diceva «entra col tuo account» a chi l'account ce l'aveva, mandandolo a rifare il login; (3) in SU-946 l'XP nuovo finiva anche sulle donazioni del super COMIZIO IN PIAZZA, che riusa busk_donate() — si saliva di livello senza suonare, in un ticket che vieta di toccare l'economia; (4) in SU-945 la schermata del cambio nome si apriva muta, perché _open_account_nome() azzerava sempre il codice del motivo: criterio 3 del ticket, verificabile solo leggendo cosa compare a schermo. 📌 Una premessa del ticket smentita dalla misura: SU-944 titolava «LATTINE INSUFFICIENTI esce dal riquadro», e quella scritta sforava di 4,3 px — a sforare di 87,3 era «SBLOCCA (150 LATTINE)» in francese, cioè il caso su cui il pulsante era considerato tarato. Accorciare la chiave del ticket non avrebbe chiuso niente. 📌 Da sapere alla prossima release: _cl_busk_result ha cambiato firma (un terzo argomento); il nome della RPC non è nuovo, quindi nessun id slitta, ma la guardia RPC di SU-934 vede le RPC nuove e non i cambi di firma delle esistenti. Alla 0.44 il minimo MP va comunque alzato (25 RPC nuove in World.gd dal tag v0.43). 📌 Cosa resta più esposto al rientro: nessuna delle cinque chiavi è stata provata su device — SU-943 vuole il cronometro sull'Honor, SU-945 e SU-940 vogliono i due telefoni con due account, SU-946 vuole una suonata vera in un angolo affollato e un collaudo a due peer che le sonde non sostituiscono.

RIENTRI ATTESI (messi In revisione il 2026-09-12, Sprint 14, giro serale da CLI): undici chiavi — SU-941, SU-947, SU-948, SU-949, SU-950, SU-951, SU-952, SU-955, SU-956, SU-957, SU-958. Perimetro di partenza: 20 ticket in «Da fare», di cui 7 fuori e non per dimenticanza: SU-871 e SU-870 fermi per decisione di Ivan già scritta sul ticket (prima si rimisura); SU-783 e SU-781 vogliono il referto della 0.44, che non c'è ancora; SU-795 chiuso dalla sua decisione del 12/09 («non chiederei ad Epic»); SU-790 e SU-461 nel backlog per sua decisione. Restano aperti SU-954 (riportato in «Da fare»: il difetto non è riproducibile, servono le condizioni in cui Ivan l'ha sentito) e SU-953 (design: la raccomandazione è sul ticket, decide lui). ⚠️ Tasso di rientro dei giri precedenti, misurato prima di aprire i lotti: 0 su 5 per il giro del mattino del 12/09 — e stavolta non è «vero per costruzione», perché Ivan ha collaudato davvero la sera del 12/09 su EOS vero coi due telefoni: è da quel collaudo che nascono SU-948, SU-949 e il KO di SU-941. Del giro dell'11/09 sera è rientrata 1 chiave su 13, SU-941. ⚠️ Cinque difetti presi dalla review incrociata o dal cancello, nessuno visto dal builder che aveva scritto il codice: (1) in SU-955 la freccia a schermo e la cartina avrebbero indicato due punti diversi, perché World.gd chiamava la funzione senza passarle la posizione e il parametro aveva un default Vector2.ZERO — e la sonda del builder non poteva vederlo, perché simulava la freccia passandole l'argomento giusto; (2) in SU-958 morire dentro Pausa → Opzioni lasciava i pannelli sopra il giornale, e (3) la chiusura del ventaglio poteva essere annullata da un'apertura già accodata nello stesso fotogramma; (4) in SU-948 la ricarica dello yeti non si armava sull'host per le vittime remote, quindi a tre peer si aggirava proprio il numero che il ticket imponeva, e (5) i 10 px di portata in più del colpo volontario prendevano anche alle spalle. 📌 Due premesse dei ticket smentite dalla misura: SU-947 parlava di «25 RPC nuove in World.gd e 13 in NetworkManager.gd» fra v0.43 e dev, e i numeri veri sono 106 e 23; SU-949 elencava due sospetti e non era nessuno dei due — il verso viene scelto e viaggia, ma nel ramo fantasma un timer di contraccolpo non scende mai e blocca ogni animazione per sempre. 📌 Un verdetto corretto in corsa: in SU-950 la causa «content scale non intero» era stata esclusa perché «stessi numeri alle due risoluzioni», ma i numeri erano in coordinate logiche, dove non potevano cambiare per costruzione; rifatti in pixel di schermo resta esclusa, per una ragione vera. 📌 Tre giri sul provino di SU-952, e nessuno dei tre difetti era nel codice del gioco: una run fotografata appena nata, poi ROI calcolate in coordinate logiche e lette su un buffer di dimensioni diverse (--windowed non rispetta la risoluzione richiesta). 📌 Da provare su device: tutte e undici. SU-957 in particolare non è finito: consegna lo strumento, e la misura che dà il verdetto la deve fare Ivan sull'Honor con bash TMP/su957/comando_honor.sh.

RIENTRI ATTESI (messi In revisione il 2026-09-13, Sprint 14, giro del mattino da CLI): undici chiavi — SU-955, SU-952, SU-962, SU-956, SU-961, SU-965, SU-964, SU-920, SU-959, SU-960, SU-963. Perimetro di partenza: 20 ticket in «Da fare», di cui 9 fuori e non per dimenticanza: SU-954 aspetta da Ivan le condizioni in cui ha sentito la musica interrompersi (non riprodotta il 12/09); SU-953 aspetta la sua scelta sulla raccomandazione; SU-871 e SU-870 fermi finché non si rimisura; SU-783 e SU-781 vogliono il referto della 0.44; SU-795, SU-790 e SU-461 in backlog per sua decisione. ⚠️ Tasso di rientro del giro serale del 12/09: 3 su 11 (SU-952, SU-955, SU-956), più SU-920 da un giro precedente — tutti dal collaudo di Ivan del 13/09 su EOS vero coi due telefoni, da cui nascono anche i sette ticket nuovi. Lo zero dei giri prima era quindi «nessuno aveva ancora provato», non «era giusto». ⚠️ Undici difetti presi dalle review incrociate o al gate, nessuno visto dal builder che aveva scritto il codice: in SU-956 l'host accettava la raccolta di una moneta da qualunque distanza; in SU-962 tre modi di attraversare un muro (nascere dentro un solido, uno scatto su una parete sottile, un passo che entra più a fondo); in SU-959 il tocco dello spettatore e le tenute di metro e banca passavano sotto il menu, e Opzioni e musica restavano accese al game over; in SU-920 un acquisto durante la lettura EOS andava perso e una scrittura fallita non si ritentava più; in SU-961 la prima patch toglieva del tutto il controllo della tenuta; in SU-964 la sonda passava anche rotta (exit code ignorati, path con lo spazio). 📌 Due premesse dei ticket smentite dalla misura: SU-961 sospettava un pezzo di configurazione mancante, ed era la tenuta di 48 px contro un pinguino che cammina; SU-965 dava due rimedi (raw o riduzione) e non era nessuno dei due: la cella da 48 era piccola per la posa alla stessa scala. 📌 Da sapere alla release: SU-956 aggiunge 2 RPC e cambia la firma di _cl_coin_collected — il minimo MP va alzato, e il cambio di firma la guardia non lo vede. 📌 Decisione aperta per Ivan: con l'host morto tossico, spazzino e gattara smettono di attaccare i vivi (SU-964, non toccato). 📌 Da provare su device: tutte e undici; SU-920 per prima con la riga «ID …» nella schermata Account dei tre dispositivi.

RIENTRI ATTESI (messi In revisione il 2026-09-17, Sprint 15, giro notturno da CLI in background, Ivan a dormire con «sei libero»): ventidue chiavi — SU-995, SU-996, SU-913, SU-999, SU-990, SU-1003, SU-1004, SU-1009, SU-984, SU-988, SU-1002, SU-1010, SU-1001, SU-997, SU-1006, SU-1007, SU-1008, SU-986, SU-1005, SU-998, SU-1000, SU-1012; SU-1011 resta In corso (misura e proposta sul ticket, Ivan sceglie la curva). Perimetro di partenza: 32 ticket in «Da fare», di cui 9 fuori e non per dimenticanza: SU-991 aspetta i segnali del suo ticket; SU-989 viene dopo SU-984/986 in produzione; SU-936 vuole Xcode 27.1 e un iPhone Duo; SU-909 è una prova sul telefono di Ivan col suo account; SU-871 e SU-870 sono FERMI per sua decisione; SU-783 e SU-781 vogliono giorni di telemetria della 0.50 uscita il 16/09; SU-26 è in backlog per sua decisione. ⚠️ Tasso di rientro formale dei giri precedenti: 0 — nessuna delle chiavi del 13/09 e del 15/09 è tornata in «Da fare»; ma cinque dei bug nuovi di stanotte vengono dal playtest di Ivan sulla 0.50 su lavoro appena consegnato (SU-1003/1004 sul Branco di SU-907, SU-1009 sui super di SU-933, SU-1010 sul fontanile di SU-406, SU-1001 sui bidoni di SU-764): valgono come rientri sostanziali. ⚠️ Diciannove difetti veri presi dalle review incrociate, nessuno visto dal builder che aveva scritto il codice, corretti in otto lotti di correzione: la potatura della telemetria che cancellava una run vera per undici scarti (SU-990); il refresh delle JWKS che a rotazione con rete giù rifiutava i token per 10 minuti e il retry del client spento (SU-984); il badge del super dentro il riquadro (SU-1009); cinque nel caffè — caffetteria dentro il ramo dei neon, caffè solo sul 4º banco, nessun rifiuto a energia piena, %d non sostituiti, manca _note_shop (SU-997); la fusione della serie chiave per chiave che regalava una lattina al giorno e la serie senza proprietario (SU-1007); lo stato del nome fidato dal client, le prenotazioni multiple per PUID e la grafia in cache (SU-986); lo shader che ignorava modulate, le ante ferme e le braci fuori campo (SU-998). ⚠️ Uno preso dal collaudo di fine onda: l'avviso del quinto giorno che non compariva mai (SU-1007), ora nel giornale. 📌 Tre ipotesi delle review smentite e dichiarate: «frame_start = p non compila» (compila, 181/181), «lo scongelamento viola l'autorità dell'host» (è il disegno del ticket), i nomi italiani in file già tutti in italiano. 📌 Una premessa del brief smentita: il Mercato ha il camioncino anche coi negozi a banco (il provino lo forzava mutando una const). 📌 Decisioni aperte per Ivan sui ticket: SU-1012 cooldown 20 s o 1 s; SU-1000 ok sul foglio dei lampioni; SU-1011 curva; SU-995 scadenze; SU-996/913/999 tre domande ciascuno. 📌 Da provare su device: tutte e ventidue; SU-1002, SU-1005, SU-998 hanno già lo screenshot dall'Honor. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

AGGIUNTA alle 03:40: SU-1011 messo In revisione dopo il «vai avanti» di Ivan (curva applicata, 10 run del bot: 0 carte al livello 5 a 15 minuti). Chiavi In revisione del giro: ventitré.

RIENTRI ATTESI (messi In revisione il 2026-09-19, Sprint 16, giro serale da CLI in background): cinque chiavi — SU-1039, SU-1023, SU-1041, SU-776, SU-783; SU-777 resta In corso (moltiplicatori committati, criterio 1 non confermato dalla sonda, scelta a Ivan con default «si tiene e decide la telemetria della 0.52»). Perimetro di partenza: 21 ticket (20 in «Da fare»/«In corso» più SU-1041 nato durante il giro dall'altra sessione), di cui 15 fuori e non per dimenticanza: SU-1040 lo chiude l'altra sessione; SU-1037 è il controllo settimanale del 24/09; SU-986, SU-989 e SU-909 vogliono la sessione dedicata decisa il 18/09; SU-936 vuole Xcode 27.1; SU-991 nessun segnale scattato; SU-772 e SU-26 aspettano una scelta di Ivan fra alternative; SU-442 è il lavoro sui simulatori, da sessione a parte; SU-781, SU-778, SU-871, SU-870 e SU-771 hanno ricevuto oggi la misura dal referto 0.50+0.51 ma il campione non basta o la decisione è sua. ⚠️ Tasso di rientro del giro precedente (17/09, ventidue chiavi): NON CONTATO in questo giro. Due rientri sono certi perché si vedono da qui — SU-997 (KO di Ivan, richiuso il 18/09, commit efcbade) e SU-986 (tornato in «Da fare» per sua decisione del 18/09, non per un KO) — ma le altre venti chiavi non sono state rilette: il conto va fatto all'apertura del prossimo giro. ⚠️ Sei difetti veri presi dalle review incrociate Codex, nessuno visto dal builder che aveva scritto il codice: in SU-1039 l'annullamento su timeout con request_id nuovo (ACK perso), il crash a metà annullamento, il recupero della 0.51 troppo largo e la ripresa sparita dal menu; in SU-1023 il guard che zittiva la seconda caduta dopo un trasloco; in SU-1041 il dito che arrivava due volte al catcher; in SU-776 la migrazione timbrata a vuoto che un cloud tardivo non riapriva, più l'indizio che diceva «più di uno» con soglia 3. 📌 Una regola del ticket smentita dalla misura: in SU-777 abbassare wanted a 1,00 peggiora la Collina (1,000 → 1,375 vite al minuto), perché il 45% delle vite perse nella sonda è del giullare. 📌 Da guardare a parte: probe_su932_tastiera dà 22 KO anche su HEAD. 📌 Da provare su device: SU-1041 su iPhone e iPad con un account che cambia nome; SU-1039 con una pratica rimasta aperta dalla 0.51; SU-1023 con due telefoni su EOS. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

RIENTRI ATTESI (messi In revisione il 2026-09-20, Sprint 16, giro mattutino da CLI in background): sette chiavi — SU-1042, SU-1043, SU-1044, SU-1045, SU-1046, SU-1047, SU-771. Perimetro di partenza: 22 ticket in «Da fare»/«In corso», di cui 15 fuori e non per dimenticanza: SU-1040 aspetta la build TestFlight su iPadOS 27 e un tester con iPhone su iOS 27; SU-1037 è il controllo settimanale di giovedì 24/09; SU-986, SU-989 e SU-909 vogliono la sessione dedicata decisa il 18/09; SU-936 vuole Xcode 27.1 (sul Mac c'è il 27) e un Duo vero; SU-991 nessun segnale scattato; SU-871 aspetta il playtest di Ivan sul tier 1 da telefono non-S23; SU-870, SU-772 e SU-26 aspettano una sua scelta fra alternative già scritte sul ticket; SU-781 (33 ingressi su 60) e SU-778 (4, 4 e 8 run su 30) non hanno campione; SU-777 aspetta la sua scelta col default già dichiarato; SU-442 è il lavoro sui simulatori, da sessione a parte. Nato durante il giro: SU-1049. ⚠️ Tasso di rientro dei giri precedenti, contato PRIMA di aprire i lotti: 0 su 5 per il giro del 19/09 (SU-1039, SU-1023, SU-1041, SU-776, SU-783: nessuna tornata in «Da fare») e 1 su 22 per quello del 17/09 — solo SU-997, già richiusa il 18/09; SU-986 è tornata indietro per decisione di Ivan, non per un KO. È il conto che il giro del 19/09 aveva lasciato in sospeso. ⚠️ Nove difetti veri presi dalle review incrociate Codex e dal cancello, nessuno visto dal builder che aveva scritto il codice, in quattro giri di correzione: in SU-1043 i district_foes erano rimasti scoperti — ed era il criterio 3 del ticket, con il report che dichiarava «nessun ramo scoperto» — e hits_tall_obstacle_segment() non è una query pura, perché sul riccone invoca cat_bounce(); in SU-1045 l'arresto arrivava dentro il nero a dormita già consumata (misurato: una vita persa, 9 → 8), il timer lasciato in volo da _enter_warn() rimetteva l'agente in caccia due secondi dopo, e la validazione dell'host guardava il solo centro del giocatore mentre il gioco usa la sovrapposizione, rompendo a intermittenza la fascia 23÷30 px; in SU-1046 la soppressione delle notifiche partiva troppo tardi, due volte di fila; in SU-1042 gli identificatori erano in italiano. ⚠️ Due misure che passavano senza misurare niente. In SU-1044 il contrasto era preso sul pixel più scuro dell'intero riquadro e col testo nascosto dava lo stesso identico 16,29:1: ristretto all'etichetta fa 14,96:1 contro 1,17:1 della controprova. In SU-1045 la spunta «reputazione invariata» restituiva letteralmente true. È lo stesso difetto delle verifiche verdi su una premessa falsa già visto l'11/09 e il 17/09, e stavolta stava nelle sonde, non nel gioco. 📌 Una premessa di ticket smentita dalla misura: SU-771 dava per scontato che chi muore di fame sia lontano dai chioschi, e i sei collassi misurati sono a 278,3 px mediani contro i 411,5 di un punto casuale raggiungibile della stessa città — più vicini, non più lontani. 📌 Un parametro di review corretto dal builder misurando: sul caso delle notifiche in chiesa il difetto non si vede a $90 (lì la vita la compra la pressione iniziale), si vede a $80. 📌 Da sapere alla release: SU-1045 aggiunge la RPC _srv_shelter_slept in files/homeless_city/scripts/world/World.gd, quindi il minimo MP va alzato. 📌 Decisioni aperte per Ivan sui ticket: SU-1047 quale strada, sapendo che nella raccomandata la frase prende il posto di «10s · ricarica 1:30»; SU-1044 la tinta del dorato del quinto giorno, se un giorno si rimette; SU-777 la scelta ancora ferma dal 19/09. 📌 Da provare su device: tutte e sette. SU-1045 e SU-1046 per primi, e su due telefoni — un client inseguito che entra nel dormitorio è l'unica parte che nessuna sonda ha attraversato intera. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.

RIENTRI ATTESI (messi In revisione il 2026-09-21, Sprint 16, giro di mezzogiorno da CLI in background): quattro chiavi — SU-1049, SU-1050, SU-1051, SU-1052. Perimetro di partenza: 21 ticket in «Da fare»/«In corso», di cui 17 fuori e non per dimenticanza, gli stessi del 20/09: SU-1040 aspetta la build TestFlight su iPadOS 27 e un tester con iPhone su iOS 27; SU-1037 è il controllo settimanale di giovedì 24/09; SU-986, SU-989 e SU-909 vogliono la sessione dedicata decisa il 18/09; SU-936 vuole Xcode 27.1 e un Duo vero; SU-991 nessun segnale scattato; SU-871 aspetta il playtest di Ivan sul tier 1; SU-870, SU-772 e SU-26 aspettano una sua scelta fra alternative già scritte; SU-781 e SU-778 non hanno campione; SU-777 aspetta la sua scelta col default dichiarato; SU-442 è il lavoro sui simulatori, da sessione a parte. ⚠️ Tasso di rientro del giro del 20/09, contato PRIMA di aprire i lotti: 0 su 7 (SU-1042, SU-1043, SU-1044, SU-1045, SU-1046, SU-1047, SU-771: nessuna tornata in «Da fare»; le tre chiavi nuove SU-1050/1051/1052 nascono dalla decisione di Ivan su SU-1047, non da un KO). Nessun bocciato in questo giro. Piani: SU-1049 a Codex sol (5 minuti, 1 punto), i tre ticket dei superpoteri a due dev-sonnet in parallelo, sul contratto comune (effect in SUPER_CHIAVI, super_effect_text(), 12 righe nel csv) messo dall'orchestratore prima dell'onda. ⚠️ Presi al gate e non dai builder: la riga d'effetto che non si aggiornava al cambio lingua a cerimonia aperta; un provino a una carta sola quando il ventaglio vero ne ha tre; la carta «tieni quella che hai» che in francese sbordava di 7,5 px, e la cura del builder che stringeva le spaziature di tutte le carte, riportata alla sola carta di scambio; una seconda lista dei 12 id nel Quaderno; nella sonda del Quaderno un rm su tutta la cartella d'uscita e una prova che dipendeva dalla lingua del gioco; identificatori italiani nel codice nuovo, compreso quello del contratto. ❌ Un rilievo del gate smentito: le «virgole non quotate» nel csv. 📌 Decisioni aperte per Ivan sui ticket: SU-1050, le frasi di SUPER SCOREGGIA (non dice che costa 30 di fame) e di ASPIRATUTTO (attira entro 400 px, non «tutti»); SU-777 la scelta ferma dal 19/09. 📌 Da provare su device: SU-1049 con due telefoni (l'agente puntato sull'altro, poi AMNESIA); SU-1050 cambiando carta col dito e con una carta di scambio; SU-1051 la linguetta POTERI col dito. Da contare al prossimo giro, PRIMA di aprire lotti nuovi.