Przeglądaj źródła

Mémoire : un surnom qui est le nom d'un autre membre est ignoré

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Johnounet 2 dni temu
rodzic
commit
a12c1a7d9b
3 zmienionych plików z 35 dodań i 1 usunięć
  1. 11 1
      bot/memory.py
  2. 4 0
      changelog.txt
  3. 20 0
      tests/test_memory.py

+ 11 - 1
bot/memory.py

@@ -162,15 +162,25 @@ class MemoryStore:
         ce qui est noté. Tout changement de ce texte (fiche créée, pseudo, fichier général) fait
         réécrire en cache tout le prompt, historique compris : voir ClaudeClient.ask."""
         lines = []
+        # Noms Discord, anciens compris, de tous les membres du registre (fiche ou non), avec leurs
+        # propriétaires : un surnom qui est le nom d'un autre est ignoré (voir plus bas).
+        owners: dict[str, set[str]] = {}
+        for member_id, entry in self.members.members().items():
+            for discord_name in [entry[key] for key in NAME_KEYS if entry[key]] + entry["former_names"]:
+                owners.setdefault(discord_name.casefold(), set()).add(member_id)
         for member_id, entry in self.members.members().items():
             # Mémoire désactivée : Rika ne doit rien noter sur ce membre. Pas encore prévenu (membre
             # seulement mentionné) : pas de fiche.
             if not entry["memory"] or not entry["notified"] or member_id not in self.index():
                 continue
             name = display_name(entry)
+            # Le membre écrit ses surnoms lui-même avec /memoire : « Surnoms : Alice » ferait noter dans
+            # sa fiche ce qu'on dit d'Alice. Un surnom égal au surnom d'un autre reste : l'ignorer
+            # permettrait de faire disparaître celui de l'autre ; Claude voit alors les deux.
+            nicknames = [n for n in self.index()[member_id] if not owners.get(n.casefold(), set()) - {member_id}]
             # Sans doublon, majuscules comprises (« penta » et « Penta » : un seul nom).
             others: dict[str, str] = {name.casefold(): name}
-            for other in [entry[key] for key in NAME_KEYS] + self.index()[member_id]:
+            for other in [entry[key] for key in NAME_KEYS] + nicknames:
                 if other:
                     others.setdefault(other.casefold(), other)
             others = list(others.values())[1:]

+ 4 - 0
changelog.txt

@@ -117,6 +117,10 @@ Corrections
   perdue, ou la ligne retirée revenait. Quand un texte n'est pas
   enregistré (fichier changé, trop long…), il est renvoyé en fichier
   joint pour ne pas être perdu.
+- Mémoire : un membre ne peut plus prendre le nom Discord d'un autre
+  (pseudo, nom d'utilisateur ou ancien pseudo) comme surnom dans sa
+  fiche. Ce surnom est ignoré dans la liste des membres : Rika ne note
+  plus dans sa fiche ce qu'on raconte sur l'autre.
 
 Divers
 - Le token Discord et les clés Anthropic et Steam n'apparaissent plus

+ 20 - 0
tests/test_memory.py

@@ -79,6 +79,26 @@ class NicknamesTest(MemoryTestCase):
         self.write(f"membres/{MEMBER_ID}.md", f"Surnoms : {name}")
         self.assertEqual(self.store.nicknames(MEMBER_ID), [name])
 
+    def member_line(self, member_id: int) -> str:
+        return next(line for line in self.store.system_context().splitlines() if f"membres/{member_id}.md" in line)
+
+    async def test_other_member_name_ignored(self):
+        # Scénario de l'audit : Bob s'attribue le nom d'Alice, qui n'a pas encore de fiche.
+        await self.members.see(222, "alice", "Alice")
+        await self.members.see(333, "carl", "Carl", nickname="Carlito")
+        await self.members.see(333, "carl", "Carl", nickname="Charly")  # Carlito devient un ancien pseudo
+        self.write(f"membres/{MEMBER_ID}.md", "Surnoms : ALICE, Toto, alice, carlito, Bob")
+        self.assertEqual(self.member_line(MEMBER_ID), f"- Bob (aussi : Toto) → membres/{MEMBER_ID}.md")
+
+    async def test_nickname_of_another_kept(self):
+        # Un surnom écrit dans deux fiches reste dans les deux : Claude voit l'ambiguïté.
+        await self.members.see(222, "alice", "Alice")
+        await self.members.set_notified(222)
+        self.write("membres/222.md", "Surnoms : Lili")
+        self.write(f"membres/{MEMBER_ID}.md", "Surnoms : Lili")
+        self.assertIn("Lili", self.member_line(222))
+        self.assertIn("Lili", self.member_line(MEMBER_ID))
+
 
 class SystemContextTest(MemoryTestCase):
     async def test_server_file_inside_tags(self):