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).
- Réaction sur texte : bouton 🙂+ (« React to selected text ») dans la toolbar
de sélection → sélecteur d'émoji EXISTANT en mode réaction (en-tête = texte
sélectionné + ✋, onglets masqués, ligne Recent au-dessus de la grille
People, Filter… et barre de catégories avec + custom inchangés)
- Backend : migration 37 text_reactions (UNIQUE plage × emoji × utilisateur →
POST idempotent) + GET/POST /api/pages/{id}/reactions (GET groupé par plage
emoji/count/mine, POST toggle, 400 sur plage vide)
- Affichage : plage commentée/réagie peinte en jaune (_paintAnchors après
render/loadComments/loadReactions), pastille 😀+compte après la plage, clic
pastille = rouvrir le sélecteur, clic ancre = ouvrir et centrer le fil
- Pastilles = annotations : gtTok/gtMd les ignorent (y compris le chemin
rapide innerText) et les offsets _srcOffset/_srcNodeLen les excluent → le
texte sauvé est identique (vérifié dans le e2e)
- Tiroir refondu : carte de fil (avatar, nom, horodatage, ✓ toggle
resolve/reopen, ⋯ → Copy link #cmt-<id>/Delete), saisie « Add a comment... »
avec @ et envoi ↑/Entrée ; #cmt-<id> ouvre et centre le fil au chargement ;
loadComments + loadReactions à l'ouverture (commentCount enfin renseigné)
- Fixes : resolveComment ne pouvait pas rouvrir (toujours resolved:true) ;
showCommentBtn ignorait les sélections à ancre élément (bouton 💬 jamais
affiché)
- Tests : tests/test_v764_comments_reactions.py (8, dont toggle API réel),
e2e/v764_comments_reactions.spec.js (8 étapes) — 3/3 specs e2e verts,
suite complète 1383 passed / 0 failed, ruff OK, OpenAPI 7.64.0 (526 chemins)