Skip to content

feature: chat moderation — gag blocks website chat, moderator message deletion - #438

Merged
lukepolo merged 4 commits into
mainfrom
feature/chat-moderation
Sep 29, 2026
Merged

lukepolo merged 4 commits into
mainfrom
feature/chat-moderation

Conversation

@lukepolo

@lukepolo lukepolo commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

A gag now also blocks website chat, and moderators can delete chat messages with a private audit trail.

  • A gag or silence refuses website sends in every group room with gagged; DMs and lines from the game are untouched
  • Moderator and up (role re-read from the DB) can delete any group-room message with lobby:delete
  • Every delete writes a chat_message_deletions row before the message leaves redis; moderators can't read the organizers room's rows
  • The message's bell rows and pending pushes are retracted by message id and blanked, including after a draft moves into its match
  • New socket events: lobby:delete {type, id, messageId, requestId?} in, lobby:<type>:<id>:deleted {id} out; acks and errors now carry action

Merge/deploy: stacked on #435; run yarn hasura:metadata after merge. Pairs with 5stackgg/web#618.

Tests: a test fails without each fix: gag on web sends, audit before removal, role on record, numeric steam id stored as no author, retraction by id after a draft move, blanked text, collapsed rows staying retired, and (new tests) the post-write re-check by audit row, so an expired message's rows are no longer retracted, plus chat-type scoping. Manual QA: as a moderator, query chat_message_deletions and confirm organizers rows are hidden. Based on DEAFCS 5be040c91

… messages

A gag (or silence) now also refuses website sends in every group room with
chat:error { code: "gagged" }; DMs and lines relayed from the game are left
alone. Moderators and up can delete any message in a group room they can
access via lobby:delete; the message is audited to chat_message_deletions
before it is removed from redis, the room gets lobby:<type>:<id>:deleted,
and its unread bell rows / pending pushes are retracted.
…at:error

- retract a deleted message's notifications by message id alone (new
  partial index), so a draft lobby's lines that moved into the match room
  are still retracted; the retracted text is blanked, since a recipient can
  read and restore their own deleted rows
- re-check after writing a message's notifications: a delete that landed
  while they were being written had nothing to retract yet
- organizers-room audit rows stay hidden from moderators (the room is
  match_organizer and up)
- chat:ack and chat:error now carry action ("send" | "delete") so the web can
  tell a failed delete from a failed send
The redis field is also gone when a message expires (a 0 TTL drops it at
once) or when a draft lobby's history moves into the match, and treating
either as a delete retracted every notification for a message nobody
removed. The audit row is committed before a delete retracts, so it answers
the same race without the false positives. The unique key leads with
message_id so that lookup is indexed. Retraction is also scoped to the chat
notification types.
The post-write re-check once read a missing redis field as a delete, which
also retracts the rows of a message that merely expired or moved with its
draft lobby. The retraction is scoped to the chat notification types.
@lukepolo
lukepolo force-pushed the feature/chat-moderation branch from 60d2f76 to af7a1ca Compare September 29, 2026 00:49
@lukepolo
lukepolo merged commit 3a74c3d into main Sep 29, 2026
@lukepolo
lukepolo deleted the feature/chat-moderation branch September 29, 2026 00:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant