docs(telegram): invert chat-gate strategy in docs; tune logs; i18n text
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 18s
CI / ui (pull_request) Successful in 57s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m15s

- Bake the final default-allow + mute-the-ineligible strategy into
  docs/ARCHITECTURE.md, docs/FUNCTIONAL.md (+_ru), platform/telegram/README.md,
  the deploy compose comment and the PRERELEASE tracker. The live test proved a
  per-user grant cannot exceed a deny-by-default group (Telegram intersects the
  chat default with the per-user permission), so the chat allows sending by
  default and the bot restricts the ineligible instead of granting the eligible.
- Lower the per-event chat_member trace and eligibility evaluation to Debug;
  keep the actual mute/unmute actions, the startup self-check and warnings at
  Info, so prod logs only what the bot did.
- Update game.searchingForOpponent (Searching -> Waiting for opponent / Поиск ->
  Ждём соперника) and the quickmatch e2e assertions to match.
This commit is contained in:
Ilia Denisov
2026-06-21 17:15:10 +02:00
parent bdd1cc7d85
commit 1ba789a1f1
10 changed files with 70 additions and 56 deletions
+11 -7
View File
@@ -997,13 +997,17 @@ sweeper for the gate — it recomputes against `now`). No operator identity is r
Basic-Auth).
**Moderated discussion chat.** A channel's linked discussion group is gated by the Telegram bot
(`TELEGRAM_CHAT_ID`): the group defaults to no-send, and a user may write only while they are
**registered and neither admin-suspended nor holding the chat-only `chat_muted` role**
(`eligible = registered AND NOT suspended AND NOT chat_muted` — the game suspension dominates). A
single backend resolver behind `POST /api/v1/internal/chat-access` answers both directions: the
bot's join-time `ResolveChatEligibility` (over the mTLS bot-link) grants write access to an
eligible joiner, and a `chat_access_changed` event — emitted on a block/unblock, a `chat_muted`
grant/revoke, or a temporary block lapsing (a dedicated `account.SuspensionSweeper`, since no
(`TELEGRAM_CHAT_ID`). The group **allows sending by default** and the bot only **restricts**: Telegram
intersects the chat default with each user's permission, so a per-user grant can never exceed a
deny-by-default group — the gate must mute the ineligible, not grant the eligible. A user may write
while they are **registered and neither admin-suspended nor holding the chat-only `chat_muted` role**
(`eligible = registered AND NOT suspended AND NOT chat_muted` — the game suspension dominates); the bot
**mutes** an ineligible member and **un-mutes** an eligible one it had muted, leaving an already-allowed
eligible member untouched (it acts only when the current state differs, so it is idempotent and never
loops on its own change). A single backend resolver behind `POST /api/v1/internal/chat-access` answers
both directions: the bot's `ResolveChatEligibility` on a `chat_member` event (over the mTLS bot-link),
and a `chat_access_changed` event — emitted on a block/unblock, a `chat_muted` grant/revoke, a first
Telegram registration, or a temporary block lapsing (a dedicated `account.SuspensionSweeper`, since no
request fires then) — drives a `ChatGate` command the gateway pushes to the bot. The bot applies it
only to a member currently in the chat (a per-user `getChatMember` probe, since bots cannot list
members); the signal is idempotent and is never an in-app or out-of-app message. `chat_muted` is an