ARCH-008. `role` est le discriminateur polymorphe, et SQLAlchemy fixe la
classe d une instance au chargement. edit_user ecrivait donc la colonne par
un UPDATE de niveau instruction puis relisait la ligne -- c est correct.
La suite ne l etait pas.
db.session.commit()
db.session.remove() # discard stale session entirely
user = User.query.get(user_id_local)
Deux defauts dans ces trois lignes.
1. remove() jette la session entiere. Tout ce que la requete tenait encore
se retrouvait detache, current_user compris ; le moindre acces a un
attribut ensuite levait DetachedInstanceError. La route ne survivait
qu en ayant recopie le nom et l id de l acteur dans des variables
locales avant -- un contournement, pas la correction. Un expunge de la
seule instance perimee suffit.
2. Le commit intermediaire coupait l edition en deux. Le role etait acquis
avant que le reste du formulaire soit applique : une erreur ensuite
laissait un compte promu et le reste perdu, sans qu aucune interface ne
le signale. Sans ce commit, l UPDATE reste dans la transaction, la
relecture le voit, et l ensemble part en un seul commit.
Les evenements d audit passent apres le commit. account.role_changed etait
journalise avant l UPDATE : le journal affirmait un changement que la
transaction pouvait encore annuler.
tests/test_role_change.py, 6 tests. Un seul echoue sur le code d avant --
celui de l atomicite ; les cinq autres fixent le comportement qui marchait
deja, pour que la suite de la vague D ne le casse pas.
Co-Authored-By: Claude Opus 5 <[email protected]>