fix(bot): un-reacting from a poll never un-counted the vote
wyr/acronym/nhie/hottake tracked votes only on reaction-add, using "add to bucket A, remove from bucket B" logic that self-corrects when switching reactions but not when a reaction is simply removed — nio never subscribed to RedactionEvent at all, so an un-react was invisible to the bot. Fixes LotusGuild/matrix#6 (repro: react agree and disagree, remove disagree, still counted as disagree). Adds unrecord_* counterparts to each record_* vote function, a reaction_id -> (poll_event_id, sender) index in Callbacks (only populated for reactions on messages we're actually tracking, so it stays bounded) so a later redaction can be traced back to what to un-count, and wires up RedactionEvent -> callbacks.redaction in bot.py. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1842,6 +1842,15 @@ def record_wyr_vote(event_id: str, sender: str, key: str) -> None:
|
||||
poll["votes"][key].add(sender)
|
||||
|
||||
|
||||
def unrecord_wyr_vote(event_id: str, sender: str) -> None:
|
||||
"""Called from callbacks when a reaction is removed from a WYR poll message."""
|
||||
poll = _WYR_POLLS.get(event_id)
|
||||
if not poll:
|
||||
return
|
||||
for bucket in poll["votes"].values():
|
||||
bucket.discard(sender)
|
||||
|
||||
|
||||
async def _generate_wyr() -> dict | None:
|
||||
# Few-shot examples anchor the format so the model doesn't drift
|
||||
examples = [
|
||||
@@ -2680,6 +2689,17 @@ def record_acronym_vote(event_id: str, sender: str, key: str) -> None:
|
||||
game.setdefault("votes", {})[sender] = idx # one vote per person
|
||||
|
||||
|
||||
def unrecord_acronym_vote(event_id: str, sender: str) -> None:
|
||||
"""Record a numbered-emoji vote removal on an acronym poll."""
|
||||
room_id = _ACRONYM_POLL_IDS.get(event_id)
|
||||
if room_id is None:
|
||||
return
|
||||
game = _ACRONYM_GAMES.get(room_id)
|
||||
if not game or game.get("phase") != "voting":
|
||||
return
|
||||
game.get("votes", {}).pop(sender, None)
|
||||
|
||||
|
||||
@command("acronym", "AI picks an acronym — submit the funniest expansion with !ac, then vote!")
|
||||
async def cmd_acronym(client: AsyncClient, room_id: str, sender: str, args: str):
|
||||
if room_id in _ACRONYM_GAMES:
|
||||
@@ -3036,6 +3056,14 @@ def record_nhie_reaction(event_id: str, sender: str, key: str) -> None:
|
||||
poll["have"].discard(sender)
|
||||
|
||||
|
||||
def unrecord_nhie_reaction(event_id: str, sender: str) -> None:
|
||||
poll = _NHIE_POLLS.get(event_id)
|
||||
if not poll:
|
||||
return
|
||||
poll["have"].discard(sender)
|
||||
poll["never"].discard(sender)
|
||||
|
||||
|
||||
_NHIE_TOPICS = [
|
||||
"travel", "food", "social situations", "school or work", "technology",
|
||||
"outdoor adventures", "relationships", "embarrassing moments",
|
||||
@@ -3138,6 +3166,14 @@ def record_hottake_reaction(event_id: str, sender: str, key: str) -> None:
|
||||
poll["agree"].discard(sender)
|
||||
|
||||
|
||||
def unrecord_hottake_reaction(event_id: str, sender: str) -> None:
|
||||
poll = _HOTTAKE_POLLS.get(event_id)
|
||||
if not poll:
|
||||
return
|
||||
poll["agree"].discard(sender)
|
||||
poll["disagree"].discard(sender)
|
||||
|
||||
|
||||
_HOTTAKE_TOPICS = [
|
||||
"food and cooking", "music genres", "social media and technology",
|
||||
"sports and fitness", "video games", "movies and TV shows",
|
||||
|
||||
Reference in New Issue
Block a user