La 0.51 è fuori su tutti e quattro i canali, e 51 tester su 52 sono stati avvisati2026-09-19
Chiusura del giro /rilascio-beta della 0.51, fatta in automatico con l'autorizzazione data da Ivan in chat il 19/09 alle 00:10 (testi approvati prima, controllo di Apple in background con caffeinate).
- ✅ Tempo 2, sbloccato da
betaReviewState APPROVED (revisione Apple partita alle 23:53 del 18/09): play_upload.sh --pubblica ha portato il versionCode 51 da draft a completed senza ricaricare il bundle; stato_canali.py → ANDROID ✅ e APPLE ✅. - ✅ Tempo 3: push FCM al topic
su_beta (messages/-951768837011085866, senza CANCELLA ACCOUNT); manifest version_stage.json pubblicato con versione minima multiplayer 0.51; devices.json rigenerato e pubblicato (3 dispositivi di 2 persone, ultima_versione 0.51, obbligatoria_dal 2026-09-26). - ✅ 51 tester avvisati su WhatsApp dall'MCP, un lancio solo di
genera_link_messaggi.py con una frase che nomina tutti e tre i canali (Play, TestFlight, cartella PC/Mac) invece dei tre lanci per piattaforma della 0.50: chi ha più piattaforme riceve un messaggio solo, e la coda col link Play la aggiunge lo script ai soli 30 Android. Apertura «🍕 Fresca di forno, la v0.51 di Street University!»; avviso «CANCELLA ACCOUNT non è ancora attivo: non toccatelo» (SU-1039). Due invii sono rimasti appesi 10-16 minuti nel bridge prima della conferma: nessuno rimandato. - ⚠️ Marco Bianco (Telegram) da avvisare a mano: l'estensione di Chrome non era collegata, il client web di Telegram non si è potuto aprire.
- ✅ Simboli nativi già caricati da Ivan sul versionCode 51 (voce 293). Tolta da
WORKFLOW/04_RELEASE.md la sezione «Per la 0.51 — oltre alla base», come chiedeva lei stessa dopo il tag.
0.51: CANCELLA ACCOUNT non si completa senza `[api] url` e congela l'account; esce così (opzione A), fix nella 0.52 (SU-1039)2026-09-19
Trovato rispondendo a Ivan («va fatto qualcosa per firebase/firestore?») con la 0.51 già in beta review. Nessun codice toccato.
- 🔎 Con
[api] url vuoto (decisione del 18/09) NicknameRegistry.delete_account (~757) va all'Apps Script storico, che delete_account non ce l'ha: la fase BACKEND della pratica fallisce sempre. E la fase 1 (Settings.gd ~1774, ProgressSync.begin_account_deletion ~342) ha già sospeso la sync e salvato la pratica, che blocca il PUID e non si annulla. - ✅ Opzione A di Ivan: la build resta. Tolti i riferimenti a CANCELLA ACCOUNT dai testi fuori dalla build: What to Test di TestFlight («non è ancora attivo: per ora non usatelo»), nota della Beta App Review (rimanda a
/cancellazione/), note della release Play (TMP/note_play_v051.txt, applicate alla bozza con --solo-note), push e messaggio ai tester («CANCELLA ACCOUNT non è ancora attivo: non toccatelo»). Restano la voce nel menu e la voce delle note in-game. - ✅ SU-1039 in backlog: voce solo con un backend vero, niente PUID congelato senza ACK, recupero per chi l'ha premuta sulla 0.51, note della 0.52 che dicono lo stato vero.
- ✅ Simboli nativi caricati da Ivan sul versionCode 51, prima del Tempo 2 per sua scelta: stesso zip combinato della 0.50 (
TMP/su709_simboli/Godot_native_debug_symbols.4.7.2.combinato.zip), motore 4.7.2 e md5 della libeosg riverificati (1351c493…). - ⏳ Giro automatico autorizzato da Ivan (19/09, 00:10): controllo di Apple in background con
caffeinate; all'APPROVED play_upload.sh --pubblica, poi ad Android completed push su_beta, manifest stage (minimo MP 0.51), /lista-beta e messaggio a 52 tester.
La 0.51 al Tempo 1: tag su main, desktop nei cloud, TestFlight in revisione, bozza Play caricata2026-09-18
Giro /rilascio-beta della 0.51, fino all'attesa della beta review di Apple. I comandi su main (merge, tag, push) e la pagina del sito li ha lanciati Ivan con !: l'auto mode di Claude Code li nega come «Modify Shared Resources» / «Out-of-Place Publication», e anche aggiungere un permesso da dentro la sessione è negato («Self-Modification»).
- ✅ Tag
v0.51-cambio-host-caffe-cancella-account su main (merge 7a89bf9), pushato; pagina Changelog del sito rigenerata (commit f54cca4 di street-university-site, con le 62 voci marcate (v0.51) in c291897); marca temporale Aruba verificata (18/09 21:38:48 GMT) in PROVE_DATATE/. - ✅ Desktop:
export_all.sh --env stage mac win --pacchetto, stage verificato nel pacchetto; dmg 173 MB e zip 128 MB su iCloud e Google Drive (MAC/, WIN/). - ✅ TestFlight: build 0.51 (0.51) caricata,
VALID alle 23:53; What to Test in italiano, nelle note della Beta App Review la riga sul percorso ACCOUNT > DELETE ACCOUNT (prima erano vuote), gruppo Divano 204, betaAppReviewSubmission 201 → externalBuildState WAITING_FOR_BETA_REVIEW. - ✅ Play: AAB versionCode 51 (
export_presets.cfg 50 → 51, commit e3260bb) caricato con play_upload.sh --bozza come draft sul canale alpha (seconda release su questa via, dopo la 0.50). I tester ricevono ancora la 50; le note di rilascio si aggiungono con --solo-note (TMP/note_play_v051.txt). - ✅ Data safety di Play (SU-1022): URL di cancellazione passato a
https://www.streetuniversitygame.com/cancellazione/ e inviato in revisione da Ivan; nel riepilogo c'era solo «Sicurezza dei dati», la bozza 51 non compariva. - 📌 Manifest stage 0.51 (minimo MP 0.51) generato in
TMP/release/version_stage.json e NON pubblicato: come per la 0.50 va al Tempo 3, insieme a /lista-beta. - ⏳ Resta: Tempo 2 (
play_upload.sh --pubblica) quando stato_canali.py dice APPLE ✅ APPROVED; poi Tempo 3 (push, manifest, /lista-beta, /avvisa-tester con «chi resta sulla 0.50 non gioca online con chi aggiorna») e i simboli nativi su Play a mano di Ivan.
Release 0.51: note in-game in otto lingue, versione a 0.51 (`/rilascio-beta`)2026-09-18
Giro di rilascio beta lanciato da Ivan con /rilascio-beta. Delta dall'ultimo tag di release v0.50-personaggi-nemici-multiplayer-inviti-megaupdate: voci di CHANGELOG 229-290, lo Sprint 15.
- ✅ Sezione v0.51 in cima a
files/homeless_city/assets/release_notes_it.txt più le 7 gemelle (_en, _fr, _es, _de, _ru, _zh, _pt): 18 voci nel formato SU-721 - TITOLO: testo, sezioni vecchie intatte. Nomi di menu, super e quartieri presi dalle chiavi di files/homeless_city/assets/translations/ (CANCELLA ACCOUNT → DELETE ACCOUNT/SUPPRIMER LE COMPTE…, IL BRANCO → THE PACK/LA MEUTE…, CONCERTONE → MEGA GIG/CONCERT DE FOLIE…, RESET PROGRESSI → RESET PROGRESS…); lattine d'oro, torcia e bonus metro con i termini già usati dalla v0.50 di ogni lingua. - 📌 Il cambio di host è raccontato per quello che fa, non come collaudato: la serie HOST (SU-1026…1030, SU-1038) è in revisione e Ivan non l'ha ancora provata in due su device. Restano fuori dalle note le cose che il giocatore non vede: backend in produzione, registro dei nomi, regole Firestore, telemetria, controllo di iOS 27.
- 📌 Voce SOLO CON LA 0.51 nelle note: la guardia RPC di
prepare_release.sh elenca 8 RPC nuove dalla 0.50 (_cl_ckpt_chunk, _cl_lease, _cl_migration_go, _cl_migration_lobby, _srv_ckpt_ack, _srv_lease_ack, _srv_migration_ready in NetworkManager.gd; _srv_drop_cat_for_torch in World.gd), quindi la versione minima multiplayer del manifest va a 0.51 e chi resta sulla 0.50 non gioca online con chi aggiorna. - ✅
config/version di files/homeless_city/project.godot a 0.51. - [NOVITA'] Il cambio di host — in multiplayer, se chi ospita cade, dopo pochi secondi un altro giocatore prende il suo posto e la partita riparte quasi da dove era.
- [NOVITA'] Il caffè — un bar con la tazzina in ogni quartiere e un banco al Mercato: cinque dollari per un bel pezzo di energia.
- [NOVITA'] Cancella account — dal pannello ACCOUNT, con due conferme, progressi sull'account, nome e punteggi se ne vanno davvero.
- [NOVITA'] L'oro per sempre — lattine d'oro e cosmetici comprati restano anche dopo RESET PROGRESSI, e una lattina d'oro arriva ogni cinque giorni di fila con almeno una partita finita.
- [NOVITA'] Carte ritarate e meno scritte — al livello 5 una carta vale tre volte, non nove; al centro dello schermo restano solo gli avvisi di quando qualcosa non si può fare.
- [NOVITA'] Brina e il treno infernale — otto lampioni, uno per quartiere; la fontana ghiacciata si scongela con una torcia; dal terzo giro del bonus metro il vagone brucia davvero e il treno ha la voce di un demonio.
Caffè: la riga sul banco diceva «Sei già carico» con la barra a 9/10, e il caffè si comprava lo stesso (SU-997 giro 5)2026-09-18
SU-997 — KO di Ivan in chat alle 19:20 con screenshot dal Mac (energia 9/10, riga «Sei già carico: il caffè può aspettare», acquisto che passa). Diagnosi e fix dell'orchestratore.
- 🔎 Causa: la riga sul banco segue le barre solo per i negozi di SU-374 (
Interactable.gd _ready, elenco FOOD_VAN, ICE_CREAM_VAN, LIQUOR_STORE, CLOTHES_STORE, BAGNO_PUBBLICO): il COFFEE_BAR, nato dopo, non c'era. La sua riga veniva calcolata UNA volta, alla generazione della città — con l'energia ancora a 100 — e restava «Sei già carico» per tutta la partita; la guardia dell'acquisto (_is_purchase_stat_full()) leggeva invece il valore vero, quindi comprava. Nessuna delle sonde precedenti leggeva la riga: solo la guardia. - ✅
files/homeless_city/scripts/world/Interactable.gd: Type.COFFEE_BAR nell'elenco dei prompt che seguono stats_changed (una riga, più il commento che spiega la trappola). - ✅ Sonda nuova
files/homeless_city/scripts/tools/probe_su997_prompt.gd + tools/autotest/probe_su997_prompt.sh: legge prompt_label.text (quello che legge il giocatore), non la guardia. Prima del fix: a 90 e 99 la riga diceva «carico» (rossa in 2 punti su 4). Dopo: energia 90/99 → «Caffè: +25 ENERGIA ($5)», 100/115 → «Sei già carico»; acquisto a 60 → 85 e riga «Caffè»; acquisto a 80 → 100 e riga «carico» nello stesso istante, che al primo tick di decadimento (99,97) torna «Caffè». 13/13 verdi. Regressione probe_su997.sh 0 falliti; compile-check OK. - ⚠️ NON PROVATO: telefono (la 0918c non lo contiene).
CONCERTONE: anche la carta della cerimonia ha le note, non più la trombetta (SU-1009 giro 3)2026-09-18
SU-1009 — KO di Ivan in chat alle 18:00 (l'icona nella casella della super andava bene, la carta grande no). Fatto dall'orchestratore, nessun codice toccato.
- ✅
files/homeless_city/assets/ui/super_hi/kazoo.png (128×128 RGBA): la faccia della carta del super CONCERTONE — quella che SuperCeremony.gd mostra alla scelta del superpotere e che LevelUpScreen.gd userebbe per una carta dorata — è ora la variante B con le note dorate, ricavata dal raw già approvato sprites_raw/UI/super_concertone_note_b_128.png con le stesse funzioni di tools/sprite/su1015_riduci_concertone.py (magenta tolto, nessuna frangia: 0 pixel residui). Il perk «Virtuoso della trombetta» (files/homeless_city/assets/ui/perk_hi/kazoo.png) resta la trombetta: è il potenziamento del busking, non il super. - ✅ Provino della cerimonia (
shot_super.gd, finestra 1280×720): carta CONCERTONE con le note, AMNESIA e ATOMICA invariate. ⚠️ Il primo scatto mostrava ancora la trombetta: cache d'import di Godot, servito --headless --import prima dello scatto. - ⚠️ NON PROVATO: telefono (la 0918c non la contiene).
HOST 4/5 giro 2: la caduta dell'host si rileva dagli heartbeat (4 s, non 60), l'host sospeso si demuove al ritorno, il tunnel torna com'era (SU-1038)2026-09-18
SU-1038 — lotto H1038 costruito da architetto-opus, gate Codex, chiuso dall'orchestratore. Nato dai tre FAIL del collaudo SU-1030; deciso in chat da Ivan alle 14:45. Nessuna RPC nuova (MSG_HOST_TIMEOUT/MSG_HOST_DEMOTED sono transizioni locali del lease): il minimo MP non cambia per questo lotto.
- ✅ Rilevamento dagli heartbeat (
files/homeless_city/scripts/net/AuthorityLease.gd: HEARTBEAT_TIMEOUT_MS 5000, SUSPEND_GAP_MS 2000, on_resumed; NetworkManager.gd: ramo di MSG_HOST_TIMEOUT che avvia lo stesso trasloco di server_disconnected chiudendo da sé il peer vecchio): con lo stesso kill -STOP dell'host, t_detect 59.555 → 4.040 ms, t_go dal rilevamento 3.411 → 203 ms. Un client tornato dal background riparte da zero e aspetta una finestra piena (5.027 ms fra ripresa e dichiarazione, contro ~0 senza guardia): nessun trasloco a vuoto. - ✅ Auto-demozione (
_permesso_scaduto, _demuoviti, _lease_demozione, gancio NOTIFICATION_APPLICATION_RESUMED in _notification): l'host che aveva client e non riceve ACK oltre LEASE_TTL_MS + MARGIN_MS, o che al ritorno trova il permesso scaduto, smette di arbitrare e chiude come vecchio host (MP_HOST_SPETTATORE): demozione 39-48 ms dal -CONT, vuoto fra le due autorità +2.280 ms, doppie autorità 0 anche nei 4 casi nuovi (f/g/h/i) di probe_host_2. Un host senza client non si demuove mai (smoke SP pulito). - ✅ Tunnel (
files/homeless_city/scripts/net/HostAdapter.gd _scrivi): bug vero — Object.set() su una proprietà Array[int] con un Array NON tipizzato non scrive e non protesta (verificato con una sonda usa-e-getta); tunnel_underground_ids, _tunnel_done_wait e _tunnel_done_rows non tornavano mai e venivano contati fra gli «applicati». Cura generica: Array.assign() nel tipo che la proprietà ha già e rilettura dopo la scrittura (chi non torna finisce in saltati). probe_host_5_tunnel_monete: tunnel_underground_ids=[1], round 97, monete 0. - ⚠️ Due difetti nelle sonde di SU-1030 che avevano falsato il «rilevamento 0-65 s»:
lancia … & metteva una subshell in mezzo e $! era l'involucro (il kill non arrivava a Godot, che usciva da solo a 80 s); i lanciatori aspettavano «OK N peer vivi» sullo stdout bufferizzato. Corretti in tools/autotest/_host5_common.sh, probe_host_5_rete.sh, probe_host_5_background.sh, probe_host_5_tunnel_monete.sh (exec env …, attesa sul referto, timestamp dentro la riga); nuovo tools/autotest/probe_host_5_client_background.sh (3 peer). Gli altri probe_host_5_* e probe_host_4.sh hanno ancora la forma vecchia: le loro righe della matrice sono da riguardare. clock_delta_s 3,33 → 8,3-9,6 s ed è giusto (il 3,33 era di una chiusura gentile; soglia della sonda a 10 s). - ✅ Regressioni:
probe_host_2/3/4, probe_coll_giullare_mp verdi; compile-check 883 script/100 scene, 0 errori. docs/HOST_MIGRAZIONE_COLLAUDO.md rimisurato nelle tre righe con nota datata. - 📌 Decisione per Ivan (conseguenza del disegno SU-999, non difetto): in una partita a DUE, se l'unico ospite — che è anche l'unico successore — sparisce per più di 4 s (app in background), l'host si demuove e la partita finisce per entrambi: l'host non distingue un ospite sospeso da uno che, oltre una rete spezzata, sta per prendersi lo scettro. La cura vera («non arbitro ma non chiudo» in attesa dell'ospite) cambia il gioco e non è stata fatta qui.
- ⚠️ NON PROVATO: due telefoni veri (ora le prove del documento dovrebbero mostrare
[MP] SU-1038 host muto … entro ~5 s e, sull'host in background, [MP] SU-1038 permesso scaduto + MP_HOST_SPETTATORE); tutto il ramo EOS (on_exit_background del bridge non è usato: il gancio è NOTIFICATION_APPLICATION_RESUMED).
Registro dei nomi: lettore di sola lettura delle due sorgenti, dopo il caso «ale senza nome»2026-09-18
Segnalazione di un tester di stage alle 13:40: in classifica «SENZA NOME» al posto di «Ale». Indagine dell'orchestratore, nessuna modifica al gioco.
- 🔎 Causa: la 0.50 di stage legge e scrive i nomi in Firestore (
registro/stage/nicknames), seminato dal foglio dell'Apps Script il 5/09 (13 nomi in comune, tutti con creato 2026-09-05). Chi si è registrato con una 0.43 dopo quella data stava solo nel foglio — Ale (08/09), Gas (12/09), Divano_Prime — e per la 0.50 non ha nome. La riconferma del tester (13:39) ha creato nicknames/ale; il cambio nome (13:50) nicknames/ale_your_mother; l'orfano nicknames/ale resta perché il client non cancella (SU-917). La pulizia della moderazione (SU-1016) tocca solo la scheda moderazione ed è estranea. - ✅
tools/firestore/leggi_registro.py (nuovo): --env stage --cerca ale --sorgente foglio|firestore|entrambe, PUID mascherati, e il confronto fra i due registri (nomi solo nel foglio = SENZA NOME nelle build nuove finché il giocatore non riconferma). Stesso service account di applica_giudizi.py. - 📌 Decisioni a Ivan: copiare in Firestore i due nomi rimasti nel foglio, cancellare l'orfano, agenda per SU-986 (migrazione vera). Miglioria separata: nel giornale la riga propria da
my_display_name() (HUD.gd 6588/6671).
Lease su EOS: un attributo lobby per successore, mai la lista unita (FAIL 1 del collaudo HOST 5/5)2026-09-18
Dal collaudo SU-1030: SU_SUCC con tre PUID uniti da virgole faceva 98 caratteri contro i 64 ammessi da EOS per il valore di un attributo (EOS_LOBBYMODIFICATION_MAX_ATTRIBUTE_LENGTH): su una lobby vera l'aggiornamento degli attributi del lease sarebbe fallito intero. Orchestratore, senza lotto.
- ✅
files/homeless_city/scripts/autoload/EOSBridge.gd: SU_SUCC1, SU_SUCC2, SU_SUCC3 (32 caratteri l'uno, vuoti se mancano), lease_successors è un PackedStringArray tagliato a tre; il numero di attributi sale a 13 su 64. - ✅
tools/autotest/probe_host_5_eos_limiti.sh misura ciò che il codice fa davvero (un PUID per attributo): SU_SUCC esito=OK (32/64), ESITO=OK; check_files su EOSBridge 0 falliti. - ⚠️ NON PROVATO su una lobby EOS vera (nessuna sonda la tocca): chi legge gli attributi in HOST 4/5 o dopo deve cercare
SU_SUCC1..3, non SU_SUCC.
HOST 5/5: la matrice di collaudo del cambio di host, riga per riga (SU-1030)2026-09-18
SU-1030 — lotto H1030 fatto dal collaudatore, gate Codex, chiuso dall'orchestratore. Nessuna modifica al gioco: solo sonde, lanciatori e il report docs/HOST_MIGRAZIONE_COLLAUDO.md (tabella, sezione «prove su device» per Ivan, «cosa non è misurato»).
- ✅ Undici lanciatori
tools/autotest/probe_host_5_kill.sh … tools/autotest/probe_host_5_minimo_mp.sh (uno per riga, più tools/autotest/_host5_common.sh) e la sonda files/homeless_city/scripts/tools/probe_host_5.gd/.tscn (deriva da probe_host_4) per i quattro casi nuovi. PASS: kill 2/3 peer (GO in 4,5 s), rete (kill -STOP, GO in 3,4 s dal rilevamento), successore_perso (cascata a due salti, GO in 4,5 s), host_rientrante (spettatore in 2 s), chunk (hash uguali, 0 doppi), npc (4 NPC rigenerati 5 s dopo il GO), peer_4_8 (solo peer finti: NON MISURATO sul filo), minimo_mp (8 RPC nuove dalla 0.50, tutte viste da rg_guardia_rpc_mp: _srv_drop_cat_for_torch, _cl_lease, _srv_lease_ack, _cl_ckpt_chunk, _srv_ckpt_ack, _srv_migration_ready, _cl_migration_go, _cl_migration_lobby). - ❌ FAIL
eos_limiti: l'attributo lobby SU_SUCC (tre PUID da 32 uniti da virgole = 98 caratteri) supera EOS_LOBBYMODIFICATION_MAX_ATTRIBUTE_LENGTH = 64 (eos_lobby_types.h): su una lobby EOS vera l'aggiornamento degli attributi del lease fallirebbe. Il resto è dentro i limiti: 11 attributi su 64, SU_HPUID 32/64, busta del checkpoint 968/1170. → corretto subito sotto (voce 286). - ❌ FAIL
background: l'host sospeso (kill -STOP 10 s, poi -CONT) torna e resta host con epoca 0: nessuna auto-demozione quando il suo permesso è scaduto (proposta §1: «controllo della scadenza al ritorno dal background»); in 2 prove su 3 il guest non ha nemmeno rilevato la caduta entro 90-150 s. - ❌ FAIL
tunnel_monete (parziale): monete a terra azzerate ✓ e tunnel_round ripristinato ✓, ma tunnel_underground_ids torna [] (HostAdapter.gd:533): bug di ripristino o limite della sonda (inietta lo stato con set() invece di un ingresso vero nel tunnel), causa non isolata. - ⚠️ La scoperta che conta: il collo di bottiglia è il RILEVAMENTO, non il trasloco. Una volta rilevata la caduta il GO arriva in 3,3-4,5 s; ma il rilevamento in ENet passa dal timeout del trasporto (
server_disconnected): quasi istantaneo in alcune prove, 60-65 s in altre, con lo stesso kill -9 (misurato 3 volte a 3 peer). Il lease di HOST 2/5 ha l'heartbeat ogni secondo ma la caduta si dichiara solo dal segnale del trasporto: per stare nei 15 s serve dichiarare l'host perso quando gli heartbeat tacciono (es. 5 s), non quando lo dice ENet/EOS. - 📌 Prove su device (Ivan, Honor + iPhone): kill dell'app, modalità aereo 15 s, home 15-20 s; righe da cercare
[MIGRA], [CKPT], SU-1027 (adb logcat acceso PRIMA; su iPhone Xcode → Devices → logs). Passi esatti nel doc. - ⚠️ NON MISURATO:
SU_SUCC su EOS vero, identità stabile dell'host rientrante (in ENet è il peer id), 4/8 peer sul filo, NPC su un client puro, doppio pagamento con soldi veri in movimento, causa della variabilità 0-64 s nel rilevamento. Tre bug corretti nella sonda stessa (grep su log bufferizzato, auto-terminazione del guest-host, run_active di uno spettatore).
HOST 4/5: il trasloco — scettro al successore in P2P, ripristino dal checkpoint, lobby nuova in background, marca «migrata» (SU-1029)2026-09-18
SU-1029 — lotto H1029 costruito da architetto-opus, gate Codex, chiuso dall'orchestratore. Il cambio di host ora AVVIENE (in ENet, provato con l'host ucciso a kill -9); il ramo EOS (lobby nuova, connessione per PUID) è scritto ma non provato. ⚠️ Tre RPC nuove: alla release il minimo MP sale alla versione che esce. HUD e MainMenu non toccati: l'avviso passa da EventBus.big_notify.
- ✅ P1 scettro in P2P (
files/homeless_city/scripts/autoload/NetworkManager.gd, ~630 righe _migra_*): alla caduta dell'host, se c'è un successore e si è in partita, niente _quiet_close: freeze con MP_HOST_CAMBIO_IN_CORSO ogni 2 s, il primo successore rispetta l'attesa del lease (TTL 3 s + 1 s) e crea il server (EOS make_server_peer(); ENet porta+1 perché sulla stessa macchina la porta del morto può essere ancora occupata), gli altri si connettono (EOS make_client_peer(puid); ENet con l'addr che il vecchio host aveva messo nel registro), rimappa per slot/identità stabile (_id_stabile, congelata al via: in ENet il peer id cambia col trasloco), barriera _srv_migration_ready(epoch, ident, slot) → _cl_migration_go(epoch, hash), poi _lease_start() con l'ordine residuo e _ckpt_start(). Il claim non va sul filo (alla caduta non c'è più canale): vale come ordine a sé stessi dopo l'attesa del lease; ai client lo consegna il GO (_lease.on_claim), riga trovata dalla sonda a tre peer. - ✅ Freeze con guardia:
get_tree().paused = true NON basta — nove punti della UI scrivono paused = false senza condizioni (HUD.gd 1155/2025/2048/4046/6793/7003, LevelUpScreen.gd 2046/2126, SuperCeremony.gd 924): una cerimonia che si chiude a metà trasloco scioglierebbe il freeze. _migra_freeze_tick() rimette la pausa a ogni frame e ricorda che qualcuno l'ha rilasciata, così al GO restituisce lo stato giusto. - ✅ P2 ripristino (
files/homeless_city/scripts/net/HostAdapter.gd apply_snapshot/apply_peer_row; World.net_migration_apply()): 31 sorgenti riapplicate, 0 saltate — orologio con la frazione (delta 3,33 s, criterio ≤5), meteo e ondata, run/difficoltà/retata, evento del giorno, riccone, tunnel per slot, registro oggetti, per ogni peer wanted/punteggi/finali/endless/raffreddamenti; transitori e NPC azzerati dal World (libera nodi: lavoro suo). Del journal si rigioca solo OBJECT: gli eventi di VALORE (MONEY/XP/CANS/LIFE/CARD/BANK) erano coniati dai segnali del giocatore LOCALE del vecchio host (HostAdapter.gd:178-217) e accreditarli al nuovo sarebbe inventare denaro (journal_valore_saltati). - ✅ P3 lobby (solo EOS, non provabile in ENet): il nuovo host crea la lobby con
SU_MIGRATED (EOSBridge.set_migrated), _cl_migration_lobby(epoch, lobby_id) porta tutti sulla nuova, la vecchia viene lasciata. - ✅ P4 marca «migrata» (
files/homeless_city/scripts/autoload/OnlineLeaderboard.gd, sola marca): busta_record() porta {"migrata": true, "epoch": n}; oggi il punteggio viaggia come stat EOS (un intero legato al nome della stat: nessuna busta), quindi la marca vive in last_submit_migrata/last_submit_epoch e nella coda su disco, pronta per il registro HTTP di SU-1017. ⚠️ Backend (Ivan): accettare e salvare due campi opzionali migrata (bool) ed epoch (int); le build vecchie non li mandano. - ✅ P5 sonda
tools/autotest/probe_host_4.sh + files/homeless_city/scripts/tools/probe_host_4.gd/.tscn (2 e 3 peer ENet, host ucciso a kill -9 dopo 20 s): a 2 peer t_authority=3421 t_go=3423 ms, a 3 peer t_go=4518 sull'erede e 4529 sull'ospite ricollegato (obiettivo 8.000, tetto 15.000: i 3,4 s sono l'attesa del lease); controprova rossa SU1029_ROSSA=1: t_go=-1, il guest torna al menu come oggi. «Vecchia lobby non in ricerca entro 30 s»: NON MISURABILE in ENet. probe_host_2, probe_host_3, probe_coll_giullare_mp verdi; compile-check 0 errori; audit emoji 0. - ⚠️ NON PROVATO / rischi: due telefoni veri con l'host che chiude l'app (il criterio); tutto il ramo EOS; il vecchio host che rientra da spettatore; in ENet l'identità al rientro è dichiarata (su EOS la legge il trasporto), l'
addr visto dal vecchio host può non valere dietro NAT (ripiego 127.0.0.1); seconda caduta durante il trasloco esclusa (proposta §4.7); spettatori non provati; WeatherSystem.state scritto con set(). Lezione: non si modifica un .sh mentre gira (bash lo rilegge a offset: «unbound variable»).
HOST 3/5: checkpoint e journal idempotente verso i tre successori, con ACK e backpressure (SU-1028)2026-09-18
SU-1028 — lotto H1028 costruito da architetto-opus, gate Codex, chiuso dall'orchestratore. Il checkpoint ARRIVA ai successori; nessuno lo riapplica ancora (HOST 4/5). ⚠️ Due RPC nuove: alla release il minimo MP sale alla versione che esce.
- ✅
files/homeless_city/scripts/net/CheckpointChannel.gd (nuovo, RefCounted, nessuna rete, clock da fuori): mittente con coda per destinatario, fotografia ogni 5 s e delta del journal raggruppati ogni 200 ms (la busta costa 68 B, un evento 36), chunk atomici con la busta di Checkpoint, ACK per chunk, ritrasmissione, budget 1.200 B/s per peer su finestra scorrevole, potatura del journal quando un id è confermato da tutti, «salta un giro» a budget esaurito; ricevente con riassemblaggio per [epoch, seq], scarto di chunk duplicati/vecchi, journal applicato SOLO via Checkpoint.journal_append (un id già visto non produce effetti). Fotografia e journal viaggiano separati: il journal è l'84% del traffico (HOST 1/5) e rimetterlo in ogni fotografia moltiplicherebbe per sei il vincolo. SCHEMA_VERSION resta 1, Checkpoint.gd intatto. - ✅
files/homeless_city/scripts/net/HostAdapter.gd (nuovo, Node solo sull'host in partita): collect_sources() legge le sorgenti vere con get() — 0 non leggibili misurate in partita — e osserva i segnali esistenti per coniare gli effetti irreversibili con id event_id(epoca, seq). beg_response non si giornala: il denaro passa già da money_changed, giornalarlo due volte sarebbe il doppio pagamento che il journal impedisce. Mancano, misurati: TUNNEL non ha segnale (i risultati stanno nella fotografia); gli effetti economici dei CLIENT non sono osservabili dall'host (solo _net_live_money) → si coniano dentro le RPC economiche in HOST 4/5. Difetto vero trovato dalla prova a due peer: _tunnel_done_wait è un Array[int], non un Dictionary — l'adapter faceva uno SCRIPT ERROR a ogni giro. - ✅
files/homeless_city/scripts/world/World.gd: registro _net_object_log (net_id → {consumed, cooldown_until}) scritto nei 4 punti dove un oggetto viene usato/consumato (ramo locale compreso: la RPC è call_remote); solo memoria, nessun ramo di gioco lo legge. È la riga «non esiste» del doc di HOST 1/5, ora chiusa (§8 aggiornato). - ✅
files/homeless_city/scripts/autoload/NetworkManager.gd: _cl_ckpt_chunk(bytes) (authority, reliable, rpc_id ai SOLI successori, busta max 968 B, margine EOS 202) e _srv_ckpt_ack(epoch, seq, index) (any_peer, mittente da get_remote_sender_id(), accettato solo da chi è in successor_order()); _ckpt_tick nel _process dell'host con tetto di 2 ms per frame, _ckpt_start in _cl_game_starting, _ckpt_stop in _quiet_close; last_checkpoint() e ckpt_stats() pubblici per HOST 4/5. - ✅ Sonda
tools/autotest/probe_host_3.sh + files/homeless_city/scripts/tools/probe_host_3.gd (1 mittente + 3 riceventi, 10 min virtuali in 0,3 s di parete, perdita 10%, duplicazione 5%, ritardo 50-500 ms e riordino anche sugli ACK): hash 406162408570697919 uguale sui tre riceventi e sul mittente, 323 eventi, 0 doppi (167 duplicati fermati da journal_append), max_Bs=1196, p95 1.156-1.160, media 572-610, max_chunk_us=18; caso B (60 eventi/s contro 1.200 B/s): 19 giri su 21 saltati, 1.110 righe potate, hash ancora uguale. Sul filo vero: guest ENet [CKPT] ricevuto epoch=0 seq=3 chunk=1/1 snapshot=true; probe_coll_giullare_mp verde; compile-check 881 script/100 scene, 0 falliti. - ⚠️ NON PROVATO: nessun device (il tetto di 2 ms è misurato solo headless sul Mac), nessuna lobby EOS, nessun trasloco; la potatura è sicura solo finché i destinatari non entrano/escono mentre si pota (un successore che rientra riceve il journal vivo: lo copre la fotografia piena, ma il conto degli eventi diverge — da tenere presente in HOST 4/5, con
peers[].last_op_seq come filigrana); reliable su ENet maschera le perdite, su EOS no.
HOST 2/5: identità autenticata, successori ordinati fino a tre e lease dell'autorità (SU-1027)2026-09-18
SU-1027 — lotto H1027 costruito da architetto-opus, gate Codex, chiuso dall'orchestratore. Solo cablaggio e contratto: alla caduta dell'host la partita si chiude esattamente come prima — il trasloco è HOST 4/5. ⚠️ Due RPC nuove: alla release il minimo MP sale alla versione che esce.
- ✅
files/homeless_city/scripts/net/AuthorityLease.gd (nuovo, class_name AuthorityLease, RefCounted, nessuna rete, clock passato da fuori): epoca, host, ordine dei successori (max 3, fisso al via: partecipanti iniziali abilitati a ospitare, spettatori esclusi), challenge/nonce/permesso come da proposta (1 s, 3 s, +1 s di margine; CLAIM_RETRY_MS 2 s distinto da CLAIM_WAIT_MS 5,5 s perché con un'attesa unica la cascata di tre cadute arrivava a 16,5 s); uscite claim, accept, reject_old_epoch, spectator, close_no_successor, migration_started. Vecchio host tornato con epoca vecchia = spettatore. Limite dichiarato in testa: «mai due autorità» vale dentro una componente connessa, non contro una rete spaccata in due. - ✅
files/homeless_city/scripts/autoload/NetworkManager.gd: puid nelle righe del registro — letto dal trasporto (EOSGMultiplayerPeer.get_peer_user_id(peer_id), firma verificata con ClassDB), mai dichiarato dal client; in ENet enet:<peer id>. Ordine dei successori calcolato al via e replicato; heartbeat _cl_lease(epoch, host_puid, successori, nonce) (authority, unreliable, ~160 B) ogni 1 s e _srv_lease_ack(nonce) (any_peer, mittente da get_remote_sender_id()); in _on_server_disconnected, PRIMA della chiusura odierna, on_host_lost e il segnale nuovo host_migration_decided(epoch, successor_puid, my_role) per HOST 4/5; getter authority_epoch(), successor_order(), local_identity(). Trovato dalla sonda ENet (non da quella a peer finti): un client nasce senza sapere chi comanda e scambiava il primo heartbeat per un'epoca estranea → corretto, con controllo dedicato. - ✅
LOBBY_CHUNK da 3 a 2 righe per blocco (orchestratore, misura con var_to_bytes): col puid il caso peggiore — nome di 16, otto quartieri sbloccati, skin lunga — fa 3 righe = 1.148 B, 1.188 B con gli argomenti della rpc: oltre i 1.170 del peer EOS, che scarta in silenzio; 2 righe = 808 B. Era la raccomandazione della proposta. - ✅
files/homeless_city/scripts/autoload/EOSBridge.gd: attributi lobby SU_EPOCH/SU_HPUID/SU_SUCC nello stesso update_async (set_lease_attrs()), mask_puid() pubblico per i log. - ✅
files/homeless_city/assets/translations/ui_gioco.csv (dove stanno tutti i MP_*): MP_HOST_CAMBIO_IN_CORSO, MP_HOST_SPETTATORE, MP_HOST_NESSUN_SUCCESSORE in 8 lingue, non ancora mostrate. - ✅ Sonda
tools/autotest/probe_host_2.sh + files/homeless_city/scripts/tools/probe_host_2.gd: 4 peer finti (5 nel caso d), bus 50-300 ms, 10% di perdita, tempo virtuale, 26 controlli: (a) cade l'host → primo successore in 3,15 s; (b) cade anche lui → secondo in 3,8 s; (b2) capofila morto prima di reclamare → 6,2 s; (c) vecchio host tornato → spettatore in 0,35 s; (d) cadono host e tre successori → chiusura a 10 s; doppie autorità 0 in tutti i casi, contando anche i morti col permesso non scaduto. probe_coll_giullare_mp (2 peer ENet) verde, anche dopo LOBBY_CHUNK=2; compile-check 878 script/100 scene, 0 falliti; audit emoji 0. - ⚠️ NON PROVATO: nessun device, nessuna lobby EOS vera (gli attributi non sono mai stati scritti su Epic), nessun PUID vero;
claim/accept/reject_old_epoch non hanno ancora una RPC (il canale nasce con la lobby nuova di HOST 4/5).
HOST 1/5: inventario dello stato di partita, contratto del checkpoint e misura vera a 2/4/8 peer (SU-1026)2026-09-18
SU-1026 — lotto H1026 costruito da architetto-opus, gate Codex, chiuso dall'orchestratore. Primo dei cinque lotti del cambio di host (SU-999, design di TMP/su999/PROPOSTA.md confermato da Ivan il 17/09). Solo contratto, doc e sonda: gameplay, RPC, NetworkManager.gd e World.gd non toccati.
- ✅
docs/HOST_MIGRAZIONE_STATO.md (nuovo, 339 righe): inventario di 134 righe di stato con file:riga di oggi e decisione scritta — 86 TIENI, 18 RICALCOLA, 29 AZZERA e un registro nuovo (le modifiche agli oggetti) da scrivere in HOST 3/5; gli NPC si azzerano e si ricalcolano dal seed. Le righe «adapter» della proposta sono chiuse: _time_accumulator e i timer delle ondate esistono; l'RNG del meteo NON esiste (randf() globale: la prossima ondata è estrazione nuova); la durata dell'evento del giorno NON esiste (vale tutto il giorno); i dispetti sono OTTO, non cinque → riga peer da 23 a 26 interi. Adapter ancora da scrivere in HOST 3/5: HostAdapter, registro persistente delle modifiche agli oggetti (oggi un consumato fa queue_free()), getter per i privati, conversione peer id ↔ slot, puid/roster_rev nel registro (HOST 2/5). ⚠️ §5 (effetti economici) e §6 (cosa si azzera) vogliono l'ok di Ivan: §6 è perdita dichiarata di prodotto. - ✅
files/homeless_city/scripts/net/Checkpoint.gd (nuovo, class_name Checkpoint, nessun autoload, nessuna RPC): SCHEMA_VERSION = 1, build_snapshot(sources), journal con id idempotente epoch<<32 | seq (journal_append rifiuta i duplicati), serialize/deserialize senza oggetti e con controllo dello schema, digest, split_chunks/join_chunks con busta [schema, epoch, seq, index, total, hash, bytes]. Regola di compatibilità: schema diverso → checkpoint rifiutato intero (nessuna conversione campo per campo; chi rifiuta tiene l'ultimo valido; senza nessuno la migrazione non parte) e quando SCHEMA_VERSION cambia si alza il minimo MP. - ✅ Sonda
tools/autotest/probe_host_1.sh + files/homeless_city/scripts/tools/probe_host_1.gd: mondo vero (seed 20261026, downtown), Engine.time_scale = 6, peer finti nel registro, 103 s di parete. Snapshot 972/1.224/1.704 B a 2/4/8 peer al minuto 1 (stima della proposta 976/1.256/1.624: regge, +80 B a 8 peer = i dispetti), 2.148 B a 8 peer al minuto 10; journal 972 → 5.436 → 11.520 B ai minuti 1/5/10 (36 B per evento); busta 968 B costante (margine EOS 202 B). serialize→deserialize con hash uguale. Compile-check 878 script/100 scene, 0 falliti. - 📌 Tetto di banda proposto a HOST 3/5: 1.200 B/s per peer (6.000 B ogni 5 s, ≤6 chunk). Il vincolo vero non è lo snapshot ma il journal: a 8 peer al minuto 10 è l'84% del traffico. Backpressure: prima si compatta il journal, poi si salta un giro.
- ⚠️ NON PROVATO: nessun peer vero, nessuna rete, nessun overhead RPC/EOS sul filo; tipi
TUNNEL/BANK/CARD senza eventi osservati (il bot non apre il tunnel; level-up spento perché la cerimonia delle carte mette in pausa l'albero). La sonda gira con folla diradata e fisica a 30 Hz: senza quelle leve time_scale non accelera.
Multiplayer: il gatto posato dal client nello scambio gatto→fiaccola lo crea l'host e lo vedono tutti (SU-1031)2026-09-18
SU-1031 — lotto K1031 costruito da dev-sonnet, gate Codex, chiuso dall'orchestratore.
- ✅
files/homeless_city/scripts/player/Player.gd drop_cat_for_torch(): non crea più il gatto in locale; il punto scelto (regola di SU-1013: nessuno lo ricalcola) va a World.net_drop_cat_for_torch(pos). has_cat resta locale e immediato: la fiaccola in mano non aspetta la rete; se l'host rifiuta, il gatto non nasce e basta (nessun rollback). - ✅
files/homeless_city/scripts/world/World.gd: net_drop_cat_for_torch (host/SP crea subito), _host_drop_cat_for_torch (id dinamico + _cl_cat_spawned a tutti come i randagi di rimpiazzo, così la raccolta successiva lo toglie a tutti), RPC nuova _srv_drop_cat_for_torch(pos, had_cat) (any_peer): l'host verifica mittente, flag dichiarato (schema di _srv_busk) e distanza dal puppet ≤ NET_DROP_CAT_MAX_DIST (120 px = 24 di posa + 96 di ritardo del puppet, SU-956). ⚠️ RPC nuova: alla release il minimo MP sale alla versione che esce. - ✅ Sonda a due peer ENet
tools/autotest/probe_su1031_mp.sh + files/homeless_city/scripts/tools/probe_su1031_mp.gd e files/homeless_city/scripts/tools/probe_su1031_mp.tscn: prima del rimedio (fix invertito sulla sola copia harness) host 16 gatti e client 17 → FAIL; dopo, un gatto a 800,760 su entrambi (0 px) e raccolta host = client → OK. probe_su1013 (singolo) verde dopo aver insegnato allo stub del World la chiamata nuova; compile-check 878 script/100 scene, 0 falliti. - ℹ️ Verso inverso (fiaccola posata quando raccogli il gatto,
_lascia_cadere_torcia): nel World non esiste alcun canale di rete per una fiaccola a terra, quindi resta in locale come oggi — riportato, non inventato. - ⚠️ NON PROVATO: due telefoni veri (solo due processi ENet sullo stesso Mac).
iOS: il crash alla chiusura dell'app era il nostro plugin, che faceva spegnere il motore due volte (SU-1032)2026-09-18
Diagnosi dai sorgenti del motore 4.7.2 e dal disassemblato dell'archivio: gli 11 .ips di TestFlight (0.43 e 0.50, tutti fra le 20:29 del 15/09 e il 16/09) muoiono in Main::cleanup+104, cioè OS::get_singleton()->benchmark_begin_measure(...) con OS::singleton già NULL — un secondo apple_embedded_finish(). Il perché è nostro: tools/ios/su_native_auth/su_native_auth.m (SU-992, link d'invito, commit 581b4c6 del 15/09 alle 19:56: nessun crash prima) registrava nel delegate di Godot un servizio costruito con objc_allocateClassPair(GDTAppDelegateService, …); GDTApplicationDelegate inoltra ogni callback UIKit a tutti i servizi che rispondono al selettore, e la sottoclasse ereditava anche applicationWillTerminate: → apple_embedded_finish() eseguito due volte. Raddoppiava anche on_focus_in/out e on_enter_background (NOTIFICATION_APPLICATION_PAUSED ×2).
- ✅
su_native_auth.m: la classe runtime del servizio deriva da NSObject (con i protocolli UIApplicationDelegate/UIWindowSceneDelegate dichiarati); il delegate ci chiama solo per i metodi del link d'invito. Plugin ricompilato con tools/ios/build_su_native_auth.sh: il dylib iOS non contiene più la stringa GDTAppDelegateService; il dylib macOS è identico byte per byte (la parte è solo TARGET_OS_IPHONE). - ✅ Rimedio economico deciso da Ivan:
EOSBridge._finish_quit() su iOS non chiama mai get_tree().quit(). Nel motore 4.7.2 (drivers/apple_embedded/godot_view_renderer.mm) il renderer ignora il ritorno di iterate(): su iOS il quit non termina nulla, l'unica uscita è quella del sistema. ESCI DAL GIOCO era già solo desktop (MainMenu._is_mobile()), WM_CLOSE_REQUEST su iOS non esiste. - ℹ️ Template più nuovi (rimedio 3): 4.7.2-stable del 18/08/2026 è l'ultima release; l'inoltro ai servizi è per disegno, un template nuovo non cambierebbe nulla. Lo swizzle nativo (rimedio 2) non serve.
- ⚠️ NON PROVATO sul telefono: serve una build iOS nuova e le 10 chiusure a swipe di Ivan (menu, in partita, subito dopo il lancio) senza nuovi
.ips (xcrun devicectl device copy from --domain-type systemCrashLogs).
Backend in produzione: progetto preparato, function `api` e Hosting pubblicati, segreto HMAC e TTL (SU-988, SU-984, SU-1018)2026-09-18
Con Ivan alla tastiera (05:30-06:10), un comando alla volta con !; verifiche da terminale dell'orchestratore. Deploy, regole e segreti restano cose che lancia Ivan.
- ✅ SU-988 (progetto): 10 API accese; Firebase CLI 15.30.2 e login; account runtime
su-api (solo roles/datastore.user) e su-telemetria (nessun ruolo finché non c'è il bucket); budget 10 e 50 EUR/mese con soglie 50/90/100 %; esclusione streetu-function-requests sul sink _Default; Hosting senza contenuti. Due correzioni alla guida: l'ID di un account di servizio vuole 6-30 caratteri («api» era troppo corto), e la CLI 583 non ha più gcloud logging exclusions (le esclusioni stanno sul sink). - ✅
functions/index.js: serviceAccount = su-api@…; dichiarato il segreto DELETE_ACCOUNT_HMAC_KEY_HEX con defineSecret e secrets: [...] sulla function, senza il quale Secret Manager non inietta la variabile che functions/lib/delete_account.js legge. 77 test verdi. In .gitignore entra la regola che tiene fuori da git ogni file .env della cartella functions/ (i tre ID dei deployment EOS stanno in functions/.env.axiomatic-path-505007-u7, compilato da Ivan dalle proprietà dell'Apps Script). - ✅ SU-984 (deploy):
firebase deploy --only functions:api,hosting → function api ACTIVE in us-central1, Node 22, account su-api, max 2 istanze, min 0, concorrenza 40; il primo deploy si ferma sulla policy di pulizia di Artifact Registry (non interattiva) → firebase functions:artifacts:setpolicy --days 1 e poi deploy --only hosting. Verifiche: radice e path a caso 404, GET /api/inviti 405, POST con token falso 200 {"ok":false,"esito":"non disponibile"} con Cache-Control: no-store sia sulla function sia attraverso Hosting; nei log del servizio api nessuna richiesta 2xx (esclusione attiva), solo audit e sistema. - ✅ SU-1018: segreto
DELETE_ACCOUNT_HMAC_KEY_HEX creato (versione 1, 32 byte da openssl rand, mai passato in chat), accesso concesso dalla CLI a su-api; TTL scade_il ACTIVE su _account_tombstones e _account_deletions (con players, legami, riscatti già attivi). - ⚠️ NON PROVATO: chiamate con un token EOS vero (conteggio inviti, cancellazione account su dev), latenza da Mac e Honor (piano SU-984 punto 7), la migrazione del registro (SU-986: gate
_registry_migration, regole chiuse) — il gioco continua a usare l'Apps Script finché [api] url per ambiente resta vuoto (SU-1017).
Via le scritte di mangia, bevi, dormi, lavati e dei bidoni; restano quelle di blocco (SU-1034, giro 2)2026-09-18
Ivan in chat (18/09): «toglierei anche le scritte quando mangi, bevi, dormi e ti lavi, terrei quelle importanti quando non riesci a fare qualcosa (tipo che non hai i soldi, che la fontana è ghiacciata, che ti sei ubriacato), toglierei anche quelle dei bidoni, e di cosa ci trovi dentro». Istruttoria Codex (luna) I1034d per l'inventario, lotto Claude dev-sonnet N1034d, review Codex (Sol) RN1034d: due rilievi medi sul controllo statico corretti dall'orchestratore.
- ✅
files/homeless_city/scripts/world/Interactable.gd: tolte alla sorgente 11 chiamate EventBus.big_notify di esito riuscito, con commento datato in ogni punto — hot dog, caffè, gelato, drink (~3815-3988), zuppa gratis (~4078), rifugio «HAI RIPRISTINATO TUTTO!» (~3623), bagno pubblico e banco igiene (~3952-3954), bidone chiuso «COPERCHIO INCASTRATO» e «HAI MOLLATO IL COPERCHIO» (~1037, ~1137) e l'esito del bidone chiuso (monete, lattine, livello, carta, scelta, gruzzolo: ~1177, i dizionari di ChestLoot.gd restano come sono). Icone +N, animazioni e suoni sono intatti; le traduzioni restano nel CSV. - ✅ Restano TUTTE le scritte di blocco: senza soldi (
MONDO_SOLDI_*), «sei già carico» (MONDO_PIENO_*), rifugio fuori orario, fontana ghiacciata, spazzino su panchina/fontana/bidone, e «ora sei ubriaco!» che Ivan vuole tenere. Resta anche «Vestiti nuovi!» (i vestiti non sono nella lista). - ✅
tools/autotest/probe_su1034.sh: controllo statico PRIMA della sonda sul sorgente nel repo — ricompone ogni chiamata notify( su una riga (anche quelle su più righe, rilievo della review) e pretende: 10 chiavi tolte assenti, 9 chiavi/prefissi di blocco ancora presenti (si accorge di una cancellazione di troppo), esito del bidone non più letto né mostrato. Provato anche in negativo su due copie (chiamata su più righe, vecchio blocco del bidone): fallisce come deve. Sonda 25/25 verde, compile-check 0 errori. - ⚠️ Non rimisurato col bot: le scritte tolte sono acquisti e bidoni chiusi, che il bot non fa. L'istruzione del coperchio incastrato («resta lì e spingi») se ne va con le altre: se serve, si rimette come «prime 2 volte per run» in
NOTIF_RUN_CAPS.
iOS 27: un mese di osservazione, controllo settimanale con un comando (SU-1037)2026-09-18
Ivan in chat (18/09): «attendiamo e controlliamo per un mese regolarmente se ci sono controindicazioni per Godot su iOS 27 e Xcode 27». Niente Xcode 27 e nessun aggiornamento per ora.
- ✅
tools/release/ios27_controllo.sh [giorni]: cerca «Xcode 27» e «iOS 27» fra issue e PR di godotengine/godot e godot-proposals (API GitHub via curl; python legge solo lo stdin, perché senza certificati CA non va in rete), elenca le ultime release di Godot e segna NUOVO ciò che è cambiato negli ultimi N giorni (default 8). - ✅
docs/IOS_27_VERIFICA.md: decisione, comando e registro dei controlli (ogni giovedì fino al 18/10/2026, decisione il 18/10) col primo esito: 2 novità su «Xcode 27», 1 su «iOS 27», nessuna release nuova, nessuna controindicazione per Godot 4.7.2 (la godot#122549 sul link iOS con i template 4.7 non ci tocca: i nostri archive con Xcode 26.6 linkano; la PR godot#120187 «Fix build with Xcode 27» è di luglio, dentro i template 4.7.2). Il ticket resta In corso solo per il controllo, non si rilavora.
Bar del caffè: edificio B col cartello tondo, cerchio marrone al Mercato, tazzina senza vapore in mappa (SU-997, giro 4)2026-09-18
Ivan in chat (18/09): «alternativa B, mettendo però un bel cartello grosso sopra come nel bar attuale, per riconoscerlo meglio (rimuovendo la finestra in alto a destra e mettendolo lì, sovrapposto senza rigenerare lo sprite); al mercato il cerchio col bordo marrone e non rosa; nella mappa una tazzina uguale ma senza vapore, così si centra nel quadrato». Fatto dall'orchestratore, nessun lotto.
- ✅
tools/sprite/su997_giro4.py: tre ritocchi deterministici sui raw 8x, poi la riduzione BOX di tools/sprite/su997_riduci_giro3.py. (1) Il disco del cartello (raggio 12,5 px, centro 70,31) del bar di giro 1 — sprites_raw/BUILDINGS/bar_building_giro1.png, lo sprite 1x che era in gioco fino al 17/09 — incollato sul raw dell'alternativa B centrato sulla finestra in alto a destra (72,36): sprites_raw/BUILDINGS/bar_building_r4_8x.png → files/homeless_city/assets/sprites/world/bar_building.png. (2) sprites_raw/UI/bancarella_cartello_coffee_8x.png: i 7.549 px rosa dell'anello ricolorati in marrone a luminanza conservata → files/homeless_city/assets/sprites/world/bancarella_cartello_coffee.png. (3) sprites_raw/UI/map_coffee_8x.png: via il vapore sopra l'orlo, tazza ricentrata a passi di 8 px (la griglia della riduzione non si sposta: la tazza ridotta è identica) → files/homeless_city/assets/sprites/world/map_coffee.png. Nessun codice toccato: l'edificio si cambia con un file, come previsto al giro 3. - ✅ Sonda
tools/autotest/probe_su997.sh: 0 controlli falliti. Provini in TMP/su997_giro4/shot/ (bar in città, banco al Mercato) e foglio di confronto TMP/su997_giro4/foglio_4x.png, allegati al ticket. - ⚠️ Il cartello copre anche il pilastro a destra della finestra e sfiora la tenda: se stona, si sposta cambiando
SIGN_CENTER_B nello script e rilanciandolo.
Metro: il rombo del treno indemoniato è il candidato 1 scelto da Ivan (SU-1036)2026-09-18
Ivan in chat (18/09): «metterei l'opzione 1 invece, sostituisci». Fatto dall'orchestratore, nessun lotto.
- ✅
files/homeless_city/assets/sounds/subway_train_demon.wav è ora la copia di Sounds_raw/subway_train_demon/treno_demone_1.wav (in gioco c'era il 2): stesso nome, stesso .import, nessun codice toccato salvo il commento in files/homeless_city/scripts/world/BonusLevel.gd (~168-190) e la nota in tools/sprite/su1036_treno_demone.py. - 🔎 Volume: sopra i 300 Hz (passa-alto a 300 Hz, 4 poli) il candidato 1 sta a −22,2 dB RMS contro −31,4 del rombo normale (il 2 stava a −21,4): +9 dB, quindi
SFX_TRENO_INFUOCATO_VOL_DB resta −5. - ✅ Sonda
tools/autotest/probe_su979_livrea.sh: 0 controlli falliti, rombo dei giri 3-5 subway_train_demon.wav a −5 dB, 5,00 s.
Meno scritte a schermo durante la partita (SU-1034)2026-09-17
Ivan in chat (17/09 sera): «compaiono troppe scritte in game, ridurle». Due istruttorie Codex (luna) per l'inventario, lotti Codex N1034/b/c/d (Sol), gate luna CN1034, tre giri di review Sol (RN1034, RN1034b, RN1034c); ultimo rilievo medio corretto dall'orchestratore.
- 🔎 Inventario e misura: TUTTI i messaggi della partita (163 punti di chiamata fra
EventBus.notify, EventBus.big_notify e chiamate interne) passano da un punto solo, HUD._queue_big_notification, ed escono come testo grande da 38 px al centro, fino a 3 impilati. Col bot (7 minuti): 6,7-8,6 scritte al minuto, e la più frequente in assoluto era «Hai fame. Trova del cibo.» — 23-25 volte in 7 minuti, perché gli avvisi di fame e sonno si ripetevano ogni 15 s a tutti i livelli. - ✅
files/homeless_city/scripts/ui/HUD.gd:~776-785, ~4591-4669: avvisi di fame e sonno a cadenza per livello — lieve ogni 60 s, alto ogni 30 s, critico invariato a 15 s. Se il livello PEGGIORA l'avviso nuovo esce subito; se la statistica risale il ricordo si azzera. I preavvisi una tantum restano. - ✅
files/homeless_city/scripts/ui/HUD.gd:~327-360, ~5600-5760 (il collo di bottiglia, nessuno dei 163 chiamanti toccato): (1) fusione — se lo stesso messaggio (numeri a parte: «Pronta tra 0:12» e «0:11» sono lo stesso) è già a schermo, si aggiorna quello e riparte la sua permanenza invece di impilarne un altro; se il testo nuovo cambia altezza la label si ricrea, così non si sovrappone alle altre; una label appena fusa non è la prima sfrattata; (2) antirimbalzo — lo stesso messaggio mostrato meno di 8 s fa si scarta; (3) al massimo 2 messaggi insieme (erano 3); (4) tetto per run ai testi di colore dei colpi dei nemici di quartiere (yeti, pinguino, pupazzo, fenicottero, cactus, sole): le prime 2 volte per run, poi parlano FX e suono. Tabella unica NOTIF_RUN_CAPS: per rimettere un testo si toglie la sua riga. Il cancello del game over (SU-393) non è toccato. - ✅
files/homeless_city/scripts/player/Player.gd:~591, ~1241-1298, ~2862: l'istruzione «Suoni per strada! (E o muoviti per fermarti)» esce solo alle prime 2 suonate della run (azzerata anche al rematch). - ✅ Misura riproducibile:
tools/autotest/misura_scritte.sh [durata] [flag del bot] (con SU_LOG_NOTIF=1 l'HUD stampa una riga per arrivo con l'esito: mostrata, fusa, scartata, risparmiata; «risparmiata» è l'ombra della vecchia cadenza a 15 s, così PRIMA e DOPO escono dalla STESSA run). Sul Mac, 7 minuti: città 6,9 → 4,4 al minuto (−35%), Brina 8,6 → 6,0 (−30%) e 4,0 → 3,3 (−18%); «Hai fame» da 23 a 6. Il bot non preme i tasti a raffica come un umano: fusione e antirimbalzo in queste run pesano quasi zero, in mano a un giocatore pesano di più. - ✅ Sonda
files/homeless_city/scripts/tools/probe_su1034.gd + tools/autotest/probe_su1034.sh: 25 controlli verdi sul Mac (fusione, conto alla rovescia aggiornato in posto, antirimbalzo, tetto a 2, sequenza A-B-A-C, fusione che va a capo su viewport da telefono senza sovrapposizioni, cadenze di fame, cancello del game over, log su una riga anche per la Retata, tetto per run e suo azzeramento, hint della suonata). Scatti dell'HUD (shot_hud_notif.gd, tre set) senza errori e con la geometria di SU-161 intatta. Smoke in singolo con ingresso nel bonus stage: 0 errori di script. - ⚠️ Scelte mie da confermare giocando: NON ho toccato i fumetti degli NPC né i
+N fluttuanti (ho inteso «scritte» = i messaggi grandi al centro); gli avvisi di fame/sonno sono rallentati, non tolti; l'obiettivo che mi ero dato (−40%) col bot non è raggiunto (−30/−35%). - ⚠️ Nota pre-esistente emersa dalla review (non una regressione): al rematch online il banner «SI RIPARTE» è scartato dal cancello del game over già da SU-393; resta la scritta sul pannello, allo spettatore non compare.
Bonus stage in multiplayer: tace anche il loop che parte DOPO la discesa (SU-1035, review RB1035)2026-09-17
Rilievo alto della review Codex sul commit 8731c7a: in multiplayer SuperPower resta vivo, quindi se un ALTRO giocatore evoca i cani mentre sei già nel tunnel, DogCircleSFX partiva a volume pieno. Lotto di correzione Codex B1035b (Sol).
- ✅
files/homeless_city/scripts/world/BonusLevel.gd:~2079, ~5790-5810, ~6169, ~6321: i lettori degli autoload si raccolgono UNA volta all'ingresso (niente find_children() a ogni frame); in multiplayer il giro del livello li ripassa a ogni frame e un loop partito sotto va a −80 dB nella stessa fotografia voci, così la risalita gli ridà il volume. I one-shot restano udibili. _muta_voce() non fotografa due volte lo stesso lettore (altrimenti salverebbe −80 come volume «originale»). - ✅ Rimesso a mano l'avviso di SU-879 che il builder aveva tolto da
_tieni_muta_la_citta(): in multiplayer il resto della funzione NON deve girare (la rete di sicurezza metterebbe in pausa la musica del quartiere per sempre); il ramo nuovo finisce con return proprio per questo. - ✅ Sonda
probe_su1035: 17 controlli verdi sul Mac (3 nuovi: DogCircleSFX vero partito sotto → playing e −80 dB; one-shot partito sotto al suo volume; volume originale all'uscita). probe_su879_mp (due peer veri) e probe_su998 verdi. - ⚠️ Non provato: due telefoni veri con i cani evocati dall'altro giocatore.
Metro: dal giro infuocato il treno ha la voce di un treno indemoniato (SU-1036)2026-09-17
Ivan in chat (17/09 sera): «treno tier 3 infuocato, cambiare suono, più evocativo di un treno indemoniato». Suono generato con ElevenLabs e composto dall'orchestratore; cablaggio inline (due punti + un helper).
- ✅
files/homeless_city/assets/sounds/subway_train_demon.wav (nuovo, 5,0 s, stereo 44,1 kHz, −20,0 dB RMS come gli altri effetti del tunnel, picco −7,2 dB): è il candidato 2 — motore che ringhia con le ruote sotto, ululato e fischio a vapore «dall'inferno» nei primi 2 s. - 🔎 Perché una composizione e non un file solo: chiesto come «passaggio», il generatore rende 2 s di suono e 3 di silenzio (inviluppo da −15 a −90 dB), ma nel gioco il rombo parte a 900 px e deve reggere tutto il passaggio; chiesto «continuo» (loop) regge i 5 s ma sta per l'80% sotto i 250 Hz, e dallo speaker di un telefono non esce niente di demoniaco. Quindi strato sostenuto (la massa) + ruggito/fischio di passaggio (le medie). Tutto riproducibile:
tools/sprite/su1036_treno_demone.py legge i sei grezzi e scrive i tre candidati in Sounds_raw/subway_train_demon/ (LFS), con i prompt nel docstring. - ✅
files/homeless_city/scripts/world/BonusLevel.gd:~166-196, ~2763-2767, ~3219-3223: _train_rumble() e _train_rumble_volume_db() decidono in un punto solo, come _train_texture(): sotto TRENO_INFUOCATO_DAL_GIRO resta subway_train_pass.wav a −2 dB, dal giro 3 subway_train_demon.wav a −5 dB. Il volume più basso è misurato, non di gusto: a parità di RMS il file nuovo ha 8-9 dB in più sopra i 300 Hz (−2,2 contro −10,9 dB), proprio dove suonano il telefono, le ruote e gli zombie. Stridio delle ruote, avviso e tonfo invariati. - ✅
files/homeless_city/scripts/tools/probe_su979_livrea.gd: la sonda della livrea per giro controlla anche il rombo (file, volume, durata 5 s) su ogni treno del corridoio e sulla metro in banchina, giri 1-5: 10 controlli nuovi verdi, 0 falliti in tutto. Nel farlo è venuto fuori che la sonda era ROSSA da SU-998 (3 controlli in banchina ai giri 3-5): contava le fiamme sul tetto come una seconda livrea. Ora le esclude solo quando la livrea attesa è quella infuocata. - ⚠️ Non provato: l'ascolto. Quale dei tre candidati sia «il più indemoniato» lo decide l'orecchio di Ivan: gli altri due sono
treno_demone_1.wav (ringhio + ruggito gutturale con corno distorto) e treno_demone_3.wav (il rombo di sempre + treno posseduto + coda di lamenti). Cambiare candidato = copiare un file.
Bonus stage: il tappeto sonoro di una super (i cani) tace entrando e riprende uscendo (SU-1035)2026-09-17
Bug di Ivan (17/09 sera): «un suono come i cani se entro nel bonus stage e ce l'avevo fuori devo zittirlo, ora se entro continua in loop per tutto il livello». Lotto Codex B1035 (Sol), gate luna CB1035; controllo sul lettore vero e codice d'uscita del lanciatore aggiunti dall'orchestratore.
- 🔎 Causa:
_congela_superficie() metteva in pausa solo i lettori audio figli della città. DogCircleSFX è figlio dell'autoload SuperPower, che in singolo viene FERMATO (AUTOLOAD_DA_CONGELARE): il timer della super non scorre più, il loop non finisce mai e nessuno lo zittisce. - ✅
files/homeless_city/scripts/world/BonusLevel.gd:~6122-6146, ~6178-6187: entrando si prendono anche i lettori (AudioStreamPlayer e AudioStreamPlayer2D) degli autoload congelati che in quel momento stanno SUONANDO. I loop entrano nelle fotografie che già esistono — suoni in singolo (pausa), voci in multiplayer (volume a fondo scala) — così il giro di guardia dopo la cerimonia delle carte e lo scongelamento li gestiscono senza codice nuovo. Un one-shot già partito si ferma e basta. Un lettore spento all'ingresso non si tocca: il ka-ching delle carte, che passa da SuperPower._sfx, resta udibile nel tunnel. _audio_in_loop() riconosce WAV (loop_mode), OGG e MP3 (loop). - ✅ Sonda
files/homeless_city/scripts/tools/probe_su1035.gd + tools/autotest/probe_su1035.sh: 14 controlli verdi sul Mac — singolo e multiplayer simulato, NOTIFICATION_UNPAUSED, lettore spento all'ingresso, one-shot, lettore 2D, volume −80 dB sotto e originale sopra, super finita mentre si è sotto, non regressione dei lettori della città, e il lettore VERO DogCircleSFX (pausa entrando, ripresa uscendo). Controprova: sul codice senza la correzione la sonda fallisce 5 controlli. probe_su998 ancora verde. Il lanciatore ora esce 1 se la sonda fallisce o muore. - ⚠️ Non provato: l'ascolto vero sul telefono (cani attivi → tombino → silenzio → risalita) e la fine naturale della super dopo la risalita.
iOS 27: nota di verifica, nessun file di gioco toccato (SU-1037)2026-09-17
Domanda di Ivan: «iOS 27? nuovo Xcode? Godot ok?». Non è un'ipotesi sui crash di SU-1032: i report dell'iPhone vengono tutti da iOS 26.6.2.
- ✅
docs/IOS_27_VERIFICA.md (nuovo): fatti di oggi (iOS 27 e Xcode 27 usciti il 14/09/2026; sul Mac Xcode 26.6 con SDK iOS 26.5; il Mac soddisfa già i requisiti di Xcode 27; deployment target iOS 15.0 ancora ammesso; da aprile 2027 le build caricate su App Store Connect devono usare l'SDK iOS 27), cosa cambia in Xcode 27 (il flag -ld_classic non ci tocca: nel progetto esportato da Godot si attiva solo con Xcode 15.0-15.1, verificato sul project.pbxproj dell'ultima build), cosa NON è provato (il gioco su un device con iOS 27; la compilazione con Xcode 27) e il piano in cinque passi, ognuno con l'ok di Ivan. - ⚠️ Nessun problema noto di Godot con iOS 27 trovato il 17/09 — ma iOS 27 è fuori da tre giorni: non è una prova.
Brina: i pupazzi di neve inseguono più piano (SU-1033)2026-09-17
Ivan in chat (17/09 sera): «ridurre velocità pupazzi di neve». Micro-task fatto dall'orchestratore.
- ✅
files/homeless_city/scripts/world/Snowman.gd:~68-72: l'inseguimento scende da 72 a 54 px/s (da 0,8× a 0,6× il barbone, −25%). A 0,8× sul ghiaccio di Brina il pupazzo ti raggiungeva quasi sempre. Il vagare resta 27 px/s; fenicotteri, yeti e pinguini invariati (il numero sta nel pupazzo, non nella base ParkFoe.gd). - ✅
files/homeless_city/scripts/tools/probe_su807_nemici.gd:~480: la sonda dei nemici ora chiede 54 ± 5 in inseguimento. Misurato sul Mac: vaga 27,1 px/s, insegue 54,0 px/s, 0 frame fuori dal parco; scioglimento e rimontaggio invariati (pozza a 59,5 s, rimontato a 60,1 s). - ⚠️ Non provato: la sensazione sul telefono. Se serve ancora più lento è un numero solo (
v_insegue), e la sonda lo segue.
Bar: niente caffè a energia piena, icona in mappa, cartello sul banco del Mercato e un edificio più coerente con la città (KO di SU-997)2026-09-17
KO di Ivan (17/09 sera) in quattro punti. Codice: lotto Codex K997 (Sol), cancello luna CK997, review Sol RK997 (nessun rilievo). Sprite: Astra con tools/sprite/su997_giro3.sh (ogni generazione ha come riferimento uno sprite ESISTENTE del gioco a 8×) e riduzione BOX con tools/sprite/su997_riduci_giro3.py.
- ✅
files/homeless_city/scripts/world/Interactable.gd:~3776-3828: il caffè entra nel controllo centralizzato di «barra piena» degli altri negozi: a energia 100 l'acquisto è rifiutato prima di spesa e FX con MONDO_PIENO_CAFFE («Sei già carico: il caffè può aspettare.», 8 lingue in ui_mondo.csv); a 99 si compra. - ✅
files/homeless_city/scripts/ui/MapOverlay.gd:~199, ~229, ~1447: il bar è in mappa come gli altri negozi, icona map_coffee.png (20×20) centrata sulla facciata (sul banco al Mercato) e voce di legenda MAPPA_BAR («Bar (caffè)», 8 lingue in ui_hud.csv). - ✅
files/homeless_city/scripts/world/WorldGenerator.gd:~5549-5552: al Mercato il banco del caffè ha il cartello tondo bancarella_cartello_coffee.png (32×32) con stesso offset, z e filtro degli altri banchi. - ✅
files/homeless_city/assets/sprites/world/bar_building.png: in via provvisoria l'alternativa A (mattoni, tetto scuro con gli impianti, vetrina verde, insegna a tazzina appesa), stessa misura 92×80 quindi nessun cambio di codice; l'alternativa B (pietra grigia, tenda a righe) è sul foglio TMP/su997_giro3/foglio_4x.png allegato al ticket: sceglie Ivan. Raw 8× in sprites_raw/BUILDINGS/ e sprites_raw/UI/. - Sonda
probe_su997: 127 controlli verdi (energia 100 → 20 $ invariati e 0 FX; 99 → 15 $ e 1 FX; voce di mappa; nodo CoffeeStallSign), rilanciata sul Mac con gli asset presenti: ESITO=OK. Provini TMP/su997/bar_centro_giorno.png e TMP/su997/banco_caffe_mercato_giorno.png guardati. NON PROVATO: telefono, due peer.
L'icona del CONCERTONE sono le note musicali dorate (SU-1015 variante B, KO di SU-1009)2026-09-17
KO di Ivan: l'icona piccola della super doveva richiamare la musica («note musicali super») e il megafono del primo giro era troppo simile a COMIZIO IN STRADA. Secondo giro con Astra (tools/sprite/su1015_concertone_giro2.sh): due varianti con le note, Ivan ha scelto la B (una nota grande, due piccole, raggiera).
- ✅
files/homeless_city/assets/ui/super_concertone.png (16×16, riduzione BOX 8× del raw 128 sprites_raw/UI/super_concertone_note_b_128.png, con .import): il codice di SU-1009 (SuperPower.gd:~1446-1467) la carica da sola al posto della trombetta del busking. - Sonda
probe_su1009 ESITO=OK; provino TMP/su1009/concertone_suona.png: nella casella della super le note dorate, distinte dalla trombetta dei poteri normali. NON PROVATO: telefono.
CANCELLA ACCOUNT 3/5: voce nel pannello ACCOUNT, pratica a cinque fasi riprendibile, pulizia locale del solo PUID (SU-1020)2026-09-17
Lotto Codex C1020 (Sol), cancello luna CC1020, review Sol RC1020 + RC1020b (tre rilievi aperti). Usa i contratti di SU-1018 (backend), SU-1019 (EOS e pratica di ProgressSync) e SU-1021 (sospensione dei punteggi); la verità della pratica resta il record di ProgressSync, nessun cfg parallelo.
- ✅
files/homeless_city/scripts/ui/MainMenu.gd:~617, ~6448, ~7507, ~8984: voce CANCELLA ACCOUNT solo da loggato, due conferme senza parola da digitare, stato della pratica e «riprova» persistenti, ricevuta copiabile. - ✅
files/homeless_city/scripts/autoload/Settings.gd:~208, ~1696-1922: coordinatore a cinque fasi con record user://account_deletion_process.json (fase, request_id, ricevuta) e ripresa automatica all'avvio: 1 sospensione delle sync (ProgressSync.begin_account_deletion), 2 backend delete_account idempotente (request_id generato una volta), 3 progressi EOS, 4 enumerazione e unlink, 5 Device ID ospite nuovo, ACK e pulizia locale. Nessun dato locale toccato prima dell'ACK. - ✅
NicknameRegistry.gd:~757, ~931 (azione delete_account sul trasporto in coda; Apps Script senza l'azione = pratica IN_CORSO, mai un falso successo; cache rimossa solo per il PUID), MetaProgress.gd:~465 (meta dell'account azzerata, best_score locale e timbri tecnici conservati), Skins.gd:~671, Inviti.gd:~623 (solo la sezione del PUID); ui_menu.csv: 15 chiavi nuove in 8 lingue, audit emoji 0. - Review RC1020 (quattro rilievi, corretti in C1020b: niente cancellazione con una partita online attiva, con la pratica in corso restano solo stato e «riprova», le risposte tardive degli inviti per un PUID in cancellazione vengono scartate, la ricevuta è legata al PUID e si archivia al login di un altro account) e RC1020b (aperti per la regola dei tre giri: la ripresa automatica non ricontrolla la partita online; la voce è disponibile senza sessione EOS viva e poi resta solo «riprova» senza login; l'errore di scrittura di
inviti.cfg è ignorato; dal cancello: la coda dei punteggi non viene pulita). - Sonda
probe_su1020 (backend ed EOS finti): rete tolta in ognuna delle 5 fasi e riavvio → fase ripresa, request_id invariato, un solo successo backend per scenario, mapping ignoto fermo in fase 4, pulizia prima dell'ACK = 0; dopo l'ACK nome, PUID, meta, skin, inviti e cache assenti, preferenze e record locale presenti; da ospite la voce non c'è; probe_su1021 ancora verde. Provini del pannello in TMP/su1020/ (IT/EN, 844×390 e 1024×768). NON PROVATO: telefono, backend vero, unlink e Device ID reali.
L'edificio BAR con la tazzina in ogni quartiere e il banco del caffè al Mercato (SU-997, sprite di SU-1014)2026-09-17
KO di Ivan (17/09): «ci va proprio un edificio bar ovunque ad hoc col simbolo della tazzina, tranne al mercato dove è un banco dedicato». Sprite generati con Astra e approvati con SU-1014. Lotto Codex I997 (Sol), cancello luna CI997, review RI997 (un rilievo corretto in I997b, uno respinto).
- ✅
files/homeless_city/assets/sprites/world/bar_building.png (92×80) e coffee_stall.png (84×54), copiati byte per byte dai raw approvati, con i .import. - ✅
files/homeless_city/scripts/world/WorldGenerator.gd:~81, ~1701, ~2078, ~2654-2691, ~5101-5577, ~5383, ~9537: un isolato COFFEE_BAR riservato dal seme (lo stesso su ogni peer); fuori dal Mercato ci sorge il BAR (porta a sud, z sulla base, ombra da palazzo, muro 92×80 allineato in basso: i 16 px a nord e i 2 per lato restano liberi, review RI997); al Mercato lo stesso slot diventa il banco del caffè dedicato, con impronta, muro 84×6, zona e ancoraggio del banco delle caramelle; via il banco riciclato e il vecchio punto caffè su facciata. L'interazione è quella di prima (Interactable.gd:~3822-3846: 5 $, +25 energia, FX tazzina). - Sonda
probe_su997 (seme 997997): 8/8 quartieri con esattamente un caffè, texture giusta (edificio fuori dal Mercato, banco al Mercato), acquisto (energia 40→65, 90→100, denaro −5), collisione piena nell'impronta e 21/21 punti esterni liberi; sul Mac ESITO=OK. Provini TMP/su997/bar_centro_giorno.png e banco_caffe_mercato_giorno.png guardati. NON PROVATO: due peer, telefono, Mercato con meno di quattro banchi.
CANCELLA ACCOUNT 4/5: stat EOS per PUID, strumento amministrativo, runbook e sospensione dei punteggi (SU-1021)2026-09-17
Lotto Codex C1021 (Sol), cancello luna CC1021, review RC1021 + RC1021b + RC1021c (sette rilievi corretti in C1021b/C1021c, tre aperti per la regola dei tre giri). Verificato sui header dell'SDK (eos_stats.h, eos_leaderboards.h): il client può solo ingerire e interrogare, nessuna API cancella o azzera stat e record per PUID: la cancellazione è amministrativa (Dev Portal, supporto Epic o Web API con credenziali che non stanno nel client).
- ✅
tools/eos/delete_stats_puid.py (nuovo): dati PUID, ambiente e request_id espliciti (dalla pratica del backend, nessun cfg del gioco), elenca le 8 stat, produce il piano idempotente, dry-run di default; con --esegui vuole un adattatore amministrativo, verifica l'eco di PUID/ambiente/request_id e accetta VERIFICATA solo con 0 righe residue (un ingest visto prima/dopo → IN_CORSO). docs/RUNBOOK_CANCELLAZIONE_ACCOUNT.md (nuovo): dev→stage→live, SLA 7 giorni, soglie T+5/T+6, seconda approvazione live, cosa resta manuale. - ✅
files/homeless_city/scripts/autoload/OnlineLeaderboard.gd:~270-274, ~414, ~684-703, ~948, ~1123-1190: con la pratica di ProgressSync in corso (user://account_deletion_pending: record assente = nessuna pratica, illeggibile o incompleto = blocco con warning) nessun nuovo invio di punteggio, code e retry compresi; contatore persistente degli ingest in volo, azzerato con warning all'avvio (nessuna coroutine sopravvive al processo); identificatori in inglese (INGEST_SUSPENDED, is_account_deletion_pending). - Sonda
probe_su1021 (HStats finto): rilievi coperti; sul Mac VERDE dopo aver reso robusto il percorso dello strumento (SU_REPO_ROOT dal lanciatore: nel clone del harness res://../../ non è la radice del repo). NON PROVATO: EOS reale, adattatore amministrativo vero. Aperti dalla review RC1021c: (1) lo strumento non può vedere un ingest ancora in volo sul telefono (limite: il runbook verifica dopo che la pratica ha sospeso il client); (2) un punteggio accodato mentre EOS non è pronto non viene rimosso se la pratica nasce in quell'attesa; (3) _ultima_run_inviata non è valorizzata sul ritorno per cancellazione (possibile doppio invio se la pratica sparisce fra le due chiamate).
CANCELLA ACCOUNT 2/5: DeleteFile di progressi.json e scollegamento degli accessi, pratica persistente (SU-1019)2026-09-17
Lotto Codex C1019 (Sol), cancello luna CC1019, review RC1019 (un critico) + RC1019b + RC1019c (Astra): otto rilievi corretti in C1019b/C1019c, tre casi limite aperti (regola dei tre giri). L'addon esponeva già PlayerDataStorage.DeleteFileOptions e Connect.unlink_account: solo GDScript.
- ✅
files/homeless_city/scripts/autoload/EOSBridge.gd:~2827-3100: delete_progress_file() (NotFound = successo idempotente, ogni altro codice = errore), enumerate_linked_accounts() (Apple, Google, Epic; gli external_N ignoti restano elencati e la pratica IN_CORSO), unlink_account(provider) con riautenticazione: il PUID della pratica è l'UNICA identità valida per DeleteFile e per ogni unlink; se la riautenticazione porta un altro account l'unlink è rifiutato e l'identità attesa viene ripristinata (Device ID/HAuth) o si esce a ospite offline con avviso; Device ID nuovo una sola volta dopo tutti gli unlink, e DeleteDeviceId fallita o CreateDeviceId in DuplicateNotAllowed = fallimento, mai device_id_new=true. - ✅
files/homeless_city/scripts/autoload/ProgressSync.gd:~5 (contratto per SU-1020), ~334-380, ~497, ~567, ~796, ~979: pratica persistente user://account_deletion_pending con PUID, provider residui e mapping ignoti; al riavvio resta IN_CORSO e ogni sync (scritture, riletture, traslochi) è sospesa; begin_account_deletion() non azzera mai un record esistente; delete_remote_progress(); gli errori non chiudono mai la pratica. - Sonda
probe_su1019 (EOS finto): 41 controlli, sul Mac ESITO=OK. NON PROVATO: EOS vero (NotFound reale, mapping del Dev Portal, callback Apple/Google/Epic), telefono. Aperti dalla review RC1019c, da lavorare in un giro successivo: (1) un upload trattenuto oltre il timeout può ricreare progressi.json dopo DeleteFile (_pending_native_transfer non è nel controllo); (2) sul percorso Epic il ripristino dell'identità non azzera epic_auth_state/HAuth.epic_account_id; (3) DeleteDeviceId riuscita + CreateDeviceId fallita lascia il tentativo successivo su NotFound senza ritentare la creazione.
CANCELLA ACCOUNT 1/5: pratica `delete_account` sulla function api, autenticata dal token EOS (SU-1018)2026-09-17
Primo dei cinque ticket di CANCELLA ACCOUNT (default di Ivan del 17/09: SLA 7 giorni, ricevuta HMAC, tombstone 365 giorni). Lotto Codex C1018 (Astra), cancello luna CC1018, review RC1018 + RC1018b (quattro rilievi: tre corretti in C1018b/C1018c, uno accettato come limite).
- ✅
functions/lib/api.js (contratto in testa), functions/lib/delete_account.js (nuovo): azione delete_account con env, id_token EOS e request_id ASCII 16-128; PUID solo dal token; pratica, pulizia, tombstone e quota nella stessa transazione; retry con lo stesso request_id = stessa pratica e stessa ricevuta (senza consumare quota); quota 10 pratiche nuove/ora per PUID consumata PRIMA di creare la pratica; spariscono player, nickname del PUID, riscatto proprio e legami degli inviti (nei riscatti altrui resta stato/data senza il codice, per non ridare premi); ricevuta JSON base64url firmata HMAC-SHA256 (chiave da DELETE_ACCOUNT_HMAC_KEY_HEX, mai nel codice); tombstone pseudonimo con solo scade_il a 365 giorni; il token non finisce mai nei log; dopo l'ACK cache e pending del conteggio inviti del cancellato e dell'invitante sono invalidati (limite accettato e documentato: per istanza, TTL 60 s). tools/firestore/firestore.rules e .legacy:~355-365: collezioni pratiche/tombstone chiuse al client. functions/test/: 77/77 verdi (+17 test), con una sonda in processo separato che verifica l'assenza del token in stdout/stderr. TMP/su1018/RUNBOOK.md: verifica di una pratica su dev. NON PROVATO: deploy della function e delle regole (li fa Ivan con SU-984/988), emulatore. Ivan decide dove sta il segreto HMAC (Secret Manager consigliato).
Gatto e fiaccola non finiscono più uno sull'altro nello scambio (KO di SU-1013)2026-09-17
KO di Ivan in chat: «gatto e fiaccola mai uno sopra l'altro». Causa: lo scambio posava l'oggetto lasciato esattamente sotto il giocatore, cioè sul punto dell'altro. Lotto Codex K1013 (Sol), cancello luna CK1013, review Sol RK1013 + RK1013b (tre rilievi corretti in K1013b/K1013c; uno, sul multiplayer, rimandato a ticket).
- ✅
files/homeless_city/scripts/player/Player.gd:~2670-2745, ~4730-4745: l'oggetto lasciato si posa a 24 px dal giocatore, in un punto scelto in modo deterministico (dietro, fianco, altro fianco, davanti) con i filtri anti-porta e anti-muro già usati per i gatti; distanza minima fra gatto e fiaccola 20 px; il punto viaggia esplicitamente da TorchPickup al Player allo spawn, senza dadi. Se nessuno dei quattro punti è libero lo scambio NON avviene (l'oggetto in mano resta): niente ripiego sul corpo del giocatore, mai has_cat e has_torch veri insieme. files/homeless_city/scripts/entities/TorchPickup.gd:~198-204: la posizione della fiaccola raccolta passa nella chiamata.- Sonda
probe_su1013 (14 controlli): gatto-giocatore 24,0 px, gatto-fiaccola 24,0 px in entrambi i versi; con i quattro punti bloccati lo scambio è rifiutato nei due versi; sul Mac ESITO=OK. NON PROVATO: due peer veri, telefono. Aperto (review RK1013b, era così dal giro 1 di SU-1013): in multiplayer il client che scambia gatto→fiaccola crea il gatto solo in locale, senza richiesta all'host → ticket SU-1031 in backlog.
Il registro nickname mette in coda le richieste: niente ERR_BUSY all'avvio (SU-1025)2026-09-17
Visto sull'Honor nel logcat della build dev di oggi: all'avvio partono insieme l'auto-claim del nome, la risoluzione del nome e il conteggio degli inviti, tutte sullo stesso HTTPRequest; la seconda e la terza ricevevano ERR_BUSY (44) e il contatore inviti restava vuoto. C'era dal 14/09 (SU-981). Lotto Codex N1025 (Sol), cancello luna CN1025, review Sol RN1025 (un rilievo, corretto in N1025b; re-review pulita).
- ✅
files/homeless_city/scripts/autoload/NicknameRegistry.gd:~246, ~916-941, ~1110-1138: coda in ordine di arrivo a biglietti; ogni via che arriva al trasporto prende il turno in _acquire_slot() e lo rilascia in ogni uscita (_release_slot(): risposta, errore, timeout), anche sul percorso Firestore e in check_pending(). Se il turno scade (QUEUE_MAX_WAIT_SEC) la chiamata torna vuota con un warning e non tocca il nodo HTTP di chi è in volo; N1025b: la scadenza si ricontrolla anche all'uscita dal ciclo (dopo una sospensione del telefono lo slot può liberarsi a scadenza già passata). - Sonda
probe_su1025 (trasporto finto ritardato): 17 controlli, tre chiamate concorrenti servite in ordine (claim → resolve → conteggio), massimo un trasporto alla volta, nessun «request() 44»; chiamata scaduta in coda = vuota senza bloccare le altre. NON PROVATO: telefono (logcat pulito all'avvio e contatore inviti popolato: da guardare sull'Honor con la prossima build).
Le fiamme del metrò non sbordano più dalle teste del vagone (KO di SU-998)2026-09-17
KO di Ivan in chat con screenshot: «all'inizio e alla fine del vagone non mettere la fiamma che sborda fuori dal vagone». Causa: la fila vicino alle porte era sfalsata di un passo intero e l'ultima fiamma, riportata a x=0 da fposmod, sporgeva per metà oltre il muso. Lotto Codex K998 (Sol), cancello luna CK998, review Sol RK998 (solo il rilievo sugli identificatori italiani, respinto: BonusLevel.gd è già in italiano).
- ✅
files/homeless_city/scripts/world/BonusLevel.gd:~3480-3504: le 4 fiamme di ogni fila stanno sulla larghezza utile (mezza fiamma, 28,8 px, di margine), le due file restano sfalsate di un quarto di passo; via il riporto a x=0. Altezze, scala, fotogrammi e animazione invariati. Per carrozza: fila lontana 56,7 / 168,3 / 279,9 / 391,5 px, fila porte 112,5 / 224,1 / 335,7 / 447,3 px (prima 0…441 con l'ultima a 0); estremi 27,9…476,1 dentro 0…504. - Sonda
probe_su998: bbox di ogni fiamma dentro il vagone (8/8 nel corridoio, 16/16 in banchina), distanza minima fra fiamme 76,3 px. Provino TMP/su998/partenza_05.png rifatto sul Mac: la prima fiamma è rientrata nel muso. NON PROVATO: telefono.
Il lampione di Brina si accende giallo (KO di SU-1000)2026-09-17
KO di Ivan in chat: «i lampioni di Brina non si illuminano: c'è la luce a terra ma la lampadina in alto non brilla come gli altri, farla gialla quando si accende». Il vetro dichiarato per Brina era bianco-azzurro (214,244,255 / 138,206,255): acceso, a scala di gioco, non si distingueva dai ghiaccioli. Lotto Codex K1000 (Sol), cancello luna CK1000, review Sol RK1000 (nessun rilievo).
- ✅
files/homeless_city/scripts/autoload/Quartieri.gd:~605-608: il vetro acceso di Brina è giallo (255,238,140 / 255,206,92) come gli altri quartieri; spento, palo, pozza di luce (giro 2, calda) e ombre invariati. - ✅
files/homeless_city/scripts/world/WorldGenerator.gd:~9382: il riflesso azzurro del giro precedente resta solo sotto il vetro, per conservare il gelo della testa. - Sonda
probe_su1000_notte: Brina accesa 8 pixel gialli (attesi ≥ 6), spenta 0; luminanza media del vetro 0,881 contro 0,816 del Centro (+7,9%, tetto 15%). Provino notturno TMP/su1000/notte_brina.png rifatto sul Mac: teste gialle leggibili a scala di gioco. NON PROVATO: telefono.
Lo yeti di Brina rispetta la zona sicura della pensilina come gli altri nemici (SU-1024)2026-09-17
Bug segnalato da Ivan in chat («in Brina lo yeti ti attacca anche sotto la pensilina, non deve farlo come gli altri nemici»). La regola degli altri nemici è SU-629 (files/homeless_city/scripts/npc/NPC.gd): nella finestra di una calamità (preavviso + ondata) chi sta sotto una ShelterZone non è aggredibile e chi gli sta addosso se ne va. Lo yeti non ci passava: _muovi() inseguiva comunque e DistrictFoe.prova_contatto() toglieva la vita al contatto. Lotto Codex Y1 (Sol), cancello luna CY1, review Sol RY1 + RY1b (tre difetti veri, corretti a mano).
- ✅
files/homeless_city/scripts/world/DistrictFoe.gd:~485-495: in prova_contatto() la stessa porta di NPC.gd — se il corpo toccato è fra ShelterZone.safe_occupants(self) niente vita tolta. Nella base, quindi vale per tutta la famiglia (yeti, pinguini, pupazzi, fenicotteri) e anche per il colpo volontario del nemico posseduto. - ✅
files/homeless_city/scripts/world/Yeti.gd:~35-40, ~90, ~191-255: bersaglio al sicuro = niente inseguimento né ruggito; entro 340 px si ritira verso un punto a 220 px in direzione opposta a V_INSEGUE, con coda di 1,2 s (soglie di SU-629), oltre torna a vagare; a finestra chiusa nessuno stato residuo. Review RY1: durante la fuga _net_insegue resta VERO, perché net_sta_inseguendo() decide chi entra nel pacchetto di correzione a 1 Hz dell'host e la fuga è un moto relativo al bersaglio (senza, le copie dei peer divergevano per tutta la coda). Review RY1b: senza bersaglio la coda si azzera invece di restare congelata per un bersaglio futuro. - Sonda
probe_su1024 (seme 424242, città vera con pensilina, yeti e pinguino) 6/6 sul Mac: A fuori calamità vite 9→8 al frame 42; B sotto la pensilina in grandine 9→9, distanza finale 325,8 px, coda armata e net_sta_inseguendo() vero in ogni frame di fuga; C fuori dalla pensilina nella stessa finestra 9→8 al frame 42 (prima della review era 184: la coda di B restava armata nella sonda); D pinguino a contatto sotto il riparo 9→9. SP 120 s e MP 90 s senza SCRIPT ERROR. NON PROVATO: due peer veri (la correzione a 1 Hz in fuga), il telefono. Fuori dalla finestra della calamità nulla cambia: la pensilina non protegge da nessuno, come dal SU-629.
La fiaccola si prende con A, ha il suo suono e si scambia col gatto in braccio (SU-1013)2026-09-17
Ticket nato dall'ok di Ivan a SU-1012 («quando prendo la fiaccola fa il suono del gatto, e devo premere A per prenderla»). Lotto Codex N1013 (Sol), cancello luna CN1013 + CN1013b sul commit; suono generato con ElevenLabs (tre candidati in Sounds_raw/temp/fiaccola/, scelto il primo; raw Sounds_raw/torch_pickup.mp3).
- ✅
files/homeless_city/scripts/entities/TorchPickup.gd:~139-222: il contatto arma l'ascolto dell'azione interact (la stessa del gatto): pressione sul posto, o A tenuto entrando, raccolgono; senza A la fiaccola resta a terra. Feedback su un player audio dedicato con assets/sounds/torch_pickup.wav (PCM 48 kHz stereo come cat.wav), mai il suono del gatto. - ✅ Scambio nei due versi: A sulla fiaccola col gatto in braccio →
Player.drop_cat_for_torch() (nuovo, Player.gd:~4590) posa il gatto dov'è il giocatore e la fiaccola va in mano (prima il gatto SCAPPAVA, regola di SU-812); A su un gatto con la fiaccola in mano → la fiaccola cade lì con la sua grazia di 1,5 s (_on_has_cat_changed, invariato). La patch a Player.gd è stata consegnata a parte e applicata dall'orchestratore dopo il lotto del CONCERTONE, che lavorava sullo stesso file. - Sonda
probe_su1013 4/4 (contatto senza A → niente; A → torcia e torch_pickup.wav nel log; scambio nei due versi con l'oggetto a 0 px). In rete non cambia nulla: has_cat e has_torch viaggiano già distinti nello stato dei puppet. NON PROVATO: due peer, resa audio percepita.
Il CONCERTONE è il busking: attivarlo suona subito, niente busking normale sopra, icona propria in arrivo, più note e un FX di folla (KO di SU-1009)2026-09-17
KO di Ivan in chat (musica in loop all'infinito all'attivazione; trombette doppie nell'HUD; più note e un FX sonoro). Lotto Claude dev-sonnet R1009; cancello luna CR1009, review RR1009. Ok di Ivan su SU-1003 e SU-1004 (Fatto).
- ✅
files/homeless_city/scripts/systems/SuperPower.gd:~492,~529: il kazoo salta super_show_fx("music") — era quello a far partire busking.wav senza che nulla lo fermasse (il loop) — e chiama player.super_start_concertone() invece di «armare». Player.gd:~2715 _start_busking(concertone) sostituisce lo stato armato; ~1181 durante il CONCERTONE il tasto busk non fa nulla (solo movimento e durata fermano il numero); ~2886 note ×3 in frequenza e ×1,8 in dimensione; ~2832 _play_concertone_fx() una tantum all'avvio con assets/sounds/super_concertone_fx.wav (folla che applaude, ElevenLabs; raw in Sounds_raw/). HUD.gd: via il badge «!» dell'armato. Testo SUPER_CONCERTONE_NOTIFICA riscritto in 8 lingue («CONCERTONE! Si suona SUBITO!»). - 📌 Le «trombette doppie» non sono un nodo doppio: l'indicatore del busking normale (
BuskReuseIndicator, sempre acceso) sta accanto allo slot della super, e la cella 4 dell'atlante delle super è di fatto la stessa tromba dorata della carta VIRTUOSO DELLA TROMBETTA. Il codice carica res://assets/ui/super_concertone.png se esiste: entra col Fatto di Ivan su SU-1015 (megafono, già allegato). - Sonda
probe_su1009 11/11 (attivazione → busking potenziato in 1 frame, durata 24 s, raggio 420; busk durante = niente; fine numero ferma busking e melodia insieme; dopo, il busking normale riparte pulito; end_local_run_effects di SU-1004 e game over fermano tutto entro 1 frame) — con tre frame di respiro prima della ripartenza, senza i quali una volta su due la sonda dava un falso KO. Provino TMP/su1009/concertone_suona.png (lanciatore tools/autotest/shot_su1009.sh in finestra: in headless si impuntava dopo la città). - ✅ Correzione R1009b dopo la review RR1009 (Codex): il loop c'era ANCORA per un'altra via — il suono «music» della super partiva da
_play_sfx e via _broadcast_fx sui puppet: per il kazoo non parte più; un solo avviso all'attivazione (prima tre nello stesso frame); FX di folla fermato da _stop_busking() e dal game over; emoji via dal testo di ripiego; sonda 18/18 (misurato: busking.wav attivi 1 → 0 a fine numero). Commit 56a0036. - ⚠️ Da guardare: all'attivazione compaiono (risolto in R1009b) DUE avvisi quasi insieme (il generico della super e «Assolo leggendario — wanted congelato» di
_start_busking): rumoroso, da decidere se tenerne uno. NON PROVATO: in multiplayer gli altri peer vedono un busking normale (note ×3 e cerchio del raggio non viaggiano in _net_state); telefono nel collaudo di fine giro.
Edificio bar con la tazzina e banco del caffè del Mercato, generati con Astra per l'approvazione (SU-1014)2026-09-17
Lotto Claude dev-sonnet A1014 che pilota Astra (tools/sprite/su1014_bar.sh + su1014_bar_giro2.sh, prompt versionati; riduzione BOX e foglio in su1014_riduci_bar.py). Nasce dal KO di Ivan su SU-997 («ci va proprio un edificio bar, e al Mercato un banco dedicato»).
- ✅ Edificio: riferimento
sprites_raw/WORLD/building_downtown_v3.png (negozio a fronte singolo, taglia w96: sprites_raw/BUILDINGS/ non ha palazzi da negozio), risultato 92×80 con insegna a tazzina e scritta COFFEE (non BAR: il locale notturno ha già un'insegna BAR), buono al primo giro. Banco: riferimento il banco delle caramelle 84×54, risultato con bbox identico (scarto 0 px), secondo giro a quattro mani con Astra (al primo la merce era sbilanciata). Scarti staccati tolti tenendo la componente connessa più grande. Foglio TMP/su_bar/foglio_4x.png allegato al ticket; nessun file in assets/: entra con SU-997 dopo il Fatto di Ivan.
Serie giornaliera: due popup nel menu (ingresso del giorno; rientro dopo le partite, con la lattina d'oro al quinto giorno), via dal giornale (KO di SU-1007)2026-09-17
KO di Ivan in chat («si vede male, farei una cosa diversa»). Lotti Codex R1007 (Sol) + R1007b dopo la review RR1007; cancello luna CR1007.
- ✅
files/homeless_city/scripts/ui/MainMenu.gd:~3446-3546: overlay modale clonato dall'avviso di aggiornamento, agganciato all'apparizione del menu; MetaProgress.gd:~998-1040: daily_notice_entry_day/daily_notice_done_day (più daily_notice_owner) persistiti con la serie; l'ingresso usa la stessa aritmetica di daily_streak_today(), il rientro ha priorità, il premio 5/5 è riconosciuto anche dopo un riavvio; lattina d'oro da Skins.BADGE_ICON_PATH. HUD.gd:~7257: via le righe della serie dal giornale; chiavi HUD_GO_SERIE_* tolte, MENU_STREAK_* aggiunte in 8 lingue. - ⚠️ Presi dalla review, non dal builder: durante
BOOT_MESSAGES un ritorno anticipato scavalcava il popup (ora è trattato come l'avviso di aggiornamento); le date erano globali mentre la serie è per owner (cambio account nello stesso giorno = niente popup); il controllo girava solo alla costruzione del menu (ora anche al resume/focus, solo in BOOT_MENU). Sonda probe_su1007 66/66; provini TMP/su1007/popup_ingresso.png, popup_giorno3.png, popup_giorno5_oro.png (844×390). NON PROVATO: sospensione e mezzanotte reali su device.
Scadenze del registro nickname: TTL di 30 giorni sui players senza nome, pulizia a 90 giorni del foglio di moderazione, bocciati per sempre (SU-1016)2026-09-17
Sprint 15, giro del mattino (Ivan sveglio, decisioni in chat). Lotto Codex N1016 (Sol) + correzione N1016b dopo la review RN1016; cancello luna CN1016. Nasce dall'ok di Ivan alle scadenze proposte in SU-995.
- ✅
functions/lib/registry.js:~101-182, functions/lib/api.js: release scrive scade_il = ora + 30 giorni sul player rimasto senza nome, claim lo toglie; bocciati mai. Script Admin functions/scripts/scade_il_righe_vuote.mjs per le righe vuote già esistenti: dry-run di default, --esegui scrive; rilanciabile finché esistono build che scrivono direttamente. - ✅
tools/firestore/firestore.rules.legacy (nuovo, = le regole di SU-995 senza le chiusure di SU-986): scade_il ammesso solo con nome vuoto e valore a 30 giorni ±5 minuti. È QUESTO il file da pubblicare finché il registro non è migrato (SU_REGOLE=… bash tools/firestore/pubblica_regole.sh); il file principale resta per la finestra di migrazione. Entrambi compilano (--solo-valida). - ✅ Apps Script del registro (fuori da git):
pulisciModerazioneScaduta() (intestazioni per nome, dal basso, solo stati conclusi oltre 90 giorni, conteggio nel log) e installaTriggerPuliziaModerazione() idempotente; test Node tools/registro/test_apps_script_registro.mjs 8/8. - ⚠️ Presi dalla review, non dal builder: il backfill lavorava su uno snapshot e poi scriveva in batch: una claim arrivata nel mezzo avrebbe ricevuto il TTL (e il TTL avrebbe cancellato un giocatore attivo); ora ogni documento è riletto e scritto in transazione, con i saltati contati. E la query prendeva anche le claim in revisione (
nome vuoto ma nome_lower pieno): escluse. Respinto il terzo rilievo (TTL obbligatorio nelle regole legacy): le build 0.50 non scrivono il campo. 60/60 test Node. - 📌 Per Ivan a fine ticket:
gcloud firestore fields ttls update scade_il --collection-group=players --enable-ttl --project=axiomatic-path-505007-u7, verifica con … ttls list (atteso players.scade_il ACTIVE). NON PROVATO: Firestore vero, foglio vero, TTL reale.
L'indirizzo della function «api» esce dal codice: per ambiente in `eos_credentials.cfg`, vuoto = Apps Script di sempre (SU-1017)2026-09-17
Lotto Codex N1017 (Sol); cancello luna CN1017, review RN1017 (un rinomino). Trovato al mattino guardando la build sull'Honor: NicknameRegistry.gd:145 aveva la costante piena e, per la regola di SU-986 (mai ripiego), la build dev non prenotava nickname né contava inviti; una release sarebbe uscita senza registro finché function e migrazione non fossero in produzione.
- ✅
files/homeless_city/scripts/autoload/Env.gd:~202 legge una volta [api] url dalle credenziali attive (assente = vuoto); NicknameRegistry.gd:145,~1165 instrada le quattro azioni (conteggio inviti, riscatto verificato, claim, release) all'Apps Script se vuoto, alla function senza ripiego se pieno. eos_credentials.example.cfg documentato; nessuna stringa web.app nel codice. - ✅ Sonde 984/986 nei due casi: url vuoto → function 0 / Apps Script 5 e 9; url finto → function 55 e 77 / Apps Script 0.
tools/release/export_all.sh pre-volo: avviso (senza stampare l'URL) se [api] url è pieno in stage o live. - 📌 Regola che ne esce: un URL pieno vuole la function in produzione E il registro migrato (col cancello chiuso la function risponde «non disponibile»). NON PROVATO: rete vera, contenuto dei cfg reali (assente = vuoto).
Icona del CONCERTONE distinta dalla trombetta, generata con Astra per l'approvazione (SU-1015)2026-09-17
Lotto Claude dev-sonnet A1015 che pilota Astra (tools/sprite/su1015_concertone.sh, prompt versionato; riduzione BOX in su1015_riduci_concertone.py).
- ✅ Megafono da concerto d'oro con raggi a zigzag (variante B su due, scelta a quattro mani con Astra per leggibilità a 16×16 e distanza dalla trombetta della cella 4):
sprites_raw/temp/su_concertone/concertone_16.png (atlante) e concertone_128.png (carte); foglio TMP/su_concertone/confronto_4x.png allegato al ticket. Nessun file in assets/: entra col Fatto di Ivan, caricato da SU-1009 se esiste.
Brina: i lampioni erano accesi ma non si vedeva; luce calda, riflesso sulla testa, contrasto misurato (KO di SU-1000)2026-09-17
KO di Ivan in chat («di notte mi pare non si accenda»), lampioni approvati. Lotti Codex R1000 (diagnosi) + R1000b (luce) + un pixel-fix da review RR1000; cancello luna CR1000.
- 📌 Diagnosi con sonda notturna (
probe_su1000_notte.gd): 117/117 lampioni di Brina accesi, energia 0,75, nessun PointLight2D (le luci sono voci per lo shader di World). L'ipotesi «luce debole» è caduta; è caduta anche quella del builder (riflesso della testa di 1 px al 35 %, portato a 3+1 px): il provino guardato diceva altro — pozza bianco-ghiaccio (0,76·0,90·1,0) su neve bianca, invisibile come luce, mentre al Centro la pozza gialla su asfalto si legge. - ✅
Quartieri.gd:~607 luce calda (1,0·0,88·0,66) per Brina, con commento; shot_su1000.gd misura il contrasto pozza/suolo (disco 12 px contro anello 40-60 px): Brina 0,437× del Centro prima, 0,488× dopo, soglia 0,45 (su neve quasi bianca la distanza RGB satura: la prova è il PNG). WorldGenerator.gd:~9382 riflesso fuso sopra il palo (blend), non sostituito: la review aveva visto tre pixel trasparenti da acceso. - Provini
TMP/su1000/notte_brina.png e notte_centro.png a 844×390, ore 00:00. NON PROVATO: telefono (nel collaudo di fine giro).
Metro in fiamme: seconda fila di fiamme verso le porte, e il fuoco resta vivo mentre il treno lascia la banchina (KO di SU-998)2026-09-17
KO di Ivan in chat (ok il giro 3 e i secondi di SU-1005). Lotti Codex R998 + R998b dopo la review RR998; cancello luna CR998.
- ✅
BonusLevel.gd:~223,~3482-3536: 8 fiamme per vagone (16 in tutto), la fila verso le porte sfalsata di mezzo passo e con fotogramma iniziale diverso (+2), stesso sheet, stessa scala, stesso materiale del tremolio. ~5429-5441: nell'outro (Fase.FINE saltava _aggiorna_fuoco) fotogrammi e tempo dello shader avanzano finché il treno è fuori. - ⚠️ Preso dalla review: nell'outro le braci nascevano ma
_aggiorna_scintille non girava: restavano ferme e opache; ora vivono e scadono (a 1,5 s: 9 vive su un tetto di 14, 9 in movimento). Il provino confrontava due rettangoli in coordinate schermo con il treno in moto: ora la zona è ancorata al vagone in ciascuno scatto e conta i fotogrammi delle 16 fiamme (16/16 diversi, 29.359 pixel diversi nella zona). Respinto: identificatori in italiano in un file italiano. - Provini
TMP/su998/partenza_05.png, partenza_15.png (844×390). Nessuna particella nuova: la misura fps di SU-998 sull'Honor resta valida (4 sprite in più per vagone).
INVITA UN AMICO: a tastiera aperta un tocco fuori dal campo o su RISCATTA chiude la tastiera e rimette il sottomenu normale (KO di SU-1002)2026-09-17
KO di Ivan in chat («ok, ma se tocco un punto qualsiasi o RISCATTA la tastiera sparisce»). Lotto Codex R1002 (Sol); cancello luna CR1002.
- ✅
MainMenu.gd:~7577-7667: in modo compatto nasce una volta un Control trasparente a schermo intero (STOP) sotto campo e RISCATTA: una pressione (ScreenTouch/MouseButton) fuori dal campo chiama _account_inviti_chiudi_tastiera(); RISCATTA prima chiude e poi riscatta (connessioni riordinate una volta, testo conservato); il tocco sul campo non chiude. - ✅ Sonda
probe_su1002b 3/3 (fuori → normale e senza fuoco, 2 pulsanti alle posizioni di prima; dentro → resta compatto; RISCATTA → normale + 1 chiamata). NON PROVATO: tastiera vera e tocco fisico — sull'Honor nel collaudo di fine giro.
Carte a 6 livelli: applicata la curva a rendimenti calanti (livello 5 = 3× invece di 9×) e XP +18 %/livello dopo il ginocchio; 10 run del bot prima/dopo (SU-1011)2026-09-17
Sprint 15, giro notturno da CLI, dopo il «vai avanti» di Ivan delle 02:30 (proposta principale applicata come default: scritto sul ticket). Lotti Codex K2 (Sol) + correzione K2b dopo la review RK2; cancello luna CK2.
- ✅
files/homeless_city/scripts/systems/PowerUpSystem.gd:~313-321,~483-534: tabella unica 1,0 · 1,8 · 2,4 · 2,8 · 3,0 al posto di valore × livello × 9/5 (1,8 · 3,6 · 5,4 · 7,2 · 9,0) per tutti i passivi, additivi compresi; il super (livello 6) resta sul suo percorso e conserva la scala vecchia esatta. files/homeless_city/scripts/autoload/XPSystem.gd:~89 XP_GROWTH_MID 1,07 → 1,18 dal livello 12 al 40 (base 5, +16 % fino al 12 e coda +3 % invariati): XP per livello ai livelli 1/12/20/30/40 da 5 · 26 · 44 · 86 · 170 a 5 · 26 · 96 · 503 · 2.635 — nel finale l'attesa fra due livelli cresce molto, ed è voluto (la mediana deve restare a zero carte al 5 dopo 15'); il commento storico del +7 % (le prove a 1,06 e 1,09, l'attesa di 1,6') è conservato sotto la costante come prima manopola da ritoccare se il finale risulta piatto. - ✅ 10 run del bot dopo (semi 101201-101210,
time_scale 4, probe_su1011) contro le 3 «prima» di K1 — a 15': livello 20 → 18, carte al livello 5 1 → 0, XP 421 → 392; a 25': livello 28 → 22, carte al 5 2 → 0,5, XP 866 → 796. Bersaglio del ticket (mediana zero carte al 5 a 15') centrato; i soldi del bot (28 → 13 $) non provano l'economia umana — la misura vera arriva dalla telemetria della prossima build (0.50: 1.025 $ a 15', stima con la formula ~342 $). Run di prova fresca dal Mac: livello 17 / 0 carte a 15', 21 / 0 a 25'. TMP/su1011/confronto.md allegato al ticket. - ⚠️ Preso dalla review, non dal builder (K2b): il testo delle carte (
_pb/_pm/_pa, ~969-1022) calcolava ancora con la scala lineare mentre l'effetto usava la tabella — STOMACO DI FERRO al livello 5 dichiarava −90 % e applicava −36 %, CARISMA al livello 1 +27 % contro +15 %; ora testo e valore passano dalla stessa funzione (sonda: STOMACO −12/−36, CARISMA +15/+45, CALAMITA 25/75 px, testo = valore). Aggiornati i commenti d'intestazione dei due file e quello del magnete (45/225 → 25/75 px). - ⚠️ Da provare a mano: il raggio della CALAMITA al livello 1 scende da 45 a 25 px per effetto della curva (i livelli 1-4 valgono 0,56/0,50/0,44/0,39 di prima): se è troppo poco, la tabella è una riga. NON PROVATO: partite umane.
Otto lampioni, uno per quartiere; a Brina la fontana ghiacciata si vede e una torcia la scongela per due minuti (SU-1000, SU-1012)2026-09-17
Sprint 15, giro notturno da CLI: lotto Claude W2 (architetto-opus, seconda onda dopo il reset della finestra); cancello luna CW2 e review Sol RW2; sonde rifatte dal Mac.
- ✅ SU-1000
files/homeless_city/scripts/autoload/Quartieri.gd (voce "lampione": testa, palo, vetro, spento, luce, accanto a musica e tinta; accessor lampione() ~1072 con ripiego al Centro) + files/homeless_city/scripts/world/WorldGenerator.gd:~8964,~9166,~9262-9387: _texture_lampione() smista su sette teste disegnate a runtime (gancio del Centro, tettoia del Mercato, anello di Nottefonda, orecchie di Gattopoli, cappello di Solleone, ghiaccioli di Brina, comignolo di Fumarola) più la lanterna da parco della Collina ora tinta dalla dichiarazione; tabella LAMPIONE_Y_PALO: sotto il collo palo e zoccolo sono identici per tutti gli otto, quindi «stesso ingombro a terra» vale per costruzione. Scartati gli otto sprite Astra (11×46 da tenere allineati per 40 righe di disegno). Misure (shot_su1000): canvas 11×46, piede a y=45 e zoccolo di 8 px per tutti; il Centro esce con 0 pixel diversi dal disegno precedente; a Nottefonda 89 lampioni, 89 pozze di luce con nucleo/raggio storici, 89 ombre. Foglio per l'ok di Ivan TMP/su1000/lampioni_4x.png (giorno e notte, nomi in inglese; allegato al ticket) + TMP/su1000/notte_nottefonda.png. - ✅ SU-1012 sprite
files/homeless_city/assets/sprites/world/fountain_frozen.png (raw sprites_raw/fountain_frozen.png, generato con Astra in 3 varianti via tools/sprite/su1012_fontana_ghiacciata.sh, ridotto da su1012_riduci_fontana.py che rifiuta le varianti fuori sagoma: bbox 0..55 × 10..55 contro 0..55 × 11..55 del fontanile, scarto 1 px in alto per i ghiaccioli; scartate B e C per la frangia magenta). files/homeless_city/scripts/world/Interactable.gd:~131,~474,~536,~3492-3525: _fountain_thaw_left locale a ogni peer, is_fountain_frozen(), thaw_fountain() (riparte da 120 s, non somma), vapore CPUParticles2D, visuale ricalcolato in un posto solo; WorldGenerator.gd:~3726 scambia lo sprite sul cooldown_changed esistente; files/homeless_city/scripts/entities/TorchFireball.gd:~141,~177 scongela con la stessa regola di contatto degli altri bersagli. Sonda SP (3 semi, 23 controlli): nasce ghiacciata e non lava (30→30 con avviso), torcia → scongelata + vapore, igiene 30 → 55, a 119 s liquida e a 121 s ghiacciata con avviso, seconda torcia a 60 s → liquida fino a 179 s. Sonda MP (due peer ENet, porta 7112): scongelo a 7 ms host / 9 ms guest dal proprio fuoco, rigelo a 120.006 / 120.001 ms (Δ5 ms, un frame). Nessuna RPC. - ⚠️ Decisione per Ivan, in prima riga sul ticket: il ticket dice «lava come altrove (+25 igiene, cooldown 1 s)», ma altrove il cooldown della fontana è 20 s e l'1 s è il rimbalzo del rifiuto; il builder ha tenuto 20 s (con 1 s l'igiene si riempirebbe in quattro secondi). Se Ivan vuole l'1 s è una riga (
Interactable.gd:~3577). - 📌 Rilievo della review non accolto: «lo scongelamento applicato dalle repliche
visual_only viola l'autorità dell'host» — è il disegno chiesto dal ticket (stato locale, torcia già replicata), misurato a Δ5 ms; limite dichiarato: un peer entrato DOPO il lancio della torcia vede la fontana ancora ghiacciata. Nomi italiani (lampione, _testa_*): seguono il file. Due difetti presi dalle sonde del builder: sprite rimasto di ghiaccio se si scongela durante il secondo di rimbalzo; la sonda MP moriva perché due minuti fermi a Brina uccidono il barbone (ora su911_immortal). NON MISURATO: device (il lampione a zoom di gioco su telefono, la testa di Brina è la più debole a 1:1), rigelo attraverso un cambio di quartiere o durante la retata, ombra del nuovo sprite pixel a pixel.
Collaudo di fine onda sull'Honor e in locale: SU-1002 confermato sul telefono; l'avviso del quinto giorno di SU-1007 non si vedeva mai, ora sta nel giornale (H1 + I1c)2026-09-17
Sprint 15, giro notturno da CLI: lotto Claude H1 (collaudatore, Honor 10 via adb) + correzione I1c su Codex Sol.
- ✅ SU-1002 sul device: build
dev di stanotte esportata (release-signed, esporta_apk_su923.sh adattato su copia) e installata sull'Honor: TMP/su1002/honor_1_tastiera.png mostra SOLO campo e RISCATTA sopra la tastiera; honor_0_normale.png vs honor_2_chiusa.png: COPIA, CONDIVIDI, RISCATTA e INDIETRO a 0 px di differenza (sole differenze attese: la freccia del pad sparisce dopo un tocco, il campo tiene il contorno «a fuoco»). - ⚠️ Difetto vero trovato dal collaudo, non dal builder né dalle review (SU-1007, criterio 4): a 5/5 l'avviso della lattina d'oro non compariva mai —
MetaProgress lo rimandava con call_deferred, ma HUD._on_game_over chiude il gate delle notifiche in modo sincrono sullo stesso segnale game_over, e _queue_big_notification scarta tutto a gate chiuso: il segnale partiva (+4 ms), il banner no. I1c files/homeless_city/scripts/autoload/MetaProgress.gd:~995-1106: tolto il big_notify differito, esposto lo stato effimero daily_streak_reward_this_run (vale anche per il 5/5 in attesa di accredito, si azzera alla partita dopo); files/homeless_city/scripts/ui/HUD.gd:~7229-7280: in singolo la riga «GIORNO n DI 5» diventa l'avviso HUD_GO_SERIE_PREMIO_ORO (8 lingue) col corpo del pannello in oro. Sonda probe_su1007 52/52; provino TMP/su1007/fine_giorno5.png (guardato: «CINQUE GIORNI DI FILA: UNA LATTINA D'ORO!» sotto il punteggio) e fine_giorno3_{telefono,tablet}.png («GIORNO 3 DI 5», pagina 2 del giornale). - ✅ Nuovo provino
files/homeless_city/scripts/tools/shot_su1007.gd + tools/autotest/shot_su1007.sh (di H1): game over VERO con GameState.trigger_game_over, serie forzata via forced_today; vuole un PUID esadecimale valido e un EOSBridge finto (quello vero senza rete risponde account_session_live()=false e azzera la serie); il SIGABRT a fine script viene dal finto EOS al quit(), dopo che tutti gli scatti sono salvati. - ✅ Regressione:
run_sp.sh 120 wander (24 dump, mem.orphans=0, 0 SCRIPT ERROR, morte naturale a 112,6 s) e run_mp.sh 90 1 (host 2/2 giocatori, client con i puppet, ENet, 0 SCRIPT ERROR; solo il teardown ObjectDB leaked noto), audit_emoji_pittogrammi.py 0 — TESTLOG aggiornato. Nessun errore di parsing incontrato mentre W2 modificava WorldGenerator/Interactable. - 📌 Sul telefono resta la build
dev di stanotte (0.50, versionCode 50, senza sonde): buona per le prove di Ivan. NON PROVATO: iPhone.
Bonus metro: solo i secondi, grandi e di lato; dal giro 3 il vagone brucia davvero, con fuoco animato e tremolio di calore (SU-1005, SU-998)2026-09-17
Sprint 15, giro notturno da CLI: lotto Claude B1 (architetto-opus, caduto una volta per il limite della finestra alle 00:5x e ripreso col contesto intatto dopo il reset) + correzione B1b su Codex Sol dopo la review RB1; cancello luna CB1; misure sull'Honor 10 collegato via adb.
- ✅ SU-1005
files/homeless_city/scripts/world/BonusLevel.gd (_costruisci_ui ~6895, _disponi_fascia_alta ~7040, _aggiorna_orologio ~7140, OROLOGIO_FONT ~809): le due barre (gialla del corridoio, azzurra della banchina) NON vengono più costruite; resta _lbl_tier; i secondi mostrano la fase in corso (sulla banchina il tempo residuo che era la barra azzurra); font 56 → 88 (1,57×), sullo scatto 28,4 → 44,7 px a 844×390 e 56 → 88 a 1024×768; ancorati in alto a destra dentro _safe_insets(), fermati 50 unità prima del bordo perché il tasto pausa sta nella stessa colonna. Screenshot dall'Honor TMP/su1005/honor.png (guardato: «45» grande, pausa e comandi virtuali liberi) + 6 provini Mac in TMP/su1005/. - ✅ SU-998
BonusLevel.gd (costanti fuoco ~177-233, _vesti_di_fuoco/_aggiorna_fuoco/_scocca_brace ~3458-3600): dal giro 3 fiamme animate sul tetto come Sprite2D a hframes (sheet generato con Astra alla prima passata, 4 frame coerenti con la palette del treno: files/homeless_city/assets/sprites/world/subway_train_fire_flames.png, raw in sprites_raw/ via tools/sprite/su998_fiamme.sh), braci nella lista _scintille già esistente, e shader canvas_item files/homeless_city/assets/shaders/heat_shimmer.gdshader sul solo vagone (un ShaderMaterial condiviso, tempo come uniform scritto da _aggiorna_fuoco, MAI TIME né overlay a schermo intero) — tutto avanza dentro _passo(delta), così le sonde a passi restano deterministiche. Giri 1-2 senza fuoco (probe_su998, 27 controlli). Provini TMP/su998/giro2.png, giro3_a.png, giro3_b.png (il fuoco cambia: 15,7 % dei pixel della fascia del tetto) e TMP/su998/honor_fuoco.png. - ✅ fps sull'Honor 10, bonus al giro 3, 1.800 fotogrammi di corridoio (
tools/android/su998_fps.sh + su998_fps_probe.gd): prima 58,55 (mediana 16,97 ms, p95 19,15) → dopo 58,29 (−0,44 %), entro il 5 %; un picco isolato di 131 ms nella build «dopo», compatibile con la prima compilazione dello shader. ⚠️ La prima misura «prima» era da buttare: col barbone fermo un treno lo spazzava via e i 30 s finivano metà in città — la sonda conta solo i fotogrammi in corridoio e fa schivare il barbone. E FIAMME_FPS 9 → 10: a 9 fps mezzo secondo è esattamente 4 fotogrammi, e i due scatti uscivano con la stessa fiamma. - ⚠️ Presi dalla review, non dal builder (B1b): lo shader faceva
COLOR = texture(...) e scartava il COLOR del vertex — dal giro 3 sparivano modulate/self_modulate dei vagoni (ora × COLOR); il tremolio era solo sulla fiancata, con le ante ferme sopra (ora stesso materiale, in fase); le braci nascevano ~1.820 px fuori campo (is_visible_in_tree() non guarda il viewport: ora intersezione col rettangolo della camera, margine 64 px). Rilievo scartato: i nomi italiani (_aggiorna_fuoco, TEX_FIAMME) seguono il file, che è tutto in italiano. - 📌 Ritirati
files/homeless_city/scripts/tools/shot_lottob2_metro.gd e tools/autotest/shot_lottob2.sh (SU-743): controllavano che la barra fosse a schermo nel corridoio, cioè proprio il requisito che SU-1005 toglie. ⚠️ NON MISURATO: iPhone (non collegato: safe-area col notch vera); MP (il fuoco dipende solo dal giro, che host e client hanno già uguale, nessuna RPC). Sul telefono resta la build di misura: l'orchestratore rimette quella normale a fine giro.
Registro nickname sulla function «api»: prenotazione e liberazione verificate dal token EOS, stato calcolato dal server, un nome per PUID (SU-986)2026-09-17
Sprint 15, giro notturno da CLI: lotto Codex F2 (Astra) + correzione F2b dopo la review RF2; cancello luna CF2. Sandbox senza rete: test Node puro, regole compilate dal Mac (--solo-valida).
- ✅
functions/lib/registry.js NUOVO + functions/lib/api.js: claim e release con la stessa verifica del token Connect di EOS di F1, PUID solo dal token (mismatch nel corpo rifiutato); claim transazionale con unicità case-insensitive, cambio nome atomico, controllo dei bocciati con norm calcolata dal server; release atomica e idempotente che rifiuta prenotazioni altrui; cancello amministrativo per ambiente (registry.js:~13, letto nella transazione): la function nasce CHIUSA finché non si fa il passaggio dal Foglio. Quote per PUID: 30 claim e 10 release l'ora. - ✅
tools/firestore/firestore.rules (+7/−7): nessuna scrittura diretta dal client su nicknames/players/bocciati (sonde dev comprese), ogni riga con motivo e data; resolve resta lettura come chiuso da R1. La collezione delle quote _api_limits non ha match: negata dal default. - ✅ Client
files/homeless_city/scripts/autoload/NicknameRegistry.gd:~1154,~1181,~1344: claim/release instradate alla function SOLO se l'indirizzo è configurato (vuoto = strada di oggi), token via EOSBridge.copy_connect_id_token; anche la promozione del nome usa il claim autenticato; il claim riuscito restituisce la grafia canonica e cache/pending/segnale usano quella; niente claim automatico di riserva dopo un dubbio (cancellerebbe la revisione appena aperta). Sonda probe_su986: 186 controlli, 0 errori. - ⚠️ Presi dalla review, non dal builder (F2b):
body.stato era fidato — un client modificato mandava ok per un nome dubbio e saltava la moderazione (ora il server classifica da sé: le cinque liste del client, 921 voci, portate in JS come funzione pura, 10/10 nomi coincidenti col client, test anti-divergenza); con dubbio lo stesso PUID poteva occupare fino a 30 nomi l'ora (ora un solo nome per PUID: il nuovo claim libera il precedente nella stessa transazione, players.nome_lower identifica la prenotazione e players.nome resta vuoto durante la revisione); la grafia in cache divergeva da quella salvata. - 📌
TMP/su986/PIANO_PASSAGGIO.md (allegato al ticket, 59 righe): fase 1 function chiusa col Foglio scrivibile; fase 2 blocco dei writer legacy, regole pubblicate, drenaggio, export/riconcilia/import; fase 3 apertura del cancello — i nomi importati dal Foglio risultano «presi» agli altri, le build vecchie conservano solo le letture. tools/firestore/prova_su986_regole.sh (18 verifiche per ambiente) e functions/scripts/prova_su986_emulatore.mjs (13, con un token vero) pronti, non eseguiti. Test Node 55/55. - ⚠️ NON PROVATO: emulatore con token EOS vero, deploy, regole remote, dati e prenotazioni orfane preesistenti.
Il gatto lanciato non attraversa più le pareti della pensilina del bus, da dentro e da fuori (SU-1008)2026-09-17
Sprint 15, giro notturno da CLI: lotto Claude C1 (dev-sonnet); cancello luna CC1 e review Sol RC1; sonde rifatte dal Mac.
- ✅ Tre cause, le due del ticket più una trovata dalla sonda: (1)
World._tall_rects riceveva dalla pensilina UN solo rettangolo pieno (80×76, tetto compreso), non tre pareti: nato dentro, il gatto restava in «grazia» finché non usciva dall'intero blocco, quindi attraversava lati e fondo; (2) il controllo guardava il solo punto di fine frame, e un passo da 52 px salta una parete da 6; (3) la grazia usava il risultato del check del PRIMO frame invece del punto di nascita: un lancio da fuori il cui primo passo atterrava già dentro veniva scambiato per «nato dentro» e passava gratis. - ✅ Rimedio:
files/homeless_city/scripts/world/World.gd:~907,~7970,~8017,~8048 — nuove «aperture» _tall_open_rects (il pavimento vero della pensilina, con priorità sulla griglia degli ostacoli alti) e hits_tall_obstacle_segment(a, b) che campiona il segmento del frame a passi di 2 px; files/homeless_city/scripts/world/WorldGenerator.gd (+27, patch di C1 applicata al cancello dopo il commit di W1): _add_bus_stop() registra l'apertura; ProjectileCrash.gd:~88 blocked(p, frame_start = p) — parametro opzionale retrocompatibile: segmento quando c'è il punto di partenza, grazia ancorata a frame_start; CatProjectile.gd:~190 lo passa. Scelta: apertura additiva invece di tre pareti sottili, perché il blocco 80×76 serve anche a _bin_avoid_rects per tenere i cestini fuori da sotto la tettoia. Bottle/Pin/TrashBag restano a un argomento (comportamento invariato, non ricollaudati). - ✅ Sonda
probe_su1008 (20 semi × 9 casi + camioncino di SU-683): prima del fix 12-13 KO su 19 per seme (il gatto finiva 130-280 px oltre la parete); dopo 181/181 OK, 0 attraversamenti, grazia del camioncino intatta. probe_su1008_mp (due peer ENet, porta 7108): stessi punti di caduta su host e client, scarti < 0,2 px. Il fix vale anche per il gatto tirato dalla gattara (from_npc): la decisione di Ivan del 16/09 sceglieva QUALE bug (il gatto lanciato, non il nemico di Gattopoli), e una fisica coerente per entrambi è voluta. - 📌 Ipotesi della review scartata: «
frame_start: Vector2 = p non compila» — il compile-check passa (6/6) e le sonde girano: in Godot 4.7 il default può riferirsi a un parametro precedente. ⚠️ NON MISURATO: device reale; il caso «passo grande» in MP (a velocità forzata i due processi non sono in lockstep: scarti fino a ~11 px senza attraversamenti); la sonda MP copre due casi su un seme.
Lattine d'oro e cosmetici a lattine d'oro per sempre; una lattina d'oro ogni cinque giorni di fila con almeno una partita finita (SU-1006, SU-1007)2026-09-17
Sprint 15, giro notturno da CLI: lotto Claude I1 (architetto-opus) + correzione I1b su Codex Astra dopo la review RI1; cancello luna CI1 (tutto NON MISURATO: artefatto noto dei lotti Claude, i numeri stanno qui); sonde rifatte dal Mac.
- ✅ SU-1006
files/homeless_city/scripts/autoload/Skins.gd:~652,~764,~778: invariante «comprato = posseduto» (golden_unlock_ids + _reconcile_paid_unlocks, richiamati da _load() e da reset_all()), così RESET PROGRESSI non richiude spilla, piccione e punk; paid è uscito dalle chiavi azzerate dal reset (prima il lato più vecchio di un reset perdeva la spesa e il saldo d'oro si gonfiava). Inviti.gd + ProgressSync.gd:~19,~54,~960,~989: inviti.cfg (saldo, codice riscattato, preferenza del piccione) viaggia in progressi.json come terzo campo FACOLTATIVO inviti_cfg, fusione per massimo; format resta 1, le build vecchie lo ignorano. Sonda probe_su1006 locale 35/35 (compra, resetta, verifica; controprova rossa col vecchio reset_all: 6 KO, saldo 4 → 10) e eos 8/8 con trasporto vero su Player Data Storage: una seconda installazione con lo stesso PUID ritrova 7 lattine, codice e paid. - ✅ SU-1007
MetaProgress.gd:~988-1100: serie in tre chiavi proprie di meta.cfg (daily_streak, daily_last_day, daily_streak_owner), agganciata al segnale game_over (non a note_honest_run_end, che salta l'online e vuole 10 minuti); prima partita finita del giorno → +1, 5/5 → +1 lattina d'oro nel contatore separato oro_serie (sommato al conteggio del server in golden_state(), così il «+1» in INVITA UN AMICO e il negozio si accendono da soli, nessuna patch a MainMenu) e serie 0; giorno saltato → 0; RESET non la azzera; accredito fallito (nessun account) → la serie resta a 5 e riprova il giorno dopo. HUD.gd:~7231-7275 (patch di I1 applicata al cancello): «GIORNO n DI 5» a fine partita, 2 chiavi in ui_hud.csv per 8 lingue, solo in singolo (in MP quella pagina è la classifica, SU-877). Sonda probe_su1007 con date forzate (forced_today): 49/49. - ⚠️ Presi dalla review, non dal builder (I1b): la fusione prendeva
daily_last_day più recente e daily_streak massimo SEPARATAMENTE — dopo il premio {5, 0} si fondeva col remoto {4, 4} in {5, 4}: una lattina ogni giorno; ora la terna si fonde come coppia (data più recente, a parità la serie più lunga; proprietari diversi: vince l'account corrente). E la serie era globale senza proprietario: 4 giorni con l'account A e il quinto con B davano il premio a B; ora daily_streak_owner e cambio account → 1/5. Rilievi lasciati: oro_serie fuso per massimo (limite comune ai contatori, SU-920); la riga «GIORNO n DI 5» compare a ogni partita del giorno (voluto). - ⚠️ NON MISURATO: mezzanotte con l'orologio vero, sync fra due telefoni con account vero; il
big_notify del quinto giorno parte mentre l'HUD monta il pannello e potrebbe finirci sotto (lo guarda il collaudo di fine onda). ⚠️ La sonda di I1b rifiuta un user:// fuori da TMP/ di radice: si lancia con SU_TMP="$PWD/TMP/su_…", non sotto /tmp.
Carte a 6 livelli: misurato quanto crescono i poteri e proposta una curva a rendimenti calanti — Ivan sceglie (SU-1011, misura e proposta, niente codice di gioco)2026-09-17
Sprint 15, giro notturno da CLI: lotto Codex K1 (Sol). PowerUpSystem.gd e XPSystem.gd NON toccati: la curva si applica dopo la scelta di Ivan.
- 📌 Telemetria 0.50 (uscita il 16/09) troppo scarsa: 5 partite valide, 3 arrivano al minuto 15 (mediane: 1.025 $, livello 40, 3 carte al livello 5, 2 super), 1 al minuto 25 (1.501 $, livello 53, 8 carte al 5, 7 super). Confronto 0.43 (N=22 a 15'): 367 $, livello 26, 0,5 carte al 5, 0 super. Fa fede la baseline col bot (3 run a
time_scale 4, probe_su1011): a 15' 28 $ / livello 20 / 1 carta al 5 / 421 XP; a 25' 6 $ / livello 28 / 2 carte / 866 XP — il bot non fa economia, quindi misura la progressione, non i soldi. - 📌 Proposta (
TMP/su1011/PROPOSTA.md, allegata al ticket): moltiplicatori per livello 1,0 · 1,8 · 2,4 · 2,8 · 3,0 al posto di 1,8 · 3,6 · 5,4 · 7,2 · 9,0 (il livello 5 vale 3× il livello 1 invece di 9×) e XP dopo il ginocchio (livello 12) +18% per livello invece di +7% (gli effetti da soli non riducono le pescate). Stima con la formula: ~342 $ a 15' e ~500 $ a 25' sui dati umani, livelli 28/33 a parità di XP. Bersaglio del ticket: a 15' zero carte al 5 nella mediana e soldi sotto la metà di oggi (512 $). - ⚠️ NON MISURATO: l'effetto dopo l'applicazione (10 run prima/dopo, criterio 3) — si fa nel lotto di codice. Sonda
files/homeless_city/scripts/tools/probe_su1011.gd + tools/autotest/probe_su1011.sh committate: è il «prima» riproducibile.
Fontanelle del Mercato con tre ingombri, bidoni agli angoli del lotto del camioncino, tazzina di caffè a 5 dollari in ogni quartiere (SU-1010, SU-1001, SU-997)2026-09-17
Sprint 15, giro notturno da CLI: lotto Codex W1 (Sol) + correzioni W1b (cinque rilievi della review RW1) e W1c (sonda); cancello luna CW1; sonde e provini rifatti dal Mac.
- ✅ SU-1010
files/homeless_city/scripts/world/WorldGenerator.gd:~7858,~7993,~8260: l'ostacolo del fontanile a raso è diviso in tre cerchi, centri misurati con PIL sui pixel accesi dei tre PNG (locali (−19,−11), (0,−11), (19,−11)), raggio 14 px (alfa massima 13,4-13,5); fra due sagome resta 1 px contro i 16 del giocatore, quindi nessun passaggio. Prompt unico invariato. Sonda: 20 semi, 240 approcci N/S/E/O, 0 attraversamenti, prompt 60/60. - ✅ SU-1001
WorldGenerator.gd:~509,~2632,~8772: due registri di esclusione — per i BIDONI il camioncino 68×40 allargato di 24 px (116×88) più la fila davanti al bancone; cabine e bancarelle leggono ancora il lotto intero (SU-764). I bidoni usano i quattro angoli esterni come i palazzi. Sonda: 20 semi, 50 camioncini, 100 bidoni d'angolo, 0 blocchi. Provini TMP/su1001/su1001_centro.png e su1001_mercato.png (guardati: bidoni ai due angoli alti). ⚠️ Il provino di Codex forzava negozi_a_banco scrivendo nella const QUARTIERI («Invalid assignment on read-only value» al secondo scatto): riscritto senza mutazioni — e al Mercato il camioncino c'è comunque. - ✅ SU-997
files/homeless_city/scripts/world/Interactable.gd:~18,~3688,~3962: tipo COFFEE_BAR, 5 $ esatti, +25 energia con tetto 100, rifiuto comico senza soldi e a energia piena, FX e suono della tazzina dei bidoni, _note_shop("coffee"), nessuna RPC (stat per-peer come il camioncino). WorldGenerator.gd:~5148,~5282,~9213: al Mercato il caffè sta sul banco delle caramelle (bancarella esistente, niente arte nuova: deciso in chat da Ivan il 16/09) — CANDY se piazzato, altrimenti l'ultimo banco, facciata di riserva a zero banchi; altrove un punto sulla facciata BAR dove c'è (Brina, Nottefonda) o su una facciata generica (Centro, Gattopoli, Solleone, Fumarola, Collina). 4 chiavi in ui_mondo.csv, 8 lingue. Sonda: 40→65 e −5 $, 90→100, senza soldi niente addebito, a 100 niente addebito; prompt 8/8 lingue senza %d; 24/24 città con un solo caffè raggiungibile; Centro a neon spenti 3/3. - ⚠️ Cinque difetti presi dalla review, non dal builder (W1b): la caffetteria nasceva DENTRO
_appendi_neon (neon spenti = niente caffè); il caffè al Mercato solo sul quarto banco riuscito; nessun rifiuto a energia piena (5 $ buttati); label_key scavalcava tf() e i %d restavano; mancava _note_shop(). - ⚠️ NON MISURATO: il caso «meno di 4 banchi al Mercato» (nessun seme su 40 lo produce: la sonda lo dichiara e non fallisce); MP reale a due peer.
INVITA UN AMICO: con la tastiera aperta restano solo il campo del codice e RISCATTA, alla chiusura il sottomenu torna identico (SU-1002)2026-09-17
Sprint 15, giro notturno da CLI: lotto Claude M1 (dev-sonnet); cancello luna CM1. Screenshot dal device a fine onda, con la build di tutti i lotti (l'Honor era del lotto B1).
- ✅
files/homeless_city/scripts/ui/MainMenu.gd (+262/−16): il LineEdit del codice ha virtual_keyboard_enabled/show_on_focus e il tocco di _on_text_field_touch come il campo nome (SU-454, non toccato); a tastiera aperta (virtual_keyboard_get_height() in coordinate logiche) il sottomenu si riduce a campo + RISCATTA ancorati in alto, il resto passa a visible = false (mai queue_free); alla chiusura la disposizione torna dai valori salvati alla costruzione (differenza misurata 0,0 su telefono e tablet). Il ramo account_inviti di _request_back() chiude prima la tastiera e ripristina subito; i rami account_nome/beta_code sono intatti. - ✅ Provino
shot_su1002.gd (tastiera finta a 300/768 dell'altezza, disegnata in ciano): TMP/su1002/a_normale_*, b_tastiera_aperta_*, c_tastiera_chiusa_* per 844×390 e 1024×768 — campo e pulsante interamente sopra la linea della tastiera; guardati. - ⚠️ NON MISURATO: l'altezza vera dichiarata da Android/iOS (sul Mac vale 0) e il gesto reale sul device; iPhone non collegato. Flusso di riscatto del codice non toccato.
Backend Firebase: la function «api» degli inviti con il PUID preso dal token EOS, e i passi per preparare il progetto (SU-984, SU-988)2026-09-17
Sprint 15, giro notturno da CLI: lotto Codex F1 (Astra) + correzione F1b dopo la review RF1; cancello luna CF1. Sandbox senza rete: test su Node puro, npm install fatto dal Mac (252 pacchetti, functions/node_modules/ ora in .gitignore).
- ✅
functions/ NUOVA: index.js (HTTPS v2 api, Node 22, us-central1 come il database, maxInstances 2, 256 MiB, timeout 15 s, concorrenza 40), lib/token_eos.js (RS256 con node:crypto sulle JWKS di Epic, cache 6 h; verifica di emittente, tokenType, client, prodotto, deployment e scadenza; PUID solo dal token), lib/api.js (conteggio_inviti con count sui riscatti con run_finita, cache 60 s; release_verificato idempotente; quote per PUID 30 conteggi e 10 liberazioni l'ora), test node --test 34/34 senza node_modules. firebase.json + .firebaserc (progetto axiomatic-path-505007-u7, Hosting con le sole rewrite /api/**). - ✅ Client
files/homeless_city/scripts/autoload/NicknameRegistry.gd:~144,~937: le due azioni vanno al nuovo indirizzo se configurato (vuoto = Apps Script: le build vecchie non cambiano), una POST senza redirect, un solo retry sui guasti di trasporto, nessuno su 4xx/5xx. Sonda probe_su984 con trasporto finto: 112 controlli, 0 errori. - ⚠️ Presi dalla review, non dal builder (F1b):
refreshAt delle JWKS avanzava PRIMA del download — a rotazione di kid con rete giù ogni token nuovo restava rifiutato 10 minuti (ora avanza solo a download riuscito, retry a 30 s, cache vecchia conservata); il retry del client era spento sul nuovo endpoint. Limite dichiarato e non cambiato: il codice invito ha 32 bit ed è derivato come nel .gs e in Inviti.gd (i codici sono già in circolazione): collisione fra invitanti ≈1,2% a 10.000 invitanti, il conteggio resta per codice. - 📌 SU-988:
TMP/su988/PASSI_IVAN.md (allegato al ticket) — API da accendere, Firebase CLI, due account di servizio api/telemetria coi ruoli minimi, avviso di budget 10/50 $, filtro di esclusione dei log, Hosting vuoto, con la verifica dopo ogni passo. maxInstances e budget non sono un tetto monetario assoluto. TMP/su984/PIANO_DEPLOY.md (allegato) dice cosa lanciare con la rete: emulatore con un ID token vero, deploy, latenza da Mac e Honor. - ⚠️ NON PROVATO: emulatore, deploy, JWKS Epic dal vivo, Firestore vero, latenza. Prima del deploy le regole devono negare ai client la collezione delle quote (
_api_limits): lo fa F2/SU-986. Claim/release del registro: SU-986.
Super: il Branco non fa più scappare i passanti, il suo suono muore col game over, e il CONCERTONE si vede e si spegne (SU-1003, SU-1004, SU-1009)2026-09-17
Sprint 15, giro notturno da CLI: lotto Codex S1 (Sol) + correzione S1b dopo la review RS1; cancello luna CS1; sonde e provino rifatti dal Mac.
- ✅ SU-1003
files/homeless_city/scripts/systems/SuperPower.gd:581: tolta la sola chiamata _area_flee(…, 1.2) dal tick del Branco; i cani inseguono i nemici come prima. Sonda: igiene 100 + Branco → 0 passanti in fuga in 10 s; igiene 5 → la fuga per puzza c'è (1). spawn_remote_dogs crea solo il branco cosmetico: nessun flee inoltrato all'host. - ✅ SU-1004
SuperPower.gd:~1022 end_local_run_effects() + files/homeless_city/scripts/ui/HUD.gd:~6764 _stop_local_run_effects() agganciato alla porta del game over e al finale MP dell'ultimo sopravvissuto: Branco (super e carta) liberato e cani_cerchio fermato nello stesso frame del pannello; i pack remoti restano. Sonda: pack=0 e playing=false entro 1 frame in entrambi i casi. ⚠️ La sonda emette il segnale di game over direttamente: collasso/arresto/retata veri da provare su device. - ✅ SU-1009, due cause vere in
files/homeless_city/scripts/player/Player.gd: (1) super_show_fx("music") avviava $SfxBusk PRIMA che _is_busking fosse vero (3075-3084), quindi movimento e nuova pressione non potevano fermarlo — è la melodia «accesa fino a fine partita» dell'Honor; (2) l'attivazione armava solo _super_concertone_armed, senza nulla da mostrare. Ora: avviso grande (SUPER_CONCERTONE_NOTIFICA, chiave già in I18n) + badge «!» all'angolo dello slot super finché non si suona, cerchio del raggio reale (420 px) e barra su 24 s durante il numero potenziato, stop della melodia — qualunque player la suoni — a scadenza, movimento, pressione e game over (sonda: playing=false in tutti e quattro). Nessuna RPC nuova, firme _cl_busk_* intatte. - ⚠️ Preso dalla review, non dal builder (S1b): il badge era figlio diretto del
PanelContainer dell'indicatore, che ne ignorava la posizione e lo metteva dentro il riquadro sopra l'icona; ora sta sull'holder (Control non-container) dello slot. Provino TMP/su1009/concertone_armato_b.png. Rilievo scartato: i nuovi identificatori con «concertone» seguono _super_concertone_armed, che esisteva già. - 📌 Il fallback sul primo nodo del gruppo
player in _stop_local_run_effects() scatta solo se _local_player è nullo: in MP l'HUD lo ha sempre. NON PROVATO: sessione ENet a due peer, Honor 10.
Telemetria su Drive: cartelle in cache, giorno della partita nel percorso, percentuale decisa dal server (SU-990)2026-09-17
Sprint 15, giro notturno da CLI: lotto Codex T1 (Sol) + correzione T1b dopo la review incrociata R990; cancello luna C990.
- ✅ M1
BETATESTING/apps_script_telemetria.gs (fuori da git, deploy a cura di Ivan, originale in TMP/su990/apps_script_telemetria.PRIMA.gs): id delle cartelle del giorno in CacheService (21.600 s), LockService solo al primo miss con doppio controllo, contatore fuori dalle Properties (in cache, ricostruito dai file della cartella), tetto 10.000 ricezioni al giorno (conta il giorno del server: una data retrodatata non lo aggira). - ✅ M2
files/homeless_city/scripts/autoload/RunRecorder.gd:~2092: il client manda day (data LOCALE d'inizio partita, dal nome stabile del file); il server lo usa nel percorso e cerca il doppione lì — la stessa partita rinviata 1, 2 e 3 giorni dopo = 0 copie in più (test Node); senza day (build vecchie) resta la data UTC del server. - ✅ M3 risposta con
sample_percent (Script Property TELEMETRY_SAMPLE_PERCENT, intero 0-100, assente = 100), salvata dal client e rispettata dalla run SUCCESSIVA (estrazione una volta a inizio run); i crash_tail partono sempre. Sonda probe_su990: 0% → normale 0 / crash 1; 100% → 1 / 1; richieste vere 0. - ⚠️ Preso dalla review, non dal builder: la prima versione teneva le run escluse come
.jsonl.skip, che contavano nel limite della coda e venivano potate «dal più vecchio»: undici scarti potevano cancellare una run vera ancora in coda. Ora le run escluse si eliminano alla chiusura, e potatura e limite contano solo i .jsonl/.sent (caso nella sonda: 1 .jsonl vecchia sopravvive a 11 scarti). Rinominati in inglese payload e identificatori (giorno→day, percentuale→sample_percent). - 📌 Test del
.gs in Node spostato in tools/telemetria/test_apps_script_telemetria.mjs (7/7: 10.000 accettate, 10.001ª rifiutata, 3 rinvii = 0 copie) — TMP/ è gitignored e l'avrebbe perso. - ⚠️ NON PROVATO: deploy, invio vero in dev e durata in Apps Script → Esecuzioni; il lock non copre gli incrementi concorrenti del contatore (tetto morbido, dichiarato dal cancello).
(DESIGN) Se l'host cade: un successore designato prima della run, checkpoint ogni 5 s, trasloco in 15 s — proposta con misure (SU-999)2026-09-17
Sprint 15, giro notturno da CLI (job in background, Ivan a dormire): lotto Codex D1 (Astra), sola lettura.
- 📌 Raccomandazione unica (allegata a SU-999,
TMP/su999/PROPOSTA.md 106 righe): successore EOS fisso eletto PRIMA della run (minimo peer id iniziale idoneo), autorità del vecchio host a scadenza (permesso rinnovato ogni 1 s, 3 s di validità), testamento ogni 5 s + journal degli effetti economici per non duplicare premi, freeze locale «TRASLOCO IN CORSO», massimo 15 s, NPC rigenerati dal seed, progressi personali conservati, nessun nuovo record online dopo il trasloco; una sola migrazione per run, poi fine partita. - ✅ Misurato headless (Godot 4.7.2,
TMP/su999/misura_testamento.gd): 8 peer = 1.432 B per testamento, 324,8 B/s per client in buste da ≤996 B (margine 174 B sui 1.170 EOS); PUID nel registro lobby = +52 B a riga. - ⚠️ La telemetria non registra la causa: 79 run MP uniche (0.42: 3, 0.43: 76), 0 cadute esplicite dell'host, ma 26 uscite di scena ambigue e 3 run senza chiusura: la frequenza reale è indeterminabile. Prima di investire (stima 15–20 giornate) va strumentata la caduta dell'host.
- Tre domande a Ivan sul ticket (un solo successore; 15 s con arretramento del mondo; classifica di sessione senza record online). NON MISURATO: overhead reale sul filo EOS, tempi di join, freeze su device.
(DESIGN) CANCELLA ACCOUNT: inventario verificato nel codice, pratica remota idempotente, 5 ticket pronti (SU-996, SU-913)2026-09-17
Sprint 15, giro notturno da CLI: lotto Codex E1 (Sol), sola lettura; le due linee guida (Apple 5.1.1(v), Google Play) lette dalla fonte e salvate in TMP/su996/fonti_store.md.
- 📌 Raccomandazione (allegata a SU-996,
TMP/su996/PROPOSTA.md 122 righe): cancellazione come pratica remota idempotente — l'app riautentica il PUID, ottiene un ACK durevole, cancella progressi.json su EOS PDS (serve DeleteFile, oggi assente), sospende i sync, pulisce i dati locali del solo PUID e torna ospite; il backend elimina Firestore (nickname, players, riscatti e legami), le 8 EOS Stats e gli accessi non riautenticabili entro 7 giorni. UI: due conferme senza parola digitata, tono del gioco, testi IT/EN pronti; ripresa al riavvio se la rete cade a metà. - ✅ Inventario di SU-913 corretto sul codice:
release_verified() cancella la prenotazione ma NON la riga players; delete di riscatti/legami vietata al client dalle regole; ProgressSync non usa DeleteFile; le Stats non hanno delete nel client; la telemetria NON manda il PUID (run_id casuale per partita), quindi non è un dato dell'account. - 📌 Informativa §3.7/§9 IT+EN (prima→dopo), voci Data safety / App Privacy e pagina web
cancellazione/ accanto a invito/; 5 ticket di implementazione già scritti nella proposta, da creare dopo le 3 risposte di Ivan (SLA 7 giorni; ricevuta HMAC + tombstone antifrode 365 giorni; pagina web con modulo). - ⚠️ NON VERIFICATO: il testo vigente di §3.7/§9 (il «prima» è concettuale) e gli strumenti Epic per sopprimere PUID/Stats.
Registro nickname: i bocciati non si leggono più senza accesso, nicknames e players solo per id; scadenze proposte (SU-995)2026-09-17
Sprint 15, giro notturno da CLI: lotto Codex R1 (Sol) + cancello luna C995; regole compilate dal Mac (pubblica_regole.sh --solo-valida: ruleset creato, release NON toccata).
- ✅
tools/firestore/firestore.rules:157-160 — nicknames: solo get puntuale, list negata; :242-245 — players: idem (get/batchGet per PUID noti, è ciò che usa resolve); :226-229 — bocciati: nessuna lettura dal client. Gli exists() nelle create (:191, :215) continuano a rifiutare le grafie bocciate senza permesso di lettura. Scritture invariate (le cambia SU-986). - 📌 Il client fa ancora un GET preliminare su
bocciati prima del commit (files/homeless_city/scripts/autoload/NicknameRegistry.gd:1236-1239): ora riceve 403 e lo ignora (solo un 200 dice «bocciato»), quindi il rifiuto arriva dal commit. Da guardare in SU-909 che il messaggio a schermo resti sensato. - ✅
tools/firestore/prova_su995_regole.sh — 9 controlli live su stage (letture negate, prenotazione, get/batchGet, liste negate, commit di grafia bocciata rifiutato), con la sola API key; vuole una grafia/norm già presente in bocciati/stage. - ⚠️ NON PROVATO dal vivo: le regole le pubblica Ivan; poi
bash tools/firestore/prova_su995_regole.sh '<grafia>' '<norm>'. Scadenze proposte e non applicate (scelta di Ivan): players senza nome 30 giorni (TTL Firestore su scade_il), foglio di moderazione 90 giorni (trigger Apps Script), bocciati mai. Informativa §3.8/§9 IT+EN pronta in TMP/su995/INFORMATIVA_DIFF.md, da pubblicare con regole e scadenze. - Sandbox Codex senza rete: l'apertura (
sandbox_workspace_write.network_access=true) è stata proposta e il classificatore di auto mode l'ha negata («Security Weaken»); la patch a codex_lotto.py (flag --rete) resta da fare a mano da Ivan, se la vuole.
Il marchio: rilievo sulla traduzione superato, domanda pubblicata l'08/09, opposizioni fino all'08/12/2026 (SU-763)2026-09-16
Ivan: «controllare marchio street university? abbiamo mandato una risposta alla richiesta di tradurre il marchio in italiano, come è finita?».
- ✅ Verificato sulla banca dati UIBM (ricerca per numero 302026000153505, senza SPID): stato «attesa scadenza periodo di opponibilità», istanza «Risposta a Rilievo» del 07/09/2026 in elenco, pubblicazione sul Bollettino n. 1643 dell'08/09/2026 fra le «Domande registrabili». La risposta era stata depositata dal portale il 07/09 alle 13:22 (ricevuta n. 772026000150775 via PEC), il giorno stesso del rilievo.
- 📌 Le date che contano ora: opposizioni fino all'08/12/2026, poi la registrazione; priorità EUTM fino al 04/03/2027. Fascicolo aggiornato in
OPUS_BRIEFS/DEPOSITO_MARCHIO_UIBM.md, esito in commento su SU-763. - [docs] Nella stessa sessione 15 ticket nuovi nello sprint dalle note di Ivan (SU-997 → SU-1011): caffè a 5 dollari, vagone in fiamme animato, (DESIGN) host che cade, lampioni per quartiere, bidoni agli angoli col camioncino, tastiera del codice invito, due bug del Branco, HUD del bonus, lattine d'oro per sempre, lattine giornaliere, gatto nella pensilina, super Concertone, fontana del Mercato, curva delle carte. Istruttoria dei file a Codex
luna (I16A/B/C).