# Bridge судит конверт, содержимое судит Inbound pipeline

Bot API 10.1 (11.06.2026) добавил классу `Message` поле `rich_message`: до 32768 символов
UTF-8 против 4096 у `text`, а само содержимое лежит в блоках. Версии 10.2 (14.07.2026) и
10.3 его дополнили — кнопки, раскрываемые цитаты, документы. Клиент свежей версии
(проверено на iOS и Telegram Web) шлёт длинное или форматированное сообщение именно так:
в апдейте есть `message_id`, `from`, `chat`, `date`, `rich_message` — и нет ни `text`, ни
`entities`, ни `caption`.
[Changelog Bot API](https://core.telegram.org/bots/api-changelog),
[RichMessage](https://core.telegram.org/bots/api#richmessage).

Ива до 0.3.33 такое сообщение теряла молча. Агент читает `rich_message` без потерь с 0.3.25
(`agent/lib/telegram-rich-message.ts`), eve upstream его пропускает, но Bridge
(`scripts/lib/telegram-queue.ts`, `hasMessagePayload`) держал свой список ключей содержимого —
`text`, `caption` и 11 медиа-ключей — и всё остальное отбрасывал как `terminal-drop`, записывая
один номер апдейта. Снаружи: короткие сообщения бот отвечает, длинные и форматированные
игнорирует, `/restart` не помогает, `iva logs poll` показывает `drop update N — terminal
ingress policy`.

Класс общий для всех, кто читает Telegram. openclaw принял `fix(telegram): preserve rich
forwarded message text` (#98735) и следом #100570: хелпер `resolveTelegramRichMessageText`
раскладывает блоки в текст до плейсхолдера «unsupported». NousResearch/hermes-agent #63485 —
входящий `rich_message` верхнего уровня терялся, потому что хендлер фильтровал по
`filters.TEXT`. nanocoai/nanoclaw #3151 — 14 тихих потерь за три дня, починка тем же
адаптером `richMessageToText`.

## Что решено

**Bridge судит конверт.** Сообщение от пользователя из Allowlist принимается, если несёт хотя
бы один ключ вне метаданных конверта Bot API (`message_id`, `from`, `chat`, `date`,
`reply_to_message`, `forward_origin`, `edit_date`, … — поля, в которых содержимого не бывает).
Новое поле Bot API поэтому доезжает до агента само.

**Содержимое судит Inbound pipeline.** Единственная власть над тем, что читается, — читалка
`agent/lib/telegram-rich-message.ts`; Bridge содержимое не открывает.

**Правило групп не меняется.** Сообщение без `text`/`caption` в группе принимается только как
reply боту.

**Нечитаемое получает ответ, а не тишину.** Если в личном сообщении нет ни текста, ни
rich-текста, ни медиа, ни локации (`poll`, `contact` или поле, которого Ива ещё не знает),
агент один раз отвечает на языке чата: `Не могу прочитать это сообщение (поля: poll). Пришли
текстом или файлом.` Раньше `poll` и `contact` пропадали молча.

**Отброс называет ключи.** Строка отброса перечисляет ключи верхнего уровня — только имена,
никогда содержимое: `iva logs poll` по-прежнему не несёт текста сообщений.

Обоснование. Доставка внутрь идёт одним швом (philosophy §2), и решение о содержимом
принимается на нём один раз, в агенте, а не дважды. Баг закрывается дизайном, а не списком
(philosophy §5): список знакомых ключей проигрывает каждому новому полю Bot API, конверт —
нет. Молчание стоит данных (ADR-0002), поэтому непрочитанное сообщение обязано получить ответ.

## Что отвергнуто

- **Добавить `rich_message` в список ключей Bridge** — закрывает одно поле, следующее поле
  Bot API теряется так же молча.
- **Второй нормализатор `rich_message → text` в самом Bridge** (предлагался ранее) — дублирует
  читалку агента, даёт два места, которые разойдутся, и заставляет Bridge читать содержимое,
  толковать которое ему нельзя.
- **Принимать всё и молчать** — пользователь не отличает потерянное сообщение от медленного.

Последствия. Незнакомое поле стоит одного круга: сообщение доезжает, приходит ответ, владелец
шлёт текстом или файлом. Группа остаётся с дырой — `rich_message` там принимается только как
reply боту, потому что `@mention` внутри rich-текста Bridge не видит; записано в
`docs/tech-debt.md`.
