Resume a round in drawing from the database after an exception or a restart (B-81, RND-01, RND-15, RND-36, ARC-27, OPS-09, OPS-13, LIM-01)
`_tick` skipped `drawing`: the wait for the draw block lived only inside the `_close_and_draw` call that entered it, so any exception (a locked database writing an audit row, a malformed header) or a restart left the round in `drawing` for ever with the pool inside and no new round able to open. Since B-73 everything the draw needs is committed on entering `drawing` (encrypted secret, ordered list with `draw_position`, `participants_hash`, `draw_height`, `draw_confirmations`), so `_tick` now calls `_complete_draw` for a round in `drawing`. `_complete_draw` rereads that state, is idempotent (a round no longer `drawing`, or with a winner, is left alone; the winner write is re-checked under BEGIN IMMEDIATE) and runs inside the single scheduler loop, so the inline call from `_close_and_draw` and the tick can never run concurrently. Tests (test_draw_proof.py): an exception in the quorum query, then a tick, completes with the same height, list, fingerprint and the winner the public proof recomputes; a brand-new scheduler (restart) resumes and a second tick draws and triggers nothing again; a failure in the very transaction that stores the winner leaves no winner and no revealed secret, and the next tick completes. Mutation-checked: without the `_tick` branch all three fail. Docs: the B-81 `*Stato:*`/`*Oggi:*` lines are gone (RND-01, RND-15, RND-36, ARC-27, OPS-09, ADR-12, ADR-25), OPS-13 no longer prescribes the manual `closing` workaround, LIM-01 is struck, storico-bug.md and BUGS.md updated. No existing test changed. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
db24287ea5
commit
473d541ab5
12 files changed
+230
-126
No files matched your search
@@ -1,6 +1,6 @@
|
||||
# ADR-12 — Il server gira solo in Docker, in sviluppo come in produzione
|
||||
|
||||
- **Stato:** Accettata — implementazione da completare (B-81)
|
||||
- **Stato:** Accettata
|
||||
- **Area:** Configurazione e ambiente
|
||||
- **Fonte di verità per:** la scelta di progetto descritta qui sotto; i requisiti (`PREFISSO-NN`) che la attuano stanno nei documenti di dominio, indicati nelle *Conseguenze*.
|
||||
|
||||
@@ -19,5 +19,3 @@ script della chiave.
|
||||
|
||||
*Codice:* `Dockerfile` · `docker-compose.yml` · `Caddyfile` ·
|
||||
*Test:* `tests/unit/test_docs_no_bare_uvicorn.py`
|
||||
*Stato:* da implementare (B-81) · *Oggi:* dopo un crash `closing` e
|
||||
`paying_out` riprendono da soli, `drawing` no ([LIM-01]).
|
||||
@@ -1,6 +1,6 @@
|
||||
# ADR-25 — Il blocco di estrazione è fissato per altezza, è successivo alla chiusura, e si usa solo quando è confermato e corroborato
|
||||
|
||||
- **Stato:** Accettata — implementazione da completare (B-81)
|
||||
- **Stato:** Accettata
|
||||
- **Area:** Round ed estrazione
|
||||
- **Fonte di verità per:** la scelta di progetto descritta qui sotto; i requisiti (`PREFISSO-NN`) che la attuano stanno nei documenti di dominio, indicati nelle *Conseguenze*.
|
||||
|
||||
@@ -32,6 +32,3 @@ chiusura significa «sconosciuta»: la prima altezza appresa fa da base.
|
||||
|
||||
*Codice:* `app/rounds/scheduler.py:RoundScheduler._wait_for_draw_block` · `app/rounds/scheduler.py:RoundScheduler._close_and_draw` · `app/rounds/scheduler.py:RoundScheduler._tick` ·
|
||||
*Test:* `tests/unit/test_scheduler.py::test_a_block_relayer_cannot_choose_the_block_that_seeds_the_draw`, `tests/unit/test_scheduler.py::test_a_disagreement_asks_the_same_height_again_and_is_audited_once_per_hash`
|
||||
*Stato:* da implementare (B-81) · *Oggi:* `draw_height`, `participants_hash` e le
|
||||
posizioni sono salvati, ma `_tick` salta i round in `drawing`: dopo un errore
|
||||
o un riavvio il round non riparte.
|
||||
@@ -554,12 +554,7 @@ implementare» non esistono ancora nel codice (vedi [ARC-60] e [ARC-22]).
|
||||
*Codice:* `app/rounds/scheduler.py:RoundScheduler._tick` ·
|
||||
`app/rounds/scheduler.py:RoundScheduler._close_and_draw` ·
|
||||
`app/rounds/scheduler.py:RoundScheduler._wait_for_draw_block` ·
|
||||
*Test:* `tests/unit/test_scheduler.py`
|
||||
*Stato:* da implementare (B-81) · *Oggi:* `_tick` salta i round in
|
||||
`drawing`; `tip_at_close` e i partecipanti vivono solo nella chiamata a
|
||||
`_close_and_draw`, quindi un'eccezione o un riavvio lasciano il round in
|
||||
`drawing` per sempre
|
||||
([LIM-01](limiti-noti.md#robustezza-del-ciclo-di-vita)).
|
||||
*Test:* `tests/unit/test_scheduler.py`, `tests/unit/test_draw_proof.py`
|
||||
- **[ARC-28]** **`ConfirmationPoller`** (10s), **`RbfBumper`** (30s) e
|
||||
**`PendingTransactionReconciler`** (al primo giro subito, poi ogni 120s)
|
||||
lavorano sulla tabella `pending_transactions` (e sulla tabella
|
||||
|
||||
@@ -23,10 +23,7 @@ adesso; l'ordine di implementazione è in
|
||||
il passo successivo riparte dallo stato salvato nel database, **in
|
||||
qualunque stato sia il round**, `drawing` compreso ([RND-36]).
|
||||
*Codice:* `app/rounds/scheduler.py:RoundScheduler.run`, `app/rounds/scheduler.py:RoundScheduler._tick` ·
|
||||
*Test:* `tests/unit/test_scheduler.py`
|
||||
*Stato:* da implementare (B-81) · *Oggi:* un errore durante l'attesa del
|
||||
blocco lascia il round in `drawing` per sempre, perché `_tick` non fa nulla
|
||||
sui round in quello stato.
|
||||
*Test:* `tests/unit/test_scheduler.py`, `tests/unit/test_draw_proof.py::test_a_tick_resumes_a_drawing_round_after_an_exception_with_the_same_draw`
|
||||
|
||||
## Gli stati
|
||||
|
||||
@@ -281,11 +278,8 @@ flowchart TB
|
||||
`draw_height + draw_confirmations − 1`. La condizione si controlla a ogni
|
||||
passo dello scheduler, rileggendo dal database tutto ciò che serve
|
||||
([RND-36]).
|
||||
*Codice:* `app/rounds/scheduler.py:RoundScheduler._wait_for_draw_block` ·
|
||||
*Test:* `tests/unit/test_scheduler.py`
|
||||
*Stato:* da implementare (B-81) · *Oggi:* la condizione si controlla dentro
|
||||
`_close_and_draw`, che resta in attesa per tutta la durata senza che
|
||||
`_tick` la riprenda: dopo un errore o un riavvio non riparte.
|
||||
*Codice:* `app/rounds/scheduler.py:RoundScheduler._wait_for_draw_block`, `app/rounds/scheduler.py:RoundScheduler._tick` ·
|
||||
*Test:* `tests/unit/test_scheduler.py`, `tests/unit/test_draw_proof.py::test_a_restarted_scheduler_resumes_a_drawing_round_and_a_second_tick_draws_nothing`
|
||||
- **[RND-16]** **Header concordato**: raggiunte le conferme, l'header
|
||||
all'altezza `draw_height` (e non la punta corrente) viene chiesto a tutti i
|
||||
server configurati, attivo compreso, e lo si usa solo se il quorum concorda
|
||||
@@ -354,10 +348,7 @@ flowchart TB
|
||||
ripresa dà sempre lo stesso vincitore, e un round già passato a
|
||||
`paying_out` non viene estratto di nuovo.
|
||||
*Codice:* `app/rounds/scheduler.py:RoundScheduler._tick`, `app/rounds/scheduler.py:RoundScheduler._complete_draw` ·
|
||||
*Test:* `tests/unit/test_draw_proof.py` (solo `_complete_draw`)
|
||||
*Stato:* da implementare (B-81) · *Oggi:* tutto ciò che serve è nel database
|
||||
e `_complete_draw` è idempotente, ma `_tick` salta i round in `drawing`:
|
||||
dopo un errore o un riavvio il round resta in `drawing` per sempre.
|
||||
*Test:* `tests/unit/test_draw_proof.py::test_a_drawing_round_is_completed_by_a_second_pass_with_the_same_winner`, `tests/unit/test_draw_proof.py::test_a_tick_resumes_a_drawing_round_after_an_exception_with_the_same_draw`, `tests/unit/test_draw_proof.py::test_a_restarted_scheduler_resumes_a_drawing_round_and_a_second_tick_draws_nothing`, `tests/unit/test_draw_proof.py::test_resuming_after_a_failure_inside_the_draw_transaction_leaves_no_half_state`
|
||||
- **[RND-37]** **Prova pubblica**: `GET /rounds/{id}/proof`, senza
|
||||
autenticazione, restituisce per un round: `server_seed_hash` e
|
||||
`pool_address` (dall'apertura); dall'ingresso in `drawing` l'elenco dei
|
||||
@@ -625,6 +616,4 @@ Due livelli indipendenti:
|
||||
## Limite noto
|
||||
|
||||
- ~~[RND-32]~~ Assorbito da [RND-36]: nel comportamento atteso un round in
|
||||
`drawing` riprende da solo dopo un riavvio o un errore. Finché B-81 non è
|
||||
implementato il limite resta: lo scheduler riprende i round in `closing` e
|
||||
`paying_out`, ma su un round in `drawing` non fa nulla.
|
||||
`drawing` riprende da solo dopo un riavvio o un errore (B-81).
|
||||
+4
-26
@@ -32,7 +32,7 @@ implementato il [piano delle correzioni](piano-correzioni.md).
|
||||
|
||||
| Limite | Blocca il non presidiato oggi? | Dopo il piano |
|
||||
|---|---|---|
|
||||
| [LIM-01] `drawing` non riprende dopo un errore o un riavvio | **Sì** — è lo stato che resta fermo con denaro in gioco | Chiuso da B-81 |
|
||||
| ~~[LIM-01]~~ `drawing` non riprende dopo un errore o un riavvio | Non più (chiuso da B-81) | — |
|
||||
| [LIM-02] RBF di una sola forma (e pagamento senza resto) | **Sì, in caso di congestione della rete** | Chiuso da B-79 e B-87 |
|
||||
| [LIM-03] Attesa in `closing` senza limite di tempo | **Sì, in caso di congestione** | Resta senza limite di tempo per scelta ([ADR-51](adr/ADR-51-dubbio-liberano-mai-fondi.md)); con B-78 e B-87 finisce quando la rete decide |
|
||||
| [LIM-04] Prelievo e RBF mai provati in rete reale | **Sì, come verifica** | Da chiudere con la prova su rete reale ([operativita.md](operativita.md#prova-su-rete-reale)) prima di aprire al pubblico |
|
||||
@@ -45,31 +45,9 @@ implementato il [piano delle correzioni](piano-correzioni.md).
|
||||
|
||||
### Robustezza del ciclo di vita
|
||||
|
||||
- **[LIM-01]** **Lo stato `drawing` non riprende dopo un errore o un
|
||||
riavvio.** Lo scheduler gestisce `open`, `closing` e `paying_out` a ogni giro
|
||||
e salta `drawing`; l'attesa del blocco (`_wait_for_draw_block`) vive solo
|
||||
dentro la chiamata a `_close_and_draw` che l'ha avviata (altezza, elenco e
|
||||
segreto sono ormai salvati nel database, ma nulla li rilegge). Non serve un riavvio: **qualunque
|
||||
eccezione** durante l'attesa (un `database is locked` scrivendo una riga di
|
||||
audit, un header malformato) la interrompe, e nessuno la riprende. Il terzo
|
||||
audit (2026-08-03) lo ha ribadito come problema **critico**, la revisione
|
||||
del 2026-09-28 lo ha numerato (B-81).
|
||||
- *Impatto:* il round resta in `drawing` per sempre con il montepremi dentro;
|
||||
poiché un nuovo round si apre solo a round chiuso, **l'intera lotteria si
|
||||
ferma**. Con `restart: unless-stopped` un crash in quella finestra è
|
||||
esattamente il caso che non si ripara da solo.
|
||||
- *Mitigazione attuale:* l'attesa è osservabile — log periodici, evento
|
||||
`draw_stalled` dopo 360s (e poi a ogni intervallo), `draw_waiting_since` su
|
||||
`GET /rounds/current`. Il recupero è manuale (vedi
|
||||
[operativita.md](operativita.md)).
|
||||
- *Stato:* da chiudere con B-81.
|
||||
- *Per chiuderlo:* al passaggio in `drawing` si salvano `draw_height`,
|
||||
`participants_hash` e la posizione di estrazione di ogni partecipante;
|
||||
`_tick` rientra nell'attesa per un round in `drawing`, in modo idempotente.
|
||||
Con l'altezza fissa e il seme impegnato di [ADR-24](adr/ADR-24-l-estrazione-commit-reveal-fra-server.md)/[ADR-25](adr/ADR-25-blocco-estrazione-fissato-altezza-successivo-chiusura.md), un'estrazione
|
||||
ripresa dà sempre lo stesso vincitore.
|
||||
|
||||
*Codice:* `app/rounds/scheduler.py:RoundScheduler._tick` · `app/rounds/scheduler.py:RoundScheduler._close_and_draw` · `app/rounds/scheduler.py:RoundScheduler._wait_for_draw_block`
|
||||
- ~~[LIM-01]~~ Rimosso: chiuso da B-81. Un round in `drawing` riprende da solo
|
||||
dopo un errore o un riavvio, con lo stesso blocco, gli stessi partecipanti e lo
|
||||
stesso vincitore ([RND-36](ciclo-di-vita-del-round.md)).
|
||||
|
||||
- **[LIM-02]** **L'RBF gestisce una sola forma di transazione**: un'unica uscita
|
||||
di resto verso il mittente, abbastanza grande da assorbire l'aumento. Non c'è
|
||||
|
||||
+21
-50
@@ -200,8 +200,8 @@ denaro di oggi.
|
||||
*dopo* il backup non sono tra i partecipanti, ma i loro soldi sono nel
|
||||
montepremi: annotarli per un rimborso manuale (nessuna procedura
|
||||
supportata, vedi [OPS-24]);
|
||||
- un round in `drawing` **non va mai sbloccato con [OPS-13]** prima di
|
||||
questo controllo: se è già stato pagato, va chiuso come sopra.
|
||||
- un round in `drawing` va controllato allo stesso modo prima di far
|
||||
ripartire l'app: se è già stato pagato, va chiuso come sopra.
|
||||
Annotare ogni modifica (data, id, motivo): nessuna lascia una riga di
|
||||
audit.
|
||||
7. **Controllare gli indirizzi riassegnabili** con [OPS-28], sempre ad app
|
||||
@@ -320,10 +320,7 @@ modifica di `.env` e da solo dopo un crash (`restart: unless-stopped`).
|
||||
*Codice:* `app/rounds/scheduler.py:RoundScheduler._tick`,
|
||||
`app/rounds/scheduler.py:RoundScheduler._retry_payout_if_due`,
|
||||
`app/tx/reconcile.py:reconcile_once` ·
|
||||
*Test:* `tests/unit/test_scheduler.py`, `tests/unit/test_reconcile.py`
|
||||
*Stato:* da implementare (B-81) · *Oggi:* un round in `drawing`
|
||||
**non riprende**: resta in `drawing` per sempre e nessun nuovo round si apre
|
||||
(serve [OPS-13]).
|
||||
*Test:* `tests/unit/test_scheduler.py`, `tests/unit/test_reconcile.py`, `tests/unit/test_draw_proof.py`
|
||||
|
||||
- **[OPS-10]** **Riavvio sicuro e deploy** (nuova versione, modifica di
|
||||
`.env`, rotazione di un segreto):
|
||||
@@ -353,7 +350,7 @@ modifica di `.env` e da solo dopo un crash (`restart: unless-stopped`).
|
||||
deploy è quindi, per il codice, un crash: durante `drawing` blocca il round
|
||||
([OPS-13]), durante un invio lascia una riga `building`. Dopo B-93 l'arresto
|
||||
chiude gli stream e le attività entro 30 secondi; il riavvio
|
||||
durante `drawing` diventa sicuro con B-81 ([OPS-09]).
|
||||
durante `drawing` è sicuro dopo B-81 ([OPS-09]).
|
||||
|
||||
La pausa non blocca scommesse e prelievi sul round in corso, né
|
||||
registrazioni e depositi.
|
||||
@@ -444,8 +441,7 @@ con `docker compose logs app` ([architettura.md](architettura.md) ARC-09).
|
||||
4. Se i server configurati sono davvero tutti inutilizzabili, aggiungerne
|
||||
altri in `ELECTRUM_FALLBACK_SERVERS` (elenco di riferimento:
|
||||
`ChainProfiles.Mainnet.BootstrapServers` del repository PalladiumWallet) e
|
||||
riavviare. **Se un round è in `drawing`, oggi il riavvio lo blocca**:
|
||||
seguire poi [OPS-13].
|
||||
riavviare. Un round in `drawing` riprende da solo dopo il riavvio ([OPS-13]).
|
||||
*Codice:* `app/electrum/listener.py:ElectrumListener.run`,
|
||||
`app/electrum/listener.py:ElectrumListener._keepalive`,
|
||||
`app/api/routes/bets.py`, `app/api/routes/withdrawals.py` ·
|
||||
@@ -477,50 +473,25 @@ con `docker compose logs app` ([architettura.md](architettura.md) ARC-09).
|
||||
sale (Electrum, vedi [OPS-11]);
|
||||
- righe `draw_header_corroboration_failed`, una per blocco: i blocchi
|
||||
arrivano ma gli altri server non li confermano (vedi [OPS-12]);
|
||||
- **nessuna riga nuova e nessun messaggio `still waiting for a block` nel
|
||||
log**: l'attesa non è più in corso. Succede dopo un riavvio del processo,
|
||||
oppure dopo un'eccezione durante l'attesa (messaggio
|
||||
`round scheduler tick failed`, per esempio un database bloccato mentre si
|
||||
scriveva `draw_stalled`). In questo caso il round non si sbloccherà mai da
|
||||
solo.
|
||||
- nessuna riga nuova per più di qualche minuto, con `round scheduler tick
|
||||
failed` nel log: un'eccezione durante l'attesa (per esempio un database
|
||||
bloccato mentre si scriveva `draw_stalled`) ha interrotto il passo. Non
|
||||
richiede un intervento: dal passo successivo (5 secondi) lo scheduler
|
||||
riprende l'estrazione dello stesso blocco ([RND-36]); se l'eccezione si
|
||||
ripete, la causa è nella riga di log che la accompagna.
|
||||
|
||||
**Causa.** L'attesa del blocco di estrazione vive solo dentro la chiamata
|
||||
dello scheduler che ha portato il round in `drawing`; a ogni ciclo successivo
|
||||
lo scheduler vede `drawing` e non fa nulla. Nessun codice riprende l'attesa.
|
||||
Dopo B-81 lo scheduler riprende da solo un round in `drawing` e il terzo
|
||||
caso scompare.
|
||||
**Causa.** L'attesa del blocco di estrazione è un passo dello scheduler che
|
||||
rilegge tutto dal database. Dopo un riavvio o un'eccezione riparte da sola:
|
||||
`draw_height`, elenco, `participants_hash` e segreto sono già salvati dal
|
||||
passaggio in `drawing`, quindi l'estrazione ripresa dà lo stesso vincitore
|
||||
(B-81).
|
||||
|
||||
**Cosa fare.** Nei primi due casi basta risolvere la causa (Electrum,
|
||||
server di riserva): l'estrazione avviene da sola al primo blocco valido.
|
||||
Nel terzo caso **non esiste una procedura supportata dal codice**. L'unico
|
||||
intervento possibile è una modifica manuale del database che riporti il round
|
||||
a `closing`, lo stato da cui lo scheduler rifà l'estrazione da capo.
|
||||
**Vale solo per un round bloccato nell'istanza in esercizio: un round in
|
||||
`drawing` arrivato da un backup ripristinato si tratta con [OPS-07],
|
||||
passo 6**, perché potrebbe essere già stato pagato.
|
||||
|
||||
1. Annotare l'id del round (dal pannello, sezione Round) e controllare che
|
||||
sia davvero in `drawing` e che `winner_user_id` sia vuoto.
|
||||
2. `docker compose stop app`.
|
||||
3. Aggiornare lo stato:
|
||||
```bash
|
||||
docker compose run --rm --no-deps app python -c "import sqlite3; c=sqlite3.connect('/app/db_data/plm_lottery.db'); n=c.execute(\"UPDATE rounds SET status='closing' WHERE id=<ID> AND status='drawing' AND winner_user_id IS NULL\").rowcount; c.commit(); print(n, 'riga aggiornata')"
|
||||
```
|
||||
Deve stampare `1 riga aggiornata`.
|
||||
4. `docker compose start app`.
|
||||
5. Al primo ciclo lo scheduler rilegge i partecipanti confermati, riporta il
|
||||
round in `drawing` con un nuovo `drawing_started_at` e aspetta un blocco
|
||||
successivo all'altezza *attuale*; poi estrae e paga normalmente
|
||||
(`winner_drawn`, `payout_sent`).
|
||||
|
||||
Conseguenze da sapere: l'estrazione usa un blocco successivo al momento
|
||||
dello sblocco invece del primo blocco dopo la chiusura, quindi quale blocco
|
||||
decide il vincitore dipende da quando l'operatore interviene; la modifica non
|
||||
lascia alcuna riga nel registro di audit, quindi va annotata altrove, con
|
||||
data, id del round e motivo. I partecipanti non cambiano: il round è fuori da
|
||||
`open`, quindi nessuna scommessa nuova può entrare.
|
||||
**Cosa fare.** Risolvere la causa visibile (Electrum, server di riserva):
|
||||
l'estrazione avviene da sola al primo blocco valido. **Non** riportare il
|
||||
round a `closing` a mano: cambierebbe il blocco che decide il vincitore, e
|
||||
non serve più.
|
||||
*Codice:* `app/rounds/scheduler.py:RoundScheduler._tick`,
|
||||
`app/rounds/scheduler.py:RoundScheduler._close_and_draw`,
|
||||
`app/rounds/scheduler.py:RoundScheduler._complete_draw`,
|
||||
`app/rounds/scheduler.py:RoundScheduler._wait_for_draw_block`
|
||||
|
||||
### Round bloccato in `closing`
|
||||
|
||||
+3
-3
@@ -229,7 +229,7 @@ cifrava di nuovo il file sbagliato (vedi [operativita.md](operativita.md)).
|
||||
| B-78 | Una transazione viene abbandonata sulla base del silenzio di un solo server | Critica | *da registrare* | `test_reconcile_proof.py`, `test_reconcile.py`, `test_pause_reason.py`, `test_migrations.py` | TX, ELC |
|
||||
| B-79 | Il pagamento di norma non ha resto, quindi non si può accelerare e può bloccare la lotteria | Critica | **aperto** | — | RND, TX |
|
||||
| B-80 | Un solo indirizzo del montepremi per tutti i round | Critica | *da registrare* | `test_round_pool_address.py`, `test_pending_address.py`, `test_scheduler.py` | RND, BET, WDR |
|
||||
| B-81 | `drawing` resta bloccato dopo qualsiasi eccezione, non solo dopo un riavvio | Critica | **aperto** | — | RND |
|
||||
| B-81 | `drawing` resta bloccato dopo qualsiasi eccezione, non solo dopo un riavvio | Critica | *da registrare* | `test_draw_proof.py` | RND |
|
||||
| B-82 | Un deposito annullato da una riorganizzazione dopo la scommessa rende il round impagabile; coinbase accreditate a 1 conferma | Critica | **aperto** | — | DEP, RND |
|
||||
| B-83 | Conferme e reintegri si basano solo sul server attivo | Alta | *da registrare* | `test_confirmation_proof.py`, `test_confirmation.py` | ELC, TX, DEP |
|
||||
| B-84 | Il quorum può ridursi a un solo server o a nessuno senza avvisi; certificati TLS non verificati | Alta | *da registrare* | `test_electrum_client.py`, `test_electrum_listener.py` | ELC, SEC |
|
||||
@@ -252,9 +252,9 @@ cifrava di nuovo il file sbagliato (vedi [operativita.md](operativita.md)).
|
||||
|
||||
- **Corretti:** B-01 … B-70, tranne B-16, che è chiuso nella sostanza (il
|
||||
crash è eliminato e `/guida` serve un segnaposto) ma lascia la guida vera
|
||||
come limite accettato; dalla revisione del 2026-09-28: B-88, B-75, B-97, B-80, B-84, B-76, B-77, B-78, B-83, B-74, B-85, B-86, B-73.
|
||||
come limite accettato; dalla revisione del 2026-09-28: B-88, B-75, B-97, B-80, B-84, B-76, B-77, B-78, B-83, B-74, B-85, B-86, B-73, B-81.
|
||||
- **Aperti:** B-71, B-72 (gravità bassa, operativi o di documentazione) e
|
||||
B-73 … B-98 dalla revisione del 2026-09-28 tranne i corretti (3 critici,
|
||||
B-73 … B-98 dalla revisione del 2026-09-28 tranne i corretti (2 critici,
|
||||
4 alti, 6 medi), da implementare nell'ordine di
|
||||
[piano-correzioni.md](piano-correzioni.md).
|
||||
- **Prossimo numero libero:** `B-99`.
|
||||
Reference in new issue
Block a user