Tiroir Comments
- Section « Reactions » au-dessus des fils : émoji, compte (si >1) et texte
ancré lu dans le DOM (reactionList() / _anchorText(), offsets source hors
pastilles) ; l'état vide ne s'affiche plus s'il reste des réactions.
- Suppression : ✕ sur la ligne du tiroir (mes réactions) ET croix ::after au
survol de la pastille sur l'émoji que j'ai posé (aucun nœud ajouté → offsets
intacts). Deux entrées → removeReaction() → POST toggle → loadReactions().
Menu de sélection (maquette ASCII)
- Ligne 4 = rangée scannée : 💬 Comment (libellé) à gauche, 🙂+ réaction à
droite (.ft-row-split) ; la réaction sort de la ligne 3.
- Entête Skills avec ≡ à droite (::after), liste Skills scrollable.
- ✨ Ask AI retiré de la toolbar : doublon exact de « Edit with AI » du pied.
- Écart volontaire à la maquette : le barré (T) de la ligne 2 est conservé.
Fix racine (flake de gate)
- _is_public_host attrape OSError (le garde SSRF renvoie un booléen, il ne
lève plus) : un socket.timeout DNS ne bascule plus fetch_og_metadata dans
son except Exception → repli silencieux → AssertionError.
- fixture stub_dns sur TestOGParser (même motif que test_agent_web_tools) :
zéro vrai DNS dans les tests OG.
Tests: pytest tests/ -q -n auto → 1390 passed / 0 failed (flake corrigé) ;
ruff check app tests → OK ; e2e v764 (réactions dans le tiroir + suppression
A/B), v762 (nouvelle ligne 4), v766, v7641, v763 → 6 passed sur :8081
(image flowdeck:v7.67.0 rebuild + redéployée).
- `app/services/http_client.py` : `async with shared_client(timeout=15)
as client:` remplace les 49 créations `async with httpx.AsyncClient(`
de 14 fichiers (gitea ×21, providers oidc/oauth ×11, calendar ×4,
automations ×3…) — le pool de connexions est réutilisé au lieu d'être
recréé à chaque appel. __aexit__ no-op (le client partagé ne se ferme
pas à la sortie).
- Cache par (boucle d'event, kwargs) en WeakKeyDictionary : un
AsyncClient n'est JAMAIS partagé entre deux loops (piège des tests
« Event loop is closed ») — une boucle par test = client propre
collecté avec la boucle. Clé = kwargs triés, repr() pour les valeurs
non hashables (`headers=` dict → TypeError rattrapé par la suite).
- Laissés délibérément : github_adapter (transport MockTransport
injecté), webhook_outbound (client « own_client » fermé par la
fonction).
- Tests : `test_http_client_shared_and_loop_scoped` (réutilisation mêmes
kwargs / cloisonné kwargs / cloisonné loop) ; le stub des webhooks
patche aussi la fabrique `http_client.httpx` + purge du cache (avant :
webhook_outbound.httpx patché mais la fabrique partagée créait un vrai
client → réseau réel dans les tests).
suite **1091/1091** · ruff OK · docs à jour