Journal des mises à jour

Les nouveautés du bot

Tout ce qui change, version après version : nouveaux jeux, améliorations et corrections.

3 version(s) publiée(s)Page mise à jour le 17/10/2026 à 19:14

Dernières versions


🗒️ Patch note — IA & Jeux

Version 7.15 · _16 octobre 2026_ — 🐱 Des GIF de chats au bot IA (CATAAS, sans clé) Version 7.14 · _16 octobre 2026_ — 👑 « Qui t'a créé ? » : il nomme Mattsou, en mystifiant un peu Version 7.13 · _16 octobre 2026_ — 🤐 Introvert'AI garde son moteur secret Version 7.12 · _15 octobre 2026_ — 🧯 Le dashboard ne sert plus d'ancien script (invitation et adresses réparées) Version 7.11 · _15 octobre 2026_ — 🔗 Toutes les adresses du bot, en liens cliquables (dans l'administration) Version 7.10 · _15 octobre 2026_ — 🚀 Inviter les trois bots depuis l'administration (avec le choix des permissions) Version 7.9 · _15 octobre 2026_ — 🎫 L'assistant des tickets rejoint Introvert'AI (une commande réservée au staff) Version 7.8 · _15 octobre 2026_ — 🔌 Six API externes pour l'IA, et trois pages publiques sur Internet Version 7.7 · _15 octobre 2026_ — ⏱️ Numingo : le chrono démarre au clic sur « Deviner » Version 7.6 · _15 octobre 2026_ — 🗣️ « Qui es-tu ? » : il dit la vérité, et le silence n'obéit qu'à ceux qui le visent Version 7.5 · _15 octobre 2026_ — 🧭 Le dashboard sépare les trois bots, avec leur statut dans le menu Version 7.4 · _15 octobre 2026_ — 🤖 Introvert'AI : un troisième bot, sa version et son monitoring Version 7.3 · _15 octobre 2026_ — 🧭 « Mes serveurs » épuré & messages « à chaque nouveau message » Version 7.2 · _15 octobre 2026_ — 🎂 /anniversaire : les dates des membres, et les vœux à 8 h Version 7.1 · _15 octobre 2026_ — 🌍 L'IA parle votre langue, traduit et corrige sans faute Version 7.0 · _15 octobre 2026_ — 🫱 Vérification : salon privé par membre, 5 minutes, auto-suppression Version 6.9 · _14 octobre 2026_ — 🛡️ Anti-triche de la Roulette, sélecteur de salons & règles de Numingo Version 6.8 · _14 octobre 2026_ — 🎡 Roulette de la Vérité : tirage simplifié Version 6.7 · _14 octobre 2026_ — 🎯 Numingo en 1 minute, récompensé en XP, et une IA qui connaît sa version Version 6.5 · _14 octobre 2026_ — 🏷️ L'IA retient les surnoms et sait dans quel salon elle parle Version 6.4 · _14 octobre 2026_ — 🛠️ Signalements : les sanctions sont vraiment appliquées (ban, kick, mute, durées) Version 6.3 · _14 octobre 2026_ — 🧭 Le dashboard devient un vrai centre de pilotage (modules, tickets, casier) Version 6.2 · _14 octobre 2026_ — 🏷️ Bans actifs : le pseudo s'affiche enfin (avec l'ID) Version 6.1 · _14 octobre 2026_ — 📱 Le classement XP devient responsive Version 6.0 · _14 octobre 2026_ — 🔐 Le bot devient privé : whitelist des serveurs (fini le blocage par IP) Version 5.9 · _14 octobre 2026_ — ⏱️ Roulette de la Vérité : 20 minutes pour répondre Version 5.8 · _14 octobre 2026_ — 😂 une commande réservée au staff, souvenirs d'hier & caisse cachée Version 5.7 · _14 octobre 2026_ — 🧘 Côtés introvertis, salutations ignorées & Roulette plus juste Version 5.6 · _13 octobre 2026_ — 🗑️ Salon des sanctions : le titre ne cite plus la commande Version 5.5 · _13 octobre 2026_ — 💬 Messages simples, « tais-toi » et une commande réservée au staff Version 5.4 · _13 octobre 2026_ — 🏷️ Le bot dit « Les introvertis » (fini le QG) Version 5.3 · _13 octobre 2026_ — 📄 route_infinie.sql enfin importable (MySQL & MariaDB) Version 5.2 · _13 octobre 2026_ — 🗂️ une commande réservée au staff réparée : bon salon + recherche profonde Version 5.1 · _13 octobre 2026_ — 🛣️ La Route de l'Infini survit vraiment au redémarrage Version 5.0 · _13 octobre 2026_ — 🗂️ Supprimer la présentation d'un membre (et le prévenir) Version 4.9 · _13 octobre 2026_ — 🖼️ L'avatar du membre, et « réessaie plus tard » Version 4.7 · _13 octobre 2026_ — ☀️ Il dit bonjour, bonne nuit et bon appétit (et il connaît l'heure) Version 4.6 · _13 octobre 2026_ — 🧠 Il connaît les DYS, le TDAH, le TDI et respecte les identités Version 4.5 · _13 octobre 2026_ — 📊 Il connaît les chiffres du serveur (« combien de membres ? ») Version 4.4 · _13 octobre 2026_ — 🧵 Plusieurs messages à la fois, soutien & rôles (confident, ami, frère, sœur…) Version 4.3 · _13 octobre 2026_ — 👁️ Il comprend les mentions, les profils, les images et les besoins Version 4.2 · _12 octobre 2026_ — 🤝 Il invite ses potes à rejoindre le serveur (sans forcer) Version 4.1 · _12 octobre 2026_ — 👥 Plusieurs personnes à la fois : il ne mélange plus Version 4.0 · _12 octobre 2026_ — 📍 Il ne nomme plus le salon où il répond Version 3.9 · _12 octobre 2026_ — 🎤 Le bot clache façon rap FR (quand il est en colère) Version 3.8 · _12 octobre 2026_ — 🍻 Culture soirée & langage jeune Version 3.7 · _12 octobre 2026_ — 💬 Pas de DM : il renvoie vers le serveur Version 3.6 · _12 octobre 2026_ — 🎯 Roulette : une commande réservée au staff (choisir soi-même le membre) Version 3.5 · _12 octobre 2026_ — ⌛ Roulette : le message de la personne précédente est supprimé Version 3.4 · _12 octobre 2026_ — 👑 « Qui t'a créé ? » → le créateur, en mode dictateur Version 3.3 · _12 octobre 2026_ — 🛡️ Protect : fin du spam d'emojis + salon exempté Version 3.2 · _12 octobre 2026_ — 💛 Humeur chaleureuse, ton compris, et jeu de séduction Version 3.1 · _12 octobre 2026_ — 🛣️ Règles publiées au démarrage Version 3.0 · _12 octobre 2026_ — 😂 Le bot a de l'humour

Résumé : le bot sait faire rire — vannes, punchlines, autodérision, absurde, références pop culture / memes / trends TikTok, anecdotes et **faits insolites**. Il en sort quand on le lui demande, en glisse une de temps en temps quand le moment s'y prête, et retient ses blagues pour ne jamais radoter.


🐱 Version 7.15 — Des GIF de chats au bot IA (CATAAS, sans clé)

