favella1 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1729 @@
1
+ # Registro delle Versioni (Changelog) - FAVELLA 1
2
+
3
+ Tutti i cambiamenti significativi a questo progetto saranno documentati in questo file.
4
+
5
+ ---
6
+
7
+ ## [1.0.0] - 2026-06-16
8
+ ### 🏁 Il linguaggio è completo — versione 1.0
9
+ Traguardo. La **1.0.0 non introduce modifiche di grammatica** rispetto alla 0.34.0:
10
+ è il rilascio che **dichiara chiuso e definitivo il linguaggio FAVELLA 1**. Un solo
11
+ numero di versione per motore, compilatore e specifica; spec di milestone
12
+ `documentazione/grammatica-1.0.0.md` (identica alla 0.34.0, con la nota di traguardo).
13
+
14
+ Cosa c'è dentro la 1.0:
15
+ - **Livelli 1–8** della roadmap (stanze, oggetti, regole «Invece di», stati e
16
+ contatori, contenitori/supporti, dialoghi, capacità di trasporto, eventi e demoni).
17
+ - **Consolidamento 0.18.0** (regole a due oggetti col `se`, posizione del giocatore,
18
+ testi d'esito, copula plurale, `al massimo`/`non è`, verbi multi-parola, `non(…)`).
19
+ - **Asse A «Il mondo vivo» 0.19.0→0.26.0** (pronomi/anafora, ANNULLA/ANCORA/
20
+ trascrizione, varietà nelle descrizioni, buio e luce, movimento degli NPC,
21
+ sinonimi di verbo, verbi intransitivi, inventario iniziale, tick silenziosi).
22
+ - **Revisione totale di solidità 0.27.0→0.28.1** (correttezza, robustezza, perf).
23
+ - **Piano di completamento**: Cassetto A (0.30.0), **Tema 1** «i contatori si parlano»
24
+ (0.31.0), **Tema 2** «casualità d'autore» (0.32.0), **Tema 4** «il mondo che cambia
25
+ in scena» (0.33.0), **Tema 3** «lo stato che parla allo stato» (0.34.0).
26
+ - **Fuori per scelta**: Tema 5a (quantità con plurali) e Tema 5b (template di entità)
27
+ — la semplicità d'autore è una feature; una scorta è già un contatore.
28
+
29
+ Garanzie della 1.0: grammatica **LALR(1) a zero ambiguità** (guardia Earley
30
+ permanente), **suite verde** (681 asserzioni di linguaggio + 43 di collaudo, pytest
31
+ 312), versioning unificato, una spec e un CHANGELOG per release. Da qui l'evoluzione
32
+ è di **ecosistema** (distribuzione, libreria di moduli, galleria di storie), non più
33
+ di linguaggio.
34
+
35
+ ### 📦 Ecosistema (2026-06-16): pacchetto PyPI, libreria standard, galleria
36
+ Primo passo dell'**ecosistema** annunciato dalla 1.0.0. **Nessuna modifica al
37
+ motore** (resta `VERSIONE_MOTORE = 1.0.0`, suite 681+43 verde): solo confezione e
38
+ contenuti attorno al linguaggio.
39
+
40
+ - **Pacchetto installabile (`pip install favella1`).** Aggiunti
41
+ `pyproject.toml` (layout piatto: i moduli del motore restano alla radice e si
42
+ installano insieme — `esporta` li rilegge da lì a runtime — più il package
43
+ `favella1` coi dati), `LICENSE` (**MIT**) e `MANIFEST.in`. La versione del
44
+ pacchetto è derivata automaticamente da `strutture.VERSIONE_MOTORE`. Verificato
45
+ con `python -m build` + `twine check` (wheel e sdist) e con un'installazione
46
+ pulita in venv (CLI completa, **`esporta` incluso**, funzionante).
47
+ - **Libreria standard di moduli `Includi`-bili** in `favella1/libreria/`:
48
+ `sinonimi.fav` (sinonimi dei verbi), `proprieta.fav` (coppie di proprietà
49
+ opposte comuni), `verbi.fav` (verbi d'azione pronti). Vocabolario riusabile,
50
+ sicuro da includere per intero (nessun avviso del linter).
51
+ - **Galleria di storie** in `favella1/galleria/`: tre avventure brevi, complete e
52
+ **vincibili** col sorgente commentato — «Il Faro Spento», «Il Giardino Murato»,
53
+ «Il Forziere dei Tre Sigilli» — più l'indice `galleria.json`. Ognuna passa il
54
+ `collaudo` statico ed è stata giocata end-to-end fino alla vittoria.
55
+ - **Nuovi sottocomandi della CLI** (`favella.py`, lo strato sottile — motore
56
+ intatto): `favella1 libreria [elenca|copia]` e
57
+ `favella1 galleria [elenca|gioca|copia]`.
58
+
59
+ ## [0.34.0] - 2026-06-16
60
+ ### Tema 3: lo stato che parla allo stato 🔗
61
+ Quinta sessione del **piano di completamento del linguaggio**
62
+ (`documentazione/espansione-oltre-0.29.md`): il **Tema 3**, l'**indirezione fra
63
+ stati**. Fino a ieri uno «stato» si assegnava/confrontava solo contro un valore
64
+ **letterale** (`il corteggiato è Anna`); ora può farlo contro il **contenuto di un
65
+ altro stato**. Costrutto piccolo e mirato, pesato con prudenza (l'indirezione è
66
+ mezzo passo verso le variabili dei linguaggi veri) e tenuto minimo. Richiedente
67
+ reale: il tester Pietro («La Talpa», impersonare un personaggio). **Additivo** (le
68
+ 4 demo e tutte le storie esistenti compilano e si comportano identiche). Modifica di
69
+ grammatica → bump **minor**; spec nuova `documentazione/grammatica-0.34.0.md` (§17).
70
+
71
+ - **Copia stato↔stato** (`ConseguenzaVariabileCopia`): `e adesso il corteggiato
72
+ diventa il preferito.` copia il valore corrente di uno stato in un altro. Forma
73
+ **nuda**, 0-ambigua (nessun `diventa PROPRIETA` compete dopo `diventa`).
74
+ - **Confronto stato↔stato** (`CondizioneVariabileUguali`): `se il corteggiato è
75
+ come il preferito: …` (anche `non è come`). Il marcatore **`come`** è obbligatorio:
76
+ senza, `VARIABILE è VARIABILE` collide con `VARIABILE è PROPRIETA` (confronto con
77
+ un letterale) — un nome di stato è anche una parola-valore lecita. `come` separa i
78
+ due casi in modo strutturale → LALR(1) 0-ambiguo (guardia Earley estesa). Si legge
79
+ come italiano corrente («è come il preferito» = ha lo stesso valore).
80
+ - **Riservato agli stati; diagnostica gentile.** La forma nuda vale solo fra due
81
+ **stati**: la copia/confronto fra **contatori** usa già il valore fra parentesi
82
+ `[nome]` (Tema 1, più espressivo). Un mismatch stato↔contatore — o l'uso della
83
+ forma nuda fra due contatori — è un errore d'autore localizzato che indirizza alla
84
+ forma corretta. Validazione **differita** (lo stato a destra può essere dichiarato
85
+ dopo). **ANNULLA-safe** (muta `Mondo.variabili`, già nelle istantanee; niente RNG).
86
+ - **Tema 5a (quantità/scorte): NO-GO.** Pesato e non realizzato: la «versione ridotta
87
+ sui contatori» non richiede codice (una scorta è già un contatore col Tema 1); la
88
+ versione piena apre plurali/concordanza, fuori dallo spirito di FAVELLA. Resta un
89
+ idioma documentato, non una primitiva. Tema 5b (template): sconsigliato.
90
+ - **Demo non retrofittate.** Nessuna delle 4 demo ha due stati simbolici fra cui
91
+ l'indirezione sia naturale (i pretendenti del dating sono entità/contatori):
92
+ forzarla sarebbe contrived e rischierebbe l'additività. Il costrutto è coperto da
93
+ 8 test dedicati. (Stessa scelta della 4a in 0.33.0.)
94
+ - **Suite:** 681 asserzioni di linguaggio (+15) + 43 di collaudo, pytest 312, LALR(1)
95
+ 0-ambiguo. Le 4 demo restano vincibili/perdibili end-to-end identiche.
96
+
97
+ ## [0.33.0] - 2026-06-16
98
+ ### Tema 4: il mondo che cambia in scena 🌒
99
+ Quarta sessione del **piano di completamento del linguaggio**
100
+ (`documentazione/espansione-oltre-0.29.md`): il **Tema 4**, due «non si può» dal
101
+ lato della *messa in scena*, indipendenti e a riuso alto. **Additivo** (le 4 demo
102
+ e tutte le storie esistenti compilano e si comportano identiche). Modifica di
103
+ grammatica → bump **minor**; spec nuova `documentazione/grammatica-0.33.0.md`.
104
+
105
+ - **4a — buio commutabile.** Una conseguenza nuova (`ConseguenzaBuioStanza`):
106
+ `e adesso la radura diventa buia.` spegne la luce di una stanza e
107
+ `… diventa illuminata.` (o `chiara`) la riaccende. Fino a ieri il buio di stanza
108
+ (`è buia`) era **statico** — solo all'avvio; ora il ciclo giorno/notte può calare
109
+ il buio in scena. La proprietà è classificata per **radice** riusando il folding
110
+ di concordanza (`bui-` → buio; `illuminat-`/`chiar-` → luce). **ANNULLA-safe**
111
+ senza RNG (è stato del mondo). Diagnostica gentile: cambiare il buio a un oggetto,
112
+ o con una proprietà non di luce, è un errore localizzato.
113
+ - **4b — battuta di nodo condizionale.** La regola della battuta guadagna una
114
+ clausola `se` opzionale, per parità con le descrizioni:
115
+ `Anna al nodo "x" dice "Ciao." se il doppiogioco è palese.` convive con la battuta
116
+ incondizionata (fallback). Le varianti si **accumulano** e a render-time vince la
117
+ prima la cui condizione è vera — riuso diretto del meccanismo «prima vera vince»
118
+ delle descrizioni.
119
+ - **4c — creazione di oggetti: pesata e rimandata.** Creare un oggetto *non
120
+ dichiarato* sfida il terminale chiuso `ENTITA`; il pattern «dichiara nel nulla e
121
+ rivela» resta sufficiente. Non entra in 0.33.0 (annotato in
122
+ `debiti-motore-da-integrare`).
123
+ - **Grammatica LALR(1) 0-ambigua.** 4a: dopo `ENTITA` il lookahead `"diventa"` è
124
+ disgiunto da `_copula`/`"va"`/`"cambia"`, ed `ENTITA` è disgiunto da `VARIABILE`
125
+ (niente collisione con `VARIABILE "diventa" …`). 4b: dopo il 2° testo il lookahead
126
+ `"se"` vs `"."` è disgiunto. **Nessun** terminale o parola riservata nuovi. Guardia
127
+ anti-ambiguità estesa a entrambi.
128
+ - **Demo.** Il saluto di Anna in `cuori-al-caffe.fav` ora si **scalda** quando
129
+ l'affinità è alta (battuta condizionale 4b): risolve l'attrito annotato nel demo.
130
+ Il 4a (buio commutabile) non è stato retrofittato nelle demo: la notte
131
+ *all'aperto* del survival non è buio pesto (stelle + uscite visibili), e
132
+ sostituirla regredirebbe le descrizioni notturne d'autore — il costrutto è
133
+ comunque pienamente coperto dai test.
134
+ - **Test.** +10 test (4a: spegne/riaccende/sinonimo-chiara/ANNULLA/2 diagnostiche;
135
+ 4b: prima-vera-vince/runtime/segnaposto/retro-compatibilità). Suite **666
136
+ linguaggio + 43 collaudo** (pytest **304**), LALR(1) 0-ambiguo.
137
+
138
+ ---
139
+
140
+ ## [0.32.0] - 2026-06-16
141
+ ### Tema 2 (resto): casualità d'autore non-numerica 🎲
142
+ Terza sessione del **piano di completamento del linguaggio**
143
+ (`documentazione/espansione-oltre-0.29.md`): il **resto del Tema 2**. L'estrazione
144
+ *numerica* (`un numero fra A e B`) era già entrata in 0.31.0; ora arrivano i due
145
+ costrutti casuali **non numerici**. Entrambi riusano `Mondo.rng` — il generatore
146
+ **seedato** e **ANNULLA-safe** già usato da A2/A5 e dall'estrazione numerica — quindi
147
+ le partite restano riproducibili e disfare un turno riavvolge anche il caso.
148
+ **Additivo** (le 4 demo e tutte le storie esistenti compilano e si comportano
149
+ identiche). Modifica di grammatica → bump **minor**; spec nuova
150
+ `documentazione/grammatica-0.32.0.md`.
151
+
152
+ - **2b — scelta casuale fra valori di stato.** Una conseguenza nuova
153
+ (`ConseguenzaSceltaStato`): `e adesso il meteo diventa uno fra sereno, pioggia,
154
+ nebbia.` assegna allo «stato» un valore *simbolico* pescato a caso dall'elenco.
155
+ È la casualità simbolica, distinta dall'estrazione numerica (i valori sono
156
+ parole-stato, non interi). Con un solo valore la scelta è deterministica.
157
+ - **2c — condizione probabilistica.** Un atomo-condizione nuovo
158
+ (`CondizioneProbabilita`): `Ogni turno se càpita (1 su 4): …` è vero con
159
+ probabilità N/M (`M su M` sempre, `0 su M` mai). È l'unico `cond_base` senza un
160
+ operando a sinistra (keyword dedicata `càpita`); componibile con
161
+ `e`/`oppure`/`non` e usabile in regole, demoni, opzioni e descrizioni.
162
+ - **Grammatica LALR(1) 0-ambigua.** 2b condivide il prefisso `VARIABILE "diventa"`
163
+ con `cons_contatore_set` ma se ne stacca al token dopo (`"uno"` vs
164
+ `{NUMERO,"[","un"}` dell'operando; `uno ≠ un`). 2c parte da `càpita`, disgiunto
165
+ da ogni altro FIRST di `cond_base`. Guardia anti-ambiguità estesa a entrambi.
166
+ Riservata aggiunta: **`càpita`**.
167
+ - **Diagnostica e IDE.** Uno stato assegnato *solo* via `diventa uno fra …` non è
168
+ più segnalato «dichiarato ma mai usato». Serializzazione JSON: `{op:"pick",…}`
169
+ (scelta) e `{op:"chance",num,den}` (probabilità).
170
+ - **Demo.** La guida `notte-di-gara.fav` ora ha un **meteo davvero imprevedibile**
171
+ (era sceneggiato su turni fissi): risolto l'attrito **D1** del suo stress-test.
172
+ - **Test.** +11 test (2b: pesca/riproducibilità/ANNULLA/valore-singolo/non-collisione/
173
+ lint; 2c: frequenza/estremi/ANNULLA/in-regola/serializzazione). Suite **642
174
+ linguaggio + 43 collaudo**, LALR(1) 0-ambiguo.
175
+
176
+ ---
177
+
178
+ ## [0.31.0] - 2026-06-16
179
+ ### Tema 1: i contatori si parlano (operando-quantità + confronti) 🔢
180
+ Seconda sessione del **piano di completamento del linguaggio**
181
+ (`documentazione/espansione-oltre-0.29.md`): il **Tema 1**, il limite strutturale
182
+ n°1 emerso in TUTTE e quattro le demo di stress-test. Fino a ieri un contatore era
183
+ una **cella isolata** — aritmetica e confronti solo contro **costanti letterali**,
184
+ mai fra celle. Ora i contatori si parlano. **Additivo** (le 4 demo e tutte le
185
+ storie esistenti compilano e si comportano identiche; i numeri letterali restano
186
+ nudi e invariati). Modifica di grammatica → bump **minor**; spec nuova
187
+ `documentazione/grammatica-0.31.0.md`.
188
+
189
+ - **Operando-quantità.** Un solo concetto nuovo, ciò che produce un intero al
190
+ momento dell'uso, in tre forme: un **NUMERO** letterale (`di 3`, storico), il
191
+ **valore di un contatore** fra parentesi quadre (`di [forza]` — come
192
+ l'interpolazione `[nome]` dei testi: `[x]` = «il valore corrente di x»), e
193
+ un'**estrazione casuale** (`un numero fra 2 e 6`). Le quadre marcano il «valore
194
+ dinamico»: il letterale resta nudo, il riferimento è fra parentesi.
195
+ - **Tema 1a — contatore come quantità.** `aumenta/diminuisci X di [Y]` e
196
+ `X diventa [Y]`: il danno scala con una statistica, il consumo con la velocità,
197
+ l'affinità con un'altra affinità. `diminuisci la vita del lich di [forza].`
198
+ - **Tema 1b — confronto grandezza↔grandezza.** I sei confronti (`è N`, `non è N`,
199
+ `almeno`, `più di`, `meno di`, `al massimo`) accettano ora un `[contatore]` come
200
+ termine destro: `se la vita del troll è meno di [la mia vita]: …`. Il confronto è
201
+ **dinamico** (risolto a ogni valutazione): abilita le soglie *relative* (gelosie,
202
+ difficoltà mobile) prima possibili solo con batterie di demoni.
203
+ - **Casualità d'autore (accorpata).** `il dado diventa un numero fra 1 e 6.`,
204
+ `diminuisci la vita di un numero fra 2 e 6.`. Riusa l'RNG **seedato** del mondo
205
+ (`Mondo.rng`, infrastruttura già esistente per A2/A5): le partite restano
206
+ **riproducibili** e **ANNULLA riavvolge** anche l'estrazione. Solo l'estrazione
207
+ numerica entra ora (è un operando-quantità della stessa famiglia); `diventa uno
208
+ fra X, Y, Z` e `càpita (1 su N)` restano per una sessione futura.
209
+ - **Grammatica LALR(1) 0-ambigua.** Le tre forme partono da token disgiunti
210
+ (`NUMERO | "[" | "un"`): `è più di 3` e `è più di [forza]` convivono con un solo
211
+ token di lookahead. Le quadre `[` `]`, prima viste solo dentro le stringhe,
212
+ diventano token letterali che non collidono con nulla. Guardia anti-ambiguità del
213
+ corpus estesa a tutti i nuovi costrutti.
214
+ - **Diagnostica e IDE.** Un contatore citato **solo** come operando non è più un
215
+ falso «dichiarato ma mai usato». Il serializzatore JSON dell'IDE espone il
216
+ letterale come int (retrocompatibile) e le forme dinamiche come
217
+ `{kind:"var",…}` / `{kind:"rand",…}`.
218
+ - **Scartato — 1c «valore successivo».** Il cambio di marcia (`sali di una
219
+ marcia`) avrebbe richiesto un concetto di «scala ordinata»: le N regole esplicite
220
+ restano più leggibili. Non fatto, per il principio «la semplicità è una feature».
221
+ - **Prova sul campo.** Una porzione della demo GDR (`esempi/demo/ruolo/`) è stata
222
+ riscritta idiomatica col nuovo costrutto al posto del workaround a soglie.
223
+ - 9 nuovi test di regressione (linguaggio), guardia anti-ambiguità estesa. Suite:
224
+ **623 + 43 di collaudo**, tutta verde (pytest e runner nativo).
225
+
226
+ ## [0.30.0] - 2026-06-16
227
+ ### Cassetto A: robustezza, diagnostica e due piccole simmetrie 🧰
228
+ Prima sessione del **piano di completamento del linguaggio** (`documentazione/espansione-oltre-0.29.md`):
229
+ quattro rifiniture a basso rischio, **additive** (le 4 demo di stress-test e tutte
230
+ le storie esistenti compilano e si comportano identiche). Una sola modifica di
231
+ grammatica (A3) → bump **minor**; spec nuova `documentazione/grammatica-0.30.0.md`.
232
+
233
+ - **A1 — Diagnostica dei nomi non validi.** Un carattere come `/` in un nome di
234
+ entità/stato/contatore chiudeva in anticipo il letterale regex del terminale
235
+ generato per-file, facendo fallire la costruzione del parser con un
236
+ `GrammarError` interno e incomprensibile (riprodotto da un tester reale). Ora la
237
+ Passata 1 (`valida_nomi_dichiarati`) lo intercetta **prima** del parser con un
238
+ errore d'autore **localizzato** (riga, colonna, carattere) e codice
239
+ `nome-non-valido`. Alfabeto ammesso nei nomi: lettere (anche accentate), cifre,
240
+ spazi e l'apostrofo — lo stesso del terminale `WORD`.
241
+ - **A3 — `dire` opzionale nelle regole.** Per simmetria con i «tick silenziosi»
242
+ di eventi e demoni (A9), una regola che muta solo lo stato può ora **omettere il
243
+ testo**: `Invece di riposa: aumenta la forza.`. `def_regola` riusa lo stesso
244
+ inline `_esito_temporale` di eventi/demoni; a runtime una regola con risposta
245
+ vuota **non** stampa una riga vuota. **LALR(1) 0-ambiguo** (guardia anti-ambiguità
246
+ del corpus estesa al nuovo costrutto).
247
+ - **A4 — Idioma di direzione.** `"sinistra" è come est.` non funziona: `è come`
248
+ rimappa **solo i verbi**. Si mantiene l'idioma esistente — più pulito —
249
+ `Sinistra e destra sono direzioni opposte.`, e si **migliora l'avviso**: quando
250
+ il bersaglio di `è come` è una direzione, il warning lo dice e indica l'idioma
251
+ corretto, invece del generico «non è un verbo noto».
252
+ - **A2 — Punto dentro le virgolette: RIMANDATO.** Indagine svolta: una diagnostica
253
+ proattiva in Passata 1 non è perseguibile senza falsi positivi (la continuazione
254
+ legittima `dire "X."` a capo seguita da `e adesso …` è indistinguibile dall'errore
255
+ senza il parser, che la Passata 1 deliberatamente non è). La regola d'autore «il
256
+ punto va fuori dalle virgolette» resta nel manuale. Decisione documentata nella spec.
257
+ - **Test.** Suite **601** asserzioni di linguaggio (era 585) + **43** collaudo, tutte
258
+ verdi (pytest e runner nativo). Versioni allineate a **0.30.0**; puntatore
259
+ anti-drift della spec aggiornato.
260
+
261
+ ---
262
+
263
+ ## [0.29.1] - 2026-06-16
264
+ ### Robustezza: niente più crash sui caratteri fuori da Windows-1252 🛡️
265
+ Patch di **sola robustezza runtime**: la grammatica è **invariata** (la spec EBNF
266
+ resta valida), nessun cambio di semantica delle storie. Emersa da uno
267
+ **stress-test di genere a tappeto** (quattro demo di generi non nativi — guida,
268
+ sopravvivenza, dating, GDR — in `esempi/demo/`; vedi `documentazione/espansione-oltre-0.29.md`).
269
+
270
+ - **Fix del crash cp1252.** Un carattere non rappresentabile in Windows-1252
271
+ (es. `★`, `─`, frecce, emoji) **dentro un testo mostrato al giocatore** faceva
272
+ terminare il gioco con un `UnicodeEncodeError` fatale sulla console Windows —
273
+ la logica era corretta, a cadere era solo la stampa. Ora la console viene
274
+ riconfigurata a UTF-8 con `errors="replace"`: il carattere degrada invece di
275
+ far crashare la partita. (I caratteri nei **commenti** `#` erano e restano
276
+ innocui: non vengono mai stampati.)
277
+ - **Fonte unica.** Nuova `utils.assicura_console_utf8()`, condivisa dalla CLI
278
+ `favella1` (`favella.py`) e dall'avvio del ciclo interattivo (`gioco.py::gioca`),
279
+ così il fix copre **ogni** modo di lanciare una storia (`python gioco.py`
280
+ incluso, che prima non riconfigurava nulla). Idempotente.
281
+ - **Bug della trascrizione.** Avviare/chiudere la `TRASCRIZIONE` ripristinava
282
+ `sys.__stdout__` (il flusso grezzo cp1252), **annullando** la riconfigurazione
283
+ e facendo riaffiorare il crash. Ora si torna al flusso console già riconfigurato.
284
+ - **Test.** Aggiunta una guardia di regressione deterministica (finta console
285
+ cp1252) in `test_linguaggio.py`. Suite **585** asserzioni di linguaggio (era
286
+ 582) + 43 collaudo, tutte verdi. Versioni allineate a **0.29.1**.
287
+
288
+ ---
289
+
290
+ ## [Manuale] - 2026-06-14
291
+ ### Rifinitura editoriale per la stampa (Amazon KDP) 📖
292
+ Lavoro **solo sul manuale** (`documentazione/manuale/`): nessun cambio al motore né
293
+ alla grammatica, suite invariate (**582** linguaggio + **43** collaudo). Gli esempi
294
+ `.fav` restano byte-corretti. Manuale allineato al motore **v0.29.0**.
295
+
296
+ - **Seconda edizione.** Etichetta «Seconda edizione · 2026» uniforme su copertina,
297
+ frontespizio e colophon (prima l'edizione era indicata solo nel frontespizio).
298
+ «Edizione» e «versione del motore» tenute distinte (lockstep su v0.29.0).
299
+ - **Doppia dedica.** Accanto a Bonaventura Di Bello, una dedica a **Pietro Bernasconi**,
300
+ i cui stress-test di genere hanno ispirato le primitive A7–A9. Due strofe nella stessa
301
+ pagina, separate da un filetto di marca.
302
+ - **Crismi tipografici di stampa.** Trim portato al formato **standard KDP 6,69×9,61″**
303
+ (169,93×244,09 mm; prima 170×240, non standard). Capitoli che aprono su **pagina
304
+ dispari** (recto, `pagebreak(to: "odd")`). Margine di cucitura interno 23 mm, ben
305
+ oltre il minimo KDP. Interno **84 pagine**, 0 warning.
306
+ - **Doppia tiratura da sorgente unica.** `manuale.pdf` (digitale, con copertina navy a
307
+ pagina intera) e `manuale-interno-kdp.pdf` (interno di stampa, senza copertina —
308
+ `typst compile --input kdp=1`).
309
+ - **Copertina KDP integrale** (`copertina-kdp.typ` → `copertina-kdp.pdf`): wrap
310
+ fronte-retro **351,0×250,4 mm** con bleed 3,175 mm e dorso 4,80 mm (84 pp., carta
311
+ bianca). Quarta di copertina, marchio, area riservata al codice a barre/ISBN (KDP).
312
+ Dorso in navy pieno senza testo (sotto 100 pp. KDP non ammette testo sul dorso).
313
+ - **Revisione linguistica integrale** dei 20 capitoli (prosa-italiana + humanizer): la
314
+ prosa era già di livello, corretti i refusi reali rimasti (`servono`→`valgono`,
315
+ `dà`→`dài`, `la dita`→`il dito`); nessun pattern LLM da rimuovere.
316
+
317
+ ---
318
+
319
+ ## [0.29.0] - 2026-06-14
320
+ ### Distribuzione multipiattaforma — installer + CLI unica + playground offline 📦
321
+ Prima release **distribuibile**: un autore (anche non tecnico) installa FAVELLA e la
322
+ usa **senza clonare il repo né installare Python**. **Nessun cambio al motore**: la
323
+ grammatica resta `grammatica-0.28.0.md`, le suite invariate (**582** linguaggio + **43**
324
+ collaudo, tutte verdi). Tutto il nuovo codice è additivo e fuori dal motore.
325
+
326
+ - **Entry-point unico `favella1`** (`favella.py`): strato sottile (argparse) sopra i
327
+ moduli esistenti, con sottocomandi `gioca` / `compila` / `collaudo` / `playground` /
328
+ `esporta` / `versione` (alias inglesi: `play`/`check`/`test`/`export`/`version`).
329
+ Console riconfigurata a UTF-8 per sicurezza sulle console legacy.
330
+ - **Playground locale offline** (`favella_playground.py`): `favella1 playground` avvia
331
+ un mini-server (sola libreria standard, nessuna dipendenza nuova) su `127.0.0.1` e
332
+ apre un editor + terminale nel browser, collegato al **motore nativo** — completamente
333
+ offline, con la diagnostica reale del compilatore. (Diverso da `esporta`, che usa
334
+ Pyodide e richiede la rete.)
335
+ - **Freeze PyInstaller** (`favella1.spec`, build *one-dir*): `--collect-all lark`, i 5
336
+ moduli del motore inclusi anche come sorgente (servono a `esporta` via `sys._MEIPASS`),
337
+ demo ufficiali nel bundle, icona di marca.
338
+ - **CI multipiattaforma** (`.github/workflows/release.yml`): build matrix
339
+ Windows/macOS/Linux con PyInstaller; impacchettamento per-OS in **installer NSIS**
340
+ (`.exe`), **`.dmg`** (Apple Silicon) e **AppImage**; smoke su ogni bundle; al push di
341
+ un tag `v*` pubblica una **GitHub Release** con i tre installer. La suite del motore
342
+ gira in CI e blocca eventuali regressioni.
343
+ - **Doc**: `PACKAGING.md` (architettura del pacchetto + procedura di rilascio
344
+ tag→Release); `packaging/` con script NSIS e file AppImage.
345
+ - Versioni in lockstep su **0.29.0** (`VERSIONE_MOTORE` fonte di verità). La firma del
346
+ codice è assente per ora: al primo avvio Gatekeeper/SmartScreen mostrano un avviso atteso.
347
+ - **Manuale tipografico aggiornato a 0.29.0** (Typst, da 17 a **20 capitoli**, 72 pp.):
348
+ copre tutta l'evoluzione dalla v0.18.0 a oggi. Tre capitoli nuovi — «Installare e
349
+ avviare FAVELLA» (installer/CLI/playground), «Buio e luce» (`è buia`/`illumina`),
350
+ «I comandi del giocatore» (pronomi/anafora, ANNULLA/ANCORA/TRASCRIZIONE) — e inserti
351
+ nei capitoli esistenti: descrizioni a varietà (`è una di`/`è in sequenza`), inventario
352
+ iniziale (`Il giocatore ha …`), copula plurale su stati/contatori (`Le vite sono un
353
+ contatore`/`partono da`), verbi intransitivi (`comando senza oggetto`) e sinonimi di
354
+ verbo (`… è come prendi`), tick silenziosi, movimento NPC (`va`/`cambia stanza`),
355
+ aggettivi con prefisso-preposizione (`è incisa`). Riepilogo e parole riservate estesi.
356
+
357
+ ---
358
+
359
+ ## [0.28.1] - 2026-06-14
360
+ ### Revisione totale del linguaggio — Lotto 3 (performance, documentazione, pulizia) 🧹
361
+ Patch di chiusura della revisione: nessun cambio di grammatica (la spec EBNF resta
362
+ `grammatica-0.28.0.md`), nessuna nuova feature. Suite invariate (**582** linguaggio
363
+ + **43** collaudo).
364
+
365
+ - **Perf — cache dei parser LALR.** Costruire la tabella LALR costa ~40 ms;
366
+ `costruisci_parser` ora riusa i parser già costruiti, indicizzati per
367
+ (grammatica, propagate_positions). Una ricostruzione identica passa da ~44 ms a
368
+ ~0,1 ms (utile a CLI e IDE che rianalizzano lo stesso file più volte). Sicuro: un
369
+ parser Lark è riusabile e senza stato fra le `.parse()`; un `GrammarError` non
370
+ viene cachato (la guardia anti-ambiguità resta valida).
371
+ - **Dedup `guarda` / ingresso in stanza.** `guarda_logica_default` ora delega a
372
+ `gioco.mostra_stanza` (fonte unica): prima ne duplicava la logica ma **ometteva
373
+ le uscite**; ora `guarda` mostra anche le uscite, coerente con l'ingresso.
374
+ - **cp1252-safety.** Sostituito l'unico `…` (U+2026) in un `print` di runtime
375
+ (l'aiuto) con `...`: non più a rischio `UnicodeEncodeError` su console Windows
376
+ legacy.
377
+ - **README allineato a 0.28.1** (stato, tabella versioni, conteggi test, roadmap;
378
+ era fermo a v0.18.0). **Commenti datati ripuliti**: «PARSING v0.2», conteggi-test
379
+ fissi nei commenti del compilatore, riferimenti al «robot dinamico B1.2 — sessione
380
+ successiva» (accantonato) in `collaudo.py` e banner di stato in
381
+ `documentazione/progettazione-collaudo.md`.
382
+
383
+ ---
384
+
385
+ ## [0.28.0] - 2026-06-14
386
+ ### Revisione totale del linguaggio — Lotto 2 (robustezza) 🧱
387
+ Secondo lotto della revisione di solidità. Una sola modifica di grammatica (D) +
388
+ due rafforzamenti del runtime + rinforzo della rete di test. Tutto verificato
389
+ eseguendo il motore; nessuna regressione (la suite collaudo ha intercettato in
390
+ corsa una regressione su `nello`, poi corretta — vedi sotto).
391
+
392
+ - **D — Aggettivi-proprietà che iniziano con una preposizione.** `La lapide è
393
+ incisa.` veniva rifiutato con un errore fuorviante («entità sconosciuta «cisa»»)
394
+ perché il lexer staccava `in` (PREP_LUOGO) dall'inizio dell'aggettivo. Ora
395
+ **`PREP_LUOGO` è una regex con confine destro** (`(?![a-zA-ZÀ-ÿ0-9'])`) sulle
396
+ forme semplici; le forme con apostrofo (`nell'`/`sull'`) ne sono esenti. Poiché
397
+ `nel` non si scompone più in `nel`+`lo`, l'insieme articolato è ora elencato per
398
+ intero (`nello`, `nei`, …). `è incisa`/`sulfurea`/`insanguinata`/`informe` ora
399
+ compilano; le posizioni (`in cella`, `nell'atrio`, `nello scriptorium`, `sullo
400
+ scaffale`) restano invariate. **Regressione intercettata dal collaudatore**: la
401
+ prima versione del confine rompeva `è nello scriptorium` (demo «Il Relitto») →
402
+ corretta completando l'insieme articolato.
403
+ - **E — Turno atomico.** Un'eccezione a metà di una conseguenza veniva inghiottita
404
+ e il turno avanzava su uno stato mutato a metà (con tanto di istantanea ANNULLA).
405
+ Ora l'eccezione risale a `elabora_comando`, che **ripristina l'istantanea
406
+ pre-turno** (rollback) e tratta il turno come no-op: niente stato incoerente,
407
+ niente avanzamento di turno/eventi/demoni, niente passo di ANNULLA spurio.
408
+ - **D-dialogo — Conversazione annullabile come unità.** Le conseguenze `e adesso …`
409
+ nelle opzioni di dialogo mutavano il mondo ma non erano annullabili (l'ingresso in
410
+ dialogo scartava l'istantanea). Ora l'istantanea pre-dialogo è messa da parte
411
+ all'ingresso (`Mondo._snap_dialogo`) e registrata all'uscita: **un solo ANNULLA
412
+ riporta a prima di `parla con …`**, con tutte le conseguenze delle scelte.
413
+ - **G — Rete di test rinforzata.** (1) L'anti-drift della spec EBNF ora verifica che
414
+ ogni regola sia **DEFINITA nei blocchi ```ebnf** della spec, non solo citata in
415
+ prosa (prima era un match per sottostringa sull'intero file). (2) Il collaudatore
416
+ ha ora test dedicati per la **vittoria via evento** (`Al turno N: … vinci`) e
417
+ **via demone** (`Quando … vinci`), rami prima coperti solo dalle demo.
418
+ - **Test**: linguaggio **+28 asserzioni** (D, E, D-dialogo, anti-drift più forte) →
419
+ **582** (era 549 a inizio revisione); collaudo **+10** → **43** (era 33). Demo
420
+ `vincibile-staticamente`. Spec EBNF **`grammatica-0.28.0.md`** (§13); puntatore
421
+ `_SPEC_EBNF` 0.27.0 → 0.28.0. Versioni allineate a **0.28.0**.
422
+
423
+ ---
424
+
425
+ ## [0.27.0] - 2026-06-14
426
+ ### Revisione totale del linguaggio — Lotto 1 (correttezza) 🛡️
427
+ Sessione di **revisione di solidità** prima del manuale (caccia a difetti/debiti, non
428
+ nuove feature). Quattro correzioni di correttezza, ciascuna verificata eseguendo il
429
+ motore e coperta da un test dedicato. Nessuna regressione.
430
+
431
+ - **A — Copula plurale `sono` su stati e contatori.** Prima `Le vite sono un
432
+ contatore.` / `Le luci sono uno stato.` venivano **rifiutati** (scanner e
433
+ grammatica accettavano solo `è`), benché i nomi di stato/contatore siano spesso
434
+ plurali (`le vite`, `i punti`, `le munizioni`) — un'asimmetria con stanze/oggetti,
435
+ che la copula plurale la accettano dalla 0.18.0. Ora `def_stato`,
436
+ `def_stato_valore` e `def_contatore` usano `_copula`; il valore iniziale accetta
437
+ `partono` oltre a `parte` (`Le vite partono da 3.`). Aggiornati i due `_RE_DEF_*`
438
+ dello scanner. **Unica modifica di grammatica**; LALR(1) 0-ambiguo (VARIABILE
439
+ resta disgiunto da ENTITA). Riservata aggiunta: `partono`.
440
+ - **B — `accesa`↔`spenta` opposte di default.** Il motore le trattava già come
441
+ coppia per la luce (`c_e_luce`/fonte di luce, confronto per radice), ma senza la
442
+ coppia precaricata in `Mondo.opposti` una conseguenza `e adesso la torcia è
443
+ spenta` lasciava l'oggetto **sia `accesa` sia `spenta`** → `se la torcia è accesa`
444
+ restava vera a luce spenta. Precaricata accanto ad `aperta↔chiusa`.
445
+ - **C — `lascia` bloccato al buio.** Al buio `prendi`/`metti`/`esamina` erano
446
+ bloccati ma `lascia` no (asimmetria fra canali). Ora `lascia_logica_default`
447
+ rispetta `c_e_luce()`; una fonte di luce accesa in mano rende comunque la stanza
448
+ illuminata, quindi posarla per fare luce resta possibile.
449
+ - **M4 — Iniziale maiuscola senza rovinare i nomi propri.** `str.capitalize()`
450
+ minuscolava il resto del nome (`La Guardia Reale` → `La guardia reale`) in
451
+ intestazioni di stanza, nomi NPC, uscite e annunci di movimento. Nuovo helper
452
+ `utils.prima_maiuscola` (maiuscola solo sull'iniziale); sostituite tutte e 7 le
453
+ occorrenze di `.capitalize()` su `nome_visualizzato`.
454
+ - **Test**: **+13 asserzioni** (5 test nuovi: copula plurale stati/contatori,
455
+ `partono`, opposte accesa/spenta, `lascia` al buio, `prima_maiuscola`); corpus
456
+ della guardia anti-ambiguità esteso con le forme plurali. Suite del linguaggio a
457
+ **562** (era 549); collaudatore invariato a **33**; demo `vincibile-staticamente`.
458
+ Spec EBNF **`grammatica-0.27.0.md`** (§10); puntatore `_SPEC_EBNF` 0.26.0 → 0.27.0.
459
+ Versioni allineate a **0.27.0** (incluso l'header di `libreria_azioni.py`, rimasto
460
+ indietro a 0.24.0).
461
+
462
+ > **Nota.** Questa release apre la revisione totale post-Asse-A. I lotti successivi
463
+ > (robustezza del turno atomico, aggettivi con prefisso-preposizione `è incisa`,
464
+ > rete di test/anti-drift, README a v0.27.0, performance) sono in valutazione con
465
+ > l'autore.
466
+
467
+ ---
468
+
469
+ ## [0.26.0] - 2026-06-14
470
+ ### Sinonimi di verbo (Asse A — A6) 🗣️
471
+ Sesta e ultima voce dell'**Asse A** di `progettazione-oltre-0.18.md`: con questa il
472
+ linguaggio chiude il gruppo «Il mondo vivo» (A4+A5+A6).
473
+
474
+ - **Sinonimo di verbo**: `"ghermisci" è come prendi.` (`def_sinonimo`,
475
+ `TESTO_QUOTATO "è" "come" VERBO "."`) — rimappa una parola-nuova (quotata, come
476
+ i verbi custom e gli alias) a un **verbo di libreria**. A differenza di un verbo
477
+ personalizzato (che richiede una regola `Invece di` per ogni oggetto), il
478
+ sinonimo eredita tutto il comportamento del bersaglio: il parser dei comandi lo
479
+ **riscrive nel canonico** prima di ogni trattamento, così funzionano regole
480
+ `Invece di prendi …`, anafora e logica di default.
481
+ - **Modello**: `Mondo.sinonimi_verbo` (parola → verbo canonico). Serve l'input del
482
+ giocatore; nelle regole d'autore vale il canonico (come per gli alias di oggetto).
483
+ Il bersaglio dev'essere un verbo noto (`VERBI_VALIDI`): altrimenti il sinonimo è
484
+ morto e si emette un **warning non bloccante** (e non viene registrato).
485
+ - **LALR(1) 0-ambiguo**: `def_sinonimo` è distinta da `def_verbo` sul lookahead
486
+ `come` vs `un` (dopo `"…" è`). Riservata aggiunta: `come`.
487
+ - **Test**: **+12 asserzioni** (6 test: registrazione, comportamento identico al
488
+ verbo bersaglio, attivazione delle regole del canonico, coesistenza col verbo
489
+ originale, warning su bersaglio ignoto, più sinonimi). Suite del linguaggio a
490
+ **549** (era 537); collaudatore invariato a **33**; demo `vincibile-staticamente`.
491
+ Spec EBNF **`grammatica-0.26.0.md`** (§12); puntatore `_SPEC_EBNF` 0.25.0 → 0.26.0.
492
+ Versioni allineate a **0.26.0**.
493
+
494
+ > **Asse A completato.** Con A6 il linguaggio FAVELLA chiude l'Asse A di
495
+ > `progettazione-oltre-0.18.md` (A1–A9). Prossimo passo della roadmap: il
496
+ > **manuale completo** rigenerato sul linguaggio finale.
497
+
498
+ ---
499
+
500
+ ## [0.25.0] - 2026-06-14
501
+ ### Movimento degli NPC (Asse A — A5) 🚶
502
+ Quinta voce dell'**Asse A** di `progettazione-oltre-0.18.md`. I personaggi erano
503
+ statici: il mondo sembrava un museo. I demoni (Livello 8) fornivano già il
504
+ *quando*; mancava la conseguenza di *movimento*.
505
+
506
+ - **Due conseguenze nuove** (classe `ConseguenzaMovimentoPNG`), usabili in regole,
507
+ eventi, demoni e opzioni di dialogo:
508
+ - **Deterministica**: `la guardia va nel corridoio` (`cons_png_va`,
509
+ `ENTITA "va" PREP_LUOGO ENTITA`) — destinazione fissa, validata come stanza
510
+ esistente a compile-time.
511
+ - **Casuale**: `il gatto cambia stanza` (`cons_png_cambia`,
512
+ `ENTITA "cambia" "stanza"`) — una stanza **adiacente** a caso fra le uscite,
513
+ pescata da `mondo.rng` (riproducibile e ANNULLA-safe, come le varianti A2).
514
+ Senza uscite, l'NPC resta dov'è.
515
+ - **Annunci**: se la mossa coinvolge la stanza del giocatore, il motore lo segnala
516
+ — uscita «La guardia se ne va verso nord.» (con la direzione se la destinazione
517
+ è adiacente) / ingresso «Il gatto arriva.». Le conseguenze restano **pure**:
518
+ accodano in `Mondo.annunci`, e il loop di gioco (`_stampa_annunci`) svuota la
519
+ coda dopo ogni blocco di conseguenze (eventi/demoni a fine turno, regole del
520
+ giocatore, scelte di dialogo). `annunci` è stato di sessione (escluso da ANNULLA).
521
+ - **Scelta di design LALR-safe**: la forma casuale **non** usa `va in una stanza
522
+ adiacente` (collide col lessico su `PREP_LUOGO` `in`, romperebbe l'invariante
523
+ 0-conflitti); `cambia stanza` è l'equivalente naturale e privo di collisioni.
524
+ Riservate aggiunte: `va`, `cambia`. **LALR(1) 0-ambiguo** (dopo ENTITA il
525
+ lookahead `va`/`cambia` vs `_copula`).
526
+ - **Linter**: `_lint_oggetti_orfani` riconosce un NPC introdotto da un movimento
527
+ deterministico (niente falso «mai collocato»).
528
+ - **Test**: **+17 asserzioni** (10 test: parsing delle due forme, movimento
529
+ deterministico e casuale-riproducibile, annunci di uscita/ingresso, nessun
530
+ annuncio fuori scena, movimento via evento e via regola del giocatore, no-op
531
+ senza uscite, destinazione non-stanza = errore). Suite del linguaggio a **537**
532
+ (era 520); collaudatore invariato a **33**; le demo restano `vincibile-
533
+ staticamente`. Spec EBNF **`grammatica-0.25.0.md`** (§11); puntatore `_SPEC_EBNF`
534
+ 0.24.0 → 0.25.0. Versioni allineate a **0.25.0**.
535
+
536
+ ---
537
+
538
+ ## [0.24.0] - 2026-06-14
539
+ ### Buio e luce come primitiva (Asse A — A4) 🔦
540
+ Quarta voce dell'**Asse A** di `progettazione-oltre-0.18.md` (la prima del gruppo
541
+ «Il mondo vivo»). Il pattern «stanza buia finché non hai una luce», universale
542
+ nell'interactive fiction, diventa una primitiva del motore invece di un esercizio
543
+ di regole.
544
+
545
+ - **Stanza al buio**: `La cantina è buia.` — `buia` è una **proprietà speciale**
546
+ della stanza (come `prendibile`), riconosciuta nel transformer per **radice**
547
+ (`bui-` → buia/buio/buie), che imposta `Stanza.buia`. **Nessuna nuova regola di
548
+ grammatica** per questa forma.
549
+ - **Fonte di luce**: `La torcia illumina.` — nuova regola di capacità
550
+ **`def_illumina`** (`ENTITA "illumina" "."`), additiva e order-independent
551
+ (crea-su-riferimento), che imposta `Oggetto.illumina`. Riservate aggiunte:
552
+ `buia`, `buio`, `illumina`.
553
+ - **Visibilità centralizzata**: `Mondo.c_e_luce()` — vero se la stanza non è buia
554
+ **oppure** è raggiungibile una fonte `illumina` **accesa** (`illumina` e non
555
+ «spenta», folding per radice `spent-`: l'interazione con le opposte accesa/spenta
556
+ è automatica; una torcia senza stato illumina sempre). Riusa
557
+ `oggetti_raggiungibili()`: una fonte in un **contenitore chiuso** non illumina;
558
+ una in mano o che brilla a terra sì.
559
+ - **Runtime**: in una stanza buia senza luce, `guarda`/`mostra_stanza` stampano
560
+ «È buio pesto.» (niente descrizione/oggetti/uscite) ed `esamina`/`prendi`/`metti`
561
+ rispondono «È troppo buio per vederci.». Le **uscite restano percorribili** (si
562
+ cammina alla cieca). Le regole d'autore (`Invece di esamina X`) mantengono la
563
+ precedenza sulla logica di default: si può rendere qualcosa percepibile al buio.
564
+ - **LALR(1) 0-ambiguo** per costruzione (`def_illumina` distinta dopo ENTITA sul
565
+ lookahead `illumina`). Spec EBNF aggiornata: **`grammatica-0.24.0.md`** (§10);
566
+ puntatore test `_SPEC_EBNF` da 0.22.0 → 0.24.0.
567
+ - **Test**: **+28 asserzioni** (15 test dedicati: buio blocca esamina/prendi,
568
+ luce in mano / a terra rischiara, spenta non illumina, contenitore chiuso vs
569
+ aperto, demone che spegne la luce, uscite percorribili, regola d'autore
570
+ prioritaria, concordanza `buio`/`buia`, order-independence). Suite del linguaggio
571
+ a **520** (era 492); collaudatore invariato a **33**; le demo restano
572
+ `vincibile-staticamente`. Versioni allineate a **0.24.0** (header core, suite,
573
+ `Mondo.__str__`, sidecar `VERSIONE_MOTORE`).
574
+
575
+ ---
576
+
577
+ ## [0.23.0] - 2026-06-13
578
+ ### Il collaudatore automatico di storie — `collaudo.py` (B1.1) 🤖
579
+ Prima voce dell'**Asse B** di `progettazione-oltre-0.18.md`: «il differenziatore».
580
+ Verificare che una storia sia **vincibile** e che il contenuto sia
581
+ **raggiungibile** senza playthrough manuali. Questa release implementa il
582
+ **Livello 1 — analisi statica** (la «catena della vittoria»); il robot dinamico
583
+ (BFS sullo spazio degli stati) è la fase B1.2, successiva. Spec completa in
584
+ `documentazione/progettazione-collaudo.md`.
585
+
586
+ - **Nuovo modulo `collaudo.py`**, *consumatore* del Mondo compilato: **non tocca
587
+ la grammatica né il loop di gioco** (la grammatica resta `grammatica-0.22.0.md`).
588
+ - `analizza_vincibilita(mondo)` → report **strutturato (dict)** riusabile dal
589
+ sidecar/IDE; `rendi_report_testuale(report)` → resa leggibile per la CLI.
590
+ - CLI: `python collaudo.py storia.fav`.
591
+ - **Catena della vittoria (a ritroso)**: raccoglie ogni conseguenza «vinci»
592
+ (in regole, eventi, demoni, opzioni di dialogo) e risale i prerequisiti fino
593
+ allo stato iniziale, scomponendo le condizioni in atomi (possesso, proprietà,
594
+ stato, contatore, posizione) e trovando, per ciascuno, **quale conseguenza —
595
+ o quale azione standard (`prendi`) o movimento (`collega`) — lo rende vero**.
596
+ Esito: `vincibile-staticamente` / `ostruzione-possibile` / `nessuna-vittoria`.
597
+ - **Diagnostica**: riusa il **linter del compilatore** (`analisi_statica`) per
598
+ stanze isolate, oggetti orfani, regole morte e stati/contatori inutilizzati —
599
+ niente reinvenzione; aggiunge le **regole potenzialmente irraggiungibili**
600
+ (condizione mai soddisfacibile), controllo distinto dal «regola morta».
601
+ - **Limite onesto dichiarato nel report**: l'analisi dà condizioni *necessarie*
602
+ ed *euristiche* (le strutture e/oppure/non sono appiattite, l'aritmetica dei
603
+ contatori è approssimata), **non una prova** di vincibilità: quella spetta al
604
+ robot della fase B1.2.
605
+ - **Test**: nuova suite **`test_collaudo.py`** (33 asserzioni) — catena su una
606
+ storia vincibile, rilevamenti su una storia rotta, ostruzione su una vittoria
607
+ irraggiungibile, e verifica end-to-end sulle tre demo reali (La Casa, Il
608
+ Relitto Silente, Salerno-Reggio), tutte `vincibile-staticamente`.
609
+
610
+ Suite del linguaggio invariata a **492 asserzioni** verdi (nessuna regressione:
611
+ collaudo è additivo). Versione-ombrello del progetto a **0.23.0**; la grammatica
612
+ del sorgente resta `grammatica-0.22.0.md`.
613
+
614
+ ---
615
+
616
+ ## [0.22.0] - 2026-06-13
617
+ ### Varietà nelle risposte: descrizioni alternate 🎲
618
+ Una descrizione può ora avere **più varianti**, così il mondo non si ripete
619
+ identico a ogni sguardo — la cosa che più «data» un gioco testuale. Terza voce
620
+ dell'Asse A di `progettazione-oltre-0.18.md`. Suite del linguaggio: **492
621
+ asserzioni** (era 484), tutte verdi; invariante LALR(1) 0-ambiguo intatto.
622
+
623
+ - **Due politiche dichiarabili**:
624
+ - `La descrizione del mare è una di: "…", "…", "…".` — **casuale**, senza
625
+ ripetere mai due volte di fila la stessa variante.
626
+ - `La descrizione del faro è in sequenza: "…", "…".` — **rotazione**: le
627
+ varianti si susseguono e l'ultima resta (descrizioni che «si consumano»).
628
+ - Vale sia per la descrizione di base sia per le varianti condizionali (`se …`),
629
+ e i segnaposto `[var]` continuano a funzionare dentro ogni variante.
630
+ - **Casualità riproducibile**: il mondo ha un generatore con **seme fisso**
631
+ (`Mondo.rng`, `SEME_CASUALE_DEFAULT`). Le partite sono deterministiche e —
632
+ punto chiave — **ANNULLA riavvolge anche la casualità** (il generatore e gli
633
+ indici delle varianti sono catturati dalle istantanee di stato). Pronto per il
634
+ futuro giocatore-robot (B1).
635
+
636
+ **Modifica di grammatica** (la prima dalla 0.19.0; 0.20.0 e 0.21.0 erano solo
637
+ runtime): `def_descrizione` delega a `descr_valore`
638
+ (`descr_singola`/`descr_casuale`/`descr_sequenza`). Nuova classe
639
+ `strutture.VariantiDescrizione`. Riservata aggiunta: `sequenza`. Spec EBNF
640
+ **`grammatica-0.22.0.md`** (puntatore test 0.19.0→0.22.0). Validazione segnaposto,
641
+ linter e serializzazione IDE aggiornati per ispezionare ogni variante.
642
+
643
+ ---
644
+
645
+ ## [0.21.0] - 2026-06-13
646
+ ### Comandi di servizio: ANNULLA, ANCORA, TRASCRIZIONE ↩️
647
+ Le tre comodità standard dell'interactive fiction dal 1985 (Infocom). Seconda
648
+ voce dell'Asse A di `progettazione-oltre-0.18.md`. **Solo runtime: grammatica
649
+ del sorgente invariata** (spec EBNF resta `grammatica-0.19.0.md`). Suite del
650
+ linguaggio: **484 asserzioni** (era 474), tutte verdi.
651
+
652
+ - **ANNULLA** (anche `disfa`): disfa l'ultimo turno. Implementato con istantanee
653
+ profonde dello stato del mondo prima di ogni turno (`Mondo.cattura_stato` /
654
+ `ripristina_stato`): un «time-machine» fedele che riavvolge posizioni,
655
+ inventario, stati, contatori, turni ed eventi/demoni — niente replay. Pila
656
+ fino a `_MAX_ANNULLA` (100) turni. «Non c'è niente da annullare.» quando vuota.
657
+ - **ANCORA** (anche `ripeti`, `g`): ripete l'ultimo comando che ha consumato un
658
+ turno (`Mondo.ultimo_comando`).
659
+ - **TRASCRIZIONE**: avvia/ferma il salvataggio della partita su
660
+ `trascrizione-favella.txt` (comandi del giocatore + output del motore). È una
661
+ funzione della sessione da riga di comando (un `_Tee` su `sys.stdout` nel loop
662
+ di `gioca`); non disponibile nei driver headless/web.
663
+
664
+ I comandi di servizio NON consumano un turno. `aiuto` ora li elenca, insieme ai
665
+ pronomi (0.20.0). Versioni core e suite a **0.21.0**.
666
+
667
+ ---
668
+
669
+ ## [0.20.0] - 2026-06-13
670
+ ### Pronomi e anafora 🗣️
671
+ Il giocatore può ora usare i **pronomi** per riferirsi all'ultimo oggetto
672
+ nominato — la singola cosa che più fa sembrare «sveglio» un parser italiano.
673
+ Prima voce dell'Asse A del documento `progettazione-oltre-0.18.md` (era marcata
674
+ ⭐ priorità massima). **Solo runtime: la grammatica del sorgente NON cambia**
675
+ (la spec EBNF resta `grammatica-0.19.0.md`), quindi l'invariante LALR(1) non è
676
+ nemmeno sfiorato. Suite del linguaggio: **474 asserzioni** (era 467), tutte verdi.
677
+
678
+ - **Clitici suffissi**: `esamina la torcia` → `prendila`; `aprilo`, `esaminale`,
679
+ `usali`. Il clitico si stacca dal verbo se il resto è un comando noto.
680
+ - **Pronomi tonici / nudi**: `prendi quella`, `apri quello`, `usa lo`.
681
+ - **Concordanza di genere e numero**: il riferito è indicizzato per
682
+ `m_sing`/`f_sing`/`m_plur`/`f_plur` (dedotto dall'articolo del nome). Un
683
+ pronome del genere sbagliato non trova riferente: «Cosa vorresti prendere?».
684
+ - **Riferito = ultima azione *o* ultimo nominato**: vale sia l'oggetto su cui hai
685
+ appena agito (`esamina la torcia`), sia un oggetto elencato dalla stanza
686
+ (`entri… → prendila`).
687
+ - **Riferito non più raggiungibile**: se l'oggetto è stato preso da altri o
688
+ lasciato indietro, «Non la vedi più.».
689
+
690
+ Implementazione in `gioco.py` (`_risolvi_anafora`) + `strutture.Mondo`
691
+ (`ultimo_riferito`, `registra_riferito`/`registra_riferiti_da_stanza`) +
692
+ `utils.chiave_genere_numero`. Versioni core e suite a **0.20.0**.
693
+
694
+ ---
695
+
696
+ ## [0.19.0] - 2026-06-13
697
+ ### Lezioni dallo stress-test di genere 🚗
698
+ Tre integrazioni al linguaggio nate costruendo un genere fuori dall'asse del
699
+ design originale — un **simulatore di guida testuale** («Salerno-Reggio
700
+ Calabria», in `esempi/demo/salerno-reggio/`). I punti d'attrito incontrati sono
701
+ diventati primitive. Suite del linguaggio: **467 asserzioni** (era 446), tutte
702
+ verdi; invariante LALR(1) 0-ambiguo intatto (guardia estesa ai tre costrutti);
703
+ `analizza_file` invariata.
704
+
705
+ - **A7 — Verbi intransitivi.** `"accelera" è un comando senza oggetto.` dichiara
706
+ un comando che il giocatore digita da solo, gestito da una regola GLOBALE
707
+ `Invece di accelera: …` (con condizioni e conseguenze, incluso `vinci`/`perdi`;
708
+ vale anche multi-parola). La dichiarazione si sdoppia in `verbo_con_oggetto`
709
+ (storico) e `verbo_senza_oggetto`; in `carica_azioni` i verbi custom si dividono
710
+ fra `_personalizzata` (transitivi) e `_personalizzata_intransitiva`.
711
+ - **A8 — Inventario iniziale.** `Il giocatore ha la torcia.` mette l'oggetto in
712
+ inventario all'avvio (`def_giocatore_inventario`, applicato in `valida_post`,
713
+ order-independent). Un oggetto per frase; oggetto inesistente = errore bloccante.
714
+ - **A9 — «Tick» silenziosi.** La battuta `dire "…"` di eventi e demoni è ora
715
+ **opzionale**, purché ci sia almeno una conseguenza:
716
+ `Ogni 3 turni: diminuisci il carburante.` muta lo stato senza stampare nulla
717
+ (regola inline `_esito_temporale`).
718
+
719
+ Nuove riservate: `senza`, `oggetto`. Spec EBNF `documentazione/grammatica-0.19.0.md`.
720
+ Versioni allineate a **0.19.0** (header core, suite, `VERSIONE_MOTORE`). La demo
721
+ di guida è inclusa in due tempi: la sfida (fattibilità sul motore 0.18.0) e la
722
+ riscrittura idiomatica resa possibile da A7/A8/A9.
723
+
724
+ ---
725
+
726
+ ## [Manutenzione] - 2026-06-11
727
+ ### Pulizia interna del motore 🧹
728
+ Nessun cambiamento al linguaggio. Suite sempre a **446 test** verdi.
729
+ - **Versione in un punto solo:** nuova costante `VERSIONE_MOTORE` in
730
+ `strutture.py`; il sidecar e il report di compilazione (`Mondo.__str__`) la
731
+ importano invece di cablare il numero in proprio.
732
+ - **Deduplicato il preprocessore:** `espandi_inclusioni` ora accetta un
733
+ `sorgente_radice` opzionale (il buffer in memoria dell'IDE) e la copia
734
+ parallela `_espandi_inclusioni_seedable` è diventata un semplice alias.
735
+ - **Diagnostica dei crash:** un errore interno del compilatore ora stampa lo
736
+ stack trace completo (prima solo il messaggio), per individuare il punto
737
+ esatto del bug.
738
+
739
+ ---
740
+
741
+ ## [Export HTML] - 2026-06-05
742
+ ### Esporta il gioco come pagina HTML autoportante 📦
743
+ Nuova funzione `esporta_html` nel compilatore (op `game.exportHtml` del
744
+ sidecar): impacchetta una storia `.fav` in **un singolo file HTML giocabile nel
745
+ browser**, con il motore Python eseguito via **Pyodide** (nessuna installazione
746
+ per chi gioca).
747
+ - Sorgente espanso (inclusioni risolte) e moduli del motore incapsulati nel
748
+ JSON dei dati; il driver Python vive nel JSON, non in un template literal
749
+ (robusto rispetto a backtick e `${}` nei testi delle storie).
750
+ - Robusto al bundle congelato di PyInstaller (`_MEIPASS`): i sorgenti del
751
+ motore vengono letti dal bundle quando il sidecar gira impacchettato.
752
+
753
+ ---
754
+
755
+ ## [Manuale] - 2026-06-04
756
+ ### Manuale d'autore completo — PDF tipografico 📖
757
+ Riscritto da zero il **Manuale di Programmazione** (`documentazione/manuale/`),
758
+ allineato alla **v0.18.0** e focalizzato esclusivamente sul linguaggio. 17
759
+ capitoli (dalle stanze ai personaggi, ai demoni, ai moduli) più appendici, con
760
+ **ogni costrutto illustrato da esempi reali** presi parola per parola da «La Casa
761
+ di Via Stradivari» (`esempi/materiale-didattico/`).
762
+ - Composto con **Typst**: copertina di marca, dedica, indice, colophon, e un
763
+ evidenziatore di sintassi `.fav` dedicato. Sorgente modulare (un file per
764
+ capitolo) + `build.ps1` + `README`.
765
+ - Font di marca (Sora, Source Code Pro) inclusi sotto licenza SIL OFL 1.1.
766
+ - Sostituisce il vecchio `manuale.md` (datato ≈0.0.9.2), ora rimosso.
767
+
768
+ ---
769
+
770
+ ## [0.18.0] - 2026-06-03
771
+ ### Consolidamento del linguaggio — «linguaggio al massimo» 🏁
772
+ Sessione dedicata a **colmare ogni buco e asimmetria** emersi scrivendo le demo,
773
+ senza più workaround: il linguaggio è ora completo ed eccellente allo stato
774
+ attuale delle conoscenze. Grammatica sempre **LALR(1) 0-ambigua**. Suite da 386 a
775
+ **446 test** verdi.
776
+
777
+ **Correzioni di limiti/asimmetrie (A):**
778
+ - **A1 — Le regole a DUE oggetti valutano il `se`.** `usa X PREP Y` ora sceglie,
779
+ fra le regole che combaciano, la prima **condizionale soddisfatta**, poi la
780
+ prima **semplice** (esatto come le regole a un oggetto), con fallback
781
+ prep-tollerante. Prima il `se` era ignorato: vinceva sempre la prima dichiarata.
782
+ - **A2 — Genitivo `dei`** nelle descrizioni: `La descrizione dei pilastri è "…"`.
783
+ - **A3 — Accenti NFC.** Sorgente e input del giocatore sono normalizzati in forma
784
+ NFC: i nomi accentati (`comò`) si risolvono in modo affidabile anche se digitati
785
+ in forma decomposta. Cade la convenzione «niente accenti nei nomi».
786
+ - **A4 — Preposizioni d'azione articolate.** `usa la batteria sul pannello`,
787
+ `metti la spada nella teca`: niente più la stonatura `su il`/`su la`.
788
+ - **A5 — Copula plurale `sono`.** `Le tacche sono una cosa`, `Le tacche sono
789
+ vergini`, `se le tacche sono segnate`: l'italiano corretto sui nomi plurali (era
790
+ obbligatorio scrivere `Le tacche È una cosa`).
791
+
792
+ **Nuovi costrutti di design (B):**
793
+ - **B1 — `se il giocatore è in [stanza]`** (+ negazione).
794
+ - **B2 — Teletrasporto:** `e adesso il giocatore è in [stanza]` (mostra la nuova
795
+ stanza; destinazione validata a compile-time).
796
+ - **B3 — Testo d'esito personalizzato:** `… e adesso vinci "Sei libero!"` (anche
797
+ `perdi`/`termina`), al posto del banner fisso.
798
+ - **B4 — Confronto `al massimo N`** (≤) sui contatori, simmetrico ad `almeno` (≥).
799
+ - **B5 — Disuguaglianza numerica `non è N`** (≠) sui contatori.
800
+ - **B6 — Verbi personalizzati multi-parola:** `"fai scattare" è un comando.`
801
+ (terminale chiuso `VERBO_MULTI` + longest-match a runtime).
802
+ - **B7 — Negazione di un gruppo:** `non ( A e B )`.
803
+
804
+ **Consolidamento:** versioni allineate a **0.18.0** (moduli core, suite, sidecar,
805
+ `Mondo.__str__`); spec EBNF `documentazione/grammatica-0.18.0.md`; demo
806
+ naturalizzate (`su il`→`sul`). Sidecar `VERSIONE_MOTORE` → 0.18.0. Dettaglio in
807
+ `documentazione/0.18.0.md`.
808
+
809
+ ## [0.17.0] - 2026-06-03
810
+ ### Robustezza d'ordine + audit dei Livelli 1-8 🧱
811
+ Due lavori della sequenza «linguaggio al massimo»: rendere il linguaggio
812
+ **indipendente dall'ordine** delle frasi e una **rassegna** dei livelli 1-8.
813
+
814
+ **Robustezza d'ordine.** Finora una frase che *usa* un'entità doveva venire DOPO
815
+ la sua definizione: `La gemma è nella scatola.` falliva se `La scatola è un
816
+ contenitore.` arrivava dopo. Ora la risoluzione delle entità per nome è
817
+ **differita a fine compilazione** (`valida_post`, a mondo completo), così l'ordine
818
+ non conta più. Vale per:
819
+ - **posizioni** (`X è in/nella/sul Y`), incluse le collocazioni in contenitori/supporti;
820
+ - **proprietà** (`X è chiusa`);
821
+ - **descrizioni** (`La descrizione di X è "…"`);
822
+ - **conseguenze** (`… e adesso la chiave è in inventario`) che citano entità definite dopo;
823
+ - **bersaglio delle regole** (`Invece di apri la porta: …` con `la porta` dichiarata dopo).
824
+
825
+ Gli errori veri restano: una destinazione/bersaglio **mai** definito fallisce
826
+ ancora la compilazione (solo il *momento* del controllo è cambiato, non l'esito).
827
+ È una modifica **semantica**: la grammatica è invariata (spec
828
+ `documentazione/grammatica-0.16.0.md` resta valida).
829
+
830
+ **Audit — due bug corretti:**
831
+ 1. **No-op a partita conclusa.** Dopo `vinci`/`perdi`/`termina`, un ulteriore
832
+ comando non avanza più il turno né fa scattare eventi/demoni (prima, un
833
+ chiamante che ignorava il valore di ritorno poteva far ripartire gli eventi).
834
+ 2. **Linter cieco ai demoni.** Le analisi statiche «variabile inutilizzata» e
835
+ «oggetto orfano» non guardavano dentro i demoni (Livello 8): una variabile o un
836
+ oggetto usati *solo* in un demone venivano falsamente segnalati. Ora
837
+ `_tutte_le_condizioni`/`_tutte_le_conseguenze`/`_tutti_i_testi` includono i demoni.
838
+
839
+ - Suite linguaggio: **386 asserzioni** (era 364), tutte verdi; 11 nuovi test
840
+ (8 di robustezza d'ordine, 1 no-op fine partita, 2 linter+demoni). `analizza_file`
841
+ invariata. Sidecar `VERSIONE_MOTORE` → 0.17.0. Dettaglio in
842
+ `documentazione/0.17.0.md`.
843
+
844
+ ## [0.16.0] - 2026-06-03
845
+ ### Valore iniziale configurabile dei contatori 🔢
846
+ Finora un contatore partiva **sempre da 0**: per dargli un valore di partenza
847
+ (forza, vita, mana iniziali per una storia in stile GDR) bisognava alzarlo a mano
848
+ con una conseguenza. Da questa versione basta una frase:
849
+
850
+ La forza è un contatore.
851
+ La forza parte da 3.
852
+
853
+ - **Additivo e order-independent.** La frase `parte da N` imposta il valore; può
854
+ comparire prima o dopo `è un contatore.` (la dichiarazione usa `setdefault` e non
855
+ sovrascrive). Richiede comunque che il contatore sia dichiarato nel file.
856
+ - **Grammatica.** Nuova produzione `def_contatore_iniziale` (`VARIABILE "parte"
857
+ "da" NUMERO "."`): inizia con VARIABILE, il lookahead `parte` vs `è` la distingue
858
+ dagli altri costrutti su variabile → **LALR(1) 0-ambiguo**. Nuova riservata: `da`.
859
+ - **Capacità di trasporto invariata.** Conferma del modello "moltiplicatore" del
860
+ Livello 7 (`Il giocatore può portare N oggetti.` + `Lo zaino dà N spazi.`):
861
+ inventario piatto, nessun contenitore-zaino, nessuno slot "indossato".
862
+ - Suite linguaggio: **364 asserzioni** (era 360), tutte verdi; guardia
863
+ anti-ambiguità estesa. Spec EBNF `documentazione/grammatica-0.16.0.md`. Sidecar
864
+ `VERSIONE_MOTORE` → 0.16.0. Dettaglio in `documentazione/0.16.0.md`.
865
+
866
+ ## [0.15.0] - 2026-06-03
867
+ ### Roadmap del Linguaggio — Livello 8: REATTIVITÀ / DEMONI 👁️
868
+ L'ultima capacità mancante del linguaggio: gli **eventi condizionali** (i
869
+ «demoni»). Finora un *if-then* in FAVELLA era sempre ancorato a qualcosa — a un
870
+ verbo del giocatore (`Invece di …`) o a un turno fisso (`Al turno N` / `Ogni N
871
+ turni`, timer **senza** `se`). Mancava la sentinella **autonoma**: qualcosa che
872
+ sorveglia una condizione a ogni turno e scatta da sola quando si avvera.
873
+
874
+ Due forme nuove, entrambe **additive** e **LALR(1) 0-ambigue** per costruzione:
875
+
876
+ - **A livello** — `Ogni turno se [condizione]: dire "…" e adesso […].`
877
+ Scatta a **ogni** turno in cui la condizione è vera (effetti continui: veleno,
878
+ fame, un allarme che pulsa). Si distingue da `Ogni N turni` sul primo token dopo
879
+ «Ogni» (un numero = timer, la parola «turno» = demone).
880
+ - **Sul fronte di salita** — `Quando [condizione] (diventa vera)?: dire "…" e adesso […].`
881
+ Scatta **una sola volta**, nel turno in cui la condizione passa da falsa a vera
882
+ (soglie, scadenze, punti di non ritorno). La chiusura `diventa vera` è
883
+ **opzionale**: `Quando X:` e `Quando X diventa vera:` sono sinonimi.
884
+
885
+ L'esempio prima impossibile, ora nativo:
886
+
887
+ La tensione è un contatore.
888
+ Ogni 1 turno: dire "La tensione cresce." e adesso aumenta la tensione di 2.
889
+ Quando la tensione è almeno 8: dire "Il portale ti risucchia." e adesso perdi.
890
+
891
+ - **Riusano tutto il già esistente**: l'albero `condizione` completo
892
+ (proprietà/stati/contatori + AND/OR/NOT/parentesi) e la coda di conseguenze
893
+ `e adesso …`.
894
+ - **Anti-loop per costruzione**: i demoni sono valutati **una volta per turno**,
895
+ in un solo passaggio in ordine di dichiarazione, **dopo** gli eventi a tempo. Un
896
+ demone può innescare a cascata i demoni *successivi* nello stesso passaggio, ma
897
+ nessuno viene ri-valutato → loop infiniti impossibili.
898
+ - **Fronte di salita corretto**: ogni demone `Quando` ricorda il valore precedente
899
+ (`Demone.era_vera`), inizializzato a fine compilazione sul mondo iniziale → una
900
+ condizione già vera alla partenza non genera un falso fronte.
901
+ - **Byte-stabile**: classe `Demone` e lista `Mondo.demoni` distinte dagli eventi a
902
+ tempo (la serializzazione degli eventi resta intatta). Nuove riservate: `quando`,
903
+ `vera` (`diventa` era già riservata). `analizza_file` invariata.
904
+ - Suite linguaggio: **360 asserzioni** (era 344), tutte verdi; guardia
905
+ anti-ambiguità estesa a entrambe le forme. Spec EBNF
906
+ `documentazione/grammatica-0.15.0.md`. Sidecar `VERSIONE_MOTORE` → 0.15.0.
907
+ Dettaglio in `documentazione/0.15.0.md`.
908
+
909
+ ## [0.14.0] - 2026-06-03
910
+ ### Concordanza di genere/numero sulle proprietà di stato 🇮🇹
911
+ In un linguaggio d'autore italiano, `aperto` e `aperta` devono valere uguale.
912
+ Finora le proprietà erano confrontate **alla lettera**: `il portale è aperto` NON
913
+ rimuoveva `chiusa`, così il contenitore restava chiuso pur dicendo «si apre».
914
+
915
+ Da questa versione il motore confronta le proprietà di stato per **RADICE**,
916
+ ignorando la desinenza regolare `-o/-a/-i/-e`:
917
+
918
+ aperto = aperta = aperti = aperte -> apert
919
+ chiuso = chiusa -> chius
920
+ spento = spenta -> spent
921
+ bloccato = bloccata -> bloccat
922
+
923
+ Il folding (nuova `utils.radice_proprieta`) si applica nei **quattro punti** che
924
+ contano: condizioni (`se X è aperto` combacia con `aperta`), conseguenze opposte
925
+ (`è aperto` rimuove `chiusa`/`chiuso`), apertura dei contenitori
926
+ (`Mondo.contenitore_aperto`) e il linter dei refusi. Le coppie opposte dichiarate
927
+ al maschile valgono anche al femminile e viceversa (`acceso/spento` ⇄ `accesa/spenta`).
928
+
929
+ - **Le proprietà restano scritte come le ha messe l'autore** (display/IDE/serializzazione
930
+ invariati): la normalizzazione è solo interna al confronto.
931
+ - **I refusi veri restano segnalati**: cambiano la radice (`chuisa` ≠ `chiusa`), quindi
932
+ il linter li intercetta ancora.
933
+ - Pochi termini invariabili (colori come `rosa`, `viola`, `blu`) sono esclusi dal troncamento.
934
+ - **Grammatica invariata** rispetto a 0.13.0 (modifica solo semantica): la spec EBNF
935
+ `documentazione/grammatica-0.13.0.md` resta valida.
936
+ - Suite linguaggio: **344 asserzioni** (era 334), tutte verdi. `analizza_file` invariata.
937
+ - Sidecar `VERSIONE_MOTORE` → 0.14.0. Dettaglio in `documentazione/0.14.0.md`.
938
+
939
+ ## [0.13.0] - 2026-06-02
940
+ ### Roadmap del Linguaggio — Livello 7: CAPACITÀ DI TRASPORTO 🎒
941
+ Primo costrutto del **Livello 7**. Aggiunge un limite **opzionale** di oggetti
942
+ trasportabili, configurabile dall'autore e **additivo**:
943
+
944
+ Il giocatore può portare 5 oggetti. # capacità base
945
+ Lo zaino dà 15 spazi. # bonus mentre lo zaino è nell'inventario
946
+
947
+ La capacità attuale è `base + somma dei bonus degli oggetti portati`
948
+ (`Mondo.capacita_attuale()`); l'azione `prendi` rifiuta un oggetto se
949
+ l'inventario è pieno («Hai le mani troppo piene…»). **Senza dichiarazione
950
+ l'inventario resta illimitato** (default storico invariato): la feature non è
951
+ vincolante. L'azione `inventario` mostra «(usati/max)» quando una capacità è
952
+ dichiarata.
953
+
954
+ **Grammatica** (LALR(1) 0-ambiguo, per costruzione): due regole nuove —
955
+ `def_giocatore_capacita` (`"Il giocatore può portare" NUMERO "oggetti"`,
956
+ distinta da `def_giocatore` sul lookahead `può` vs `comincia/inizia/parte`) e
957
+ `def_capacita_oggetto` (`ENTITA "dà" NUMERO "spazi"`, unico costrutto `ENTITA "dà"`).
958
+ Nuove parole riservate: `può`, `portare`, `oggetti`, `dà`, `spazi`.
959
+
960
+ **Modello**: `Mondo.capacita_base` (None = illimitata), `Oggetto.bonus_capacita`.
961
+ L'IDE espone `carryUsed`/`carryMax` nello snapshot (`world.snapshot`); l'inspector
962
+ mostra «Inventario (n/max)».
963
+
964
+ Suite: **334 asserzioni** (era 321), tutte verdi; la guardia anti-ambiguità copre
965
+ i nuovi costrutti (1 albero / 0 conflitti LALR). Spec EBNF aggiornata in
966
+ **`documentazione/grammatica-0.13.0.md`**. Header core (compilatore/strutture/gioco/
967
+ libreria_azioni/suite) + `Mondo.__str__` a **v0.13.0**. Doc: `documentazione/0.13.0.md`.
968
+
969
+ ---
970
+
971
+ ## [0.11.3] - 2026-05-31
972
+ ### Roadmap del Linguaggio — Livello 6: SPEC EBNF FORMALE VERSIONATA 📐
973
+ Terza patch del Livello 6 (verso `0.12.0`). Aggiunge il documento tecnico
974
+ **`documentazione/grammatica-0.12.0.md`**: la specifica formale versionata della
975
+ grammatica di FAVELLA 1 — scheletro statico in EBNF (Lark) + modello dei
976
+ **terminali chiusi generati per-file** (`ENTITA`/`VARIABILE`/`DIREZIONE`),
977
+ priorità lessicali (`PROPRIETA`, `NUMERO`, `_PREP_DESCR`) e invariante LALR(1).
978
+ Non è il manuale d'autore: descrive il linguaggio dal lato compilatore.
979
+
980
+ **Guardia anti-drift**: nuovi test verificano che la spec citi tutte le regole
981
+ `def_/cond_/cons_` della grammatica reale (`_GRAMMAR_TEMPLATE`) e documenti i
982
+ terminali chiusi — così la spec non potrà divergere dal codice senza far fallire
983
+ la suite.
984
+
985
+ Suite: **321 asserzioni** (era 314), tutte verdi. Header `test_linguaggio.py` a
986
+ **v0.11.3** (il compilatore non cambia in questa patch).
987
+
988
+ ---
989
+
990
+ ## [0.11.2] - 2026-05-31
991
+ ### Roadmap del Linguaggio — Livello 6: MODULI / IMPORT MULTI-.FAV 📦
992
+ Seconda patch del Livello 6 (verso `0.12.0`). Introduce gli **import multi-file**
993
+ come **preprocessore (Passata 0)** testuale: la direttiva
994
+
995
+ Includi "file.fav".
996
+
997
+ viene espansa in un unico sorgente **prima** delle due passate, quindi **non
998
+ raggiunge mai il parser** → invariante LALR(1) 0-ambiguo intatto per costruzione.
999
+
1000
+ Il preprocessore (`compilatore.espandi_inclusioni`) gestisce:
1001
+ - **Path relativi** al file che include (anche in sottocartelle).
1002
+ - **Deduplica** — lo stesso file incluso più volte (diamanti) è espanso una sola volta.
1003
+ - **Rilevamento dei cicli** — un'inclusione circolare è un **errore bloccante**.
1004
+ - **File incluso mancante** — errore bloccante con il nome del file.
1005
+ - **Source map** riga-espansa → (file, riga): gli errori di sintassi e le
1006
+ diagnosi d'entità sono **attribuiti al file e alla riga originali**.
1007
+ - Il path quotato è *vocabolario nuovo tra virgolette* (come alias/verbi); le
1008
+ direttive dentro stringhe/commenti non vengono interpretate.
1009
+
1010
+ Suite: **314 asserzioni** (era 302), tutte verdi; guardia anti-ambiguità
1011
+ invariata. Superficie pubblica `analizza_file()` intatta. Header `compilatore.py`
1012
+ e `test_linguaggio.py` a **v0.11.2**.
1013
+
1014
+ ---
1015
+
1016
+ ## [0.11.1] - 2026-05-31
1017
+ ### Roadmap del Linguaggio — Livello 6 «Maturità toolchain»: LINTER SEMANTICO 🔍
1018
+ Prima patch del Livello 6 (verso la release `0.12.0`). Introduce un **linter
1019
+ semantico** nel compilatore: analisi statica **non bloccante** sul mondo
1020
+ compilato, che emette avvisi sul canale `warnings` già esistente. **Nessuna
1021
+ modifica alla grammatica** → invariante LALR(1) 0-ambiguo intatto per costruzione.
1022
+
1023
+ Quattro controlli (in `FavellaTransformer.analisi_statica`, eseguita in coda a
1024
+ `valida_post`):
1025
+ - **Stanze irraggiungibili** — reachability (BFS) dal punto di partenza sulle
1026
+ uscite (`collega`); una stanza non raggiunta è segnalata.
1027
+ - **Oggetti orfani** — oggetti (NPC/contenitori/supporti inclusi) mai collocati
1028
+ e mai introdotti da una conseguenza di spostamento.
1029
+ - **Regole morte** — regole oscurate da una precedente con identica firma
1030
+ (verbo, bersaglio, secondario, preposizione) che scatta sempre; criterio
1031
+ conservativo allineato all'ordine delle fasi del runtime (zero falsi positivi).
1032
+ - **Stati/contatori inutilizzati** — variabili dichiarate ma mai lette in una
1033
+ condizione, conseguenza o interpolazione `[var]`.
1034
+
1035
+ Suite: **302 asserzioni** (era 287), tutte verdi; guardia anti-ambiguità
1036
+ invariata. Superficie pubblica `analizza_file()` intatta. Header `compilatore.py`
1037
+ e `test_linguaggio.py` a **v0.11.1**.
1038
+
1039
+ ---
1040
+
1041
+ ## [0.11.0] - 2026-05-31
1042
+ ### Roadmap del Linguaggio — Livello 5b «NPC e dialoghi ramificati» COMPLETATO 🗣️
1043
+ Release minore che consolida le patch `0.10.1` → `0.10.4` e aggiunge al linguaggio
1044
+ un **sistema di dialogo completo da interactive fiction**. In sintesi (dettaglio
1045
+ per-patch sotto e nel documento tecnico `documentazione/0.11.0.md`):
1046
+
1047
+ - **NPC** (`0.10.1`): `Il mercante è un personaggio.`, `parla con X`, conversazione
1048
+ modale con battute e opzioni numerate (scelta per numero o testo).
1049
+ - **Ramificazione** (`0.10.2`): `l'opzione "…" conduce al nodo "…"` — alberi di
1050
+ dialogo con cicli e ritorni.
1051
+ - **Conseguenze sulle scelte** (`0.10.3`): `… e adesso …` — una scelta dà oggetti,
1052
+ muta stati/contatori, può vincere/perdere la partita.
1053
+ - **Opzioni condizionali** (`0.10.4`): `l'opzione "…" se [condizione] …` — scelte
1054
+ che compaiono solo a requisiti soddisfatti.
1055
+
1056
+ Le battute e le opzioni passano per l'interpolazione `[var]` (Livello 5); le
1057
+ interazioni di dialogo non consumano un turno di gioco.
1058
+
1059
+ **Principio LALR-safe del livello**: etichette dei nodi e testi delle opzioni sono
1060
+ *sempre quotati* (vocabolario nuovo, come alias/verbi del Livello 4), quindi non
1061
+ entrano in contesa con i terminali chiusi; si sono evitati di proposito `porta` e
1062
+ `parla` come keyword (collidono con nomi-oggetto comuni). Vincoli mantenuti:
1063
+ grammatica **LALR(1) non ambigua per costruzione**, guardia permanente (1 albero /
1064
+ 0 conflitti) estesa a ogni costrutto di dialogo, superficie pubblica
1065
+ `analizza_file()` invariata. Suite del linguaggio: **287 asserzioni**, tutte verdi
1066
+ (erano 247 a inizio livello). Header core e `Mondo.__str__` a **v0.11.0**.
1067
+
1068
+ > **Prossimo**: Livello 6 (Maturità linguaggio/toolchain) verso **v0.12.0** —
1069
+ > linter semantico, moduli/import multi-`.fav`, spec EBNF formale versionata.
1070
+
1071
+ ---
1072
+
1073
+ ## [0.10.4] - 2026-05-31
1074
+ ### Aggiunto (Roadmap Livello 5b «NPC e dialoghi ramificati» — verso 0.11.0)
1075
+ - **Opzioni di dialogo condizionali** (`[Livello 5b]`). Una scelta può essere
1076
+ subordinata a una condizione e comparire **solo se è vera**:
1077
+ - `Al nodo "saluto" l'opzione "Ecco la chiave!" se il giocatore ha la chiave
1078
+ conduce al nodo "grazie".`
1079
+ - Le condizioni sono quelle complete del linguaggio (possesso, proprietà, stati,
1080
+ contatori, `e`/`oppure`/`non`). Una scelta non disponibile non viene mostrata
1081
+ né numerata; la numerazione segue sempre le sole opzioni disponibili.
1082
+ - **Grammatica**: clausola `( "se" condizione )?` tra il testo dell'opzione e
1083
+ l'esito in `def_opzione`. Dopo il testo, il lookahead `se` la distingue da
1084
+ `conduce`/`chiude` → **LALR(1) 0-ambiguo**. Il transformer estrae per-tipo
1085
+ condizione, esito e conseguenze (tutti opzionali e in qualsiasi combinazione).
1086
+ Guardia anti-ambiguità estesa con un'opzione che combina `se` + `conduce` +
1087
+ conseguenza nello stesso costrutto.
1088
+ - **Suite del linguaggio**: **287 asserzioni** (erano 281). Header core a **v0.10.4**.
1089
+ - Con questa patch il sistema di dialogo è **completo** (ramificazione +
1090
+ conseguenze + condizioni): pronto per la release **v0.11.0**.
1091
+
1092
+ ---
1093
+
1094
+ ## [0.10.3] - 2026-05-31
1095
+ ### Aggiunto (Roadmap Livello 5b «NPC e dialoghi ramificati» — verso 0.11.0)
1096
+ - **Conseguenze sulle scelte di dialogo** (`[Livello 5b]`). Un'opzione può ora
1097
+ cambiare lo stato del mondo, con la clausola `e adesso …` riusata da regole ed
1098
+ eventi (Livello 3):
1099
+ - `Al nodo "saluto" l'opzione "Sì!" conduce al nodo "fine" e adesso la gemma è
1100
+ in inventario e adesso aumenta l'oro di 5.`
1101
+ - `Al nodo "fine" l'opzione "Addio." chiude il dialogo e adesso vinci.`
1102
+ - Le conseguenze valgono sia con `conduce` sia con `chiude`; una scelta può dare
1103
+ oggetti, mutare stati/contatori e perfino **vincere/perdere** la partita.
1104
+ Vengono eseguite *prima* della transizione, così la battuta del nodo d'arrivo
1105
+ riflette già il nuovo stato (interpolazione `[var]`).
1106
+ - **Grammatica**: coda `( "e" "adesso" conseguenza … )?` in `def_opzione`,
1107
+ identica a quella di regole/eventi. Nessun nuovo terminale → **LALR(1)
1108
+ 0-ambiguo**. Le conseguenze sono validate a compile-time come le altre. Guardia
1109
+ estesa con conseguenze su un'opzione (mutazione + fine partita).
1110
+ - **Suite del linguaggio**: **281 asserzioni** (erano 274). Header core a **v0.10.3**.
1111
+
1112
+ ---
1113
+
1114
+ ## [0.10.2] - 2026-05-31
1115
+ ### Aggiunto (Roadmap Livello 5b «NPC e dialoghi ramificati» — verso 0.11.0)
1116
+ - **Ramificazione dei dialoghi** (`[Livello 5b]`). Un'opzione può ora **condurre a
1117
+ un altro nodo**, non solo chiudere la conversazione:
1118
+ - `Al nodo "saluto" l'opzione "Chi sei?" conduce al nodo "presentazione".`
1119
+ - `Al nodo "saluto" l'opzione "Addio." chiude il dialogo.`
1120
+ - A runtime, scegliere un'opzione con transizione mostra la battuta e le opzioni
1121
+ del nodo di arrivo; si possono creare cicli (tornare a un nodo precedente).
1122
+ - **Grammatica**: l'opzione ha un **esito** (`opzione_esito`): `conduce al nodo
1123
+ "X"` oppure `chiude il dialogo`. Dopo il testo dell'opzione il lookahead
1124
+ `conduce` vs `chiude` distingue le alternative → **LALR(1) 0-ambiguo**. Nuova
1125
+ parola riservata `conduce` (si evita `porta`, che è un nome-oggetto comune).
1126
+ - **Validazione**: un'opzione che conduce a un nodo **inesistente** genera un
1127
+ avviso non bloccante (ramificazione morta). Guardia anti-ambiguità estesa con
1128
+ un dialogo a più nodi e una transizione.
1129
+ - **Suite del linguaggio**: **274 asserzioni** (erano 267). Header core a **v0.10.2**.
1130
+
1131
+ ---
1132
+
1133
+ ## [0.10.1] - 2026-05-31
1134
+ ### Aggiunto (Roadmap Livello 5b «NPC e dialoghi ramificati» — verso 0.11.0)
1135
+ - **NPC e dialoghi, fondazione** (`[Livello 5b]`). Prima patch del sistema di
1136
+ dialogo: personaggi e conversazione modale minima.
1137
+ - **Personaggi**: `Il mercante è un personaggio.` introduce un NPC (un oggetto
1138
+ speciale che vive in una stanza ed è raggiungibile).
1139
+ - **Nodo d'ingresso**: `Il dialogo del mercante comincia con "saluto".`
1140
+ - **Battuta**: `Il mercante al nodo "saluto" dice "Benvenuto, viaggiatore!".`
1141
+ - **Opzione di uscita**: `Al nodo "saluto" l'opzione "Addio." chiude il dialogo.`
1142
+ - **Runtime**: `parla con X` avvia una conversazione modale; la battuta dell'NPC
1143
+ e le opzioni numerate vengono mostrate; il giocatore sceglie per **numero** o
1144
+ per **testo**; `esci`/`addio`/`basta` chiudono la conversazione (non il gioco).
1145
+ Le interazioni di dialogo **non consumano un turno** di gioco. Le battute e le
1146
+ opzioni passano per l'interpolazione `[var]` (Livello 5).
1147
+ - **Principio LALR-safe**: etichette dei nodi e testi delle opzioni sono *sempre
1148
+ quotati* (vocabolario nuovo, come alias/verbi del Livello 4) → non entrano in
1149
+ contesa con i terminali chiusi. Si evitano di proposito `porta`/`parla` come
1150
+ keyword di grammatica (collidono con nomi-oggetto comuni: «la porta»). Guardia
1151
+ anti-ambiguità estesa con un NPC e un dialogo completo: **1 albero / 0 conflitti**.
1152
+ - **Suite del linguaggio**: **267 asserzioni** (erano 247). Header core a **v0.10.1**.
1153
+
1154
+ ---
1155
+
1156
+ ## [0.10.0] - 2026-05-31
1157
+ ### Roadmap del Linguaggio — Livello 5 «Espressività narrativa» COMPLETATO
1158
+ Release minore che consolida le patch `0.9.1` → `0.9.4` e porta a compimento la
1159
+ promessa di copertina del progetto — *«il codice è prosa»* — sul versante della
1160
+ resa narrativa. In sintesi (dettaglio per-patch sotto e nel documento tecnico
1161
+ `documentazione/0.10.0.md`):
1162
+
1163
+ - **Interpolazione di testo dinamico** (`0.9.1`): segnaposto `[punteggio]`,
1164
+ `[semaforo]`, `[chiave]` nelle stringhe d'autore, risolti a render-time.
1165
+ - **Regole globali senza oggetto** (`0.9.2`): `Invece di guarda se il punteggio è
1166
+ almeno 3: …` — risolve il limite noto del Livello 3, sbloccando verifiche
1167
+ globali su stati e contatori.
1168
+ - **Descrizioni condizionali** (`0.9.3`): `La descrizione della torcia se il
1169
+ semaforo è verde è "…".`, con varianti in ordine e fallback alla base.
1170
+ - **Concordanza grammaticale italiana minima** (`0.9.4`): genere/numero inferiti
1171
+ dall'articolo del nome; articoli concordati negli elenchi di output.
1172
+
1173
+ Vincoli mantenuti per tutto il livello: grammatica **LALR(1) non ambigua per
1174
+ costruzione** (guardia permanente 1 albero / 0 conflitti, estesa a ogni nuovo
1175
+ costrutto) e superficie pubblica `analizza_file()` invariata. La 0.9.3 ha inoltre
1176
+ **corretto un'ambiguità latente preesistente** di `def_descrizione` (terminale
1177
+ unico filtrato `_PREP_DESCR`), rendendo le descrizioni *genuinamente* 0-ambigue.
1178
+ Suite del linguaggio: **247 asserzioni**, tutte verdi (erano 192 a inizio livello).
1179
+ Header dei moduli core e `Mondo.__str__` allineati a **v0.10.0**.
1180
+
1181
+ > **Ambito della release**: NPC e dialoghi ramificati — la seconda metà del
1182
+ > Livello 5 — sono volutamente rinviati a una **v0.11.0** dedicata (Livello 5b),
1183
+ > dove l'alta complessità della macchina a stati dei dialoghi potrà essere
1184
+ > affrontata con il margine per rinviare i costrutti che non superano puliti il
1185
+ > gate anti-ambiguità.
1186
+
1187
+ ---
1188
+
1189
+ ## [0.9.4] - 2026-05-31
1190
+ ### Aggiunto (Roadmap Livello 5 «Espressività narrativa» — verso 0.10.0)
1191
+ - **Concordanza grammaticale italiana (minima)** (`[Livello 5]`). Genere e numero
1192
+ vengono **inferiti dall'articolo che l'autore già scrive** nel nome (`La torcia`
1193
+ → femminile singolare, `Il tavolo` → maschile singolare, `Le chiavi` → femminile
1194
+ plurale): nessuna nuova sintassi.
1195
+ - L'elenco degli oggetti in una stanza usa ora l'**articolo indeterminativo
1196
+ concordato** (o il partitivo al plurale): *«Puoi vedere qui: una torcia, un
1197
+ tavolo, uno specchio, delle chiavi.»* — al posto del nome grezzo con l'articolo
1198
+ determinativo maiuscolo.
1199
+ - Gestiti i casi della fonologia italiana: `uno`/`gli` davanti a *s* impura, *z*,
1200
+ *gn*, *ps*…; `un'` femminile davanti a vocale; partitivi `dei`/`degli`/`delle`.
1201
+ - Nuovi helper `utils.genere_numero()` / `utils.frase_indeterminativa()` e
1202
+ `Oggetto.concordanza()`. Un nome senza articolo riconoscibile resta invariato
1203
+ (non si inventano articoli: meglio nessuno che uno sbagliato); `l'…` è ambiguo
1204
+ nel genere e ripiega sul maschile.
1205
+ - **Grammatica invariata**: è tutta logica di *render* + inferenza dai metadati,
1206
+ nessun impatto su parsing o ambiguità.
1207
+ - **Suite del linguaggio**: **247 asserzioni** (erano 225). Header core a **v0.9.4**.
1208
+
1209
+ ---
1210
+
1211
+ ## [0.9.3] - 2026-05-31
1212
+ ### Aggiunto (Roadmap Livello 5 «Espressività narrativa» — verso 0.10.0)
1213
+ - **Descrizioni condizionali** (`[Livello 5]`). La descrizione di una stanza o di
1214
+ un oggetto può ora variare in base allo stato del mondo, con una clausola `se`:
1215
+ - `La descrizione della torcia è "Una torcia spenta.".` (base/fallback)
1216
+ - `La descrizione della torcia se il semaforo è verde è "Una torcia che brilla.".`
1217
+ - Più varianti per la stessa entità sono valutate **in ordine di dichiarazione**:
1218
+ vince la prima la cui condizione è vera; se nessuna lo è, vale la descrizione
1219
+ di base. Le condizioni sono quelle complete del linguaggio (stati, contatori,
1220
+ proprietà, possesso, `e`/`oppure`/`non`).
1221
+ - Si combinano con l'interpolazione `[var]` (0.9.1): una variante può contenere
1222
+ segnaposto.
1223
+ - **Grammatica**: `def_descrizione` accetta una clausola `( "se" condizione )?`
1224
+ opzionale tra l'entità e `"è"` (lookahead netto `se` vs `è` → LALR(1) 0-ambiguo).
1225
+ Nuovi `Stanza.descrizione_attuale(mondo)` / `Oggetto.descrizione_attuale(mondo)`.
1226
+
1227
+ ### Corretto
1228
+ - **Ambiguità latente preesistente di `def_descrizione`** (`[Livello 5]`). Le
1229
+ preposizioni articolate (`del`/`della`/…) erano terminali anonimi inline: il
1230
+ lexer dinamico poteva spezzare `della` in `del` + `la` (con `la` assorbito
1231
+ dall'articolo opzionale di `ENTITA`), rendendo `def_descrizione` formalmente
1232
+ ambiguo (mascherato finora dal determinismo di LALR e mai esercitato dalla
1233
+ guardia). Ora sono un **terminale unico filtrato** `_PREP_DESCR` (maximal-munch,
1234
+ come già `PREP_LUOGO`): la grammatica delle descrizioni è **genuinamente
1235
+ 0-ambigua**. La guardia anti-ambiguità include ora una descrizione condizionale.
1236
+
1237
+ ### Note
1238
+ - **Suite del linguaggio**: **225 asserzioni** (erano 216). Header core a **v0.9.3**.
1239
+
1240
+ ---
1241
+
1242
+ ## [0.9.2] - 2026-05-31
1243
+ ### Aggiunto (Roadmap Livello 5 «Espressività narrativa» — verso 0.10.0)
1244
+ - **Regole globali senza oggetto** (`[Livello 5]`) — risolve il limite noto del
1245
+ Livello 3. Una regola `Invece di` può ora **omettere il bersaglio** e scattare
1246
+ sul solo verbo, valutando la sua condizione:
1247
+ - `Invece di guarda se il punteggio è almeno 3: dire "Una luce pulsa.".`
1248
+ - Sblocca le **verifiche globali su stati e contatori**, finora agganciabili
1249
+ solo a regole su oggetto o agli eventi a turni.
1250
+ - **Precedenza**: una regola specifica (con bersaglio) vince sempre su una
1251
+ globale; le globali scattano solo se nessuna specifica si è attivata, e
1252
+ valgono anche per le azioni senza oggetto (`guarda`, `aiuto`, `inventario`).
1253
+ - Una globale senza condizione scatta sempre (sostituisce il comportamento di
1254
+ default del verbo).
1255
+ - **Grammatica**: il bersaglio di `def_regola` è ora opzionale, incapsulato nella
1256
+ sottoregola `regola_target`. Questo mantiene la grammatica **LALR(1) 0-ambigua**
1257
+ (dopo `VERBO` il lookahead distingue nettamente `ENTITA`/`DIREZIONE` dal `se`/`:`)
1258
+ e permette al transformer di non confondere il bersaglio con la risposta quando
1259
+ il primo manca. Guardia anti-ambiguità estesa con una regola globale.
1260
+ - **Limite residuo** (minore): per un verbo che richiede un oggetto, una regola
1261
+ globale non scatta se il giocatore digita il verbo *senza* oggetto (l'azione
1262
+ chiede prima l'oggetto). Le globali danno il meglio con verbi senza oggetto.
1263
+ - **Suite del linguaggio**: **216 asserzioni** (erano 204). Header core a **v0.9.2**.
1264
+
1265
+ ---
1266
+
1267
+ ## [0.9.1] - 2026-05-31
1268
+ ### Aggiunto (Roadmap Livello 5 «Espressività narrativa» — verso 0.10.0)
1269
+ - **Interpolazione di testo dinamico** (`[Livello 5]`) — *prima patch del livello*.
1270
+ Le stringhe d'autore possono ora contenere **segnaposto** `[nome]` che vengono
1271
+ sostituiti, al momento della stampa, con il valore corrente del mondo:
1272
+ - **Stati e contatori**: `dire "Hai [punteggio] punti."` → il numero corrente;
1273
+ `"Il semaforo è [semaforo]."` → la parola-stato attuale (uno stato non ancora
1274
+ impostato rende stringa vuota).
1275
+ - **Oggetti**: `[chiave]` → il nome visualizzato dell'oggetto.
1276
+ - Vale per **descrizioni** (di stanze e oggetti), **risposte delle regole** e
1277
+ **messaggi degli eventi a turni**: ogni testo d'autore passa per
1278
+ `utils.rendi_testo(mondo, testo)`.
1279
+ - Un segnaposto che non corrisponde a nessuno stato/contatore/oggetto resta
1280
+ **invariato** a runtime (letterale `[nome]`) e genera un **avviso non
1281
+ bloccante** a compile-time (possibile refuso).
1282
+ - **Vincoli invariati**: l'interpolazione vive *dentro* le virgolette
1283
+ (`TESTO_QUOTATO`), quindi è del tutto invisibile alla grammatica: **nessun
1284
+ rischio di ambiguità**. Guardia LALR (1 albero / 0 conflitti) estesa con un
1285
+ costrutto che usa segnaposto. Superficie pubblica `analizza_file()` invariata.
1286
+ - **Suite del linguaggio**: **204 asserzioni** (erano 192), tutte verdi. Header dei
1287
+ moduli core allineati a **v0.9.1**.
1288
+
1289
+ ---
1290
+
1291
+ ## [0.9.0] - 2026-05-31
1292
+ ### Roadmap del Linguaggio — Livello 4 «Estendibilità vocabolario e topologia» COMPLETATO
1293
+ Release minore che consolida le patch 0.8.1 → 0.8.5. L'autore può ora **estendere
1294
+ il vocabolario e la topologia** del mondo, finora in parte cablati nel motore. In
1295
+ sintesi (dettaglio per-patch sotto e in `documentazione/0.9.0.md`):
1296
+ - **Alias/sinonimi di oggetti** (`0.8.1`): `La torcia si chiama anche "lanterna".`
1297
+ - **Verbi personalizzati** (`M1`, `0.8.2`): `"spingi" è un comando.`
1298
+ - **Direzioni estese data-driven** (`L1`, `0.8.3`): `Alto e basso sono direzioni
1299
+ opposte.` con fonte unica per le direzioni (prima cablate in 4 punti).
1300
+ - **Contenitori e supporti** (`M1`, `0.8.4`–`0.8.5`): `La scatola è un
1301
+ contenitore.`, `La gemma è nella scatola.`, verbo `metti`, visibilità a catena.
1302
+
1303
+ Vincoli mantenuti per tutto il livello: grammatica **LALR(1) non ambigua per
1304
+ costruzione** (guardia permanente: 1 albero / 0 conflitti, estesa a ogni nuovo
1305
+ costrutto) e superficie pubblica `analizza_file()` invariata. Header dei moduli
1306
+ core allineati a **v0.9.0** (`compilatore`, `strutture`, `gioco`,
1307
+ `libreria_azioni`, suite). Suite del linguaggio: **192 asserzioni**, tutte verdi
1308
+ (erano 133 a inizio livello).
1309
+
1310
+ > Nota di design: il *vocabolario nuovo* (alias e verbi) si introduce **tra
1311
+ > virgolette**, perché non è ancora un token noto e così non intacca l'invariante
1312
+ > dei nomi come simboli chiusi (Livello 2.5). Le direzioni custom usano invece un
1313
+ > terminale `DIREZIONE` generato per-file (regex con `\b`, priorità alta) per
1314
+ > vincere il prefix-clash con le keyword, senza toccare la disambiguazione `e`=est.
1315
+
1316
+ ---
1317
+
1318
+ ## [0.8.5] - 2026-05-31
1319
+ ### Aggiunto (Roadmap Livello 4 — verso 0.9.0)
1320
+ - **Contenitori e supporti** (`[M1]`) — *runtime*. La meccanica di gioco completa
1321
+ il modello introdotto in 0.8.4:
1322
+ - **Visibilità a catena**: un oggetto è raggiungibile se è nella stanza,
1323
+ nell'inventario, o dentro/sopra un contenitore/supporto a sua volta
1324
+ raggiungibile. Un **contenitore chiuso** (`è chiusa`) nasconde il contenuto;
1325
+ aprirlo lo rivela. I supporti sono sempre accessibili.
1326
+ - **Nuovo verbo `metti`** (`metti`, `poni`, `inserisci`, `infila`, `appoggia`…):
1327
+ `metti la gemma in la scatola`, `metti la tazza sul tavolo`. Rifiuta i
1328
+ contenitori chiusi e gli oggetti che non sono contenitori/supporti.
1329
+ - **`esamina`** di un contenitore aperto/supporto ne elenca il contenuto
1330
+ (`Dentro vedi: …` / `Sopra vedi: …`); chiuso, dice «È chiuso.».
1331
+ - **`prendi`** funziona anche su oggetti dentro contenitori aperti / sui supporti.
1332
+ - Le **conseguenze di spostamento** accettano ora un contenitore/supporto come
1333
+ destinazione: `… e adesso la gemma è nella scatola.`
1334
+ - `strutture.py`: `Mondo.oggetto_raggiungibile()`, `oggetti_raggiungibili()`,
1335
+ `contenitore_aperto()`, `rimuovi_da_posizione()` (centralizza la rimozione da
1336
+ stanza/inventario/contenitore); `ConseguenzaSpostamento` gestisce le
1337
+ destinazioni contenitore/supporto.
1338
+ - `libreria_azioni.py`: `esamina`/`prendi` riscritte sulla raggiungibilità; nuova
1339
+ azione `mettere` con la sua logica di default; helper `_elenca_contenuto`.
1340
+ - `compilatore.py`: `_valida_conseguenze` accetta destinazioni contenitore/supporto.
1341
+ - `gioco.py`: lo scope di `risolvi_nome_oggetto` usa `oggetti_raggiungibili()`;
1342
+ `mettere` escluso dalla ristampa automatica della stanza.
1343
+ - `test_linguaggio.py`: sei nuovi test runtime (scope contenitore aperto,
1344
+ chiuso↔apertura, metti in contenitore/su supporto, rifiuto chiuso, conseguenza
1345
+ di spostamento in contenitore). Suite a **192 asserzioni** (era 174).
1346
+
1347
+ ---
1348
+
1349
+ ## [0.8.4] - 2026-05-31
1350
+ ### Aggiunto (Roadmap Livello 4 — verso 0.9.0)
1351
+ - **Contenitori e supporti** (`[M1]`) — *modello e grammatica* (il runtime arriva
1352
+ in 0.8.5). Si dichiarano oggetti capaci di contenere o reggere altri oggetti, e
1353
+ si possono collocare oggetti al loro interno/sopra fin dalla definizione:
1354
+ ```
1355
+ Una scatola è un contenitore.
1356
+ La scatola è in cella.
1357
+ Una gemma è una cosa.
1358
+ La gemma è nella scatola.
1359
+
1360
+ Un tavolo è un supporto.
1361
+ La tazza è sul tavolo.
1362
+ ```
1363
+ Un contenitore tiene gli oggetti *dentro* (visibili solo se aperto, semantica a
1364
+ runtime in 0.8.5); un supporto li regge *sopra* (sempre visibili). Collocare un
1365
+ oggetto dentro qualcosa che non è né contenitore né supporto è un **errore
1366
+ bloccante** chiaro.
1367
+ - `strutture.py`: `Oggetto.is_contenitore`, `Oggetto.is_supporto`,
1368
+ `Oggetto.contenuto: Set[str]`. L'oggetto collocato ha `posizione` = id del
1369
+ contenitore/supporto (la catena fino alla stanza sarà risolta dal runtime).
1370
+ - `compilatore.py`: scanner `_RE_DEF_CONTENITORE`/`_RE_DEF_SUPPORTO` (un
1371
+ contenitore/supporto è a tutti gli effetti un oggetto); regole `def_contenitore`
1372
+ e `def_supporto` (distinte da `def_proprieta` sul token `un`, come
1373
+ `def_contatore`); `def_posizione` accetta come luogo anche un contenitore/
1374
+ supporto; parole riservate `contenitore`, `supporto`.
1375
+ - `test_linguaggio.py`: sei nuovi test (dichiarazione contenitore/supporto,
1376
+ collocazione dentro/sopra, errore su non-contenitore, scanner); corpus della
1377
+ guardia esteso con contenitore, supporto e una collocazione. Suite a **174
1378
+ asserzioni** (era 162).
1379
+
1380
+ ---
1381
+
1382
+ ## [0.8.3] - 2026-05-31
1383
+ ### Aggiunto / Modificato (Roadmap Livello 4 — verso 0.9.0)
1384
+ - **Direzioni estese, data-driven** (`[L1]`). Le direzioni del mondo (finora
1385
+ cablate in 4 punti del codice) hanno ora un'**unica fonte di verità** e sono
1386
+ **estendibili dall'autore**:
1387
+ ```
1388
+ Alto e basso sono direzioni opposte.
1389
+ La torre collega basso a cantina.
1390
+ ```
1391
+ Le direzioni personalizzate si dichiarano sempre **in coppia opposta**, così
1392
+ l'auto-ritorno della connessione è garantito (qui `cantina` torna a `torre` con
1393
+ `alto`). Funzionano sia nelle connessioni sia come comando di movimento a
1394
+ runtime. Il nome di una direzione non può coincidere con una parola riservata o
1395
+ un'entità: è un **errore bloccante** con messaggio chiaro.
1396
+ - Miglioria collaterale: nelle regole il bersaglio-direzione è ora
1397
+ **canonicalizzato** (`Invece di vai n` equivale a `vai nord`); le direzioni
1398
+ sono riconosciute **case-insensitive**.
1399
+ - `utils.py`: `DIREZIONI_BASE` e `DIREZIONI_OPPOSTE_BASE` come **fonte unica**.
1400
+ - `strutture.py`: `Mondo.direzioni` (forma → canonica) e `opposte_direzioni`
1401
+ (canonica → opposta), precaricate dalle basi; `dichiara_direzione_opposta()`,
1402
+ `direzione_canonica()`, `opposta_di()`.
1403
+ - `compilatore.py`: scanner Passata 1 `_RE_DEF_DIREZIONI`
1404
+ (`TabellaSimboli.coppie_direzioni`); regola `def_direzioni`; il terminale
1405
+ **`DIREZIONE` è generato per-file** (base + custom) come regex con `\b` e
1406
+ priorità `.2` — vince il longest-match contro le keyword di cui una direzione
1407
+ custom condivide il prefisso (es. `alto` vs `al` di «Al turno»), senza intaccare
1408
+ l'invariante `e`=est / congiunzione (il lexer contestuale non le mette mai nello
1409
+ stesso stato). `def_connessione` e `def_regola` consultano le mappe del mondo
1410
+ invece dei dict cablati. `valida_direzioni_dichiarate()` blocca i conflitti.
1411
+ Parola riservata `direzioni`.
1412
+ - `gioco.py`: rimosso il dict cablato `DIREZIONI_VALIDI`; movimento e
1413
+ `risolvi_nome_oggetto` usano `mondo.direzioni`.
1414
+ - `test_linguaggio.py`: cinque nuovi test (connessione+auto-ritorno custom,
1415
+ movimento runtime, canonicalizzazione abbreviazione, conflitto bloccante,
1416
+ scanner); corpus della guardia esteso con una `def_direzioni` e una connessione
1417
+ che la usa; le chiamate della guardia passano ora le direzioni dichiarate. Suite
1418
+ a **162 asserzioni** (era 151).
1419
+
1420
+ ---
1421
+
1422
+ ## [0.8.2] - 2026-05-31
1423
+ ### Aggiunto (Roadmap Livello 4 — verso 0.9.0)
1424
+ - **Verbi personalizzati** (`[M1]`): l'autore può introdurre nuove parole-comando
1425
+ che il giocatore potrà digitare e usare nelle regole `Invece di`.
1426
+ ```
1427
+ "spingi" è un comando.
1428
+ Invece di spingi la pietra: dire "La pietra rotola via.".
1429
+ ```
1430
+ Il verbo è una **stringa quotata** monoparola (coerente con gli alias: il
1431
+ vocabolario nuovo si introduce tra virgolette). Una regola che usa un verbo
1432
+ dichiarato non è più segnalata come "morta". A runtime il comando attiva la
1433
+ regola corrispondente; se nessuna regola si applica, il motore risponde con un
1434
+ messaggio neutro (`Non succede nulla di particolare.`) anziché "Non capisco
1435
+ questo verbo.". Come gli altri verbi, un comando custom agisce su un oggetto.
1436
+ - `strutture.py`: `Mondo.verbi_personalizzati: Set[str]` + `dichiara_verbo()`;
1437
+ `carica_azioni()` instrada i verbi custom a un'azione generica `_personalizzata`
1438
+ (priva di logica di default; `setdefault` → non scavalca i verbi di libreria).
1439
+ - `compilatore.py`: regola `def_verbo` (`TESTO_QUOTATO "è" "un" "comando" "."`),
1440
+ unica dichiarazione che inizia con `TESTO_QUOTATO` → 0 conflitti LALR; parola
1441
+ riservata `comando`; un comando multiparola genera un *warning* ed è ignorato;
1442
+ il check dei verbi delle regole ora accetta anche i verbi personalizzati.
1443
+ - `gioco.py`: un'azione con `logica_di_default is None` (verbo custom senza regola)
1444
+ stampa il messaggio neutro; `_personalizzata` escluso dalla ristampa stanza.
1445
+ - `test_linguaggio.py`: quattro nuovi test (dichiarazione+niente warning, runtime
1446
+ con regola, runtime senza regola, multiparola); corpus della guardia esteso con
1447
+ un `def_verbo` e una regola che lo usa. Suite a **151 asserzioni** (era 142).
1448
+
1449
+ ---
1450
+
1451
+ ## [0.8.1] - 2026-05-31
1452
+ ### Aggiunto (Roadmap Livello 4 — verso 0.9.0)
1453
+ - **Alias/sinonimi di oggetti**: l'autore può dare a un oggetto un nome
1454
+ alternativo con cui il giocatore potrà riferirlo.
1455
+ ```
1456
+ La torcia si chiama anche "lanterna".
1457
+ ```
1458
+ Il sinonimo è una **stringa quotata** (può essere multiparola, es.
1459
+ `"vecchia lanterna"`); a runtime il parser dei comandi lo risolve all'oggetto
1460
+ canonico (corrispondenza esatta e parziale). Il nome proprio dell'oggetto ha
1461
+ sempre la precedenza. Gli alias servono l'input del **giocatore**: nelle regole
1462
+ d'autore (`Invece di …`) vale il nome canonico.
1463
+ - `strutture.py`: `Mondo.alias: Dict[str, str]` (alias normalizzato → id canonico)
1464
+ + `dichiara_alias()`. Header e report a v0.8.1.
1465
+ - `compilatore.py`: regola `def_alias`
1466
+ (`ENTITA "si" "chiama" "anche" TESTO_QUOTATO "."`); si distingue dalle altre
1467
+ dichiarazioni che iniziano con `ENTITA` grazie al keyword `si`, senza conflitti
1468
+ LALR. Parole riservate `si`/`chiama`/`anche`. Validazione non bloccante: alias
1469
+ verso oggetto inesistente o verso una non-entità-oggetto → *warning*.
1470
+ - `gioco.py`: `risolvi_nome_oggetto` consulta `mondo.alias` (esatto e parziale).
1471
+ - `test_linguaggio.py`: quattro nuovi test (risoluzione esatta, multiparola,
1472
+ parziale, warning su bersaglio non-oggetto); corpus della guardia esteso con
1473
+ una `def_alias`. Suite a **142 asserzioni** (era 133); guardia anti-ambiguità
1474
+ (1 albero / 0 conflitti LALR) verde.
1475
+
1476
+ ---
1477
+
1478
+ ## [0.8.0] - 2026-05-31
1479
+ ### Roadmap del Linguaggio — Livello 3 «Stato di gioco e meccaniche» COMPLETATO
1480
+ Release minore che consolida le patch 0.7.1 → 0.7.5. Il linguaggio FAVELLA passa
1481
+ da descrittore di mondi statici a motore di **avventure complete**, con stato
1482
+ astratto e meccaniche temporali. In sintesi (dettaglio per-patch sotto e in
1483
+ `documentazione/0.8.0.md`):
1484
+ - **Proprietà opposte dichiarabili** (`M5`): `Accesa e spenta sono opposte.`
1485
+ - **Fine partita**: conseguenze `vinci` / `perdi` / `termina`.
1486
+ - **Stato astratto** (`G3`): **stati** enum-like (`Il semaforo è uno stato.` →
1487
+ `… è rosso`, `se … è verde`) e **contatori** numerici (`Il punteggio è un
1488
+ contatore.`, `aumenta … di N`, `diventa N`, confronti `almeno`/`più di`/`meno di`).
1489
+ - **Eventi a turni**: `Al turno N: …`, `Ogni N turni: …`.
1490
+
1491
+ Vincoli mantenuti per tutto il livello: grammatica **LALR(1) non ambigua per
1492
+ costruzione** (guardia permanente: 1 albero / 0 conflitti) e superficie pubblica
1493
+ `analizza_file()` invariata. Header dei moduli core allineati a **v0.8.0**
1494
+ (`compilatore`, `strutture`, `gioco`, `libreria_azioni`, suite). Suite del
1495
+ linguaggio: **133 asserzioni**, tutte verdi (erano 65 a inizio livello).
1496
+
1497
+ > Nota architetturale chiave: stati e contatori sono una **terza classe di
1498
+ > simboli chiusi** (terminale `VARIABILE`) disgiunta da `ENTITA`/`PROPRIETA`,
1499
+ > raccolta in Passata 1. È questa separazione a garantire **zero ambiguità** tra
1500
+ > i costrutti su variabili e quelli su oggetti.
1501
+
1502
+ ---
1503
+
1504
+ ## [0.7.5] - 2026-05-31
1505
+ ### Aggiunto (Roadmap Livello 3 — verso 0.8.0)
1506
+ - **Eventi a turni**: costrutti temporali a livello di mondo.
1507
+ - `Al turno 3: dire "..." e adesso ...` — scatta **una sola volta** al turno N.
1508
+ - `Ogni 5 turni: dire "..." e adesso ...` — scatta a **ogni multiplo** di N.
1509
+ Riusano la stessa coda di conseguenze delle regole (incluse fine partita,
1510
+ stati e contatori), così si può far perdere allo scadere del tempo o
1511
+ incrementare un contatore a ogni turno.
1512
+ - `strutture.py`: classe `Evento` (`scatta_a()`, `esegui_conseguenze()`),
1513
+ `Mondo.eventi` + `turno_corrente` + `aggiungi_evento()`.
1514
+ - `gioco.py`: contatore dei turni nel loop. `elabora_comando` è ora un wrapper
1515
+ che, dopo un comando reale, chiama `avanza_turno_e_processa(mondo)` (avanza il
1516
+ turno e attiva gli eventi scattati, terminando se un evento chiude la partita);
1517
+ la logica del comando è in `_esegui_comando`. Header allineato a v0.7.5.
1518
+ Policy: ogni comando non vuoto e diverso da `esci` conta come un turno.
1519
+ - `compilatore.py`: regola `def_evento` (forme `evento_al`/`evento_ogni`), parole
1520
+ riservate `al`/`turno`/`turni`/`ogni`; validazione conseguenze condivisa
1521
+ (`_valida_conseguenze`, usata anche da `def_regola`); un numero di turni < 1 è
1522
+ un warning e l'evento è ignorato. Suite a **133 asserzioni** (era 119), con
1523
+ test d'integrazione del loop e guardia anti-ambiguità estesa agli eventi.
1524
+
1525
+ ---
1526
+
1527
+ ## [0.7.4] - 2026-05-31
1528
+ ### Aggiunto (Roadmap Livello 3 — verso 0.8.0)
1529
+ - **Contatori numerici** (completano `[G3]`), sulla stessa classe di simboli
1530
+ degli stati (`VARIABILE`):
1531
+ - dichiarazione: `Il punteggio è un contatore.` (valore iniziale 0)
1532
+ - mutazioni: `e adesso aumenta il punteggio` (+1), `... aumenta il punteggio di 5`,
1533
+ `... diminuisci il punteggio (di N)`, `... il punteggio diventa 10`
1534
+ - confronti: `se il punteggio è almeno 3` (≥), `... è più di 2` (>),
1535
+ `... è meno di 5` (<), `... è 0` (=)
1536
+ - `strutture.py`: `CondizioneContatore` (operatori `==`/`>=`/`>`/`<`),
1537
+ `ConseguenzaContatore` (modi `aumenta`/`diminuisci`/`diventa`),
1538
+ `Mondo.dichiara_contatore()`. `compilatore.py`: scanner `è un contatore`,
1539
+ terminale `NUMERO` (priorità alta su `PROPRIETA`, che include le cifre),
1540
+ regole `def_contatore`, `cond_contatore_*`, `cons_aumenta`/`cons_diminuisci`/
1541
+ `cons_contatore_set`; parole riservate `contatore`/`almeno`/`più`/`meno`/
1542
+ `aumenta`/`diminuisci`/`diventa`. I confronti dopo `VARIABILE è` si
1543
+ distinguono dal valore-stato per il lookahead (NUMERO/`almeno`/`più`/`meno`
1544
+ vs PROPRIETA) → nessuna ambiguità. Suite a **119 asserzioni** (era 102).
1545
+
1546
+ > **Limite noto** (non risolto in questo livello): una regola `Invece di [verbo] …`
1547
+ > richiede sempre un **oggetto bersaglio**; non esistono ancora regole senza
1548
+ > oggetto del tipo `Invece di guarda se il punteggio è almeno 3: …`. Le verifiche
1549
+ > globali su contatori/stati vanno per ora agganciate a una regola su oggetto
1550
+ > (o agli eventi a turni, 0.7.5).
1551
+
1552
+ ---
1553
+
1554
+ ## [0.7.3] - 2026-05-31
1555
+ ### Aggiunto (Roadmap Livello 3 — verso 0.8.0)
1556
+ - **Stato astratto del mondo** (criticità `[G3]`): gli **stati**, variabili globali
1557
+ con nome non legate ad alcun oggetto. Uno stato contiene una *parola-stato*
1558
+ (modello enum-like, più potente di un booleano):
1559
+ - dichiarazione: `Il semaforo è uno stato.`
1560
+ - valore iniziale: `Il semaforo è rosso.`
1561
+ - condizione: `... se il semaforo è verde` (e negazione `... non è verde`)
1562
+ - conseguenza: `... e adesso il semaforo è verde.`
1563
+ - Architettura: gli stati sono una **terza classe di simboli chiusi** (terminale
1564
+ `VARIABILE`), raccolta in Passata 1 e **disgiunta** da `ENTITA`/`PROPRIETA`.
1565
+ LALR distingue i costrutti su stato da quelli su oggetto al primo token →
1566
+ **zero ambiguità** anche con parole-stato omonime a proprietà di oggetti.
1567
+ - `strutture.py`: `CondizioneVariabile`, `ConseguenzaVariabile`, `Mondo.variabili`
1568
+ + `dichiara_variabile()`. `compilatore.py`: scanner `è uno stato`, terminale
1569
+ `VARIABILE` iniettato per-file, regole `def_stato`/`def_stato_valore`/
1570
+ `cond_variabile(_neg)`/`cons_variabile`; parola riservata `stato`. Corretto un
1571
+ bug latente: il terminale "vuoto" ora è `[^\s\S]` (larghezza 1) invece di `(?!)`
1572
+ (zero-width, rifiutato da Lark). Suite a **102 asserzioni** (era 84), guardia
1573
+ anti-ambiguità estesa agli stati.
1574
+
1575
+ ---
1576
+
1577
+ ## [0.7.2] - 2026-05-31
1578
+ ### Aggiunto (Roadmap Livello 3 — verso 0.8.0)
1579
+ - **Condizioni di fine partita**: nuove conseguenze `vinci` / `perdi` / `termina`,
1580
+ usabili in coda a una regola (`... dire "..." e adesso vinci.`). Impostano lo
1581
+ stato globale della partita; il messaggio narrativo è quello della clausola
1582
+ `dire`. Combinabili con altre conseguenze nella stessa regola
1583
+ (es. `... e adesso la porta è aperta e adesso vinci.`).
1584
+ - `strutture.py`: nuova `ConseguenzaFinePartita` (esiti `vinta`/`persa`/`terminata`)
1585
+ e `Mondo.stato_partita` (default `in_corso`).
1586
+ - `gioco.py`: il loop interattivo controlla `partita_finita(mondo)` dopo ogni
1587
+ conseguenza e termina con il banner di esito. Header allineato a v0.7.2.
1588
+ - Grammatica: tre nuove alternative di `conseguenza`, parole riservate
1589
+ `vinci`/`perdi`/`termina`. Validazione conseguenze resa robusta alle
1590
+ conseguenze prive di oggetto. Guardia anti-ambiguità estesa (corpus con
1591
+ `vinci`). Suite a **84 asserzioni** (era 72).
1592
+
1593
+ ---
1594
+
1595
+ ## [0.7.1] - 2026-05-31
1596
+ ### Aggiunto (Roadmap Livello 3 — Stato di gioco e meccaniche, in lavorazione verso 0.8.0)
1597
+ - **Proprietà opposte dichiarabili** (generalizza la criticità `[M5]`): l'autore può
1598
+ dichiarare coppie di proprietà mutuamente esclusive con la frase
1599
+ `Accesa e spenta sono opposte.`. Assegnare una proprietà a un oggetto rimuove
1600
+ automaticamente tutte le sue opposte. La coppia `aperta`↔`chiusa`, prima
1601
+ cablata in `ConseguenzaProprieta.esegui`, è ora una semplice **coppia
1602
+ precaricata di default** (retro-compatibilità totale con le storie esistenti).
1603
+ - Nuova regola di grammatica `def_opposti` (`PROPRIETA "e" PROPRIETA "sono" "opposte" "."`),
1604
+ nuove parole riservate `sono`/`opposte`. La guardia anti-ambiguità (1 albero / 0
1605
+ conflitti LALR) copre il nuovo costrutto. Suite a **72 asserzioni** (era 65).
1606
+
1607
+ Dettaglio tecnico cumulativo del livello: `documentazione/0.8.0.md`.
1608
+
1609
+ ---
1610
+
1611
+ ## [0.2.1] - 2026-05-21
1612
+ ### Risolto (Criticità Gravissime)
1613
+ - **Normalizzazione dell'input dell'utente:** Risolto il bug gravissimo che impediva la risoluzione degli oggetti in scope quando digitati con articoli (es. `prendi la keycard` falliva mentre `prendi keycard` funzionava). Ora l'input dell'utente viene normalizzato tramite `normalizza_nome` prima del confronto in `risolvi_nome_oggetto`.
1614
+ - **Risoluzione movimenti con direzioni abbreviate:**
1615
+ - Risolto il blocco della navigazione quando le connessioni erano definite con abbreviazioni nel file `.fav` (es. `collega n a il corridoio`). Ora vengono normalizzate a compile-time a nomi interi (`nord`, `sud`, etc.).
1616
+ - Abilitato il supporto per direzioni abbreviate inserite con il verbo `vai` (es. `vai n` o `vai s` ora si risolvono correttamente a `nord` e `sud`).
1617
+
1618
+ ---
1619
+
1620
+ ## [0.3.0] - 2026-05-21
1621
+ ### Risolto (Criticità Gravi)
1622
+ - **Conservazione del nome visualizzato originale:** Ristrutturazione delle classi `Oggetto` e `Stanza` in `strutture.py` e della logica del transformer in `compilatore.py` per preservare la capitalizzazione e gli articoli originali scritti dall'autore (es. `"Una keycard magnetica"`, `"La cella di contenimento"`), mantenendo gli ID normalizzati in minuscolo solo per la logica interna del gioco. Aggiornato l'interprete in `gioco.py` e le azioni in `libreria_azioni.py` per visualizzare questi bellissimi nomi originali.
1623
+ - **Corrispondenza flessibile delle preposizioni nelle regole a due oggetti:** Implementazione di una logica di tolleranza e fallback in `gioco.py` (`elabora_comando`, FASE 0): se non si trova una corrispondenza esatta con la preposizione specificata nella regola (es. `usa chiave su porta`), il motore tenta un fallback tollerante ignorando la preposizione (es. accettando `usa chiave con porta`) a patto che i due oggetti coincidano univocamente con la regola.
1624
+
1625
+ ---
1626
+
1627
+ ## [0.4.0] - 2026-05-21
1628
+ ### Aggiunto & Ottimizzato (Criticità Medie)
1629
+ - **Rendering asincrono e ottimizzato della mappa:** Spostato il calcolo pesante delle posizioni dei nodi del grafo (`nx.spring_layout`) all'interno di un thread secondario dedicato (`LayoutWorker` ereditato da `QThread`) in `favella_studio.py`. In questo modo si previene efficacemente il congelamento (UI freeze) dell'intera interfaccia utente di PySide6 durante la compilazione di storie di grandi dimensioni. Lo sfondo della figura Matplotlib si armonizza ora con la Dark Mode.
1630
+ - **Design System Premium "Cyber-Scrittore" (Dark Mode):** Sviluppato e applicato un foglio di stile QSS completo, scuro e moderno (`CYBER_STYLESHEET`) per tutta l'interfaccia dell'IDE. Coinvolge menu, toolbar, splitter, schede (tab), barre di scorrimento, bottoni e dialoghi `QMessageBox`, curando la tipografia monospazio e i feedback di hover.
1631
+ - **Marker visivi degli errori di sintassi nell'editor:** Integrato un sistema dinamico che, al fallimento della compilazione di Lark, estrae tramite regex la riga d'errore dal log, evidenzia con uno sfondo rosso scuro soffuso (`#4a1515`) la riga esatta nell'editor sfruttando `QTextEdit.ExtraSelection` e posiziona automaticamente il cursore per agevolare il debug.
1632
+
1633
+ ### Risolto (Criticità Lievi)
1634
+ - **Generazione di righe vuote superflue nella console:** Ottimizzato l'intercettore di standard output in `GameSession` filtrando le stringhe che, dopo la rimozione dei caratteri di spaziatura finali (`.rstrip()`), risultano vuote, risolvendo il problema dei doppi a capo fastidiosi nella console dell'IDE.
1635
+ - **Feedback visivo se il gioco non è avviato:** Aggiornata la gestione dell'input in `on_console_input` di `FavellaStudio` per visualizzare un messaggio informativo elegante e colorato direttamente nella console di gioco se l'utente tenta di inviare comandi quando non c'è una sessione attiva.
1636
+
1637
+ ---
1638
+
1639
+ ## [0.5.0] - 2026-05-31
1640
+ ### Roadmap del Linguaggio — Livello 1: Consolidamento e Robustezza
1641
+ Primo passo della roadmap evolutiva del linguaggio FAVELLA: mettere in sicurezza
1642
+ i costrutti esistenti prima di estenderli. L'obiettivo è impedire all'autore di
1643
+ scrivere una storia "rotta" senza ricevere alcun feedback. Nessuna funzionalità
1644
+ narrativa nuova, ma fondamenta molto più solide e diagnostica d'autore.
1645
+
1646
+ ### Risolto (Criticità Gravissime)
1647
+ - **[GG1] Posizione iniziale esplicita del giocatore.** Introdotta la primitiva di linguaggio `Il giocatore comincia in [stanza].` (accetta anche *inizia* / *parte*). Prima la stanza di partenza era implicitamente la prima nell'ordine di parsing (`list(stanze.keys())[0]`), fragile e non controllabile dall'autore. Ora `Mondo.posizione_iniziale` è dichiarabile; in sua assenza resta il fallback alla prima stanza. Una stanza di partenza inesistente è un **errore bloccante**.
1648
+ - **[GG2] Rilevamento refusi nelle proprietà.** Una condizione `se [oggetto] è [proprietà]` che controlla una proprietà mai assegnata a quell'oggetto (né come stato iniziale né tramite conseguenza) emette ora un **avviso di possibile refuso** (es. `chuisa` per `chiusa`), invece di fallire silenziosamente lasciando il puzzle morto.
1649
+ - **[GG3] Validazione dei verbi delle regole.** Il verbo di ogni regola `Invece di` viene confrontato a compile-time con il vocabolario noto al motore (`VERBI_VALIDI`). Un verbo sconosciuto (regola che non si attiverebbe mai) genera ora un **avviso esplicito**.
1650
+
1651
+ ### Aggiunto & Migliorato
1652
+ - **[G1] Disambiguazione esplicita della grammatica.** Aggiunte priorità di regola (`def_*.2` vs `def_proprieta.1`): la scelta del parser Earley sulle frasi formalmente ambigue (`X è una cosa` vs proprietà) è ora deterministica e documentata, non più affidata al tie-break interno di Lark.
1653
+ - **Suite di test del linguaggio (`test_linguaggio.py`).** 12 test / 28 asserzioni che "congelano" disambiguazione, posizione iniziale, validazioni e parsing della storia di esempio. Garanzia anti-regressione (`python test_linguaggio.py`).
1654
+ - **[M6] Escape nelle stringhe.** `TESTO_QUOTATO` supporta ora `\"` e `\\`: è finalmente possibile inserire virgolette dentro le battute (`dire "Lui disse \"ciao\"."`).
1655
+ - **Avvisi non bloccanti.** Nuovo canale diagnostico: gli avvisi (`[FAVELLA 1] Avvisi`) informano l'autore senza interrompere la compilazione, distinti dagli errori fatali.
1656
+
1657
+ ### Risolto (Criticità Lievi)
1658
+ - **[L2] Normalizzazione tipografica.** Apostrofi e virgolette "curve" (`'` `'` `"` `"`), tipiche del copia-incolla da editor di testo, vengono convertite nelle versioni dritte attese dalla grammatica, evitando errori di sintassi oscuri.
1659
+ - **[L5] Rimosso il refuso di versione "v0.8"** nel report di `Mondo.__str__`; allineati gli header di versione di tutti i moduli core a `v0.5.0`.
1660
+
1661
+ ---
1662
+
1663
+ ## [0.6.0] - 2026-05-31
1664
+ ### Roadmap del Linguaggio — Livello 2: Logica Composita
1665
+ Le regole `Invece di` passano da un singolo trigger a vere espressioni logiche.
1666
+ Questo sblocca i puzzle multi-stato senza dover duplicare le regole.
1667
+
1668
+ ### Aggiunto (Criticità Gravi)
1669
+ - **[G2] Condizioni booleane composite.** Le condizioni supportano ora `e` (AND) e `oppure` (OR), con precedenza `OR < AND < atomo` e raggruppamento tramite parentesi. Esempio: `se la porta è chiusa e il giocatore ha la chiave`. (Si usa `oppure` e non `o`, che resta l'abbreviazione di *ovest*.)
1670
+ - **[M3] Negazione infissa.** Nuove forme negate, idiomatiche in italiano: `se il giocatore non ha [oggetto]` e `se [oggetto] non è [proprietà]`. Internamente generano una `CondizioneNot`.
1671
+ - **[G2] Conseguenze multiple.** Una regola può applicare più conseguenze in sequenza: `... e adesso la porta è aperta e adesso la chiave è nel nulla` (accettata anche la forma breve `e adesso X e Y`). `Regola.conseguenza` (singola) diventa `Regola.conseguenze` (lista) con il nuovo metodo `esegui_conseguenze()`.
1672
+
1673
+ ### Modifiche Architetturali
1674
+ - Nuove classi in `strutture.py`: `CondizioneAnd`, `CondizioneOr`, `CondizioneNot` (gerarchia `Condizione` polimorfica, valutazione ricorsiva).
1675
+ - Grammatica delle condizioni stratificata (`cond_or` / `cond_and` / `cond_base`) con priorità di regola: le forme negate (`.2`) battono quelle affermative, impedendo che il token `non` venga assorbito dentro `entita` invertendo la semantica.
1676
+ - Il rilevamento refusi `[GG2]` ora attraversa ricorsivamente le condizioni composite (`_atomi_proprieta`) per trovare i refusi annidati dentro AND/OR/NOT.
1677
+ - Suite `test_linguaggio.py` estesa: **44 asserzioni** (era 28), inclusi AND/OR, negazioni, conseguenze multiple ed end-to-end.
1678
+
1679
+ ---
1680
+
1681
+ ## [0.6.1] - 2026-05-31
1682
+ ### Roadmap del Linguaggio — Livello 2.5 (Disambiguazione strutturale): Fondamenta
1683
+ Primo commit incrementale verso la **risoluzione definitiva dell'ambiguità grammaticale [G1]** (target `v0.7.0`). La causa radice è il terminale aperto `entita: WORD+`, che rende la grammatica formalmente ambigua: oggi ogni dichiarazione genera più alberi di parsing (misurato: da 1 a 7 nodi `_ambig` per frase) e il parser Earley "indovina" tramite priorità di regola — deterministico ma fragile. La cura, decisa al massimo livello di robustezza, è un compilatore a **due passate** con `ENTITA` come token *chiuso* risolto da una symbol-table + parser **LALR(1)**, unambiguo per costruzione.
1684
+
1685
+ Questo commit introduce le **fondamenta isolate** (ancora non cablate nel parsing, che cambierà in `0.6.2`):
1686
+
1687
+ ### Aggiunto
1688
+ - **Passata 1 — scanner della symbol-table** (`costruisci_symbol_table` in `compilatore.py`). Estrae dal sorgente i nomi di tutte le stanze e gli oggetti *dichiarati* (`è una stanza`, `è una cosa`, `collega … a …`) senza eseguire il parsing completo; robusto ai punti dentro le stringhe e ai commenti. Restituisce una `TabellaSimboli` con i nomi già normalizzati (supporta i nomi multiparola, es. `cella di contenimento`).
1689
+ - **Set di parole riservate esplicito** (`PAROLE_RISERVATE`): vocabolario strutturale del linguaggio, base per la futura risoluzione delle entità e per la documentazione d'autore.
1690
+ - **`utils.normalizza_tipografia`**: estratta la normalizzazione di apostrofi/virgolette tipografiche `[L2]` in un helper condiviso (usato sia da `analizza_file` sia dallo scanner). `utils.ARTICOLI`: lista unica degli articoli, ora condivisa con `normalizza_nome` (eliminata la duplicazione).
1691
+ - Suite `test_linguaggio.py`: **54 asserzioni** (era 44), con 10 nuovi controlli su scanner e parole riservate.
1692
+
1693
+ ---
1694
+
1695
+ ## [0.6.2] - 2026-05-31
1696
+ ### Roadmap del Linguaggio — Livello 2.5 (Disambiguazione strutturale): Il refactor del cuore
1697
+ Il compilatore passa da single-pass **Earley** (grammatica formalmente ambigua, salvata solo da priorità di regola) a **due passate + LALR(1)**, unambiguo per costruzione. L'ambiguità `[G1]` è eliminata **alla radice**, non più mitigata.
1698
+
1699
+ ### Modifiche Architetturali
1700
+ - **Terminale `ENTITA` chiuso, generato per-file.** Sparisce `entita: WORD+` (la causa radice). Le entità sono ora un terminale risolto per **longest-match** contro la symbol-table della Passata 1 (con articolo iniziale opzionale, nomi multiparola come `cella di contenimento`). Le parole-chiave non possono più collidere coi nomi.
1701
+ - **Migrazione a `parser='lalr'`.** Il parser si costruisce per-file da `costruisci_parser(simboli)`; un'eventuale ambiguità emergerebbe come `GrammarError` a build-time anziché come scelta silenziosa a runtime. Più veloce di Earley.
1702
+ - **Proprietà coniate = terminale `PROPRIETA` separato**, di **una sola parola** e a priorità lessicale bassa: non può inghiottire i keyword che la seguono (`e`, `oppure`, `:`). *Conseguenza author-facing:* le proprietà di stato sono ora monoparola (i nomi multiparola restano supportati per le entità). Nessuna storia/test esistente ne è impattato.
1703
+ - **`è prendibile` unificato in `def_proprieta`** come proprietà speciale: rimossa la regola `def_prendibile`, che era l'unica collisione lessicale residua. La grammatica è ora **0-ambigua** anche sotto Earley, non solo risolta da LALR.
1704
+ - **Rimosse tutte le priorità-cerotto `.2`/`.1`**: con i nomi come token chiusi non servono più (né per le definizioni base né per le forme negate delle condizioni).
1705
+
1706
+ ### Aggiunto
1707
+ - **Guardia anti-ambiguità permanente** in `test_linguaggio.py`: un corpus che in `v0.6.0` generava da 1 a 7 alberi per frase ora ne produce **esattamente uno** (0 nodi `_ambig`), e si verifica che **LALR(1) si costruisca senza conflitti**. Rete di sicurezza definitiva contro le regressioni di `[G1]`.
1708
+ - Suite a **58 asserzioni** (era 54).
1709
+
1710
+ ---
1711
+
1712
+ ## [0.7.0] - 2026-05-31
1713
+ ### Roadmap del Linguaggio — Livello 2.5: Disambiguazione strutturale COMPLETATA
1714
+ Rilascio che chiude il Livello 2.5: la grammatica di FAVELLA è ora **non ambigua per costruzione** (parser LALR(1), nomi come token chiusi). La criticità `[G1]` — la grammatica formalmente ambigua salvata solo dal tie-break di Earley — è **risolta in via definitiva**, non più mitigata. Questo rilascio raccoglie le fondamenta (`0.6.1`) e il refactor del cuore (`0.6.2`) e vi aggiunge la rifinitura della diagnostica d'autore.
1715
+
1716
+ ### Aggiunto
1717
+ - **Errori d'autore mirati per le entità non dichiarate.** Sfruttando i nomi come token chiusi, un riferimento a un'entità mai dichiarata non produce più un parse error criptico ma un messaggio chiaro: *«Entità sconosciuta: "porta" non è mai stata dichiarata. Dichiarala prima dell'uso…»*. In caso di refuso vicino a un nome noto, viene proposta la **correzione** (es. `chave` → *«Forse intendevi: chiave?»*) tramite `difflib`. Un vero errore di sintassi (es. punto mancante) continua a ricevere il messaggio generico, senza falsi positivi.
1718
+
1719
+ ### Documentazione
1720
+ - Nuova sezione **«Parole riservate»** e nota sulle **proprietà monoparola** nel manuale autore (`documentazione/manuale/manuale.md`).
1721
+ - `documentazione/0.7.0.md`: dettaglio tecnico del Livello 2.5 (due passate, ENTITA chiuso, LALR, guardia).
1722
+
1723
+ ### Riepilogo del Livello 2.5 (0.6.1 → 0.6.2 → 0.7.0)
1724
+ - Compilatore a **due passate**: Passata 1 = symbol-table dei nomi; Passata 2 = parsing LALR(1) con `ENTITA` chiuso (longest-match).
1725
+ - Eliminato `entita: WORD+` e **tutte** le priorità-cerotto `.2`/`.1`.
1726
+ - Proprietà coniate = terminale `PROPRIETA` separato, **monoparola** (i nomi multiparola restano per le entità).
1727
+ - **Guardia anti-ambiguità permanente**: corpus a 1 albero (0 `_ambig`) + LALR senza conflitti.
1728
+ - Suite del linguaggio a **65 asserzioni** (era 44 a inizio livello), tutte verdi.
1729
+ - Allineati a `v0.7.0` gli header dei moduli core del linguaggio (`compilatore`, `strutture`, `test_linguaggio`) e il report di `Mondo.__str__`.