Skip to content

OctoGuard : le cran « Retenir » et Signalements dans OctoGuard (lot 2) - #951

Merged
Pokled merged 3 commits into
mainfrom
feat/octoguard-retenir
Nov 7, 2026
Merged

Pokled merged 3 commits into
mainfrom
feat/octoguard-retenir

Conversation

@Pokled

@Pokled Pokled commented Nov 7, 2026

Copy link
Copy Markdown
Owner

Remplace #948, fermée automatiquement par GitHub quand la branche de #947 a été supprimée à la fusion. Même code, reposé sur main (arbre identique, vérifié par git diff).

Lot 2 de la mise en conformité avec la maquette validée (CDC E4h, D17 validée le 04/11).

Ce que ça change

Le 5e cran, Retenir, entre Signaler et Avertir. Le message n'est pas publié : son auteur le voit « en attente de validation », personne d'autre ne le voit. L'équipe l'approuve (il est publié pour de vrai) ou le refuse. Sans décision au bout de 72 h, il est refusé et l'auteur est prévenu.

  • Chat, réponse du forum, nouveau fil, modification d'un message.
  • Profils, sondages et wiki n'ont pas d'attente : à ces endroits la règle signale, et l'écran de la règle le dit.
  • L'auteur ne voit jamais le nom de la règle (D20).

Signalements entre dans OctoGuard, avec la page à trois colonnes de la maquette (la file, le contenu, la décision) et les onglets À traiter, À relire, Traités. L'ancienne adresse /admin/reports y mène. Le compteur rouge du menu compte aussi les messages à relire. La conversation autour et l'historique des modifications arrivent au lot 3, dans cette même page.

Modèles : Jeunesse retient les liens des comptes neufs et Jeu compétitif retient les invitations, comme le montre la maquette.

Conception

Un contenu retenu n'est jamais écrit dans channel_messages, posts ou threads. Il attend dans octoguard_held (migration 131) et n'est publié qu'à l'approbation, par les mêmes modèles que la publication normale. Aucune lecture existante (historique, recherche, mentions, aperçus, notifications) n'a donc à être filtrée : rien ne peut fuiter.

La décision est atomique (UPDATE ... WHERE status = 'pending' RETURNING) : deux membres de l'équipe qui cliquent en même temps ne publient qu'une fois. On ne relit pas son propre contenu, et le garde-fou de rang est le même que pour les signalements.

Deux trous trouvés au banc d'essai, présents avant cette PR

Le moteur lisait l'aperçu des signalements au lieu du texte complet du forum et du wiki :

  1. un lien caché derrière un texte (« ici ») échappait aux règles de liens ;
  2. tout ce qui suivait les 1000 premiers caractères n'était pas lu.

Corrigé par textForModeration. Le test de régression tombe sur l'ancien code.

Preuves

  • Cœur : 1373 tests, dont 20 nouveaux sur Retenir.
  • Frontend : 411 tests, 0 erreur de types, les 5 portes i18n vertes (fr et en).
  • SQL : toutes les requêtes de Retenir passées dans un vrai PostgreSQL (PGlite), migration 131 idempotente.
  • Bout en bout, sur un banc jetable (cœur de la branche, PostgreSQL PGlite, Redis séparé, aucune donnée de production) :
    • 28 vérifications HTTP et socket : chat, file, double clic, refus, nouveau fil, réponse ;
    • 5 vérifications pour la modification retenue (l'ancien texte reste en ligne jusqu'à la décision) ;
    • 19 vérifications dans un vrai navigateur, captures en clair, en sombre et au format téléphone, zéro erreur JS ;
    • les 5 modèles passent l'aperçu du vrai cœur.

Lot 2 de la mise en conformité avec la maquette validée (CDC E4h, D17).