Quand la conversation parle de chat, le bon GIF est un chat — et le bot IA (Introvert'AI) le sait désormais. Grâce à CATAAS (Cat as a Service), un service public gratuit et sans clé d'API, il peut poster de vrais GIF de chats, en deux circonstances :

  • à la demande : « envoie un gif de chat », « montre-moi un chat », « un chat

mignon stp » → il en poste toujours un ;

  • spontanément : si la conversation parle de chat (« mon chat fait la

sieste »), il en fait apparaître un de temps en temps (probabilité AI_CATAAS_CHANCE, ≈ 35 % par message concerné).

Ce qui change

OùAvantMaintenant
Demande de chatGIF générique (ou rien, sans clé Tenor)toujours un vrai chat (CATAAS, prioritaire)
Sujet « chat »aucun lien avec les chatsGIF de chat spontané, dosé
Configuration—AI_CATAAS_ENABLED (déf. 1), AI_CATAAS_CHANCE (déf. 0.35)
Sources de GIFTenor / Giphy (clé), nekos.best (repli)+ CATAAS (sans clé, prioritaire sur le sujet chat)

La mécanique

  • 🎯 Priorité au sujet : dès que le message demande ou parle de chat

(ai_cataas), CATAAS est interrogé avant Tenor/Giphy et nekos.best : le résultat est garanti d'être un chat.

  • 🐈 Jamais deux fois le même : l'identifiant du chat servi entre dans le

registre anti-répétition (ai_gif.BUDGET), au même titre que les autres GIF.

  • 🧠 Repérage prudent : « dans le chat » (le salon de discussion) ne

déclenche rien ; « application » (qui contient « cat ») non plus. Seules les formes sans ambiguïté (« mon chat », « un chat mignon », « minou », « chaton », « miaou »…) sont reconnues.

  • 🛑 Les garde-fous restent entiers : aucun chat sur un message de détresse,

un message hostile ou juste après un « tais-toi » ; le GIF accompagne la réponse, il ne la remplace jamais.

  • 🔌 Sans clé, sans dépannage : CATAAS est gratuit et public ; s'il est en

panne, le bot passe aux autres sources (Tenor/Giphy, nekos.best) et répond en texte seul si besoin — rien ne casse.

  • 📊 Traçabilité : chaque chat envoyé est journalisé (ai_media_sent,

👑 Version 7.14 — « Qui t'a créé ? » : il nomme Mattsou, en mystifiant un peu

À « qui t'a créé ? », le bot ne se contente plus de signaler une personne : il prononce son nom, le mentionne (la personne reçoit donc une notification), et le fait avec une pointe de mystère et d'humour — sans jamais rien lâcher sur les origines.

Ce qui change

OùAvantMaintenant
Réponse à « qui t'a créé ? »« mon créateur » + mention, ton dictateur« Mattsou » + mention, ton dictateur et mystère (« certains l'appellent l'Ombre, d'autres le Sauveur… »)
ConfigurationAI_CREATOR_ID seulementAI_CREATOR_ID + AI_CREATOR_NAME (défaut : Mattsou)

La mécanique

  • 🎯 Le nom est imposé au modèle : le prompt lui ordonne d'écrire « Mattsou »

dans sa réponse — il ne peut plus esquiver.

  • 👑 La mention reste posée par le code (jeton {CREATEUR} remplacé à

l'envoi), avec le filet de repli : si le modèle « oublie » le jeton, la mention est ajoutée quand même. Le créateur est notifié à coup sûr.

  • 🎭 Une pointe de mystère : sous-entendus grandiloquents et taquins, pour

garder le personnage — mais jamais de propos politique, jamais de violence, et le nom est toujours prononcé.

  • 🛑 Rien d'autre ne bouge : le ton « dictateur bienveillant », la détection

souple de la question et la désactivation par AI_CREATOR_ENABLED=0 sont inchangés.


🤐 Version 7.13 — Introvert'AI garde son moteur secret

Ce qui fait tourner l'IA — l'entreprise, le modèle, le nombre de services, ceux qui sont limités — est une information d'exploitation. Elle n'a plus aucune raison de sortir, et le bot lui-même ne répond plus à ces questions.

Ce qui change

OùAvantMaintenant
Statut Discord du botune liste des moteursAI service: available / limited / unavailable
une commande réservée au staffnombre de moteurs prêts, liste des indisponiblesétat du service uniquement
une commande réservée au staff, /introvert statutle nom des modèles« Service IA : disponible »
Pages publiques (/nouveautes…)l'historique citait les moteurspassages retirés ou masqués

Si on lui pose la question

À « tu tournes sur quoi ? », « t'es [confidentiel] ? », « quel modèle tu utilises ? »…, le bot répond toujours la même chose, sans consulter aucun modèle :

*« Je suis Introvert'IA, une intelligence artificielle locale, développée et

configurée en interne pour le bien du serveur 🤖 »*

Il ne confirme donc aucun nom, n'en démens aucun, et ne laisse rien deviner : il dit seulement qui il est. Trois autres barrières l'accompagnent : une consigne absolue dans son prompt, un filet qui retire toute phrase trahissant le moteur avant l'envoi, et le masquage de tout ce qui est publié.

Les questions innocentes ne sont pas touchées (« quel modèle de casque ? », « j'adore [confidentiel] gagnant »…). Les journaux de la console, côté exploitant, gardent

Réglage : AI_CONFIDENTIAL=0 coupe la détection des questions et le filet de réponse ; l'affichage (statuts, dashboard, pages publiques) reste protégé.


🧯 Version 7.12 — Le dashboard ne sert plus d'ancien script (invitation et adresses réparées)

Après la 7.10 et la 7.11, l'invitation par identifiant, la détection des serveurs et la liste des adresses ne réagissaient plus. La cause n'était pas le code : derrière le tunnel Cloudflare, app.js et style.css étaient gardés en cache 4 heures. La page (toujours à jour) affichait les nouvelles cartes, mais le navigateur recevait l'ancien script, qui ne savait pas les faire fonctionner — d'où des boutons muets, sans la moindre erreur.

Ce qui change

  • Adresse versionnée. index.html pointe vers app.js?v=… et style.css?v=…,

où la version est la date de modification du fichier : dès qu'un fichier change, son adresse change, et aucun cache existant (Cloudflare compris) ne peut plus servir une ancienne copie.

  • Plus de cache aveugle. /static/.js et /static/.css sont servis en

no-cache : le navigateur revalide à chaque fois, sans retélécharger un fichier inchangé.

  • Une carte en panne n'entraîne plus les autres. Si les statistiques de

l'administration échouent, l'invitation, les adresses et la whitelist se chargent quand même.

À faire une fois : redémarrer le bot, puis recharger la page (Ctrl/Cmd + Maj + R).


🔗 Version 7.11 — Toutes les adresses du bot, en liens cliquables (dans l'administration)

Le dashboard publiait une dizaine d'adresses — pages publiques, mêmes contenus en JSON, supervision, retour OAuth2 — mais aucune ne figurait nulle part : il fallait les retenir, ou fouiller le code. Et surtout, la seule adresse qui compte vraiment est celle qui change à chaque redémarrage quand le bot tourne derrière un tunnel (…trycloudflare.com).

L'Administration porte maintenant une carte **« 🔗 Toutes les adresses du dashboard »**, avec de vrais liens à cliquer et à copier.

Ce qu'on y trouve

GroupeAdresses
🌍 Pages publiques/nouveautes, /introvert-ia, /jeux, /classement (+ les jumelles .html)
🧩 Données JSON/api/nouveautes.json, /api/introvert-ia.json, /api/jeux/classements.json, /api/xp/classement
🔐 Tableau de bord/, /login, /healthz
⚙️ Réglage Discord/callback — l'adresse à déclarer dans le portail développeur

Chaque ligne montre l'intitulé, le chemin, l'adresse complète et deux boutons : Ouvrir (nouvel onglet) et Copier. Un bouton « Copier la liste » met tout en texte, prêt à coller dans un message Discord.

Les détails qui évitent les pièges

  • L'adresse suit le tunnel. Elle est reconstruite à l'instant de l'affichage

depuis l'URL publique courante : les liens restent justes après un redémarrage qui change l'adresse trycloudflare.

  • Une page éteinte est signalée, pas cachée. Avec PUBLIC_PAGES=0 ou

XP_LEADERBOARD_PUBLIC=0, la ligne reste visible, marquée « désactivé », avec la variable exacte à remettre à 1 — au lieu d'un lien qui renvoie 404.

  • Local et public sont distingués. L'adresse d'écoute (http://127.0.0.1:…,

jamais 0.0.0.0) est rappelée à part, et si l'adresse publique est privée, un avertissement explique qu'il faut un tunnel ou un reverse proxy pour la rendre joignable depuis Internet.

  • Réservé au propriétaire. L'écran révèle l'URL publique, la redirection

OAuth2 et l'adresse de supervision : c'est la configuration du bot, pas celle d'un serveur. Un simple membre reçoit un refus explicite (403).

Une garantie de fond, vérifiée par les tests : **aucune page publiée ne peut plus passer inaperçue**. Le test de fumée compare le catalogue aux routes réellement enregistrées par l'application — ajouter une route ouverte sans session fait échouer la suite tant qu'elle n'est pas listée ici.


🚀 Version 7.10 — Inviter les trois bots depuis l'administration (avec le choix des permissions)

Inviter un bot sur un serveur demandait de se souvenir d'un lien, de l'ouvrir à part, et de recommencer trois fois — un par bot, sans jamais savoir lequel manquait. L'Administration du dashboard porte maintenant un écran dédié : « 🚀 Inviter les trois bots ».

Ce qu'il fait

Vous choisissez…L'écran fait le reste
Nos serveurs (où le bot est déjà)Affiche la présence des trois bots et prépare les liens pour ceux qui manquent
Vos serveurs (où vous êtes administrateur)Idem, pour installer les trois bots sur un serveur de votre compte
Un identifiant de serveur saisi à la mainPrépare les liens pour n'importe quel serveur

Et surtout : il DEMANDE quelles permissions donner

Avant de préparer les liens, trois niveaux sont proposés — le choix est explicite, jamais décidé à votre place :

NiveauAdministrateur
Recommandées (par défaut)non — les permissions nécessaires au projet
Toutes les permissions, SANS « Administrateur »non — le bot peut tout faire, sauf contourner ses propres permissions
Toutes les permissions, « Administrateur » COMPRISoui — signalé en rouge : le bot devient tout-puissant

Un rappel utile : Discord **n'autorise pas un bot à rejoindre un serveur tout seul. L'écran prépare donc les liens ; c'est votre clic** chez Discord qui autorise, une fois par bot.

Trois garde-fous

  1. Vos serveurs : il faut y être administrateur (vérifié côté serveur, pas

seulement dans l'affichage) ;

  1. Un identifiant saisi : réservé au propriétaire du bot — hors de votre

liste de serveurs, aucun droit n'est vérifiable ;

  1. Le niveau de permissions est un choix fermé : une valeur fabriquée par le

navigateur est ignorée, et une valeur inconnue retombe sur le niveau le plus prudent. Impossible d'obtenir les pleins pouvoirs par erreur.

Un bot non configuré est affiché comme tel (avec la variable à renseigner) plutôt que de produire un lien qui ne mènerait nulle part, et un bot **dont on ne sait rien** (client non connecté) est marqué « ? » — jamais « absent », ce qui éviterait une double invitation.


🎫 Version 7.9 — L'assistant des tickets rejoint Introvert'AI

L'assistant qui répond dans les tickets tournait sur Introvert'Bot (le premier bot). Il vit désormais sur Introvert'AI (le troisième) : la fonctionnalité a été migrée, et retirée du premier bot. Un seul bot parle donc à tout le monde — dans la conversation et dans le support.

Ce qui change

AvantMaintenant
ticket_ai_cog.py, chargé par Introvert'BotIntrovert'AI/ai_ticket_cog.py, chargé par Introvert'AI
Commandes une commande réservée au staffune commande réservée au staff
Le système de tickets appelait directement le cog de l'IALes deux bots communiquent par la base (ticket_ai_state)

Pourquoi une commande réservée au staff ?

Le troisième bot a déjà un une commande réservée au staff : l'interrupteur et le niveau d'humour de la conversation. Deux groupes de commandes ne peuvent pas porter le même nom sur un même bot : les commandes de l'assistant tickets sont donc regroupées sous une commande réservée au staff, ce qui les rend au passage plus lisibles.

Comment les deux bots se coordonnent maintenant

Les deux bots sont des applications Discord distinctes — ils ne peuvent plus s'appeler. Trois mécanismes, entièrement automatiques :

  1. L'accès aux tickets. À chaque ouverture de ticket, le premier bot ajoute le

troisième aux permissions du salon (lecture, écriture, historique — pas l'administration). Les tickets déjà ouverts au moment de la mise à jour sont rattrapés au démarrage, une fois : personne ne perd son assistant.

  1. La base comme canal. Un module partagé (ticket_ai_state.py) porte une

seule fois la table, les statuts et les écritures. Quand le staff s'attribue un ticket, le premier bot écrit « escalated » — et l'assistant, qui relit ce statut à chaque message, se tait aussitôt. L'escalade survit au redémarrage des deux bots, et les boutons du dashboard agissent exactement au même endroit.

  1. Les garde-fous ne bougent pas : analyse du serveur en séparant salons

publics et privés, filtrage des mentions de salons privés, escalade au staff (avec mention des rôles), aucune action de modération.

Rien à faire de votre côté

Le redémarrage suffit : la table est créée par l'assistant au chargement, et rien n'est à migrer en base. Un [confidentiel] absent laisse simplement l'assistant inactif — le système de tickets continue de fonctionner normalement.

⚙️ TICKET_AI_ENABLED=0 coupe l'assistant (et l'accès du troisième bot aux

salons des tickets : inutile d'ouvrir un salon à un bot inactif).

📄 Détails, transcripts et boutons : TICKETS.md § 5.


🔌 Version 7.8 — Six API externes pour l'IA, et trois pages publiques sur Internet

Jusqu'ici, Introvert'IA ne savait que ce que le modèle savait : aucune blague neuve, aucune météo, aucune question de culture, aucune définition. Et côté site, seuls les membres connectés (et le classement XP) existaient. Cette version lui ouvre six services publics et met trois pages en ligne, accessibles à tous.

🔌 Six API externes, toutes optionnelles

APICe qu'elle apporteDemande type
JokeAPIUne blague réelle, en français ou en anglais« raconte-moi une blague », « une blague de dev »
ImgflipUn mème créé sur mesure« fais-moi un mème sur les lundis »
OpenWeatherMapLa météo d'une ville, aujourd'hui et demain« quel temps à Lyon ? », « et demain ? »
Open Trivia DBDes quiz de culture générale« un quiz facile », « une question sur les animaux »
Free DictionaryLa définition anglaise d'un mot« définition de stunning »
nekos.bestDes GIF animés de réaction (sans clé)« envoie un gif », et spontanément
  • Il ne récite pas une fiche technique : la donnée exacte lui est transmise et

il la raconte avec ses mots — en interdisant d'inventer un chiffre, de changer une chute de blague ou de citer une source.

  • Le mème, lui, est écrit par lui : il reçoit le gabarit choisi et rend ses

deux légendes (meme_top / meme_bottom), qui sont incrustées dans l'image.

  • Le quiz se joue en plusieurs tours : il pose la question (en gardant la

réponse secrète), la question attend dans le salon, et le **verdict est rendu par le code** (juste ou faux, jamais à l'appréciation du modèle). Les scores par membre sont conservés (ai_trivia_scores).

  • GIF spontanés : de temps en temps (≈ 1 message sur 5), il réagit avec un GIF

en rapport avec le sujet du message — « mdr » → un fou rire, « bonne nuit » → un dodo, « merci » → un pouce levé.

  • Jamais dans un moment grave : détresse, sujet sensible ou hostilité coupent

blague, mème et météo.

  • Si un service est coupé ou en panne, il parle quand même : aucun appel, aucun

bloc, aucune erreur. Nouvelle commande une commande réservée au staff pour voir l'état, le nombre d'appels et le dernier incident de chaque service. AI_APIS_ENABLED=0 éteint les six d'un coup.

🌍 Trois pages publiques sur Internet

PageContenu
/nouveautesLe patch note complet, lu à la volée : publier une version met la page à jour tout seul
/introvert-iaQui est Introvert'IA et tout ce qu'elle sait faire — la liste vient du module de présentation, donc elle ne peut pas mentir
/jeuxLes classements de Numingo et de la Roulette de la Vérité, rechargés automatiquement (temps réel)

Chaque page existe aussi en JSON (/api/nouveautes.json, /api/introvert-ia.json, /api/jeux/classements.json) pour être intégrée ailleurs. Elles sont accessibles sans connexion, n'exposent qu'un serveur, aucun identifiant brut, et tout le texte est échappé. PUBLIC_PAGES=0 les ferme.

🗄️ Un nouveau fichier SQL

ai_apis.sql décrit les huit tables des API (ai_api_usage, ai_api_cache, ai_jokes_told, ai_memes, ai_trivia_questions, ai_trivia_scores, ai_weather_cache, ai_media_sent) : elles conservent le cache, les compteurs, les scores de quiz et l'anti-rabâchage d'un redémarrage à l'autre. Le bot les crée tout seul — le fichier sert à les inspecter ou à les créer à la main.

✅ Réglages

Tout se règle dans .env : AI_APIS_ENABLED, AI_JOKES_ENABLED, AI_MEME_KEY, AI_MEME_CHANCE, AI_WEATHER_KEY, AI_WEATHER_CACHE_SECONDS, AI_TRIVIA_ENABLED, AI_TRIVIA_DIFFICULTY, AI_DICTIONARY_ENABLED, AI_NEKOS_ENABLED, PUBLIC_PAGES, PUBLIC_PAGES_TOP. Les clés d'API (Imgflip, OpenWeatherMap) sont déjà renseignées.


⏱️ Version 7.7 — Numingo : le chrono démarre au clic sur « Deviner »

Jusqu'ici, la minute de jeu commençait à l'ouverture du fil : le temps de lire le message, de comprendre les règles et de se préparer était déjà perdu. Le chrono attend désormais le premier geste de jeu.

🖱️ Le clic sur « ❓ Deviner » lance le chrono

AvantMaintenant
Le chrono partait à l'ouverture du filIl part au clic sur ❓ Deviner — ou dès le premier nombre écrit
Lire le message coûtait des secondes de jeuLe joueur lit tranquillement, puis joue quand il est prêt
Le bonus de rapidité dépendait de la vitesse de lectureIl mesure du premier clic à la trouvaille
  • 🗣️ au démarrage, le bot annonce le top départ dans le fil (« ⏱️ **C'est

parti !** Tu as 1 minute — fin de la partie dans 1 minute ») et réédite le message d'ouverture avec l'échéance exacte (dans 42 secondes), qui reste consultable en haut du fil ;

  • 🔁 un second clic ne réarme rien : le chrono ne repart jamais à zéro ;
  • ⌨️ écrire un nombre directement vaut le clic (les deux chemins démarrent le

même chrono) — impossible de jouer au clavier sans lancer le temps ;

  • 💬 la confirmation dans le salon précise que le chrono démarre au clic ;
  • ⚙️ NUMINGO_START_ON_FIRST_GUESS=0 rétablit l'ancien comportement (chrono dès

l'ouverture du fil).

🚪 Un fil jamais lancé est fermé, sans compter de défaite

Puisqu'on peut désormais prendre son temps, il fallait une limite — sinon un fil ouvert par erreur resterait indéfiniment dans le salon.

  • ⌛ 2 minutes (NUMINGO_WAIT_SECONDS) pour lancer la partie : passé ce délai,

le fil est fermé et la partie est annulée ;

  • ✅ aucune défaite n'est comptée : rien n'avait commencé. Le message le dit

noir sur blanc (« ✅ Rien n'est compté : ni victoire, ni défaite »), et le nombre secret n'est pas révélé (il resservira) ;

  • 🏳️ abandonner avant de jouer suit la même règle : la partie est annulée, pas

perdue. Après le lancement du chrono, l'abandon reste une défaite ;

  • 🧹 dans tous les cas le fil est supprimé comme après une partie normale ;
  • 🛰️ l'attente survit au redémarrage du bot : deadline IS NULL en base

signifie « le joueur n'a pas encore lancé la partie », et le balayage de secours (check_timeouts) ferme les parties dont l'attente est dépassée ;

  • ⚙️ NUMINGO_WAIT_SECONDS=0 rend l'attente illimitée.

📋 Le panneau des règles suit

Le panneau publié par /numingo regles explique désormais que **le clic sur ❓ Deviner lance le chrono, qu'il y a 2 minutes pour se lancer**, et que l'attente comme l'abandon avant de jouer n'entament pas les statistiques. Comme toujours, ses chiffres viennent du .env : changer un réglage met le panneau à jour tout seul.

🎉 Tests : _smoke_numingo.py (201 vérifications) — clic sur le bouton

réel, saisie au clavier, second clic inopérant, délai d'attente, abandon avant

et après le lancement, réédition du message d'ouverture, persistance.


🗣️ Version 7.6 — « Qui es-tu ? » : il dit la vérité, et le silence n'obéit qu'à ceux qui le visent

Trois demandes, trois corrections de fond sur le troisième bot (Introvert'AI).

🪪 « Qui es-tu ? » → Introvert'IA, une IA, créée pour « Les Introvertis »

Le personnage joue un membre du serveur : son prompt lui interdit de se présenter comme une IA. Mais quand on lui demande directement qui il est, esquiver serait mentir. Il répond donc désormais :

« Moi c'est Introvert'IA 👋 — une intelligence artificielle, créée

spécialement pour le serveur Discord « Les Introvertis ». »

… puis il cite le résumé de TOUTES ses fonctionnalités : comprendre et répondre, langues (27) & traduction, orthographe, mémoire, souvenirs profonds, émotions & humeur, humour & GIF, convenances, relations & attitudes, perception, chiffres du serveur, sujets sensibles, soutien, silence, version.

Ce qui déclenche la présentationExemples
Identité« qui es-tu ? », « t'es qui ? », « tu es quoi ? », « présente-toi »
Nature« t'es une IA ? », « tu es un bot / un robot ? », « tu es humain ? »
Nom« c'est quoi ton nom ? », « comment tu t'appelles ? »
Capacités« tu sais faire quoi ? », « tes fonctionnalités ? », « à quoi tu sers ? »
English« who are you », « what are you », « are you a bot », « what can you do »
  • ✍️ le message est rédigé par le code, pas par le modèle : le nom, le

serveur et la liste complète sont donc garantis, quel que soit le modèle, son humeur ou son envie de faire court ;

  • 🔄 il se met à jour tout seul : la version vient du patch note, et les

chiffres (langues, émotions, états, durée du silence) sont **lus dans les modules**. Ajouter une langue ou publier une version suffit à actualiser la présentation — et il l'annonce à partir de la version courante ;

  • 🧩 ajouter une fonctionnalité = une ligne dans FEATURES

(ai_presentation.py) — c'est la seule liste à tenir à jour ;

  • 🤐 en dehors de ces questions, rien ne change : il reste un membre du

serveur, et la règle « jamais dire que tu es une IA » porte désormais une exception explicite (la question directe, cf. AI_NO_IA_CLAIM) ;

  • 🎯 il ne se présente que si on le vise (mention, réponse à un de ses

messages, son nom) ou dans un salon de discussion déclaré.

⚙️ AI_PRESENTATION_ENABLED=0 rétablit l'ancien comportement (il esquive) ;

AI_PRESENTATION_MODE=model laisse le modèle rédiger la présentation ;

AI_ASSISTANT_NAME / AI_HOME_SERVER changent le nom et le serveur.

🤫 « Tais-toi » → il détecte QUI le lui demande (et si on le visait)

Avant, n'importe quel message contenant « tais-toi » le faisait taire : une dispute entre deux membres rendait le bot muet pour celui qui n'avait rien demandé. Désormais la demande doit viser le personnage :

  • le mentionner (« @Introvert'Bot tais-toi ») ;
  • répondre à un de ses messages ;
  • ou écrire son nom (« Introvert'Bot, tais-toi ») — son surnom compte.

Sinon rien ne se passe : il ne se tait pas, et il ne s'invite pas dans la dispute en répondant. AI_HUSH_REQUIRE_TARGET=0 rétablit l'ancien comportement.

On sait QUI a parlé :

  • le nom de la personne est retenu avec le silence et affiché dans

une commande réservée au staff (« 🤫 Membres à qui il ne répond plus » : le membre visé, le temps restant, qui l'a demandé) ;

  • l'accusé de réception la mentionne (« @Alice Ok, je me tais 🤐 ») : elle

voit noir sur blanc que la demande a été prise en compte pour elle ;

  • le journal du bot nomme également la personne (nom et identifiant).

↩️ « Reviens » → il revient (vraiment)

Le rappel fonctionne dans tous les cas : seule compte la personne en silence (inutile de le mentionner), et le silence restant est annulé sur-le-champ, avec le retour annoncé en la mentionnant.

De nouvelles formulations sont reconnues : « tu peux revenir », « on reprend », « on continue », « tu peux continuer », « tu es toujours là ? », « t'es encore là ? », « viens me parler », « au temps pour moi », « **mille excuses** », « sorry »…

  • ⛔ une tournure négative conserve le silence : « ne reviens pas », « ne me

reparle pas », « réponds pas » ;

  • 🎯 le silence reste individuel (lever celui d'Alice ne libère pas Bob) ;
  • 🚫 il est levé même si l'annonce échoue : personne n'est bloqué par une

erreur d'envoi.

⚙️ AI_HUSH_MENTION=0 désactive les mentions dans l'accusé et le retour.


🧭 Version 7.5 — Le dashboard sépare les trois bots, avec leur statut dans le menu

Le dashboard gérait tout d'un bloc. Désormais, chaque bot a sa partie, et le menu affiche l'état de chacun en permanence.

🧩 Trois parties, une par bot

BotSection du menuOnglets du serveur
🏠 Introvert'BotTableau de bord, Tickets, Casier & Logs, Whitelist, AdministrationPilotage, Aperçu, Modules, Structure, Assistant de construction, Messages, Modération, Staff, Tickets IA, Activité, Pseudo du bot
🛡️ Introvert'ProtectProtection du serveurProtection
🗣️ Introvert'AIIA conversationnelleIA conversationnelle
  • 🗂️ les onglets d'un serveur sont regroupés en trois lignes, chacune sous le

nom de son bot : on ne mélange plus l'IA, la protection et la gestion du serveur ;

  • 🖱️ les entrées « Protection du serveur » et « IA conversationnelle »

du menu ouvrent directement l'écran correspondant du serveur en cours ;

  • 🌘 un bot éteint se voit tout de suite : sa ligne se ternit, et son écran

explique pourquoi il ne répond pas ;

  • 🏷️ l'ancien « Assistant IA » devient « Assistant de construction », pour ne

plus le confondre avec l'IA conversationnelle (le troisième bot).

🟢 Le statut de chaque bot, dans le menu

Chaque section affiche son état : pastille colorée, version et santé — v7.5 · opérationnel, v1.4 · opérationnel, v1.7 · dégradé…

  • 🏷️ version du bot principal = version du projet (celle que le personnage

annonce aux membres) ; versions de Protect et d'Introvert'AI = leurs propres compteurs de redémarrages ;

  • 💚 santé de l'IA reprise de son surveillant (opérationnel, dégradé,

en panne) : le dashboard dit exactement la même chose que le statut Discord ;

  • 🔄 rafraîchi à chaque navigation et toutes les 60 s, mais uniquement si

l'onglet du navigateur est visible — et l'infobulle explique ce qui manque (« jeton absent du .env », « bot non lancé »…) ;

  • 🛰️ aucune donnée inventée : le serveur interroge les vrais clients Discord

(bot.side_bots, publiés par bot.py).

🗣️ Nouvel onglet : « IA conversationnelle » (Introvert'AI)

serveurs, latence, présence du cerveau — les mêmes chiffres que une commande réservée au staff ;

  • 💬 interrupteur des conversations du serveur : équivalent exact de

une commande réservée au staff ;

  • 😂 niveau d'humour (off, discret, normal, frequent, max) ou

« Personnalisé (.env) » : équivalent de une commande réservée au staff, avec la fréquence réellement appliquée ;

  • 🧠 les réglages passent par le cerveau du bot (jamais d'écriture directe en

base) : le changement est donc pris en compte immédiatement ;

  • 🚫 si le troisième bot n'est pas lancé, les commandes sont désactivées avec

l'explication, au lieu d'enregistrer un réglage sans effet.

📄 Détail : DASHBOARD.md (§ 10.0 bis et § 10.0 ter) · tests :

_smoke_dashboard_bots.py (145 vérifications, dont un test HTTP réel).


🤖 Version 7.4 — Introvert'AI : un troisième bot, sa version et son monitoring

L'IA conversationnelle quitte le bot principal pour vivre **sur son propre bot Discord. Le projet compte désormais trois bots** qui démarrent ensemble.

🧩 Une IA à part : dossier Introvert'AI/

BotRôle
Introvert'BotJeux, XP, modération, tickets, dashboard — il ne parle plus.
Introvert'ProtectProtection des salons pièges — inchangé.
Introvert'AI 🆕Toute la conversation : répondre, traduire, corriger, mémoire.
  • 📁 tous les fichiers de l'IA ont été déplacés dans Introvert'AI/ :

introvert_ai.py (le cerveau), introvert_cog.py (les commandes), les douze

  • 🧠 mêmes règles, mêmes fonctionnalités, mêmes réglages : le personnage, ses

émotions, sa mémoire, les langues et la traduction, les surnoms, la version… rien ne change pour les membres — **aucune variable du .env n'a été renommée** ;

  • 🗣️ le bot principal ne répond plus du tout : ses modules introvert_ai et

introvert_cog ont été retirés de sa liste d'extensions. Une seule voix répond désormais ;

  • 🚀 les trois démarrent ensemble : python bot.py les lance dans le même

processus, sur le même hébergeur ; une commande réservée au staff les relance tous les trois ;

  • 💾 même base de données : le personnage retrouve son humeur et ses

souvenirs d'un redémarrage à l'autre ;

  • 🔑 réglage : AI_DISCORD_TOKEN, AI_APP_ID, AI_PUBLIC_KEY (.env). Les

intents SERVER MEMBERS INTENT et MESSAGE CONTENT INTENT doivent être activés dans le portail développeur de cette application.

🎚️ une commande réservée au staff : la commande qui règle l'humeur a suivi, toujours admin

La commande d'administration qui règle le niveau d'humour du bot — et, avec elle, une commande réservée au staff, /introvert statut et /introvert analyser — est exposée par le troisième bot, et **reste réservée aux administrateurs** (revérifié dans le code, pas seulement par la permission par défaut).

🏷️ Version automatique : 1 → 1.1 → 1.2…

LancementVersion
1ᵉʳ1
2ᵉ1.1
3ᵉ1.2
…1.9, puis 1.10 (le nombre après le point est un entier)
  • 💾 stockée en base (ai_version) : elle survit aux redémarrages — un

compteur en mémoire reviendrait toujours à 1 ;

  • 📜 historique daté de chaque démarrage (ai_version_history, avec le

nombre de serveurs) ;

  • 🛡️ incrémentation unique : un on_ready rappelé après une reconnexion

Discord ne fait pas grimper la version ;

  • 🩺 consultation : une commande réservée au staff.

🟢 Statut personnalisé, en anglais

La présence alterne toutes les 30 s, toujours préfixée par la version — et le premier texte reflète l'état de santé réel :

``` v1.3 • All systems operational v1.3 • Watching 12 servers ```

En cas de problème : v1.3 • Degraded: database unreachable ou jamais affiché à tort.

📈 Monitoring : quatre sondes, un verdict

SondeCe qu'elle vérifie
Passerelle DiscordConnecté, latence, nombre de serveurs.
Base de donnéesPool ouvert et une vraie lecture de introvert_ai_state.
Cog IALe cog IntrovertAI est chargé et actif.
  • 🟢 operational · 🟠 degraded (le bot fonctionne, il manque quelque chose) ·

🔴 outage (il ne peut pas répondre) ;

  • 🔁 une sonde toutes les 60 s et **un seul message console par changement

d'état** : un bot qui va bien ne remplit pas les journaux ;

  • 💾 ai_health (les 500 derniers points) et ai_health_events (les transitions

seules — de quoi dater une panne) ;

  • 🩺 une commande réservée au staff (sonde relancée à la demande), une commande réservée au staff,

une commande réservée au staff — administrateurs.

📄 Détail : Introvert'AI/INTROVERT_IA.md (§ 10 bis) · tables :

Introvert'AI/ai_bot.sql · tests : _smoke_ai_bot.py (136

vérifications), plus les quinze tests IA déplacés (tous verts).


🧭 Version 7.3 — « Mes serveurs » épuré, et un message à chaque nouveau message

Deux améliorations du dashboard web.

🏠 « Mes serveurs » n'affiche plus que les serveurs où le bot est présent

AvantAprès
Tous les serveurs du compte, mélangés« Mes serveurs » = uniquement ceux où le bot est présent
La liste complète s'imposaitElle est séparée et repliée : on l'ouvre si besoin
  • 🏠 « Mes serveurs » ne contient que les serveurs où le bot est là —

ceux sur lesquels on peut agir (bouton Gérer) ;

  • 📂 « Autres serveurs de votre compte (N) — ouvrir la liste » : bloc

replié (<details>), avec le bouton Inviter le bot pour les administrateurs. Rien ne s'affiche d'office ;

  • 🛰️ Passerelle déconnectée : bot_present vaut null (présence

indéterminée) — le dashboard ne prétend pas « bot absent », il l'explique ;

  • 🔌 séparation faite côté serveur (dashboard/access.partition_guilds,

exposée par /api/me : guilds_with_bot / guilds_without_bot).

✉️ Messages automatiques : « à chaque nouveau message dans le salon »

Une quatrième fréquence vient s'ajouter aux trois existantes : le message part à chaque nouveau message écrit dans le salon ciblé — au lieu d'être planifié dans le temps (ni intervalle, ni heure : les champs disparaissent du formulaire).

  • 📌 Avec « supprimer le message précédent », le message remonte en bas à

chaque échange au lieu d'empiler des copies : un vrai « message collant » ;

  • 🛡️ anti-rafale : un délai (SCHEDULE_TRIGGER_COOLDOWN, 5 s par défaut)

évite qu'une rafale de dix messages ne produise dix copies — la valeur réellement appliquée est annoncée dans le formulaire ;

  • 🤖 les bots ne déclenchent rien (dont le message publié lui-même : sans

cela, il se déclencherait en boucle) ;

  • 🗓️ les jours de la semaine restent utilisables comme filtre ;
  • 🕐 la fiche affiche « déclenché à chaque nouveau message » au lieu d'une

« prochaine échéance », et le compteur d'envois continue ;

  • 💾 base : la valeur message est ajoutée à l'ENUM automatiquement au

démarrage (migration idempotente) — sans quoi MySQL l'aurait tronquée en silence.

📄 Détail : DASHBOARD.md (§ 10.0 et § 11) · tests :

_smoke_dashboard_features.py, _smoke_messages_programmes.py.


🎂 Version 7.2 — /anniversaire : les dates des membres, et les vœux à 8 h

Chaque membre peut désormais enregistrer son anniversaire, et le bot s'occupe du reste : le jour J à 8 h, il publie un message de vœux en mentionnant la personne.

  • 🗓️ /anniversaire enregistrer date:14/03/1990 — date au **format

français** (JJ/MM/AAAA) ;

  • 🎈 L'année est facultative : date:14/03 enregistre l'anniversaire **sans

âge** (le bot n'annonce alors aucun âge — il ne devine jamais) ;

  • 🧮 L'âge est calculé à partir de l'année et bascule le jour même :

/anniversaire enregistrer date:14/03/1990 → les vœux diront « 36 ans » ;

  • 🥳 Le jour J à 8 h (heure de Paris), les vœux partent dans le salon des

anniversaires, avec la mention du membre et son avatar ;

  • 🔁 Jamais oublié, jamais doublé : si le bot était éteint à 8 h, il

rattrape son retard au démarrage — et un membre ne reçoit **qu'un vœu par an**, même après plusieurs redémarrages ;

  • 🛠️ /anniversaire supprimer (retirer sa date) et /anniversaire liste

(les anniversaires du serveur, du plus proche au plus lointain) ;

  • 🔓 Utilisable par tout le monde, sans rôle ni permission : chacun

enregistre le sien. Viser un autre membre demande les droits d'administrateur (ANNIVERSAIRE_OTHERS_ADMIN=0 pour ouvrir complètement) ;

  • ❄️ 29 février : fêté le 28 février les années communes ;
  • 💾 Table anniversaires (cf. anniversaire.sql), créée automatiquement au

démarrage ; salon réglable par ANNIVERSAIRE_CHANNEL_ID.

📄 Fichier SQL : anniversaire.sql · testé par _smoke_anniversaire.py

(135 vérifications).


🌍 Version 7.1 — L'IA parle votre langue, traduit sur demande et écrit sans faute

Le prompt imposait une langue unique — « réponds UNIQUEMENT en FRANÇAIS (jamais d'anglais ni de traduction) ». Résultat : un « How are you? » recevait une réponse française, et une demande de traduction était refusée. C'est réparé.

AvantAprès
Réponse toujours en français, traduction interditeRéponse dans la langue de la personne (27 langues reconnues)
« traduis ça » → refusTraduction donnée — et la langue cible est DEMANDÉE si elle n'est pas précisée
Orthographe jamais mentionnéeZéro faute exigé dans chaque réponse (accents, accords, ponctuation)
  • 🌍 Il répond dans votre langue : écriture (cyrillique, arabe, hébreu, grec,

idéogrammes, hangul…), mots-outils, accents et marqueurs forts sont analysés localement — et en cas de doute, il ne devine pas ;

  • 🔤 Traduction fidèle : le sens d'abord, ni résumé ni commentaire ;

l'éventuel commentaire reste dans la langue de la personne ;

  • ❓ Jamais de langue choisie au hasard : « traduis ça » sans langue →

« dans quelle langue ? » ;

  • 📝 Mot isolé : « comment on dit bonjour en anglais ? », « traduis "chat"

en espagnol » → la traduction la plus courante, avec un exemple en une ligne ;

  • ✍️ Correction : « corrige mes fautes », « relis mon texte » → le texte

corrigé, puis les fautes principales (sans en inventer si le texte est correct) ;

  • 🧾 Orthographe impeccable partout, y compris dans la langue par défaut ;
  • ⚙️ Réglages : AI_LANGUAGE_ENABLED (0 = ancien comportement),

AI_DEFAULT_LANGUAGE (langue par défaut) — nouveau module ai_language.py, testé par _smoke_ai_language.py (146 vérifications).

📄 Détail : INTROVERT_IA.md (§ 1 nonies).


🫱 Version 7.0 — Vérification anti-bot : salon privé, éphémère et 5 minutes

Le salon de vérification des comptes récents n'est plus un salon unique partagé : c'est désormais un salon privé créé pour chaque membre.

AvantAprès
Un salon unique, visible de tousUn salon par membre, visible uniquement par lui et les rôles d'équipe
10 minutes pour cliquer5 minutes, sinon expulsion
Le salon restait (créé une fois, jamais supprimé)Auto-suppression à la fin (réussite ou échec/kick), recréé pour le suivant
  • 🕵️ Visible par la seule personne concernée (bouton « Je suis humain » en

lecture seule) plus les rôles d'équipe 1546825515875176488, 1546825518245093459, 1554219949470519336 ; @everyone ne voit pas le salon ;

  • ⏱️ 5 minutes (VERIFY_TIMEOUT_SECONDS) avant expulsion automatique ;
  • 🧹 auto-suppression dès la vérification terminée — au clic (réussite) comme

à l'expulsion (échec) — puis recréation pour le membre suivant ;

  • 💾 traçage par ligne : protect_joins.verify_channel_id (nouvelle colonne,

migration automatique) ;

  • ⚙️ Réglages : PROTECT_VERIFY_STAFF_ROLE_IDS (rôles d'équipe),

PROTECT_VERIFY_CHANNEL_NAME (préfixe du nom), PROTECT_AUTO_VERIFY_CHANNEL=0 pour revenir au salon de repli (configuré puis salon de logs, jamais supprimé).

📄 Détail : Introvert'Protect/README.md (section « Vérification

anti-bot »).


🛡️ Version 6.9 — Anti-triche de la Roulette, sélecteur de salons & règles de Numingo

Trois corrections de fond : un garde-fou pour le jeu de la Roulette de la Vérité (il était contournable en supprimant un message), un **sélecteur de salons qui remonte vraiment les salons du serveur, et le panneau des règles de Numingo** remis à niveau sur le jeu réellement joué.

🛡️ Anti-triche de la Roulette de la Vérité (nouveau module)

Le message de la manche — question + mention de la personne attendue — était supprimable par n'importe quel modérateur, et le bot ne s'en apercevait pas : la manche finissait en « abandon », sans réponse et sans conséquence.

  • 🗑️ Détecté et annulé : supprimer (ou balayer) le message de la manche

annule la manche et relance un tirage — le membre visé **ne perd pas son tour et ne récolte aucun abandon** ;

  • 🚫 Le tricheur est écarté du tirage : au-delà de 3 infractions, plus

candidat pendant 60 min (s'il ne reste personne d'autre, il est réintégré : le jeu ne se bloque jamais) ;

  • 📋 Tout est tracé : journal roulette_anticheat et alerte publiée dans

le salon — la triche se voit au lieu de se cacher ;

  • 🕵️ Le fautif est nommé grâce au journal d'audit de Discord (pensez à

donner au bot la permission « Voir les logs d'audit » ; sans elle, l'infraction reste détectée et annulée, mais sans attribution) ;

  • ✍️ Réponse validée retouchée : réécrire ou supprimer une réponse **déjà

comptée est signalé — avec un délai de grâce de 60 s** pour que corriger une faute de frappe reste permis ;

  • ⚙️ Réglages : VERITE_ANTICHEAT (actif par défaut), VERITE_ANTICHEAT_ACTION

(annuler / signaler), VERITE_ANTICHEAT_MAX, VERITE_ANTICHEAT_EXCLUDE_MINUTES, VERITE_ANTICHEAT_GRACE_SECONDS, VERITE_ANTICHEAT_ALERT, VERITE_ANTICHEAT_LOG — et un interrupteur dans le dashboard (Modules → Réglages globaux) ;

  • 🤐 les règles ne changent pas : elles ne décrivent ni le tirage, ni

l'anti-triche.

📄 Tout le détail (effets, limites, requêtes de contrôle) : ROULETTE_VERITE.md.

📋 Messages automatiques : le sélecteur remonte les salons du serveur

Le formulaire ne construit plus sa liste à partir de l'onglet Structure (qui pouvait laisser la liste vide, sans explication, et masquait les salons inaccessibles) : il interroge une route dédiée.

  • 📋 Tous les salons du serveur sont remontés, groupés par catégorie ; les

fils actifs et les salons hors catégorie sont ajoutés dans « Autres salons » ;

  • ⚠️ un salon où le bot ne peut pas écrire apparaît quand même, avec

« ⚠️ droits manquants » : on voit tout, et on sait ce qui échouera ;

  • ✍️ repli par identifiant : si la liste est vide (ou l'appel échoue), un

champ « identifiant du salon » s'ouvre tout seul, avec un message explicite. L'option « Autre salon — saisir l'identifiant… » reste disponible en permanence ;

  • 🔁 en modification, un salon disparu de la liste est repris tel quel dans le

champ manuel — plus de retombée silencieuse sur un autre salon.

🎯 Numingo : les règles affichées rattrapent enfin le jeu

Le message de /numingo regles (et le panneau publié automatiquement dans le salon de jeu) décrivait le jeu à moitié : les bornes et le chrono y étaient, mais rien sur le refus des nombres hors limites, l'abandon, le nettoyage du fil ni l'astuce de dichotomie.

  • 📋 toutes les règles y passent désormais, numérotées en 6 étapes : proposer un

nombre, suivre les indices, le chrono d'1 minute, les récompenses en XP (100 XP — ou 500 XP en moins de 30 s, la récompense de rapidité remplaçant la base), le classement en direct, puis un bloc « Bon à savoir » : nombre hors de 1 à 500 refusé sans consommer d'essai, une seule partie à la fois, 🏳️ Abandonner comptabilisé comme une défaite ;

  • 💡 l'astuce de dichotomie est affichée : premier essai au milieu de la

fourchette (250), puis on coupe en deux — 9 essais suffisent pour 500. Ces nombres sont calculés depuis NUMINGO_MAX (aucune valeur en dur) ;

  • ⚙️ valeurs lues dans la configuration (NUMINGO_DURATION_SECONDS,

NUMINGO_XP_WIN, NUMINGO_XP_FAST, NUMINGO_DELETE_THREAD_SECONDS) : modifier un réglage dans le .env met le panneau à jour tout seul ; le pied de page rappelle que le fil est nettoyé au bout de 30 secondes ;

  • 🧪 test renforcé : _smoke_numingo.py vérifie chaque règle affichée et que

le panneau reste dans les limites d'embed Discord (25 champs / 6000 caractères).

🎉 Tests : _smoke_verite_antitriche.py (nouveau), _smoke_numingo.py (panneau

des règles), _smoke_messages_programmes.py (route des salons + interface),

_smoke_roulette_verite.py.


🎡 Version 6.8 — Roulette de la Vérité : tirage simplifié

Le tirage de la Roulette de la Vérité ne retient plus qu'un seul critère : les rôles du jeu (VERITE_ROLE_IDS). Le choix est ensuite un pur hasard parmi les membres qui portent au moins un de ces rôles.

AvantMaintenant
Seuls les membres en ligne, occupés ou absents étaient tirés ; les déconnectés étaient écartésTous les porteurs des rôles du jeu sont tirables, en ligne ou non
Le vocal et l'activité récente donnaient un avantage (poids ×10)Aucun avantage : chaque porteur a la même chance
Le tirage pondéré privilégiait les « présents »Hasard uniforme, seule la rotation est respectée (on ne pose pas deux questions de suite à la même personne si d'autres candidats existent)
  • 🧹 Un seul critère lisible : les rôles configurés — plus de « pourquoi lui

et pas moi ? » lié au statut Discord ;

  • 🎲 tirage uniforme : un membre hors ligne a exactement la même probabilité

qu'un membre en vocal ;

  • 🔄 rotation conservée : le membre de la manche précédente est écarté quand

d'autres candidats existent — il reste tirable s'il est seul ;

  • 🛡️ inchangé : la question n'est publiée que pour un membre qui peut **voir

et écrire** dans le salon (sans quoi elle ne lui parviendrait pas), les bots sont exclus, la pause après trop d'abandons et le délai de réponse restent identiques ;

  • 🗑️ réglages supprimés : VERITE_STATUSES, VERITE_ONLINE_ONLY et

VERITE_ACTIVITY_MINUTES n'ont plus d'effet — vous pouvez les retirer du .env ;

  • 🤐 les règles ne changent pas de discours : elles n'ont jamais décrit la

mécanique interne du tirage, et elles continuent de ne décrire que le principe (« un membre du jeu est désigné au hasard »).

🎉 Tests : _smoke_roulette_verite.py (tirage uniforme sur 1 200 tirages,

éligibilité du hors ligne, rotation, et **vérification que les règles ne

parlent ni de ligne, ni de vocal, ni de statut**).


🎯 Version 6.7 — Numingo en 1 minute avec XP, et une IA qui connaît sa version

Trois changements pensés pour le jeu et pour la conversation : une partie plus juste et mieux récompensée, des fils qui ne s'accumulent plus, et un personnage qui sait enfin de quelle version il est quand on lui pose la question.

🎯 Numingo : plus court, plus jouable, récompensé

AvantMaintenant
Nombre secret entre 1 et 10 000Nombre secret entre 1 et 500 (NUMINGO_MAX) : 9 essais suffisent en coupant la fourchette en deux, au lieu de 14
30 secondes1 minute (NUMINGO_DURATION_SECONDS=60)
Aucune récompense en jeu100 XP en trouvant le nombre, 500 XP si c'est trouvé en moins de 30 secondes
Les fils de partie restaient ouvertsLe fil est supprimé automatiquement 30 s après la fin de la partie
  • ⭐ XP versée au vrai classement : le gain passe par le module XP du bot

(grant_xp) — il compte donc dans le classement XP du serveur et sur le compte du membre, montée de niveau comprise (annonce incluse) ;

  • 🏅 le bonus de rapidité REMPLACE la récompense de base : trouver en 20 s

rapporte 500 XP (pas 600). Les deux montants se règlent dans le .env (NUMINGO_XP_WIN, NUMINGO_XP_FAST, NUMINGO_XP_FAST_SECONDS) ;

  • 🧹 fils fantômes : fini : la grâce de 30 s (NUMINGO_DELETE_THREAD_SECONDS)

laisse le temps de lire le résultat, puis le bot supprime le fil — et le résultat annonce la couleur (« ce fil s'auto-détruira dans 30 secondes ») ;

  • 🛟 ça survit au redémarrage : l'échéance de suppression est en base, un

balayage de secours rattrape les fils oubliés après un redémarrage ;

  • 📊 le classement Numingo affiche en plus les XP gagnées au jeu et les

victoires rapides.

🧠 L'IA connaît sa version, ses nouveautés et sa dernière mise à jour

Demandez-lui « t'es en quelle version ? », « **c'est quoi tes dernières nouveautés ? » ou « ta dernière mise à jour date de quand ?** » : il répond exactement, sans inventer.

  • 📄 la source est le patch note du projet (PATCH_NOTES.md) : ce que vous

écrivez dans le fichier est ce qu'il raconte (version, date, titres) ;

  • 🔒 anti-invention : le modèle reçoit l'ordre de ne citer QUE ces

informations — et de dire « je ne sais pas » plutôt que de broder ;

  • 🎭 il reste dans son personnage : il parle de « sa dernière mise à jour »

(« on m'a mis à jour », « je suis en 6.7 depuis le 14 octobre ») et ne se présente jamais comme un programme ;

  • 🚫 aucun faux positif : « la nouvelle version de Minecraft » ou « la mise à

jour de Windows » ne déclenchent rien (il faut que la question porte sur lui) ;

  • 🧯 jamais muet : si le fichier est absent (déploiement minimal), une version

de repli codée en dur prend le relais ;

  • ⚙️ réglable : AI_RELEASE_ENABLED=0 coupe la fonctionnalité,

AI_RELEASE_HISTORY fixe le nombre de versions rappelées (3 par défaut).

📄 Détail complet des correctifs : NUMINGO_IA_PATCH.md.

🎯 Règles du jeu et configuration : NUMINGO.md.

🧠 Côté IA : INTROVERT_IA.md.


🏷️ Version 6.5 — L'IA retient les surnoms et sait dans quel salon elle parle

Deux petits détails qui font toute la différence entre « un bot qui répond » et « un habitué du serveur » : retenir comment on l'appelle, et savoir **où l'on est** en train de parler.

🏷️ « Appelle-moi Matt » : il s'en souvient

Un surnom, ça se retient. Désormais, le personnage mémorise par membre :

Ce qu'on lui ditCe qu'il retient
« appelle-moi Matt », « mon surnom c'est Mat », « tu peux m'appeler Mattou ? », « je m'appelle Matt », « mon blaze est Zozo »il appelle la personne « Matt » — et l'utilise naturellement dans ses réponses
« je t'appelle Titi », « ton surnom c'est Bibi », « je te surnomme Zozo », « ton blaze est… »« Titi » est son propre surnom : il le reconnaît comme étant le sien, il répond quand on l'appelle « Titi » (sans attendre d'être mentionné) et ne demande plus jamais « c'est qui Titi ? »
  • 🧠 mémorisé en base (introvert_ai_members.member_nick et .bot_nick) :

le surnom survit au redémarrage, et il est par personne (chacun peut l'appeler différemment) ;

  • ⚡ détection déterministe : aucun appel au modèle, donc aucune latence ni

coût — juste du repérage de formulations ;

  • 📣 il répond à son surnom : un message commençant par « **Titi, tu es

là ?** » est traité comme s'il portait son nom complet — il comprend que c'est lui et répond, sans attendre d'être mentionné ;

  • 🚫 les faux positifs sont rejetés : « appelle-moi quand tu veux » ne

mémorise rien (pas plus qu'un nombre seul, une mention <@123> ou un mot vide) ;

  • ✍️ les surnoms composés sont acceptés (« Petit Loup », « Jean-Luc »,

« Matt_du_13 ») ;

  • 🔄 changer de surnom remplace l'ancien (« appelle-moi Mattou ») ;
  • 🛡️ anti-invention : si la formulation échappe au repérage (« tu peux me

rebaptiser en Mattou ? »), le modèle peut proposer le surnom — mais il n'est accepté que si une intention de surnom existe vraiment dans le message. Jamais sur une réponse de conversation : un surnom inventé ne se grave pas ;

  • 🧯 tolérant : base non migrée ou écriture impossible → le personnage

fonctionne simplement sans surnom, sans jamais lever d'erreur.

📍 Il sait dans quel salon il parle

Fini le classique « va poster ça dans #général »… alors que la conversation a lieu dans #général. Le salon courant est maintenant explicitement signalé au personnage :

  • une ligne d'en-tête nomme le salon courant en tête de son analyse du

serveur (elle survit donc à la troncature de cette analyse) ;

  • la ligne du salon dans la liste porte le marqueur ⟵ TU ES ICI ;
  • conséquence directe : il ne conseille jamais d'aller là où vous êtes déjà,

et si c'est bien ici qu'il faut poster, il le dit sans nommer le salon (« poste-le ici », « juste là ») ;

  • pour désigner les autres salons, il continue de les conseiller normalement.

En complément, un filet de sécurité déterministe réécrit le nom du salon courant quand il l'écrit en clair (« va dans #général » → « va dans ici »), avec nettoyage de la préposition devenue inutile. Les autres salons ne sont jamais touchés.

🔌 Fichiers concernés

FichierRôle
ai_perception.pyDétecteurs de surnoms (detect_member_nickname, detect_bot_nickname), validation (normalize_nickname), garde-fou (accepts_model_nickname), bloc de prompt (nickname_block)
introvert_ai.pyColonnes + migrations, mémorisation (_remember_nicknames, _save_nickname), réponse au surnom (mentions_persona(..., extra_names=…)), mark_current_channel, sanitize_current_channel, bloc SURNOMS dans le prompt, champs surnom / surnom_pour du contrat JSON
introvert_ai.sqlColonnes member_nick et bot_nick (+ notes de mise à niveau)

🎉 Tests : nouveau _smoke_ai_nicknames.py — détection (28 formulations,

dont les faux positifs), validation, anti-hallucination, mémorisation en base (relecture, remplacement, tolérance), prompt, contrat JSON, marquage du salon, filet de sécurité et câblage. Toute la suite (65 smoke tests) reste verte.


🛠️ Version 6.4 — Signalements : les sanctions sont vraiment appliquées

C'était le défaut le plus frustrant du salon de signalements : le panneau « Traiter le signalement » proposait **Bannissement, Kick, Mute, Warn, Message supprimé**… mais cochait seulement des cases. Les décisions étaient enregistrées en base et envoyées au signalant — **aucune sanction n'était posée sur Discord**. Cette version fait ce que le panneau annonce.

✅ Ce qui est réellement exécuté désormais

DécisionEffet réel
🚫 Bannissementguild.ban() avec la durée choisie (levée automatique à l'échéance par le bot) ou définitif
🔇 Mutemember.timeout() avec la durée choisie (plafonnée à 28 jours, limite Discord)
👞 Kickmember.kick() — expulsion sans bannissement : le membre peut revenir
⚠️ WarnAvertissement inscrit au casier + MP au membre
🗑️ Message suppriméLe message signalé est retrouvé (via son lien de saut) et supprimé

Chaque sanction produit exactement les mêmes effets que les commandes slash : ligne au casier moderation_sanctions, entrée au journal des sanctions, message privé au membre, et garde-fous identiques (on ne sanctionne ni soi-même, ni le bot, ni le propriétaire, ni un rang supérieur).

⏳ Les durées enfin prises en compte

Le panneau proposait une seule durée (celle du ban). Il en propose maintenant deux : Durée du ban et Durée du mute. Elles s'écrivent librement — « 7 jours », « 48h », « 2 semaines », « 1 mois », « 90 minutes », « définitif », « à vie »… et sont converties en minutes avant application :

  • ✅ « 1 mois et 3 jours » s'additionne correctement ;
  • ✅ « définitif » = aucune échéance ;
  • ⛔ une durée incomprise (« bientôt », « 7 lustres ») est **refusée avec son

motif** — jamais devinée, et le reste des décisions s'applique quand même ;

  • ⚠️ une exclusion de plus de 28 jours est plafonnée à 28 jours (limite

imposée par Discord), et c'est signalé.

📝 La raison est transmise partout

Le motif envoyé à Discord, inscrit au casier et rappelé dans le MP cite toujours la référence du signalement, le motif du signalement et l'explication du staff :

Signalement SIG-2026-4F9K2A — Insultes répétées — Récidive après avertissement

📋 Le staff voit ce qui a réellement été fait

Avant, un « oui » dans la décision ne garantissait rien. Désormais :

  • la confirmation (message éphémère du staff) et le message du signalement

portent un champ « 🛠️ Sanctions appliquées » : appliqué / **non appliqué — avec la raison** (permissions du bot, rôle trop haut, membre introuvable…) ;

  • decision_summary en base contient cette issue : le dashboard et le casier ne

peuvent donc plus annoncer une sanction qui a échoué ;

  • côté dashboard, la réponse JSON expose applied et failed, et l'alerte

s'affiche en rouge.

🐛 Deux bugs de fond corrigés au passage

  1. AttributeError silencieux sur les sanctions du dashboard :

dashboard/moderation.py lisait cog.DEFAULT_MUTE_MINUTES, cog.MAX_TIMEOUT_MINUTES et cog.BAN_DELETE_SECONDS — or ces constantes étaient définies au niveau du module, pas de la classe. Un mute ou un ban depuis le web levait donc une erreur. Elles sont désormais exposées sur la classe ModerationCog.

  1. « kick » absent de l'ENUM du casier : la table moderation_sanctions

n'acceptait pas kind='kick' (alors que le dashboard le comptait !). L'ENUM accepte maintenant les expulsions, avec une migration douce au démarrage (bot.py) pour les bases existantes, et moderation.sql est à jour.

🧩 Un seul chemin d'exécution

Les sanctions ont été déplacées dans le cog Moderation (apply_warn, apply_mute, apply_unmute, apply_ban, apply_unban, apply_kick) :

  • le dashboard délègue (dashboard/moderation.py traduit simplement

SanctionError → réponse HTTP) ;

  • le traitement des signalements appelle les mêmes méthodes via

SignalementCog.apply_decisions ;

  • plus aucune logique n'est recopiée : un correctif sur une commande réservée au staff profite

automatiquement aux trois points d'entrée.

🎉 Tests : _smoke_signalement.py vérifie désormais l'exécution réelle

(ban avec durée, mute chronométré, kick, warn, message supprimé, ordre

d'application, garde-fous, durée illisible refusée, plafond du mute) ;

_smoke_signalement_integration.py couvre le panneau et le refus des durées

invalides ; _smoke_dashboard_sanctions.py prouve que le web applique les

mêmes sanctions et rapporte les échecs.


🧭 Version 6.3 — Le dashboard devient un vrai centre de pilotage

Le dashboard était complet mais éparpillé : pour savoir « comment va ce serveur ? », il fallait ouvrir quatre onglets (Modules, Tickets, Casier, Activité) et recouper soi-même l'information. Cette version ajoute un écran de pilotage — la réponse tient désormais en un seul regard.

🧭 Onglet « Pilotage » (premier onglet du serveur)

Un nouvel écran d'accueil, servi par une seule requête (GET /api/guilds/{id}/pilotage) :

  1. Alertes — uniquement ce qui mérite une action, du plus grave au plus

anodin : bot sans permission Administrateur, maintenance en cours, protection coupée ou non configurée, mode raid actif, modules indisponibles, tickets en attente, pic de sanctions sur 24 h, bannissements actifs. Chaque alerte porte un bouton « Ouvrir » qui mène directement à l'onglet concerné. S'il n'y a rien à signaler : « Tout est normal » — et aucune alerte n'est inventée pour remplir l'écran ;

  1. Chiffres clés — membres, tickets ouverts, sanctions 24 h, journal 24 h,

modules actifs, bannis actifs ;

  1. Actions rapides — traiter les tickets, ouvrir le casier & logs, gérer les

modules, protection, modération, activité : de grosses cibles, un clic ;

  1. Interrupteurs — tous les modules activables/désactivables **directement

depuis le pilotage, avec l'effet immédiat** (mêmes appels que l'onglet « Modules », même confirmation pour les actions sensibles) ;

  1. Activité récente — les derniers événements du journal, avec le pseudo

de l'auteur, colorés par type.

🧠 Une base incomplète ne casse rien : chaque lecture est tolérante. Une

table absente affiche « — » (valeur inconnue), jamais un « 0 » trompeur ni

une erreur.

🎛️ Onglet « Modules » : retrouver un interrupteur en un clic

  • 🔎 Recherche instantanée (nom ou description) ;
  • 🏷️ filtres d'état : Tous · Actifs · Inactifs · Indisponibles ;
  • ⚡ actions groupées par catégorie (« Tout activer » / « Tout désactiver »),

proposées uniquement sur les modules réellement modifiables ;

  • 🟢 état visuel renforcé (bordure verte quand le module est actif), badge

« sensible » conservé pour les interrupteurs à risque.

🎫 Tickets : le ticket oublié saute aux yeux

Un ticket encore ouvert et en attente depuis plus de 24 h est mis en évidence dans la boîte de réception (bordure et fond orangés, pastille « ⏰ N h »). C'est le risque numéro un d'une gestion au quotidien, et il était invisible.

📜 Journal : filtrer par type d'événement

Le journal du serveur gagne un filtre par type (suppression, édition, vocal, tickets…). La liste des types vient du serveur (kinds) : elle ne peut donc jamais diverger de ce que le journal contient réellement.

🔌 Fichiers concernés

FichierRôle
dashboard/pilotage.pyNouveau — agrégation (modules, tickets, casier, journal) + alertes
dashboard/modules.pycollect_modules() extrait de list_modules → réutilisé par le pilotage
dashboard/app.pyEnregistrement de la route /pilotage
dashboard/static/index.htmlOnglet + panneau de pilotage, filtre du journal
dashboard/static/app.jsloadPilotage, rendu, actions rapides, filtres/actions groupées
dashboard/static/style.cssAlertes, actions rapides, interrupteurs, fil d'activité

🎉 Tests : nouveau _smoke_dashboard_pilotage.py (route, alertes et leur

ordre de gravité, synthèse bout en bout, tolérance à une base incomplète,

interface) ; _smoke_dashboard_features.py et _smoke_dashboard_watch.py

étendus. Aucun HTML n'est injecté : tout passe par textContent.


🏷️ Version 6.2 — Bans actifs : le pseudo s'affiche enfin (avec l'ID)

Dans l'onglet Modération, le tableau « Bans actifs » n'affichait qu'un identifiant (« Membre 123456789012345678 ») : les membres bannis ayant **quitté le serveur**, get_member() ne pouvait pas les retrouver.

🔎 Le pseudo est résolu via la liste des bannissements

L'API interroge guild.bans() — un seul appel pour tout le tableau (et non un fetch_user par ligne) — puis affiche « Pseudo » suivi de l'identifiant :

AvantAprès
Membre 777123456789012345LeFugitif 777123456789012345

Ordre de résolution, la première source qui répond gagne :

  1. le membre du serveur (s'il est encore là) ;
  2. la liste des bannissements Discord ;
  3. le cache du bot (get_user, aucun appel réseau) ;
  4. sinon, « Membre <id> » — jamais un pseudo inventé.
  • 🪶 Sobriété réseau : si aucun ban n'est actif, aucun appel à Discord

n'est émis ; sans la permission Bannir des membres, la lecture échoue proprement (avertissement dans la console) et l'affichage retombe sur le cache ;

  • 🖥️ l'identifiant s'affiche dans une petite pastille discrète (.member-id),

copiable, à côté du pseudo ;

  • ♿ toujours aucune injection HTML : pseudo et identifiant passent par

textContent.

🎉 Tests : _smoke_dashboard_features.py couvre la résolution (4 sources), la

dégradation sans permission, et un bout en bout prouvant qu'un banni absent

du serveur revient bien avec son pseudo et son identifiant — plus le fait

qu'aucun appel Discord n'est fait sans ban actif.


📱 Version 6.1 — Le classement XP devient responsive

La page /classement s'affiche désormais comme le reste du site : du téléphone au grand écran, sans défilement horizontal ni colonne coupée.

🧩 La page réutilise la coquille du dashboard

  • enveloppe main.content (mêmes marges, même centrage, même largeur maximale)

et en-tête topbar — au lieu d'un <main> nu collé aux bords ;

  • l'en-tête rappelle sobrement qu'il s'agit d'une page publique (🌍) ;
  • ✅ la règle historique est conservée : aucun lien vers le dashboard.

📐 Quatre paliers, un seul tableau

ÉcranRendu
Ordinateur (≥ 1025 px)Tableau complet — 7 colonnes
Tablette (≤ 1024 px)🎙 Vocal masqué, paddings resserrés
Petite tablette (≤ 780 px)💬 Messages + 🎙 Vocal masqués
Mobile (≤ 640 px)Liste de cartes : rang + membre en tête, progression pleine largeur, puis Niveau / XP / Messages / Vocal
Très petit (≤ 400 px)Cartes compactées, barre ▰▱ remplacée par la jauge
ImpressionTableau complet, sans décor

🛡️ Deux garde-fous d'affichage

  • le tableau ne casse plus la page : il est enveloppé (.table-wrap) et

c'est lui qui défile dans son cadre si la place manque ;

  • les noms longs sont tronqués proprement (ellipsis) au lieu de pousser les

colonnes.

📊 Une vraie jauge de progression

En plus de la barre ▰▰▱▱▱ (conservée, c'est l'identité du tableau) et du détail chiffré (50 / 475 (10.5 %)), chaque ligne affiche une **jauge graphique** — indispensable au pouce sur mobile, où elle occupe toute la largeur.

♿ Accessibilité : <th scope="col"> conservés, zone défilante navigable au

clavier, éléments décoratifs en aria-hidden, et un @media print propre.

🎉 Tests : _smoke_dashboard_xp.py vérifie la coquille, l'enveloppe du tableau,

les data-label, la jauge, les cinq paliers responsive et l'absence de lien

vers le dashboard.


🔐 Version 6.0 — Le bot devient privé : whitelist des serveurs (fini le blocage par IP)

La protection change de cible : **on ne bloque plus les visiteurs du dashboard, on bloque les serveurs** auxquels le bot accepte d'appartenir.

🌍 Le dashboard n'est plus filtré par adresse IP

DASHBOARD_ALLOWED_IPS ne bloque plus rien par défaut : le dashboard est ouvert (chacun peut s'y connecter avec Discord), mais **seuls le propriétaire du bot et les administrateurs d'un serveur où le bot est présent peuvent agir** — et le bot refuse d'être ajouté ailleurs qu'en liste blanche.

  • 🔁 le filtre IP reste disponible (opt-in) : DASHBOARD_IP_FILTER=1

+ DASHBOARD_ALLOWED_IPS=<adresse> ;

  • 📊 le classement /classement reste public dans tous les cas.

🤖 Le bot n'accepte plus n'importe quel serveur

  • on_guild_join fait le tri : un serveur non autorisé est **quitté

aussitôt, après un MP d'explication à son propriétaire** ;

  • balayage au démarrage : les serveurs déjà présents avant cette version en

sont retirés (on_ready) ;

  • 🛡️ deux sécurités : le balayage exige la base (sinon il est reporté, pour

ne jamais expulser un serveur légitime) et le serveur fondateur (BOT_WHITELIST_GUILD_IDS, par défaut 1546821570637340682) est autorisé **en permanence**, même si MySQL tombe.

📨 Les gens font une demande, tu acceptes ou refuses

Nouvel onglet Whitelist dans le dashboard :

  1. le membre se connecte, choisit un de ses serveurs (il doit y être admin

— vérifié côté serveur, jamais cru sur parole) et dépose une demande ;

  1. dans l'onglet Administration, la carte 📨 Demandes de whitelist liste

les demandes (filtre en attente / acceptées / refusées) ;

  1. ✅ Accepter → le serveur est autorisé et le demandeur reçoit un **MP

avec le lien d'invitation préciblé ; ❌ Refuser → il reçoit un MP de refus. Il peut aussi retirer** une entrée (retirer l'autorisation).

ℹ️ Pourquoi un clic final ? Discord interdit à un bot de rejoindre un

serveur par programmation. Le MP contient donc un lien OAuth déjà pré-rempli

pour son serveur : au clic, le bot rejoint — et on_guild_join le laisse entrer

puisqu'il est autorisé. Si le MP échoue (MP fermés), le dashboard **affiche le

lien** à l'administrateur pour qu'il le transmette.

⚙️ Nouveaux réglages

```env DASHBOARD_IP_FILTER=0 # 1 = réactiver le filtre par IP BOT_WHITELIST_ENABLED=1 # 0 = bot de nouveau public BOT_WHITELIST_GUILD_IDS=1546821570637340682 # serveurs autorisés en permanence BOT_WHITELIST_AUTO_LEAVE=1 # 0 = observer sans expulser BOT_WHITELIST_NOTIFY_CHANNEL_ID= # salon prévenu des demandes/ajouts ```

  • 🗄️ nouvelle table bot_whitelist (demandes et autorisations, une ligne

par serveur) — cf. whitelist.sql ;

  • 📚 documentation dédiée : WHITELIST.md.

🎉 Tests : _smoke_whitelist.py (cycle de vie, liste blanche, invitation,

garde-fous) et _smoke_dashboard_whitelist.py (routes, contrôles d'accès,

acceptation/refus, MP, interface). _smoke_dashboard_ipfilter.py vérifie en

plus que le filtre IP est inactif par défaut.


⏱️ Version 5.9 — Roulette de la Vérité : 20 minutes pour répondre

Le délai de réponse de la Roulette de la Vérité passe de 5 à 20 minutes.

AvantAprès
5 minutes pour répondre20 minutes
  • 🕒 Plus de temps pour réagir : on laisse aux membres le temps de lire la

question et de formuler une vraie réponse, sans se faire tirer le tour dessus trop vite ;

  • 🤖 Le reste est inchangé : seuls les membres en ligne sont désignés, et

après 3 non-réponses d'affilée la roulette prend toujours sa pause d'1 h ;

  • 📣 Le délai est rappelé automatiquement partout où il apparaît : règles du jeu

(/verite regles), panneau du salon, embed de la manche (⏱️ Temps imparti) et annonce d'abandon ;

  • ⚙️ Modifiable : VERITE_TIMEOUT_MINUTES (défaut 20 dans le .env).

🎉 Tests : _smoke_roulette_verite.py vérifie l'échéance (~20 min) et le texte

des règles.


😂 Version 5.8 — une commande réservée au staff, souvenirs d'hier & caisse cachée

🎚️ une commande réservée au staff — les admins règlent la dose d'humour

Nouvelle commande réservée aux administrateurs pour doser l'humour du personnage par serveur, sans redémarrer le bot :

``` ```

NiveauHumour spontané
off Coupé0 % — aucune vanne, même sur demande
discret~15 %
normal~35 %
frequent~60 %
max~90 %

👉 Le réglage est persisté en base (introvert_ai_settings.humor_level) : il survit au redémarrage. Sans réglage, les valeurs du .env (AI_HUMOR_ENABLED, AI_HUMOR_CHANCE) s'appliquent (« Personnalisé »). La règle d'or reste : tristesse ou colère → aucun humour, quel que soit le niveau.

🧠 Il se souvient d'hier (et d'avant)

Quand on lui demande de se rappeler d'un échange ancien — « tu te souviens quand on parlait de… ? », « hier… », « la dernière fois… » — le personnage va chercher dans l'historique des salons du serveur les messages échangés avec cette personne (et ses propres réponses) pour retrouver le sujet.

  • 🔎 à la demande (jamais à chaque message : lire un serveur coûte cher) ;
  • ⏱️ fenêtre bornée (AI_RECALL_MIN_AGE → AI_RECALL_DAYS), tri par mots-clés

puis récence, souvenirs situés (« hier », « il y a 3 jours ») ;

  • 🛡️ borné (AI_RECALL_CHANNELS, AI_RECALL_MESSAGES, AI_RECALL_RESULTS) et

mis en cache par (serveur × membre) ;

  • 🚫 sans extrait pertinent, aucun bloc : le personnage n'invente rien.

⚙️ AI_RECALL_ENABLED=0 coupe la fonctionnalité.

🎁 une commande réservée au staff — la chasse au trésor

Un nouveau paramètre dépose la caisse dans un salon au hasard du serveur, puis publie une annonce dans XP_DROP_ANNOUNCE_CHANNEL_ID (1548780132334837814) :

🎁 Une caisse d'XP est cachée dans le serveur ! Sois le **premier à la

trouver et à cliquer sur 🎁 Récupérer**…

  • 🎲 salon tiré au hasard (le salon d'annonce est exclu) ;
  • 🙈 le salon n'est jamais révélé au public — seul l'admin le voit

(réponse éphémère) ;

  • 🏆 le premier à la trouver encaisse (réclamation atomique, bouton unique).

🎉 Tests : _smoke_xp.py (option aleatoire, helpers) et

_smoke_ai_quiet.py (niveaux d'humour, souvenirs profonds).


🧘 Version 5.7 — Côtés introvertis, salutations ignorées & Roulette plus juste

Le serveur s'appelle « Les introvertis » : le personnage s'y adapte enfin vraiment.

🤫 Il ne répond plus aux « bonjour » / « ça va ? »

Un « bonjour » ou un « ça va ? » lancé à la cantonade ne le fait plus parler — ce n'est pas adressé à lui, et un introverti ne répond pas à tout le monde. Quand on s'adresse vraiment à lui (mention, réponse à un de ses messages, ou son nom prononcé), il répond normalement — et il salue alors en retour, avec le mot juste pour l'heure.

  • les autres convenances continuent de le faire réagir : bonne nuit, « bon

appétit », au revoir ;

  • réglable : AI_SOCIAL_TRIGGER_IGNORE_KINDS=salutation,ca_va (laisser vide

rétablit l'ancien comportement, où il saluait tout le monde).

🧘 Des côtés réservés, qui comprennent les gens discrets

Un nouveau bloc apprend au personnage à comprendre les gens réservés : réponses courtes quand l'autre parle peu, aucune relance insistante (« alors ? », « tu es là ? », « réponds-moi »), respect du silence et du besoin d'espace, sans jamais culpabiliser personne. Il s'adapte au tempo : plus doux avec un réservé, plus joueur avec un expansif.

⚙️ Réglage : AI_INTROVERT=0 coupe le bloc (personnage extraverti par défaut).

🎡 Roulette de la Vérité : que des gens en ligne, 5 min, et une pause si ça décroche

AvantAprès
10 minutes pour répondre5 minutes
Les hors ligne pouvaient être tirés au sortSeuls les membres EN LIGNE sont désignés
Le jeu posait des questions sans fin devant un salon videAprès 3 non-réponses d'affilée, il se met en pause 1 h puis repart tout seul
  • 🟢 En ligne, vraiment : le tirage ne retient que les membres en vocal,

actifs récemment dans le salon, ou dont le statut Discord n'est pas « hors ligne ». La question n'est donc jamais posée à quelqu'un qui n'est pas là.

  • 😴 Pause automatique : VERITE_MAX_MISSES=3 non-réponses consécutives

(une réponse remet le compteur à zéro) → pause de VERITE_BREAK_MINUTES=60. La pause survit au redémarrage : le bot reprogramme la reprise au bon moment.

  • ⚙️ Réglages : VERITE_ONLINE_ONLY (0 = ancien tirage), VERITE_TIMEOUT_MINUTES=5,

VERITE_MAX_MISSES, VERITE_BREAK_MINUTES.

  • ℹ️ Sans l'intent presences (portail Discord), « en ligne » se lit sur le

vocal et l'activité récente — déjà suffisant pour ne jamais désigner un absent.

🎉 Tests : _smoke_roulette_verite.py (en ligne seulement, pause d'une heure),

_smoke_ai_quiet.py (salutations ignorées), _smoke_ai_social.py.


🗑️ Version 5.6 — Salon des sanctions : le titre ne cite plus la commande

Dans le salon des sanctions (1554219964804632577), les messages publiés par le bot affichaient la commande utilisée dans leur titre. Le titre décrit maintenant l'action, rien d'autre.

AvantAprès
🗑️ Suppression de messages une commande réservée au staff🗑️ Suppression de messages
🗑️ Message supprimé une commande réservée au staff🗑️ Message supprimé
🗑️ Présentation supprimée une commande réservée au staff🗑️ Présentation supprimée

👉 Le staff qui a agi reste indiqué, dans le champ « Modérateur » : le titre n'a pas besoin de répéter l'outil employé.

ℹ️ Les autres titres ne changent pas — les parenthèses qui restent

(« Expulsion (kick) », « Exclusion automatique (AutoMod) »,

« Mute (exclusion temporaire) »…) ne sont pas des commandes : ce sont

des précisions sur la nature de l'action.

🔒 Garde-fou automatique

Un test parcourt tous les titres du journal (SANCTION_STYLES, 21 types) et échoue si l'un d'eux contient un « / ». Impossible de réintroduire une commande dans un titre sans casser la suite de tests :

``` ✅ Titres vérifiés (21 kinds) : aucun ne cite de commande ```


💬 Version 5.5 — Messages simples, « tais-toi » et une commande réservée au staff

Trois demandes, trois livraisons. La première corrige un vrai bug : le personnage savait reconnaître « bonjour », mais il ne répondait jamais.

1. « Bonjour », « ça va ? », « bonne nuit », « bon appétit » → il répond

Le bot ne s'exprimait que si on le mentionnait, si on répondait à un de ses messages, ou si on prononçait son nom (le fameux AI_CHAT_CHANNEL_IDS était vide). Donc un « bonjour » lancé à la cantonade restait sans réponse — alors que la détection des convenances existait déjà.

Désormais, une simple convenance le fait répondre, sans mention : c'est ce qui le fait passer pour un membre du serveur plutôt que pour un outil.

MessageAvantAprès
« Bonjour »⛔ silence✅ « Salut ! ça va ? »
« ça va ? »⛔ silence✅ il répond et renvoie la question
« Bonne nuit »⛔ silence✅ « bonne nuit, dors bien »
« Bon appétit »⛔ silence✅ « régale-toi »
« au revoir »⛔ silence✅ il rend le départ
« @Introvert'Bot … »✅✅ (inchangé)

Trois garde-fous, sans lesquels ce serait vite insupportable :

  • 🔇 anti-rafale par salon — dix « bonjour » d'affilée = une réponse

(AI_SOCIAL_CHANNEL_COOLDOWN, 60 s) ;

  • 🔁 anti-radotage par personne — il ne resalue pas la même personne dans la

minute (AI_SOCIAL_COOLDOWN, 5 min) ;

  • 📏 message court uniquement (≤ 120 caractères) : au-delà, c'est une

conversation, il attend d'être mentionné ;

  • 🚫 salons exclus configurables (AI_SOCIAL_IGNORE_CHANNEL_IDS : annonces,

logs, tickets…).

⚙️ AI_SOCIAL_TRIGGER=0 rétablit l'ancien comportement.

2. « Tais-toi » → il se tait (et il obéit vraiment)

Quand un membre lui demande de se taire, le personnage obéit : il cesse de lui répondre — mentions comprises — pendant AI_HUSH_MINUTES (30 min).

Ce qui déclenche le silence : « tais-toi », « arrête de répondre », « arrête de me parler », « chut », « stop », « silence », « laisse-moi tranquille », « lâche-moi », « pas maintenant », « ne me mentionne plus », « lâche-moi la grappe »…

  • 💬 un accusé de réception très court (« Ok, je me tais 🤐 ») confirme que la

demande est passée — AI_HUSH_ACK=0 pour un silence total ;

  • 👥 les autres membres ne sont pas affectés : seul l'auteur de la demande

est mis au silence ;

  • ⏳ après le délai, il lui reparle normalement.

🔎 Les mots courts à risque (« stop », « chut », « silence ») sont reconnus

en tant que mots entiers : « chutney » ou « backstop » ne

déclenchent rien.

3. une commande réservée au staff (administrateurs)

``` ```

L'interrupteur coupe tout : mentions, nom prononcé, réponses, salons de discussion et salutations. Le reste du bot (modération, tickets, XP, jeux, Protect) n'est pas touché.

Le vrai apport : le réglage est PERSISTÉ. Jusqu'ici, une commande réservée au staff coupait l'IA en mémoire seulement : un redémarrage la réactivait en douce, ce qui rendait la commande inutilisable en pratique. Le choix est maintenant écrit dans introvert_ai_settings, par serveur — il survit au redémarrage. Si la base est indisponible, la coupure fonctionne quand même **et la commande le dit** (sinon elle annoncerait un enregistrement qui n'a pas eu lieu).

Les anciennes commandes une commande réservée au staff restent disponibles : ce sont des alias de une commande réservée au staff, branchés sur la même logique (aucune duplication, donc aucune divergence possible).

📋 Documentation complète : INTROVERT_IA.md — § 1 sexies (messages

simples & silence), § 2 (quand il répond), § 7 bis (interrupteur).


🏷️ Version 5.4 — Le bot dit « Les introvertis » (fini le QG)

L'ancien serveur « Le QG » n'existe plus : le bot parlait donc d'un serveur qui n'est plus le vôtre. Son nom était inscrit en dur à plusieurs endroits — dans l'identité du personnage (injectée dans chaque prompt) et dans les invitations. C'est corrigé partout : « Les introvertis ».

Où le nom était figé

EndroitEffet visibleAvantAprès
Identité du personnage (introvert_ai.py)Le bot se présentait comme membre du « QG des Introvertis » dans toutes ses réponsesLe QG des IntrovertisLes introvertis
Invitations (AI_INVITE_SERVER_NAME)« On veut inviter des gens sur « … » »Le QG des IntrovertisLes introvertis
Phrase d'écoute des demandes de lien« je peux rejoindre le QG ? »rejoindre le qgrejoindre les introvertis
Dashboard (titre + pastille)Onglet du navigateur, logo de repliDashboard — Le QG / QGDashboard — Les introvertis / LI
Documentation.env, INTROVERT_IA.md, Introvert'Protect/READMELe QGLes introvertis

Ce qui n'a pas changé (et pourquoi)

  • 📅 PATCH_NOTES.md : les entrées des versions passées restent telles

quelles — un journal de version décrit ce qui a été livré à ce moment-là.

  • 🧪 Les _smoke_*.py : les serveurs qui y figurent sont fictifs (ils

servent à tester la logique). Ils ont tout de même été renommés pour rester cohérents, mais ils n'affectent en rien le bot en production.

🔒 Impossible de revenir en arrière

Un garde-fou automatique a été ajouté aux tests : il vérifie que

  1. AI_INVITE_SERVER_NAME vaut bien « Les introvertis » (et ne contient plus « QG ») ;
  2. l'identité du personnage et le prompt système complet ne citent plus l'ancien nom ;
  3. aucun fichier « vivant » du dépôt (code, .env, dashboard, docs) ne

contient « Le QG ».

Si quelqu'un réintroduit l'ancien nom un jour, **les tests échouent immédiatement**.

ℹ️ Le nom affiché dans le dashboard vient du nom Discord du bot

(Introvert'Bot) : il se met à jour tout seul. Le nom du serveur, lui, est

lu dynamiquement dans l'analyse du serveur — il n'est donc jamais inventé.


📄 Version 5.3 — route_infinie.sql enfin importable (MySQL & MariaDB)

Importer route_infinie.sql échouait avec :

```

1064 - Erreur de syntaxe près de 'ALTER TABLE route_state

ADD COLUMN IF NOT EXISTS baseline_value INT NOT…' « Une virgule ou une parenthèse droite était attendus. » ```

Deux causes, deux corrections — et le fichier fonctionne maintenant **quel que soit votre serveur**.

1. Un CREATE TABLE non fermé (cause de l'erreur 1064)

Rappel MySQL : tant qu'une instruction CREATE TABLE … ( … n'est pas fermée par );, tout ce qui suit est avalé par la même instruction. Le mot-clé ALTER qui arrivait ensuite n'avait donc aucun sens pour le serveur — d'où « erreur près de 'ALTER TABLE' ».

C'est un copier-coller tronqué (la ligne ); manquante). Le fichier du dépôt est désormais vérifié automatiquement à chaque exécution des tests : parenthèses équilibrées, guillemets appariés, chaque CREATE TABLE fermée, aucune instruction laissée ouverte.

⚠️ Copiez le fichier ENTIER (bouton Télécharger ou Importer un fichier

de phpMyAdmin), plutôt que de sélectionner un passage au hasard.

2. ADD COLUMN IF NOT EXISTS = MariaDB uniquement

Cette syntaxe n'existe pas sur MySQL 5.7/8 : elle est refusée en erreur 1064. Le § 4 du fichier n'utilise donc plus cette clause, mais une forme portable qui fonctionne partout (MySQL 5.7, MySQL 8 et MariaDB) :

```sql SET @sql := IF((SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'route_state' AND COLUMN_NAME = 'baseline_value') = 0, 'ALTER TABLE route_state ADD COLUMN baseline_value INT NOT NULL DEFAULT 0', 'DO 0'); PREPARE s FROM @sql; EXECUTE s; DEALLOCATE PREPARE s; ```

  • ✅ idempotent : relancez le fichier autant de fois que nécessaire ;
  • ✅ sans risque : seules des colonnes manquantes sont créées, aucune

valeur enregistrée n'est touchée (le compteur ne repart jamais de zéro) ;

  • ✅ un bloc par colonne (14 au total) : une erreur isolée n'annule pas tout.

La version courte IF NOT EXISTS reste disponible en § 4 bis, commentée, pour ceux qui savent qu'ils sont sur MariaDB (SELECT VERSION();).

Au passage

  • 📄 Le fichier explique en tête quoi faire en cas d'erreur d'import ;
  • 🔢 Le contrôle de structure indique les 14 colonnes attendues ;
  • 🛡️ Un test vérifie que **le fichier SQL migre exactement les mêmes colonnes que

le cog** (_MIGRATION_STATEMENTS) : impossible que les deux divergent.


🗂️ Version 5.2 — une commande réservée au staff réparée : bon salon + recherche profonde

une commande réservée au staff ne trouvait aucune présentation. Deux causes, deux corrections.

1. Le bot ne regardait pas le bon salon

Le salon des présentations était configuré sur 1517766105488167073, alors que les présentations sont publiées dans 1546825534015541360. Le bot cherchait donc dans un salon vide — et répondait « aucune présentation trouvée ».

OùAvantAprès
.envPRESENTATION_CHANNEL_ID=15177661054881670731546825534015541360
Constante du cog15177661054881670731546825534015541360

ℹ️ La variable du .env surcharge la constante : c'est la première chose à

vérifier si la commande « ne marche pas ».

2. La recherche était trop superficielle

Le salon n'était parcouru que sur les 2 000 derniers messages : la présentation d'un membre arrivé un peu avant passait sous le seuil et devenait introuvable. La profondeur passe à 10 000 messages par défaut (PRESENTATION_MAX_SCAN, 0 = tout l'historique), avec arrêt dès que les messages sont trouvés : instantané dans le cas courant, exhaustif sinon.

Et quand le message reste introuvable ? Le bot demande l'ID

C'est désormais sans ambiguïté : si le membre n'a rien posté dans la fenêtre parcourue, rien n'est supprimé et le bot répond en **demandant le message_id**, avec la marche à suivre :

``` 🔍 Aucune présentation trouvée @Léa n'a publié aucun message dans #présentations parmi les 10 000 messages les plus récents du salon — rien n'a été supprimé.

Relancez la commande avec l'option message_id : ➡️ Comment obtenir le message_id • clic droit sur la présentation → Copier l'identifiant du message ; • ou clic droit → Copier le lien du message (collez le lien, il fonctionne aussi). ```

Deux robustesses en plus

  • 🔎 Repli API : si le salon n'est pas (encore) dans le cache du bot — après

un redémarrage, par exemple — il est désormais récupéré par l'API. Avant, la commande répondait « salon introuvable » alors que le salon existait.

  • 💬 Les messages d'erreur indiquent maintenant quel identifiant est

configuré et où le corriger (.env ou constante du cog).

⚙️ Réglages : PRESENTATION_CHANNEL_ID, PRESENTATION_MAX_SCAN,

PRESENTATION_DELETE_COPY_CHANNEL_ID, MODLOG_CHANNEL_ID.

Documentation complète : PRESENTATION.md.


🛣️ Version 5.1 — La Route de l'Infini survit vraiment au redémarrage

Le compteur de la Route de l'Infini était censé être sauvegardé en base à chaque nombre validé… mais il repartait de 1 dès que le bot redémarrait. La cause est trouvée et corrigée.

Pourquoi le nombre était perdu

CREATE TABLE IF NOT EXISTS ne modifie jamais une table déjà existante. Or route_state a été créée par une version antérieure du bot, sans les colonnes ajoutées depuis (baseline_value, validations, failures, last_user_id…).

Résultat : à chaque validation, la sauvegarde échouait sur une erreur MySQL 1054 Unknown column — signalée nulle part dans les logs clairs. Le compteur restait donc en mémoire vive, et tout redémarrage le ramenait à 1.

SymptômeCauseCorrectif
Le compteur repart de 1 après un redémarrageTable route_state ancienne, colonnes manquantes → chaque écriture échouait en silenceMise à niveau automatique de la table au démarrage + fichier SQL de réparation

Ce qui a changé

  • 🧩 Le cog gère lui-même ses tables (ensure_schema) : il ne dépend plus de

l'ordre de démarrage de bot.py, et il **ajoute automatiquement les colonnes manquantes** (_MIGRATION_STATEMENTS) — idempotent, jamais bloquant.

  • 📣 Une sauvegarde impossible est désormais signalée avec la solution

(« exécutez route_infinie.sql § 4 ») au lieu de faire perdre la partie en silence.

  • 📄 route_infinie.sql réparé et documenté : le fichier crée les trois

tables, remet à niveau une table ancienne (ADD COLUMN IF NOT EXISTS), affiche l'état enregistré (compteur, record, classement) et explique comment réinitialiser à la main. ⚠️ Il ne remet jamais le compteur à zéro tout seul.

  • 🛡️ Non-régression verrouillée par un test : toute colonne écrite par

_save_state doit exister dans le schéma, dans les migrations et dans le fichier SQL — impossible de réintroduire le bug sans casser le test.

💡 Après mise à jour, rien à faire : la réparation est automatique au

démarrage du bot. Le fichier route_infinie.sql reste utile pour réparer à la

main (ou vérifier SHOW COLUMNS FROM route_state en PhpMyAdmin).

⚙️ Le seul moyen de repartir de zéro reste la commande une commande réservée au staff

(administrateurs) ou une erreur de comptage — c'est la règle du jeu.


🗂️ Version 5.0 — Supprimer la présentation d'un membre (et le prévenir)

Le bot savait retrouver la présentation d'un membre (une commande réservée au staff). Il sait maintenant la supprimer proprement : avec un motif, une **copie pour la personne concernée, et une trace qui survit à la suppression**.

``` ```

Une suppression, quatre traces

OùQuoi
📬 MP au membreLa copie de son message d'origine (texte + pièces jointes) et le motif — il sait exactement ce qui a disparu et pourquoi.
🗑️ Sanction (1554219964804632577)La sanction apparaît dans le salon des sanctions, à côté des bans et des mutes (🗑️ Présentation supprimée).
🗂️ Copie (1554219968370053241)La copie intégrale du message d'origine et le motif, avec l'auteur, le staff qui a décidé, la date et le lien du message supprimé.
📇 Casier du membreUne ligne delete dans casier_sanctions : la sanction reste consultable dans une commande réservée au staff, avec son motif et son lien.

L'administrateur reçoit une confirmation éphémère qui liste le résultat de chaque étape (MP ✅, copie ✅, sanction ✅, casier ✅) et, s'il en existe, les autres présentations du membre — pratique quand il y en a plusieurs.

Les garde-fous

  • 🔒 Administrateurs uniquement : la permission est exigée par la commande

et revérifiée dans le code (les permissions par défaut sont modifiables dans les Intégrations du serveur).

  • ✍️ Motif obligatoire : sans motif, rien n'est supprimé.
  • 🎯 Jamais le message d'un autre : si le message visé n'est pas celui du

membre, la commande s'arrête — sinon la personne visée serait sanctionnée sans avoir rien écrit.

  • 📪 MP fermés : la suppression n'échoue pas, la confirmation le signale.
  • 🧮 Base indisponible : la suppression reste valable, seule l'entrée du

casier est manquante (signalée elle aussi).

⚙️ Réglages : PRESENTATION_CHANNEL_ID (salon des présentations),

PRESENTATION_DELETE_COPY_CHANNEL_ID (salon des copies),

MODLOG_CHANNEL_ID (salon des sanctions, partagé avec le reste du bot).

Documentation complète : PRESENTATION.md.


🖼️ Version 4.9 — L'avatar du membre, et « réessaie plus tard »

Deux finitions qui changent tout au quotidien : le bot voit de qui on parle, et il ne reste plus jamais muet.

Il voit l'avatar de la personne citée

Quand on cite quelqu'un (« @Mathieu, c'est qui ce gars ? ») ou qu'on pose une question sur une personne, le bot recevait déjà un profil écrit (rôles, ancienneté, boost…). Il reçoit désormais aussi son avatar, transmis en image au modèle : il peut donc le décrire (« t'as un avatar de chat trop mignon ») au lieu de broder. Le profil est complété de la bannière, de la **couleur d'accent et du « à propos » — mais uniquement s'il est lisible**.

ÉlémentSourceExemple
Avatarimage transmise au modèle« il ressemble à quoi ? » → il le voit
Bannièrefait« bannière de profil : présente »
Couleur d'accentfait« couleur d'accent du profil : #5865f2 »
« À propos »seulement s'il est lisiblejamais inventé

ℹ️ Discord ne transmet pas le « à propos » des autres membres à un bot :

le bot ne l'affiche donc que s'il le reçoit, et n'en invente jamais. Si

l'avatar est illisible (réseau, taille, format), l'échec est silencieux :

la réponse part quand même, avec le profil écrit seul.

⚙️ Réglages : AI_MEMBER_AVATAR=0 coupe la transmission de l'avatar,

AI_MEMBER_PROFILE=0 coupe toute l'analyse de profil.

Il ne reste plus jamais muet

[confidentiel] et [confidentiel], ou API injoignable), le bot restait silencieux — impossible de distinguer « il m'ignore » de « il est en panne ».

Désormais, il prévient et invite à réessayer plus tard :

``` Mathieu : @Introvert'Bot tu es là ? Bot : @Mathieu J'ai donné tout ce que j'avais pour aujourd'hui 😅 — redemande-moi un peu plus tard, je serai de nouveau là ! ```

  • la personne est mentionnée comme dans une réponse normale ;
  • un seul avertissement par salon (AI_BUSY_COOLDOWN, déf. 180 s) : pas de spam ;
  • le texte est fixe (jamais généré par le modèle, qui est justement

indisponible) : il passe donc toujours ;

  • AI_BUSY_ENABLED=0 rétablit l'ancien comportement (silence).

☀️ Version 4.7 — Il dit bonjour, bonne nuit et bon appétit

Le bot n'attend plus qu'on lui pose une question : il salue, souhaite une bonne nuit à ceux qui vont se coucher, dit bon appétit quand l'heure s'y prête, rend un au revoir et répond à un simple « ça va ? ».

Il connaît enfin l'heure

L'heureCe qu'il dit
8 h« Bonjour »
14 h« Bon après-midi »
20 h« Bonsoir », et bon appétit s'il est question de manger
23 h« Bonsoir », et il sait qu'il se fait tard

Il repère aussi les fenêtres de repas (déjeuner 11 h 45–13 h 30, dîner 19 h–21 h 30…) : c'est ce qui rend le « bon appétit » juste, au bon moment.

Ce à quoi il répond maintenant

  • 👋 « bonjour », « salut », « coucou » → il salue en retour, avec le mot juste pour l'heure.
  • 🌙 « je vais me coucher », « au dodo », « bonne nuit » → il souhaite une bonne nuit, sans retenir la personne.
  • 🍽️ « je vais manger », « bon appétit », « à table » → il dit bon appétit, en une phrase légère.
  • 🙂 « ça va ? », « comment tu vas ? », « quoi de neuf ? » → il répond vraiment et renvoie la question.
  • 👋 « au revoir », « bonne journée », « à demain » → il rend le départ.
  • ⏰ « il est quelle heure ? » → il donne l'heure exacte, jamais inventée.

Deux garde-fous

  • 🕐 Jamais à contretemps : à 15 h, il ne souhaite pas « bon appétit » sans

que vous ayez dit que vous alliez manger.

  • 🔁 Jamais radoteur : il ne re-salue pas la même personne toutes les deux

minutes (AI_SOCIAL_COOLDOWN) — mais « ça va ? » et l'heure passent toujours, par politesse.

⚙️ Réglages : AI_SOCIAL_ENABLED=0 coupe tout, AI_SOCIAL_TZ règle le fuseau

(Europe/Paris par défaut), AI_SOCIAL_COOLDOWN l'anti-radotage.


Le bot parle maintenant juste des sujets sur lesquels une maladresse fait vraiment mal — et il respecte ceux qui se confient.

Ce qu'il connaît vraiment

SujetCe qu'il sait
Troubles DYSDyslexie, dysorthographie, dysgraphie, dyscalculie, dysphasie, dyspraxie. Rien à voir avec l'intelligence : ce qui aide, ce qui fait mal.
TDAHFonctions exécutives, 3 présentations (dont sans hyperactivité), ni paresse ni éducation, traitement prescrit par un médecin.
TDIIssu d'un traumatisme : un mécanisme de survie. Ni comédie, ni danger.
OrientationHétéro, homo, lesbienne, bi, pan, ace, aro. Ni choix ni maladie ; les « thérapies de conversion » sont nuisibles et illégales.
GenreTrans, non-binaire, genderfluid. Pas une maladie mentale (CIM-11). Pronoms respectés, deadname jamais employé.
Coming outC'est la personne qui décide. Oter quelqu'un est une violence.

Ce qu'il ne fera JAMAIS

  • 🚫 Diagnostiquer — il parle des sujets en général, jamais du cas de quelqu'un (« tu as donc un… » est proscrit).
  • 🚫 Juger ou minimiser — pas de « c'est dans ta tête », « tu fais semblant », « c'est une phase ».
  • 🚫 Tenir de propos validiste, LGBTphobe ou pathologisant ; jamais de « guérison » ni de thérapie de conversion.
  • 🔒 Trahir la confiance : prénom et pronoms respectés, deadname jamais employé, identité jamais révélée à un tiers — et une confidence n'est jamais recopiée dans le salon de journal.
  • 😄 Plaisanter dessus : humour, clash et chambrage sont coupés sur ces sujets.

Une confidence, pas une question

Quand quelqu'un se livre (« je crois que je suis bi », « je suis dys »), il accueille d'abord — « merci de me l'avoir dit » — au lieu de réciter un cours. Et quand un danger est évoqué (violence, harcèlement, détresse), il passe en mode grave et oriente vers de l'aide réelle : 3114, 3018, 119, 3919, SOS homophobie.

⚙️ Réglage : AI_KNOWLEDGE_ENABLED=0 coupe la fonctionnalité.


« Combien de membres ? » « Il y a des tickets ouverts ? » « **Qui est en ligne ? » — il ne devine plus : il regarde et il répond avec les vrais chiffres du moment**.

Ce qu'il sait vous dire

Vous demandezIl répond avec
« Combien de membres il y a ? »Le total, le nombre d'humains, de bots et de boosters
« Qui est en ligne ? » / « Qui est en vocal ? »Les membres connectés et ceux en vocal, salon par salon
« Il y a des tickets en attente ? »Les tickets de support par statut + les candidatures + la file d'attente du staff
« Combien d'avertissements ? »Les sanctions par type, les bans et mutes actifs
« Ça bouge ici ? »Accueils, départs, signalements, sessions vocales
« C'est quoi ce serveur ? »Nom, description, date de création, rôles, salons, émojis, propriétaire

Trois promesses

  • 🎯 Jamais de chiffre inventé. Si une donnée n'est pas lisible (table

absente, intention manquante), il dit simplement qu'il ne l'a pas — il n'annonce jamais un faux zéro.

  • ⚡ Réponse instantanée. Les compteurs sont relus au moment de la question

(cache de 15 s), et seulement pour les sujets demandés.

  • 🔒 Chiffres, jamais de contenu. Sur les tickets, il donne des nombres —

jamais le contenu privé d'une conversation.

« Combien » = une question, pas un mot au hasard

« j'ai un souci avec mon ticket » ne déclenche rien : il faut une vraie question (« combien », « il y a… ? », « qui… ? »). Pas de chiffres qui tombent au milieu d'une conversation.

⚙️ Pour « qui est en ligne » : activez PRESENCE INTENT dans le portail

Discord puis DISCORD_PRESENCE_INTENT=1. Les membres en vocal sont

comptés sans rien activer. Réglage global : AI_SERVER_STATS=0 coupe tout.


Le bot suit vraiment la conversation : il encaisse une rafale de messages, n'oublie pas de quoi on lui parle, rassure, motive, et peut tenir le rôle qu'on lui demande — confident, ami, petit ami, frère, sœur.

À plusieurs messages en même temps

SituationAvantMaintenant
« salut » + « tu es là ? » + « j'ai un souci » d'affiléeIl pouvait répondre à « salut » sans avoir vu le souci — et noyer le salon sous 3 réponsesIl répond à l'ENSEMBLE, une seule fois, en tenant compte de chaque message
Bob s'intercale au milieuRisque de mélangeChacun garde son message, son sujet
« et du coup ? » 5 minutes plus tard« De quoi tu parles ? »Il reprend le fil : « ton souci de commandes, on en était où ? »
  • 🔗 Rafale reconnue : tous les messages écrits d'affilée par la même personne

sont marqués ➤ et lus comme une seule prise de parole.

  • 🧲 Regroupement (AI_COALESCE) : une rafale ne déclenche pas une réponse

par message — les messages arrivés pendant la génération sont traités **une fois**, sur l'état frais.

  • 🧵 Fil de conversation (AI_THREAD_ENABLED) : un fil par personne, qui

survit aux interventions des autres et à un silence (30 min).

Rassurer, motiver, redonner confiance

Dès qu'il sent le doute, la peur ou la dévalorisation — « je n'y arrive pas », « j'ai peur de rater », « je suis nul », « je me sens seul », ou simplement un message triste —, il accueille l'émotion, ne minimise jamais, **rassure sur du concret, redit sa confiance et propose une** petite action faisable. Aucune formule creuse. AI_SUPPORT_ENABLED.

Confident, ami, petit ami, frère, sœur

Il tient le rôle qu'on lui demande (« tu es comme un frère », « sois mon confident », « je te vois comme ma grande sœur ») et il s'en souvient : la relation s'installe, et elle change si la personne change d'avis.

RôleCe qui change
🤫 ConfidentÉcoute sans juger, garde tout pour soi, ne banalise jamais un aveu
🤝 AmiComplicité, chambrage gentil, franchise quand il faut
💞 Petit(e) ami(e)Tendresse assumée, fierté de l'autre — « PEGI 18 », jamais explicite
🧑 FrèreProtecteur et taquin, conseils francs sans dureté
👧 SœurDouce et complice, rassure, prend soin avec tact

🛡️ Garde-fous : le rôle colore le ton mais ne remplace pas sa

personnalité ; jamais deux rôles incompatibles dans la même réponse ; **aucune

ambiguïté amoureuse si la personne est mineure ou en cas de doute** ; les

limites habituelles restent (jamais vulgaire, jamais insistant).

ℹ️ Réglages : AI_COALESCE, AI_THREAD_ENABLED, AI_THREAD_TTL,

AI_SUPPORT_ENABLED, AI_RELATION_ENABLED (0 = coupé).


Le bot ne lit plus seulement des mots : il **perçoit qui parle, de qui on parle, ce qu'on lui montre et ce qu'on attend vraiment**.

Ce qui change

SituationAvantMaintenant
« @Mathieu, tu penses quoi de ça ? »La mention était effacée : il ignorait de qui on parlaitIl voit « @Mathieu » et répond de la bonne personne
« C'est qui, ce gars ? »Il inventaitIl décrit le vrai profil : depuis quand le compte existe, depuis quand la personne est là, ses rôles, son boost, ce qu'elle fait
On lui envoie une image (capture, photo, meme)Il voyait juste « (image) » et broderIl voit vraiment l'image et commente ce qu'il observe
« ça marche pas, aide-moi »Il répondait à la lettreIl repère le besoin réel (aide, écoute, envie de lien…) et y répond
  • 🔗 Mentions comprises : @Mathieu, @Modérateur, #général sont

résolus en clair dans ce que lit le bot (AI_MENTION_NAMES).

  • 🪪 Profil Discord analysé à partir de données publiques du serveur

uniquement (AI_MEMBER_PROFILE) — jamais de donnée privée (e-mail, MP…).

  • 🖼️ Analyse d'images (vision) : l'image est réellement transmise au

modèle, encodée pour fonctionner chez [confidentiel] comme chez [confidentiel] (AI_VISION). Les vignettes d'aperçu de lien et les GIF animés sont écartés (bruit, poids).

  • 🎯 Besoins & attentes : le bot nomme le besoin derrière la demande et

s'y adresse (AI_NEEDS_DETECTION).

ℹ️ Chaque brique se coupe indépendamment : AI_MENTION_NAMES=0,

AI_MEMBER_PROFILE=0, AI_VISION=0, AI_NEEDS_DETECTION=0.


🤝 Version 4.2 — Il invite ses potes à rejoindre le serveur (sans forcer)

Le bot invite naturellement ses interlocuteurs à ramener leurs potes sur le serveur — mais avec parcimonie : jamais « calé » à chaque phrase.

Ce qui change

SituationComportement
Message banal, moment propiceIl glisse, en quelques mots, une invitation naturelle (« ramène tes potes », « fais tourner »…), intégrée à sa réponse
On demande (« comment inviter ? », « c'est quoi le lien ? »)Il répond toujours vraiment — lien exact s'il est configuré
Personne triste / en colère ou clash en coursAucune invitation
Un salon a déjà eu une invitation récemmentAucune invitation (cooldown)
  • 🎚️ Dosage garanti : invitation rare (AI_INVITE_CHANCE, ~1 sur 8) et

jamais deux fois d'affilée (AI_INVITE_COOLDOWN, déf. 15 min). C'est exactement l'inverse de « le caler à toutes les phrases ».

  • 🧩 Intégrée, pas plaquée : quelques mots sur son ton habituel, jamais un pavé

publicitaire. Le lien n'est donné que si on le demande.

  • ✍️ Aucun lien inventé : sans AI_INVITE_URL, il invite sans URL et ne

fabrique rien ; avec, il donne le lien tel quel.

  • 🙅 Jamais dans un moment difficile : tristesse, colère, clash → aucune

invitation.

Réglages

```dotenv AI_INVITE_ENABLED=1 # 0 = ne plus inviter du tout AI_INVITE_CHANCE=0.12 # probabilité d'une invitation spontanée AI_INVITE_COOLDOWN=900 # délai mini entre deux invitations (s) AI_INVITE_URL= # lien donné tel quel (vide = aucun, jamais inventé) AI_INVITE_SERVER_NAME=Le QG des Introvertis ```


👥 Version 4.1 — Plusieurs personnes à la fois : il ne mélange plus

Quand plusieurs membres interpellent le bot en même temps dans un salon, il répondait parfois au mauvais message (le dernier du salon) ou mélangeait les propos de plusieurs personnes. C'est corrigé.

Ce qui change

AvantMaintenant
Il répondait au dernier message du salon — qui pouvait être celui d'un autreLe message de la personne visée est marqué (➤) et le prompt nomme l'interlocuteur : il répond à elle
Deux interpellations simultanées généraient deux réponses en parallèle sur le même historique (mélange, humeur en course)Les réponses d'un salon sont sérialisées : une à la fois, dans l'ordre
Risque d'attribuer à quelqu'un ce qu'un autre a écritInterdit explicite : une réponse = une personne
  • 🎯 Ciblage explicite : le prompt dit « tu réponds à X, et seulement à SON

message ; les messages des autres ne te sont pas adressés ».

  • 🧷 Double protection : consigne dans le prompt et marqueur ➤ dans

l'historique envoyé au modèle.

  • 🔒 Verrou par salon (_channel_lock) : plus de génération en parallèle ni de

course sur l'humeur/émotion quand deux personnes parlent en même temps.

  • ✅ Chacun reçoit sa réponse, avec sa mention (@Camille …, @Yanis …).

Réglages

Aucun nouveau réglage : la correction est active par défaut. Elle s'appuie sur AI_HISTORY_LIMIT (nombre de messages relus) et AI_MENTION_ON_REPLY.


📍 Version 4.0 — Il ne nomme plus le salon où il répond

Le bot ne cite plus jamais le salon où il répond — c'est-à-dire celui où on vient de l'interpeller. Fini les « ici dans #général » : il répond comme dans une conversation, tout simplement.

Ce qui change

AvantMaintenant
Pouvait rappeler / citer le salon où il répondaitJamais : il ne le nomme pas, n'écrit pas de mention de salon (<#…>)
Une mention de salon écrite par le modèle pouvait partir telle quelleElle est retirée automatiquement avant l'envoi (strip_channel_mentions)
—Les autres salons restent utilisables : « je poste où mes memes ? » → « va dans #memes »
  • 🧭 Le nom du salon courant est transmis au prompt pour qu'il **sache lequel

éviter** — la règle est donc précise, sans casser les conseils vers les autres salons.

  • 🧹 Double protection : une règle dans le prompt et un filet de code qui

retire toute mention de salon (<#…>) de la réponse publiée.

  • 🎛️ Désactivable : AI_NO_CHANNEL_NAME=0 (il peut alors nommer le salon courant).

Réglages

```dotenv AI_NO_CHANNEL_NAME=1 # 0 = autorise le bot à nommer le salon où il répond ```


🎤 Version 3.9 — Le bot clache façon rap FR (quand il est en colère)

Quand il est vraiment en colère (colere) ou en rage, le personnage sait rendre les coups comme une grande gueule du rap français — Booba, Kaaris et consorts : punchlines qui claquent, egotrip, tacles.

Ce qui change

SituationComportement
Message normal / taquinerieRien ne change : chaleureux, drôle, aucun clash
Vraiment provoqué (colère → rage après 3 provocations)Il clashe : punchlines courtes et percutantes, egotrip, style rap FR
L'autre se calme ou s'excuseIl raccroche le clash et retrouve son calme
  • 🎤 Crédible : punchlines personnalisées (il rebondit sur ce que l'autre

vient de dire), du rythme, un champ lexical rap (kick, flow, barre, ego). Une punchline, pas une engueulade.

  • 😤 Uniquement énervé / en colère : le registre est **déclenché par

l'émotion**, jamais au calme.

  • ⚖️ Clash verbal, jamais de la haine : il attaque les idées et l'attitude,

jamais la personne. Interdit même en rage : insulte raciste / sexiste / homophobe / validiste / anti-religieuse, moquerie sur le physique, l'origine, la religion, le handicap, la santé, un deuil ou la misère, la famille, et **toute menace de violence. On clash avec des mots**.

  • 🎛️ Désactivable : AI_CLASH_ENABLED=0.

Réglages

```dotenv AI_CLASH_ENABLED=1 # 0 = coupe le clash (froid et sec, sans punchlines) AI_CLASH_MAX_SENTENCES=3 # longueur max d'un clash (phrases) ```


🍻 Version 3.8 — Culture soirée & langage jeune

Le personnage baigne dans la culture jeune : il connaît l'alcool, le tabac, les soirées et les boîtes de nuit, et il parle le **langage des jeunes (argot, verlan, refs rap / TikTok) quand on lui parle comme ça**.

Ce qu'il maîtrise

DomaineExemples
Alcoolbières, cocktails, shots, apéro, vin, whisky, rhum, punch, le lendemain de veille
Tabacclopes, roulées, chicha / narguilé, vape / puff, sevrage, ce que ça coûte
Soiréespré-soirée / before, apéro, anniversaires, playlists, l'after
Boîtesclubs, entrées, vestiaire, DJ set, dress code, teuf, prix des consos
Logistiquecomment rentrer, le SAM, le budget, où dormir, plans pas chers
  • 🗣️ Registre jeune / cité : il capte et rend l'argot (« wesh », « de ouf »,

« ça dit quoi »…), les refs rap FR / US, TikTok, streetwear — et il s'adapte : pas d'argot face à quelqu'un qui parle normalement.

  • 😄 Un pote FUN, pas un mauvais conseil : anecdotes de soirée, taquineries —

on rit avec lui, jamais contre lui.

  • 🛡️ Responsable, toujours : 🚫 aucune incitation à boire ou fumer, aucune

apologie de la défonce ; rappels malins (l'eau entre deux verres, le SAM, jamais au volant), rien d'illégal, rien pour les mineurs, jamais vulgaire.

  • 😂 Deux registres d'humour en plus : argot et ref_soiree.
  • 🎛️ Désactivable : AI_URBAN_ENABLED=0.

Réglages

```dotenv AI_URBAN_ENABLED=1 # 0 = coupe la culture sortie + le langage jeune ```


💬 Version 3.7 — Pas de DM : il renvoie vers le serveur

Le personnage ne discute jamais en message privé. Si on l'invite en DM / MP, il le dit clairement — « je ne peux pas venir ni discuter en privé » — et il invite la personne à rester active sur le serveur pour lui parler.

Ce qui change

SituationComportement
« viens en DM », « on peut parler en privé ? », « tu peux me MP ? »Il refuse gentiment et explique qu'il ne peut pas aller ni discuter en privé
EnsuiteIl renvoie vers le serveur : c'est ici qu'il parle, et il invite à y être actif (participer, discuter, traîner dans les salons)
Message normalRien ne change : aucun rappel des DM sans raison
Message privé reçu par le botIl n'y répond pas : le bot ne parle que sur le serveur
  • 🚫 Le refus est poli et chaleureux : jamais sec, jamais vexé — il reste taquin.
  • 🧭 C'est le serveur qui compte : il pousse à la participation plutôt qu'au privé.
  • 🎛️ Désactivable : AI_DM_REFUSAL_ENABLED=0 (le bot ne refuse plus explicitement).

Réglages

```dotenv AI_DM_REFUSAL_ENABLED=1 # 0 = ne plus refuser explicitement les DM / MP ```


🎯 Version 3.6 — Roulette : une commande réservée au staff (choisir soi-même le membre)

Nouvelle commande réservée aux administrateurs pour désigner le membre d'une manche, au lieu de laisser faire le tirage au sort.

``` ```

  • 👑 Remplace la manche en cours : la personne désignée est mentionnée et reçoit

sa question immédiatement, même si elle n'était pas « prioritaire » au tirage.

  • 🔄 La manche précédente est remplacée, son message est retiré (même

nettoyage que lors d'un délai dépassé — cf. Version 3.5).

  • 🛡️ Contrôles : réservé aux administrateurs, impossible de désigner un

bot, et le membre doit pouvoir voir/écrire dans le salon de jeu.

  • 🎛️ Utilise le réglage VERITE_DELETE_TIMEOUT_MESSAGE pour la suppression de

l'ancien message.

Commandes /verite (rappel)

CommandeRôleAdmin
une commande réservée au staffDémarre la roulette✅
une commande réservée au staffL'arrête✅
une commande réservée au staffForce un nouveau tirage aléatoire✅
une commande réservée au staffDésigne un membre précis✅
une commande réservée au staffAjoute une question✅
/verite statutÉtat et manche en cours—
/verite classementLes plus joueurs—
/verite reglesRappelle les règles—

⌛ Version 3.5 — Roulette : le message de la personne précédente est supprimé

Dans le salon du jeu (1559174149761671208), quand un membre ne répond pas dans le délai et que la roulette tire un autre membre, le **message de la question — celui qui mentionnait** la personne précédente — est désormais supprimé automatiquement avant la nouvelle question.

  • 🧹 Fini la mention obsolète qui traînait dans le salon avec ses boutons morts.
  • ✅ Le message de la nouvelle personne, lui, reste bien en place.
  • 🎛️ Désactivable : VERITE_DELETE_TIMEOUT_MESSAGE=0 (le message est conservé).
  • ℹ️ Seule la question expirée est retirée : l'annonce « on passe au suivant »

reste publiée, et le bouton Passer n'est pas concerné.


👑 Version 3.4 — « Qui t'a créé ? » → le créateur, en mode dictateur

Quand on demande au bot qui l'a créé, il désigne son créateur… et le mentionne (la personne reçoit une notification), le tout sur un ton de fidèle serviteur d'un « dictateur bienveillant » : déférent, théâtral, drôle (« gloire à mon créateur », « vive notre guide suprême »).

  • 🎯 Détection souple : « qui t'a créé ? », « c'est qui ton créateur ? », « qui

t'a fait ? », « ton patron ? »… → le gag se déclenche.

  • 👑 Le créateur mentionné est configurable : AI_CREATOR_ID

(défaut 1061367673952424026).

  • 🛡️ Toujours mentionné : si le modèle « oublie » de le citer, le code pose

la mention lui-même — le créateur est donc notifié à coup sûr.

  • 🎛️ Désactivable : AI_CREATOR_ENABLED=0.
  • 🎭 C'est de l'humour : aucune apologie réelle, aucun propos politique,

aucune violence — uniquement le culte du chef gentiment moqué.


🛡️ Version 3.3 — Protect : fin du spam d'emojis + salon exempté

Côté Introvert'Protect (le second bot), deux ajustements demandés :

🚫 Plus de détection « spam d'emojis »

La détection d'abus d'emojis / caractères spéciaux (emoji_spam) est désactivée : plus aucun avertissement pour un déluge d'emojis, un message en majuscules, un caractère répété ou du texte « zalgo ».

  • 🎛️ Réactivable à tout moment : PROTECT_EMOJI_SPAM=1 dans le .env

(le code de détection est conservé, juste désactivé par défaut).

  • ✅ Les protections sérieuses restent actives : arnaque, phishing, liens

suspects, invitations, fichiers dangereux, mentions de masse, raid.

🛡️ Salon 1546825534015541360 exempté d'anti-spam

Ce salon rejoint la liste des salons de bavardage : l'anti-spam de messages (cadence, messages répétés, emojis) y est désactivé. Les protections lourdes y restent actives.

```dotenv PROTECT_SPAM_EXEMPT_CHANNELS=1552787521761448038,1546825534015541360 PROTECT_EMOJI_SPAM=0 ```


💛 Version 3.2 — Humeur chaleureuse, ton compris, et jeu de séduction

Le personnage devient plus sympathique et moins sur la défensive par défaut, comprend le ton qu'on emploie, et sait jouer la séduction — avec tact.

Ce qui change

AvantMaintenant
Neutre par défaut, pouvait paraître secDe bonne humeur par défaut : chaleureux, drôle, avenant
Pouvait se braquer pour une taquinerieLit le ton : si on est gentil, aucune raison de s'énerver ; le chambrage amical le fait rire
Ne s'énervait qu'en cas d'hostilité réelleIdem, mais plus juste : la colère ne monte que si on le cherche vraiment (insulte, mépris, menace)
Aucun contenu sexuel, jamaisSi on le chauffe, il répond dans le même sens — taquin, allusif, registre « PEGI 18 »

Le ton suggestif (« chauffe »)

  • 🎯 Il suit le ton de l'autre : un peu chaud → un peu chaud ; il n'insiste

pas → il redescend ; on s'arrête → il s'arrête aussitôt.

  • 🚫 Il reste toujours dans l'allusion : jamais de description sexuelle

explicite, jamais de terme cru ou pornographique, jamais vulgaire.

  • 🙅 Il n'initie jamais la chose : il répond au ton qu'on lui donne.
  • 🎛️ Pour un personnage strictement non sexuel : AI_SPICY_ENABLED=0.

Réglages

```dotenv AI_DEFAULT_MOOD=4 # humeur de départ (bonne humeur par défaut) AI_SPICY_ENABLED=1 # 0 = réponse strictement non sexuelle ```

ℹ️ Les nouveaux sentiments taquin, suggestif et chaud affinent

l'analyse : une vanne amicale n'est plus jamais prise pour de l'hostilité.


🛣️ Version 3.1 — Règles publiées automatiquement au démarrage

Au lancement du bot, les règles des deux jeux sont désormais publiées d'elles-mêmes dans leur salon, sans qu'aucune commande ne soit nécessaire.

SalonJeuCe qui est publié au démarrage
1552787521761448038La Route de l'InfiniLes règles + le chiffre de départ (Prochain nombre : 1)
1559174149761671208Roulette de la VéritéLes règles + un membre tiré au sort mentionné pour l'inviter à jouer

Rappels :

  • 🔁 Route : quand un joueur casse la route, le bot renvoie toujours le

chiffre de redémarrage (➡️ Prochain nombre : 1).

  • 🎲 Roulette : la publication d'un membre est une simple invitation ; la

manche, elle, démarre toujours avec une commande réservée au staff.

  • 🚫 Anti-doublon : le panneau n'est pas republié s'il est déjà le **dernier

message** du salon (pas de spam à chaque redémarrage).

  • 🎛️ Réglages (facultatifs) : ROUTE_AUTO_RULES, VERITE_AUTO_RULES,

VERITE_AUTO_MENTION — mettre 0 pour désactiver.


😂 Version 3.0 — Un vrai sens de l'humour

✨ Ce qui change

Avant, le bot pouvait être taquin, mais il n'avait pas de réserve d'humour propre : il ne savait pas « raconter une blague ».

Maintenant, il a un répertoire de 12 registres qu'il fait varier :

RegistreExemple de ce que ça donne
vannevanne courte avec une chute inattendue
punchlineréplique qui fait mouche en une phrase
autoderisionil se moque gentiment de lui-même (geek, introverti…)
absurdedécalage logique inattendu
exagerationun détail poussé à l'extrême
jeu_de_motscalembour, même un peu nase — assumé
referencepop culture, meme, trend TikTok, format de sketch
anecdotepetite anecdote perso crédible et drôle
fait_insolitefait réel surprenant lié au sujet
storytellingmini-histoire en 2 phrases avec un twist
comparaisonmétaphore improbable mais juste
plot_twistça part d'un côté, puis ça part ailleurs

🎯 Quand ?

SituationComportement
On lui demande (« raconte-moi une blague », « fais-moi rire », « balance une vanne », « un fun fact », « story time »…)Il en sort une à coup sûr
Conversation normale, moment qui s'y prêteAI_HUMOR_CHANCE (35 % par défaut) : une touche d'humour naturelle
La personne est triste, en colère, ou parle d'un problème sérieuxAucun humour — il écoute (règle d'or)

🛡️ Les garde-fous

  • Jamais de moquerie qui blesse : physique, origine, religion, handicap,

orientation, santé, deuil, misère → interdits. Rien de raciste, sexiste, homophobe ou gras. On rit avec les gens, jamais d'eux.

  • La chute n'est jamais expliquée : si tu dois expliquer que c'était drôle,

ce n'est plus drôle.

  • Aucune invention présentée comme un fait réel : si c'est inventé, c'est de

l'humour assumé.

  • Références comprises par tous : au moindre doute, il le dit en clin d'œil

(« ref de vieux, désolé ») ou il change. Pas de ref obscure ou périmée.

🔁 Anti-radotage

Le modèle déclare sa chute dans le champ vanne de sa réponse JSON. Les AI_HUMOR_MEMORY dernières blagues (8 par défaut) lui sont ensuite rappelées avec interdiction absolue de les resservir — fini les blagues en boucle.

💰 Coût maîtrisé

Le bloc d'humour (~2 100 caractères ≈ 500 jetons) n'est injecté **que quand l'humour est actif** : jamais sur les réponses sérieuses, et seulement ~35 % du temps en conversation normale.

Réglages : AI_HUMOR_ENABLED, AI_HUMOR_CHANCE, AI_HUMOR_MEMORY.


💬 Version 2.9 — Le bot te mentionne quand il te répond

✨ Ce qui change

Avant : → Salut, ça va et toi ? — sans destinataire apparent ; la personne devait surveiller le salon pour voir la réponse.

Maintenant : → @Mathieu Salut, ça va et toi ? — la personne est notifiée.

AvantMaintenant
Salut, ça va ?@Mathieu Salut, ça va ?

🔒 Comment c'est fait (et pourquoi c'est sûr)

La mention n'est pas écrite par le modèle : elle est posée par le code, à partir de l'identifiant Discord réel de la personne.

  • _apply_mention() préfixe la réponse par <@id> ;
  • si le modèle écrit quand même des mentions, elles sont retirées puis

remplacées par la bonne : pas de doublon, et aucun faux @inconnu ;

  • le prompt interdit explicitement au modèle d'écrire une mention lui-même ;
  • garde-fou Discord : l'envoi déclare `AllowedMentions(users=[cette

personne], roles=[], everyone=False). Résultat : @everyone, @here` et les rôles sont impossibles, même si le modèle les écrivait ;

  • la mention est conservée hors de la mémoire anti-répétition (elle est

identique à chaque fois : elle fausserait la détection de répétition).

🎯 Quand exactement ?

SituationMention ?
On mentionne le bot (@Introvert'Bot …)✅ oui
On répond à un de ses messages✅ oui
On prononce son nom (« tu penses quoi, Introvert'Bot ? »)✅ oui
Salon « de discussion » (AI_CHAT_CHANNEL_IDS), sans l'avoir visé❌ non (volontaire)

Réglage : AI_MENTION_ON_REPLY=0 pour désactiver les mentions.


💗 Version 2.8 — Un seul bot, et il ressent l'amour

🔇 Fin du « couple de bots »

Les deux personnages qui discutaient entre eux (et formaient un couple) ont été retirés. Désormais :

  • un seul bot répond, et c'est Introvert'Bot : mention, réponse à un de

ses messages, ou son nom prononcé ;

  • Introvert'Protect garde uniquement ses fonctions de protection : il ne

monte plus l'IA et ne parle jamais ;

  • le salon de couple, la relance automatique et la mémoire de couple

ont disparu (plus de AI_COUPLE_*).

Pour éviter tout doublon, le cog IA est inerte pour tout persona autre que le bot principal : même si un second bot tentait de le monter, il ne répondrait pas.

💗 Un cœur qui bat

Le moteur émotionnel gagne une émotion affection (18 émotions au total) et deux nouveaux sentiments détectés : affectueux (tendresse) et flirteur (drague). Surtout, l'attachement se construit au fil des messages :

SituationTrajectoire
Compliments / gentillessejoie → (3 d'affilée) affection → (6 d'affilée) attachement
Dragues répétées(1ʳᵉ) gêne — il rougit — → (2ᵉ) affection → (3ᵉ) amour
Mot tendre (affectueux)affection directement
  • Il tient aux gens : les habitués deviennent des proches, et il le montre.
  • Il est romantique quand il faut : si on le drague, il est flatté, maladroit,

puis tendre — sans jamais forcer le trait.

  • Fidélité : un amour installé ne retombe pas sur un simple compliment.
  • Garde-fous : jamais vulgaire, jamais obscène, jamais insistant, aucun

contenu sexuel. Il n'a pas de partenaire attitré : son affection est sincère mais libre.

Réglages : AI_AFFECTION_AFTER, AI_ATTACHMENT_AFTER, AI_LOVE_AFTER_FLIRTS.

🧹 Rangement

  • introvert_ai.py : suppression du couple (config, mémoire, tâches, partenaires).
  • introvert_cog.py : la commande /introvert discuter disparaît ;

/introvert statut affiche désormais l'émotion courante et son intensité.

  • Introvert'Protect/protect_bot.py : ne monte plus le cog IA.
  • introvert_ai.sql : table introvert_ai_couple retirée.
  • Tests : _smoke_introvert_ai.py couvre l'affection, la drague et l'amour, et

vérifie qu'un seul bot peut répondre.


🛡️ Version 2.5.2

🐛 « DISCORD_TOKEN est VIDE » : la cause enfin neutralisée

Le message revenait malgré un .env parfaitement rempli :

``` ❌ DISCORD_TOKEN est VIDE : renseignez-le dans la section correspondante du .env. ❌ [Bot principal] jeton absent : renseignez DISCORD_TOKEN dans le .env. ```

Rappel de la cause : load_dotenv() n'écrase jamais une variable déjà présente dans l'environnement — même si elle est vide. L'hébergeur (Pterodactyl / Pelican…) déclare DISCORD_TOKEN= sans valeur : le jeton du .env est donc purement ignoré.

OùValeurAvantMaintenant
Panneau hébergeurDISCORD_TOKEN= (vide)⚠️ prioritaire → bot mort⚠️ ignorée (traitée comme non renseignée)
Fichier .envDISCORD_TOKEN=MTU0…❌ ignoré✅ utilisé → bot démarré

Le correctif : au chargement, une variable d'environnement vide est désormais traitée comme non renseignée et **la valeur du .env reprend la main**. Aucune action de votre part n'est nécessaire.

``` ⚠️ DISCORD_TOKEN : la variable d'environnement est VIDE → valeur du .env utilisée (MTU0…vJoc (72 caractères)). ➜ Sur un hébergeur, renseignez OU SUPPRIMEZ cette variable vide dans SON PANNEAU (une variable vide masque le .env). ```

🔒 Rien n'est cassé pour autant : une variable renseignée n'est jamais touchée. Si votre hébergeur fournit la vraie valeur, c'est toujours elle qui gagne — le filet ne fait que remplacer du vide.

🤝 Fonctionne pour les DEUX bots (même hébergeur)

Le même filet est appliqué dans :

  • bot.py → DISCORD_TOKEN (bot principal) ;
  • Introvert'Protect/protect_bot.py → PROTECT_DISCORD_TOKEN (lancement autonome).

Comme les deux bots tournent dans le même processus, ils démarrent maintenant ensemble même si le panneau déclare l'une des deux variables vide. Le bot de protection n'est pas modifié dans son comportement : seule la récupération du jeton est sécurisée.

✅ Vérifié en conditions réelles

Test reproduisant exactement la panne (variable vide dans l'environnement, puis démarrage du vrai bot.py) :

``` ⚠️ DISCORD_TOKEN : la variable d'environnement est VIDE → valeur du .env utilisée… check_environment() : [] ← plus aucun conflit signalé validate_tokens() : [] ← plus d'erreur « jeton absent » TOKEN principal : MTU0…vJoc (72 caractères) Bot principal -> OK Introvert'Boo 🎃 id 1543911182132449391 Introvert Protect -> OK Introvert'Protect id 1558423986440896522 ```

❌ Avant : bot principal refusé au démarrage. ✅ Après : les deux bots se connectent.

💡 Le message d'avertissement reste affiché : si vous voulez le faire

disparaître proprement, supprimez la variable vide du panneau de

l'hébergeur — mais ce n'est plus indispensable.

🧪 Test étendu

./venv/bin/python _smoke_env_tokens.py couvre maintenant 37 points, dont : variable vide réparée depuis le .env, variable renseignée jamais écrasée, vide des deux côtés, .env absent, et **vérification que le filet est bien exécuté avant la lecture du jeton** au démarrage.


🔑 Version 2.5.1

🐛 « DISCORD_TOKEN est VIDE » alors que le .env est rempli

Un cas très déroutant était mal expliqué au démarrage :

``` ❌ DISCORD_TOKEN est VIDE : section à renseigner dans le .env. ❌ [Bot principal] jeton absent : renseignez DISCORD_TOKEN dans le .env. ```

Alors que la ligne DISCORD_TOKEN=… du .env était parfaitement correcte.

La cause : load_dotenv() n'écrase jamais une variable déjà présente dans l'environnement du processus — même si elle est vide. Sur un hébergeur (Pterodactyl / Pelican…), le panneau peut créer la variable DISCORD_TOKEN **sans valeur : le jeton du .env est alors purement et simplement ignoré**.

OùValeurEffet
Panneau de l'hébergeurDISCORD_TOKEN= (vide)⚠️ prioritaire
Fichier .envDISCORD_TOKEN=MTU0…❌ ignoré

Ce qui a été corrigé : le contrôle du démarrage détecte désormais cette situation et le dit clairement, au lieu d'accuser le .env :

``` ⚠️ DISCORD_TOKEN : l'environnement du système déclare cette variable VIDE, et une variable vide ÉCRASE le .env. environnement → « vide » .env → MTU0…vJoc (72 caractères) ➜ Sur un hébergeur, SUPPRIMEZ la variable vide dans SON PANNEAU (ou renseignez-la) : elle a la priorité sur le .env. ```

Et le message d'erreur « jeton vide » renvoie maintenant vers cette piste.

✅ Le conflit entre deux valeurs différentes (ancien jeton du panneau vs

nouveau du .env) était déjà détecté ; c'est le cas vide qui passait

inaperçu.

🔑 Jeton du bot principal mis à jour

Le jeton d'« Introvert'Bot » a été renouvelé (l'ancien n'était plus valide) :

  • mis à jour dans le .env ;
  • vérifié auprès de Discord : Introvert'Boo 🎃 (id 1543911182132449391).

⚠️ À faire de votre côté : si le bot tourne sur un hébergeur, reportez

aussi le nouveau jeton dans le panneau de l'hébergeur (il a la priorité sur

le .env), et supprimez toute variable vide du même nom.

🧪 Nouveau test : jetons & environnement

```bash ./venv/bin/python _smoke_env_tokens.py ```

Il vérifie 25 points : masquage des secrets, détection d'un jeton vide / tronqué / entouré de guillemets / avec espaces, détection d'une variable d'environnement qui écrase le .env (vide ou différente), et la cohérence du .env du projet (dont la correspondance entre le jeton et l'APP_ID — pour savoir immédiatement si c'est le jeton du bon bot).


🧠 Version 2.5

Résumé : les deux bots se parlent tout seuls dans leur salon, **se souviennent de chaque membre et des conversations passées, et connaissent le serveur** (ils répondent vraiment aux questions). Le tout en plus de la v2.4.

💬 Les deux bots discutent entre eux, sans qu'on les mentionne

Dans leur salon, Introvert'Bot et Introvert'Protect se parlent **tout seuls** — aucune mention n'est nécessaire. Et « de temps en temps », ils reprennent la conversation de leur propre initiative :

RéglageRôle
AI_COUPLE_AUTO=1Active la reprise spontanée.
AI_COUPLE_AUTO_MINUTES=15Le salon est surveillé toutes les 15 min.
AI_COUPLE_REPLY_MINUTES=90Délai minimum entre deux reprises (réel : entre 90 et 270 min, au hasard).
AI_COUPLE_QUIET_SECONDS=900Le salon doit être calme depuis 15 min (si des humains discutent, le couple ne s'incruste pas).
AI_COUPLE_HOURS=9-23Il ne se parle que dans cette plage horaire.

✅ Résultat : un vrai couple qui s'écrit quand ça lui prend, jamais à heure fixe — puis la discussion s'enchaîne toute seule (avec une limite d'échanges pour éviter toute boucle infinie).

🧠 Ils se souviennent vraiment de vous

Fini l'amnésie : chaque personnage tient un carnet de souvenirs.

Il se souvient…Exemple
de chaque membre« Mathieu adore les memes de chats et déteste le lundi. »
de son couple« Ils ont parié qu'ils testeraient ce jeu de cuisine, sans jamais le faire. »

Concrètement : quelqu'un revient trois jours plus tard et écrit « salut, tu te souviens de ce que je t'avais dit pour mon entretien ? » — **le bot sait de quoi il parle**. Pareil pour le couple : il rebondit sur ce qu'ils s'étaient raconté la fois d'avant.

Chaque bot a son propre souvenir d'un même membre (comme deux humains

différents). Et le souvenir est réécrit seulement tous les 8 échanges pour

💡 AI_MEMORY_ENABLED=0 coupe la mémoire durable si vous n'en voulez pas.

🗺️ Ils connaissent le serveur (et répondent pour de vrai)

Le bot ne dit plus « je ne sais pas » sur des questions simples : il reçoit une analyse du serveur (salons publics et privés, rôles, commandes du bot) et répond avec les vraies informations.

Question d'un membreCe que le bot peut répondre
« c'est quoi le salon des memes ? »Il cite le bon salon, avec son sujet réel.
« où je poste ma candidature ? »Il indique le salon public prévu pour ça.
« comment gagner de l'XP ? »Il conseille la vraie commande (/niveau, …).

🔒 Les salons privés / staff sont signalés comme interdits à nommer : le bot n'envoie jamais un membre vers un salon auquel il n'a pas accès.

Les commandes sont lues directement dans le bot (/niveau, /route, /verite…), donc l'IA n'invente plus jamais de commande qui n'existe pas.

Nouveaux réglages : AI_SERVER_CONTEXT=1 (analyse activée) et

AI_SERVER_CONTEXT_TTL=600 (durée de cache, en secondes).


🧠 Version 2.4

Résumé : les bots ne parlent que quand on s'adresse à eux, jouent **17 émotions qui évoluent vraiment, comprennent les GIF**, dosent leurs emojis et arrêtent de se répéter.


🧠 Version 2.4 (détail)

📣 Ils ne répondent que si on les appelle

Avant, un bot pouvait s'inviter dans n'importe quelle conversation. Désormais, il ne parle que lorsqu'on s'adresse à lui :

DéclencheurExemple
On le mentionne@Introvert'Bot tu es là ?
On répond à un de ses messagesclic droit → Répondre
On prononce son nom« tu penses quoi, Introvert'Bot ? »
Dans le salon de coupleles deux se répondent entre eux

✅ La détection du nom est tolérante : INTROVERT BOT, introvertbot, avec ou sans apostrophe… tout fonctionne. Et un mot proche ne suffit pas : « protecteur » ne réveille pas Protect.

❌ Un message qui ne le concerne pas (« vous avez vu la météo ? ») **ne déclenche rien du tout**.

💡 Pour qu'un bot participe à toute la conversation d'un salon précis,

décommentez AI_CHAT_CHANNEL_IDS dans le .env.

🧠 Un vrai système émotionnel : 17 émotions

Le personnage ne se contente plus d'être « content » ou « énervé » : il **joue une émotion (avec son intensité), et elle évolue**.

😡 Colère · 🤬 Rage · ❤️ Amour · 😍 Attachement · 😄 Joie · 🥳 Excitation · 😢 Tristesse · 😭 Chagrin · 😨 Peur · 😳 Gêne · 😏 Provocation · 😒 Jalousie · 😴 Fatigue · 🤔 Curiosité · 🥹 Émotion · 😐 Indifférence · 🙂 Neutre

Ce qui change concrètement :

SituationRéaction
Vous le provoquez une foisIl devient sec et agacé 😡
Vous insistezLa colère monte… puis devient de la rage 🤬
Vous vous excusezIl retombe immédiatement et repart au calme 🕊️
Vous êtes sympa plusieurs foisIl s'attache à vous 😍
Petit message neutreIl garde son humeur (pas de saute d'humeur sans raison) 🧊

⚠️ Même énervé, il n'insulte pas, ne menace pas, ne harcèle pas : il hausse le ton, mais reste dans les règles du serveur.

Son humeur et son émotion sont enregistrées : elles survivent aux redémarrages du bot.

🎬 Les GIF et images sont compris

Le bot sait quand un message contient un GIF, une image, une vidéo ou un sticker — et il y réagit naturellement. Mieux : il lit les mots-clés des GIF ! Un tenor.com/view/chat-drole-mignon est compris comme « GIF : chat drole mignon », un GIF Giphy utilise son titre.

👉 Il ne décrit jamais ce qu'il ne peut pas voir : il réagit à l'intention, sans inventer.

🚫 Fini les répétitions et les discours creux

Le bot ne ressort plus les mêmes formules :

  • les phrases toutes faites sont interdites : « restons calmes », « le

respect avant tout », « je suis là pour aider », « n'hésite pas », « je veille sur le serveur », « mon rôle est de… » ;

  • ses dernières réponses lui sont rappelées, avec interdiction de les

reformuler ;

  • une réponse trop proche d'une précédente est automatiquement réécrite ;
  • il varie son rythme, son vocabulaire et ses tournures.

✍️ Des phrases plus humaines

Le prompt demande désormais d'écrire comme un vrai membre du tchat : réagir au contenu précis, taquiner, donner un avis, être concret… et jamais faire la police ou rappeler les règles.

Avant : « Je suis là pour t'aider, restons calmes et respectueux. » Après : *« T'as un souci technique ou c'est juste pour tester si je suis encore là ? »*

🙂 Emojis : utilisés pour de bonnes raisons, sans excès

Maximum 2 emojis par réponse, uniquement s'ils apportent du ton (joie, gêne, clin d'œil). Aucun emoji dans une réponse sérieuse ou tendue. Ce n'est pas qu'une consigne : un plafond strict est appliqué après génération, donc le résultat est garanti.

Réglage : AI_MAX_EMOJIS_PER_REPLY dans le .env.


🔧 Version 2.3.1

🚑 « Improper token has been passed » — corrigé

Le bot refusait de démarrer avec le message :

``` ❌ [Bot principal] arrêt inattendu : Improper token has been passed. ```

Le jeton n'y était pour rien. Le message venait d'un problème de certificats HTTPS que discord.py présentait de façon trompeuse :

  • discord.py fabrique sa propre connexion HTTP et n'utilisait pas le

module http_ssl du projet (celui qui règle précisément ce souci) ;

  • sans lui, il cherchait les certificats dans le magasin du système — vide

sur macOS et dans la plupart des conteneurs ;

  • la connexion échouait en SSL, et le message affiché envoyait sur une **fausse

piste** (« jeton invalide »).

Ce qui a été corrigé :

CorrectifEffet
🔐 Certificats HTTPS fournis à discord.pyLa connexion à Discord fonctionne partout
🧪 Contrôle du jeton au démarrageJeton vide/mal formé détecté avec un message clair
⚠️ Détection des variables d'environnementRepère une variable de l'hébergeur qui écrase le .env
📉 Erreurs explicitesFini le message obscur : cause et solution affichées

Nouveaux messages au démarrage (exemples) :

``` 🔐 [Bot principal] certificats SSL : certifi (…/certifi/cacert.pem) ✅ Connecté en tant que Introvert'Boo 🎃 (ID: 1543911182132449391) ```

En cas de vrai problème de jeton, le bot explique désormais comment le régénérer et rappelle que l'hébergeur prime sur le .env :

``` ❌ [Bot principal] authentification REFUSÉE par Discord. ➜ Le jeton est invalide, tronqué ou a été RÉVOQUÉ.

  1. Régénérez-le : Discord → Portail développeur → … → « Reset Token ».
  2. Reportez-le aux DEUX endroits : le .env ET le panneau de l'hébergeur.

```

🔒 Protection des secrets

Ajout d'un .gitignore : les fichiers sensibles (.env, clés, état d'exécution) ne peuvent plus être publiés par un git add .. Rappel : **un jeton Discord publié est révoqué automatiquement** — c'est la première cause d'une authentification refusée.

🆕 Version 2.3

🎡 Nouveau jeu : « Roulette de la Vérité » (/verite)

Le bot tire au sort un membre, qui doit répondre à une question. S'il ne répond pas dans les 10 minutes, un autre membre est tiré au sort — en privilégiant ceux qui sont en ligne.

ÉtapeDétail
🎡 TirageLe bot désigne un membre au hasard et lui pose une question.
✍️ RéponseLe membre répond dans le salon ou via le bouton Répondre.
⏭️ PasserLe bouton Passer rend la main tout de suite.
⌛ DélaiSans réponse au bout de 10 min, on passe au suivant.
🎯 PrioritéEn vocal > vient de parler > statut en ligne > hors ligne.

Salon du jeu : 1559174149761671208 (configurable via VERITE_CHANNEL_IDS).

Commandes :

``` /verite statut → manche en cours, temps restant, bilan /verite classement → les membres les plus joueurs /verite regles → rappelle les règles ```

Bon à savoir :

  • 30 questions sont fournies d'origine, et vous pouvez en ajouter autant que

vous voulez avec une commande réservée au staff ;

  • la roulette survit aux redémarrages : la manche en cours reprend, boutons

réattachés ;

  • les manches s'enchaînent automatiquement (courte pause de 20 s entre deux) ;
  • le tirage fait tourner les membres : celui qui vient de passer est

fortement pénalisé au tirage suivant ;

  • tout le monde participe : si personne n'est « en ligne », la roulette

pioche quand même parmi les membres du serveur ;

  • astuce : activez l'intent « Presence » dans le portail développeur

Discord (onglet Bot) pour que le critère « statut en ligne » soit pris en compte. Sans lui, la priorité repose sur le vocal et l'**activité récente**, qui fonctionnent déjà.

🛣️ Rappel : « La Route de l'Infini » (/route)

Comptage collectif dans 1552787521761448038 : chacun écrit le nombre suivant, et une seule erreur remet le compteur à 1. Voir le détail ci-dessous.


🆕 Version 2.2

🛣️ Nouveau jeu : « La Route de l'Infini » (/route)

Un jeu de comptage collectif : simple, addictif, et ça crée de l'activité.

Le principe : ne jamais couper la Route de l'Infini.

Chacun son tour, écrivez le nombre suivant : 1, 2, 3, 4…

Une seule erreur et le compteur se réinitialise à 1.

RègleDétail
🟢 DépartLa route commence à 1.
✅ Bon nombreLe bot réagit avec un ✅ (discret, pas de spam).
💥 Erreur❌ + un message explique qui a coupé la route, et on repart de 1.
🏆 RecordAnnoncé quand la route se coupe, si le score dépasse le record.
🎉 PaliersCélébrés tous les 100 nombres.
💬 Hors jeuLes messages sans nombre sont ignorés (la discussion ne casse rien).

Salon du jeu : 1552787521761448038 (configurable via ROUTE_CHANNEL_IDS).

Commandes :

``` /route regles → publie les règles du jeu dans le salon /route statut → compteur en cours, record, palier suivant, erreurs /route classement → top 10 des meilleurs compteurs ```

Bon à savoir :

  • la route survit aux redémarrages (état enregistré en base) ;
  • deux personnes qui cliquent « envoyer » en même temps ne peuvent pas valider

deux fois le même nombre ;

  • l'IA conversationnelle ne répond pas aux nombres de ce salon : le jeu

reste lisible ;

  • options dans le .env : ROUTE_NO_DOUBLE_POST (interdire deux nombres

d'affilée du même membre), ROUTE_DELETE_WRONG (supprimer le message fautif), ROUTE_ANTICHEAT (éditer/supprimer un nombre validé coupe la route).

🤖 Introvert'Bot autorisé par Introvert'Protect

Introvert'Protect expulsait tout bot non autorisé arrivant sur le serveur. Les bots du projet sont désormais whitelistés d'office :

  • Introvert'Bot (1543911182132449391) — il poste les compteurs du jeu ;
  • Introvert'Protect lui-même.

C'est automatique (les identifiants sont lus dans le .env) et visible dans une commande réservée au staff (catégorie 🤖 Bot). Pour ajouter un bot à la main :

``` ```

📈 Fiabilité de l'IA

L'API peut limiter le débit (erreur 429) : le bot **réessaie automatiquement** après le délai indiqué, puis bascule sur son modèle de repli. Il ne reste donc plus muet lors d'un pic d'activité. (Depuis la v2.6, ce mécanisme s'applique à l'API [confidentiel].)


🤖 1. L'IA prend le temps d'écrire

Avant, les bots répondaient presque instantanément. Maintenant :

  • Petite pause de « lecture » du message reçu ;
  • puis indicateur « en train d'écrire » affiché pendant toute la frappe ;
  • durée proportionnelle à la longueur de la réponse (message court = réponse

rapide, message long = réponse plus lente).

RéponseTemps avant le message
Courte (~30 caractères)≈ 1,6 s
Moyenne (~90 caractères)≈ 5,5 s
Longue (200+ caractères)≈ 5,5 s (plafond)

👉 Résultat : on a l'impression qu'une vraie personne est derrière l'écran.


🚫 2. Moins de spam de messages

Les bots ne noient plus les salons sous leurs réponses :

  • délai d'attente avant une nouvelle réponse dans un même salon

(6 s en discussion, 3 s dans le salon de couple) ;

  • mentions et réponses directes : le bot répond toujours immédiatement ;
  • le couple garde sa limite d'échanges (il finit toujours par s'arrêter).

💬 3. Salon bavardage exclu de l'anti-spam

Le salon 1552787521761448038 est maintenant un salon de bavardage :

  • ❌ plus de sanction pour spam de messages (cadence), messages répétés

ou abus d'emojis ;

  • ❌ plus de slowmode automatique déclenché par une conversation animée ;
  • ✅ les protections sérieuses restent actives : arnaque, phishing, liens

suspects, invitations Discord, fichiers dangereux, mentions de masse, spam de photos multi-salons, raid.

Ajouter/retirer un salon (administrateurs) :

``` ```


😊 4. Anti-spam beaucoup moins strict sur les emojis

Le bot avertissait parfois pour un simple emoji. C'est corrigé :

  • un emoji seul, ou quelques emojis dans un message → plus rien ;
  • il faut désormais plus de 20 emojis dans un seul message pour que ce soit

considéré comme un abus ;

  • les messages très courts ou sans texte (ok, +1, mdr, un emoji

répété) ne comptent plus comme du spam de messages ni comme des « messages répétés » ;

  • seuils de cadence relevés : 6 messages en 5 s (au lieu de 5) et

12 messages en 15 s (au lieu de 10) ;

  • messages identiques : 4 fois (au lieu de 3), et jamais sur du contenu

trivial ;

  • ces seuils sont automatiquement appliqués aux serveurs déjà configurés

(aucune manipulation en base).


⚙️ 5. Réglages (fichier .env)

Tout est ajustable sans toucher au code :

```dotenv

Rythme d'écriture de l'IA

AI_TYPING_CPS=18 # vitesse de frappe (caractères/seconde) AI_MIN_TYPING_DELAY=1.2 # délai minimum AI_MAX_TYPING_DELAY=5.0 # délai maximum AI_COUPLE_COOLDOWN=3 # anti-spam dans le salon de couple (secondes) AI_CHANNEL_COOLDOWN=6 # anti-spam dans les autres salons (secondes)

Introvert'Protect : salons de bavardage (anti-spam désactivé)

PROTECT_SPAM_EXEMPT_CHANNELS=1552787521761448038

Tolérance des emojis

PROTECT_MAX_EMOJIS=20

Seuils minimums de cadence (les valeurs plus strictes sont relevées)

PROTECT_MIN_SPAM_FAST=6 PROTECT_MIN_SPAM_MSGS=12 PROTECT_MIN_IDENTICAL=4 ```

Besoin de revenir à l'ancien comportement très strict ?

Mettre PROTECT_STRICT_MODE=1 dans le .env.


🧪 Vérifications

```bash ./venv/bin/python _smoke_introvert_ai.py # IA : mémoire, couple, analyse serveur, émotions ./venv/bin/python _smoke_env_tokens.py # Jetons & variables d'environnement ./venv/bin/python _smoke_protect_module.py # Protect : détections, sanctions, garde-fous ```

Tous les tests passent ✅


📌 À retenir

AvantAprès
Réponse instantanéeRéponse « tapée à la main », 1,5 à 5,5 s
Réponses en rafale possiblesUn seul message par salon toutes les 3-6 s
Avertissement pour un emojiTolérant jusqu'à 20 emojis par message
Salon de bavardage surveilléSalon 1552787521761448038 libre (anti-spam off)