Real SQLite transactions: BEGIN IMMEDIATE and synchronous=FULL (B-88, DAT-74, DAT-52, ARC-07, TX-28, BET-11, DAT-16)

pysqlite's legacy mode emitted BEGIN only at the first DML, so every read
before it ran outside any transaction and a lock wait surfaced as "database is
locked" at an arbitrary later statement; place_bet also mistook that error for
a write-snapshot conflict, which SQLite cannot produce.

- _register_sqlite_pragmas: synchronous=FULL, isolation_level=None and a
  `begin` event that emits BEGIN / BEGIN IMMEDIATE.
- begin_immediate(session): takes the write lock before the first read; called
  first thing in place_bet, request_withdrawal, the scheduler transitions,
  _trigger_payout, the confirmation poller, the reconciler, bump_fee's persist
  phase, deposit crediting / external-spend marking / reinstating, and the
  derivation-index allocation at registration.
- A lock not granted before a broadcast answers service_busy (503, all seven
  languages), nothing built or sent; after a broadcast nothing is undone, the
  rows stay `building` for the reconciler.
- Spec, storico, BUGS.md and CLAUDE.md updated; 37 new tests on a real file DB.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
davideandClaude Sonnet 5.5 committed 2026-09-29 16:26:01 +02:00
1 parent 4be58709d1
commit 7ba8e22bb4
25 files changed
+1165 -82

No files matched your search

+2 -4
View File
@@ -354,10 +354,8 @@ Formato di ogni voce: **decisione** in grassetto, poi *Motivazione*,
invariante che non dipende dal processo singolo è «al più un round
attivo», garantito da un indice ([DEC-22]).
*Codice:* `app/db/base.py:_register_sqlite_pragmas` · `app/tx/locks.py:UserLocks` · `app/rounds/events.py:RoundEventBroadcaster` ·
*Test:* `tests/unit/test_db_base.py`
*Stato:* da implementare (B-88) · *Oggi:* `synchronous=NORMAL` e `BEGIN`
emesso solo alla prima scrittura (modalità legacy di pysqlite).
*Codice:* `app/db/base.py:_register_sqlite_pragmas` · `app/db/base.py:begin_immediate` · `app/tx/locks.py:UserLocks` · `app/rounds/events.py:RoundEventBroadcaster` ·
*Test:* `tests/unit/test_db_base.py` · `tests/unit/test_sqlite_transactions.py`
### Economia del gioco