Le 5e cran, entre Signaler et Avertir. Un contenu retenu n'est jamais écrit
dans channel_messages, posts ou threads : il attend dans octoguard_held
(migration 131), invisible de tous sauf de son auteur (« en attente de
validation ») et de l'équipe. Il n'est publié qu'à l'approbation, par les
mêmes modèles que la publication normale. Rien à filtrer dans les lectures
existantes (historique, recherche, mentions, aperçus), donc rien ne fuit.

- Chat, réponse du forum, nouveau fil et modification d'un message.
  Profils, sondages et wiki n'ont pas d'attente : la règle y signale, ce
  que l'écran de la règle annonce.
- Décision atomique (UPDATE ... WHERE status = 'pending') : deux clics
  simultanés ne publient qu'une fois. On ne relit pas son propre contenu,
  garde-fou de rang comme pour les signalements.
- D17 : sans décision au bout de 72 h, refus automatique, l'auteur est
  prévenu (en direct et par notification). L'auteur ne voit jamais le nom
  de la règle (D20).
- Signalements rejoint OctoGuard (page à trois colonnes de la maquette) :
  À traiter, À relire, Traités. L'ancienne adresse /admin/reports y mène.
  Le compteur du menu compte aussi les messages à relire.
- Modèles : Jeunesse retient les liens des comptes neufs, Jeu compétitif
  retient les invitations, comme la maquette.

Deux trous trouvés au banc d'essai, présents avant ce lot, corrigés :
le moteur lisait l'aperçu des signalements au lieu du texte du forum et
du wiki, donc un lien caché derrière un texte (« ici ») échappait aux
règles de liens, et tout ce qui suivait les 1000 premiers caractères
n'était pas lu (textForModeration).
- Déni de service : le lecteur du texte du forum (textForModeration)
  tournait sur le contenu brut, avant nettoyage, avec des expressions
  régulières qui reviennent en arrière. 40 000 « <a href> » jamais fermés
  bloquaient tout le cœur plus de deux minutes. Réécrit en un passage :
  880 ms pour 480 Ko, et le cœur répond aux autres pendant ce temps.
  Même durcissement pour le lecteur de l'écran de l'équipe.
- Le moteur lit désormais tout le message (avant : 1000 caractères).
  Mesuré : 90 ms au pire pour les 7 règles sur 500 Ko hostiles.
- Inondation de la file : 5 contenus en attente au plus par auteur, la
  limite est dans la requête d'insertion. Au-delà, refus avec un motif.
- Jamais de publication sur un échec : si la mise en attente échoue, le
  contenu est refusé (avant, chat et forum le publiaient).
- Approuver ne contourne plus un bannissement ni un verrouillage
  intervenus depuis (409 AUTHOR_BANNED / THREAD_LOCKED).
- Le texte d'un contenu refusé ou expiré est effacé 30 jours après la
  décision (le journal garde l'extrait).
- Forum : une modification refusée par OctoGuard ne ferme plus l'éditeur
  en silence en perdant le texte ; le motif s'affiche.
Relecture du 07/11, avant fusion.

- La publication d'un contenu retenu enchaînait plusieurs écritures sans
  transaction. Une erreur APRÈS la création (points de réputation,
  notification, étiquettes, cache) faisait croire que rien n'était publié :
  le contenu repassait en attente et une seconde approbation le publiait
  deux fois. Désormais, dès que le message ou le fil existe, la publication
  est acquise ; le reste est fait au mieux et journalisé s'il échoue.
- Un nouveau fil dont le premier message échoue est retiré : plus de fil
  vide laissé derrière.
- Le résumé envoyé à l'auteur est borné avant toute expression régulière.
- Signalements : « À traiter » vide alors que des messages attendent dans
  « À relire » (le compteur du menu les compte) : la page le dit et y mène.
  Trouvé en testant le parcours d'un modérateur.
@Pokled
Pokled merged commit 284ee74 into main Nov 7, 2026
10 checks passed
@Pokled
Pokled deleted the feat/octoguard-retenir branch November 7, 2026 16:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant