- Les 36 routes d'api_v2 dont le SEUL `await` était
`body = await request.json()` (bloc try/except uniforme) → paramètre FastAPI
`body: dict = Body(default={})` + conversion en `def` → threadpool :
toute leur séquence SQLite quitte l'event loop.
- Équivalences vérifiées avant engament (probe FastAPI) :
· corps absent → `{}` (identique à l'ancien try/except)
· JSON invalide → 422 (avant : avalé comme `{}` — 422 est plus juste)
· zéro `body[...]=` / setdefault / update dans api_v2 → défaut partagé
jamais muté
- verify_webhook_signature (signature multi-ligne) traitée à la main.
- Piège courant évité : première version du script supprimait 5 lignes au
lieu de 4 (slice m-1:m+4) → fichier restauré depuis git, slice corrigée,
0 ligne perdue (diff logique +39/-183).
api_v2 : 96/115 routes hors loop (60 phase 1 + 36 ici) ; 19 async restantes
(fire_event, request.form, gitea/webhooks) = phase 2b.
suite **1037/1037** (242 s) · `ruff check app tests` OK · docs à jour