From e1b2c8575ce0e61b90d6e8de1d820e0e0d477bf2 Mon Sep 17 00:00:00 2001 From: Lotus CI Date: Tue, 27 Oct 2026 20:04:27 -0400 Subject: [PATCH] fix: explicit m.mentions for ticket notifications and roasts (ahead of Synapse 1.164) Synapse 1.164 turns on MSC4210 by default: the legacy push rules that pinged when a user ID or display name appeared in the body are removed, so a message only notifies the users listed in m.mentions. - hookshot/tinker-tickets.js deliberately pings assignees/watchers (notify_users) with matrix.to links; those pings would stop. Return mentions: { user_ids: notifyUsers } (hookshot 7.3.2 v2 transforms support it). - matrixbot: send_html takes optional mention_user_ids; !roast mentions the target when given as a full Matrix ID. Winner announcements stay without a ping (the player is already in the room). No @room is sent anywhere. Lotus Chat already sends m.mentions. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5 --- hookshot/tinker-tickets.js | 11 ++++++++++- matrixbot/commands.py | 4 +++- matrixbot/utils.py | 22 +++++++++++++++------- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/hookshot/tinker-tickets.js b/hookshot/tinker-tickets.js index 47d29bc..ff22829 100644 --- a/hookshot/tinker-tickets.js +++ b/hookshot/tinker-tickets.js @@ -77,4 +77,13 @@ if (event === 'ticket_created') { html = '[tinker-tickets] event: ' + event + ' ticket #' + id; } -result = { version: 'v2', plain: plain, html: html, msgtype: 'm.text' }; +// Explicit mentions (m.mentions): from Synapse 1.164 the legacy push rules +// that pinged on a user ID or display name in the body are off by default +// (MSC4210), so the people to notify must be listed here. +result = { + version: 'v2', + plain: plain, + html: html, + msgtype: 'm.text', + mentions: { user_ids: notifyUsers } +}; diff --git a/matrixbot/commands.py b/matrixbot/commands.py index f704069..8490946 100644 --- a/matrixbot/commands.py +++ b/matrixbot/commands.py @@ -2273,7 +2273,9 @@ async def cmd_roast(client: AsyncClient, room_id: str, sender: str, args: str): f'
{roast}
' f'via {_model_label(CREATIVE_MODEL)}' ) - await send_html(client, room_id, plain, html) + # Ping the person being roasted when they were named by Matrix ID. + target_id = target_raw if re.fullmatch(r"@[^\s:]+:[^\s]+", target_raw) else None + await send_html(client, room_id, plain, html, mention_user_ids=[target_id] if target_id else None) # --------------------------------------------------------------------------- diff --git a/matrixbot/utils.py b/matrixbot/utils.py index a7040a2..020a80a 100644 --- a/matrixbot/utils.py +++ b/matrixbot/utils.py @@ -70,17 +70,25 @@ async def send_text(client: AsyncClient, room_id: str, text: str): return resp -async def send_html(client: AsyncClient, room_id: str, plain: str, html: str): +async def send_html( + client: AsyncClient, room_id: str, plain: str, html: str, mention_user_ids: list[str] | None = None +): logger = logging.getLogger("matrixbot") + content = { + "msgtype": "m.text", + "body": plain, + "format": "org.matrix.custom.html", + "formatted_body": html, + } + # Explicit mentions (m.mentions). From Synapse 1.164 a name or user ID in + # the body no longer pings anyone (MSC4210), so a message that should + # notify someone has to say so. + if mention_user_ids: + content["m.mentions"] = {"user_ids": mention_user_ids} resp = await _room_send_trusted( client, room_id, message_type="m.room.message", - content={ - "msgtype": "m.text", - "body": plain, - "format": "org.matrix.custom.html", - "formatted_body": html, - }, + content=content, ) if not isinstance(resp, RoomSendResponse): logger.error("send_html failed: %s", resp) -- 2.47.3