bug(bilan) : « database is locked » lors de la proposition des comptes standards (proposeStarterAccounts) #258
Labels
No labels
autopilot:pending-human
source:analyste
source:defenseur
source:human
source:medic
status:approved
status:blocked
status:in-progress
status:needs-clarification
status:needs-fix
status:ready
status:review
status:triage
type:bug
type:feature
type:infra
type:refactor
type:schema
type:security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: maximus/Simpl-Resultat#258
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Symptôme
Erreur « database is locked » lors du script de proposition/migration de la hiérarchie de comptes standard (Compte chèque, CELI, REER, Compte non-enregistré) dans le module Bilan.
Piste (à confirmer via /analyze)
proposeStarterAccounts(src/services/balance.service.ts:703) est wrappé danswithTransaction(l.708), maisproposeStarterAccountsInTransaction(l.713) émet AUSSIawait db.execute("BEGIN")(l.720). À vérifier : BEGIN imbriqué ou transaction non refermée → connexion strandée du pool sqlx = verrou zombie. Même classe de bug que le fix v0.10.1 (sérialisationwithTransaction, jamais dedb.execute("BEGIN")brut concurrent). Vérifier aussi le second site l.1507/1524.Reproduction (à préciser)
Déclencher la proposition de comptes standards (StarterAccountsModal). Scénario exact à confirmer : profil vide, après un abandon, ou enchaînement rapide ?
Fichiers
src/services/balance.service.ts—proposeStarterAccounts/proposeStarterAccountsInTransaction(l.703-720+)src/components/balance/StarterAccountsModal.tsxsrc/components/balance/StarterAccountsModal.test.tsx(régression obligatoire)Note
type:bug → test de régression requis.
/analyzerecommandé avant fix pour confirmer la cause racine.Fermé — déjà corrigé, pas de bug résiduel. (Investigation code sur
main@ v0.12.0.)La piste « BEGIN imbriqué » est une mauvaise lecture.
withTransaction(src/services/db.ts) n'émet aucunBEGIN— il tient le verrou FIFO et pose le flaginTransaction=truependant le callback (docstring : « fn is responsible for issuing BEGIN/COMMIT »). Ledb.execute("BEGIN")deproposeStarterAccountsInTransaction(balance.service.ts:720) est donc le seul BEGIN, pas un second.Preuve par cohérence :
upsertSnapshotLines(:1507→1524) etsaveSnapshotAtomic(:1595→1610) utilisent exactement le même patternwithTransaction((db) => …InTransaction(db))avec BEGIN/COMMIT dans le callback. Si ce pattern double-BEGIN-ait, chaque sauvegarde de snapshot deadlockerait — ce n'est pas le cas. Le proxydb.tsbypasse d'ailleurs le verrou quandinTransaction===true, donc pas de self-deadlock (couvert pardb.test.ts:89-114).Le vrai « database is locked » (stranding de connexion sur le pool sqlx multi-connexions) a été fermé en v0.10.1 (commit
8cb7e53, sérialisation viawithTransaction) — présent dansv0.11.0etv0.12.0(git tag --contains 8cb7e53). Avant le fix (≤ v0.10.0),getDb()renvoyait le handle brut du pool → BEGIN et COMMIT pouvaient frapper des connexions différentes → transaction strandée = verrou zombie. Le pattern actuel est correct : ne pas rendrewithTransactionréentrant ni retirer le BEGIN interne.L'absence de repro en 0.12.0 est cohérente : le code tourné a le fix, et il n'y a aucun nesting résiduel.
Point latent (hors scope, non bloquant) : le garde
inTransactionest un booléen global, pas un compteur → une requête simple dispatchée par du code non lié pendant unwithTransactionen cours liraittrueet bypasserait le verrou. Pas un reproducteur pour ce chemin (profil vide = quasi aucune activité DB concurrente pendant la transaction), mais à traiter dans une issue dédiée si on veut blinder la sérialisation.