# ADR-033: Текст отказа у неотправленного сообщения

Уточнён [ADR-036](036-resend-keeps-ulid.md) (новая попытка заводит запись без поля `error`) и [ADR-060](060-unknown-device-keeps-pending.md) (`403 unknown_device` — не отказ сообщению).

## Контекст

`docs/storage.md` задаёт судьбу исходящего: `202` → `sent`, сетевая ошибка → остаётся `pending`, `4xx` → `failed` «с текстом ошибки». Поля для этого текста в записи `messages` нет — есть только `status`.

`docs/ui.md` описывает вторую половину так же наполовину. У сообщения в ленте есть пометка «не отправлено · повторить», одна на все причины. `clock_skew` записан в «Сеть и состояния» с текстом «проверьте часы на устройстве: расхождение больше 5 минут», но где он показывается — не сказано, а показать его негде: пометка у сообщения фиксирована, строка состояния формы (ADR-028) в чате не живёт.

Этап 2 упёрся в это на первой же отправке. Причина отказа известна ровно в момент ответа сервера, а сообщение живёт дальше и переживает перезагрузку страницы.

## Решение

- Запись `messages` получает необязательное поле `error: string` — текст отказа, из-за которого сообщение стало `failed`. Тексты берутся из тех же перечней, что и у форм: коды `docs/protocol.md` и строки ADR-028. Новых строк интерфейса это решение не заводит.
- Поле живёт только у `failed`. Новая попытка отправки заводит запись с новым ULID и без него.
- Текст показывается полосой над вводом цветом `mark` — там же, где «нет соединения» и предупреждение о ключе. Место одно, как требует ADR-028; пометка «не отправлено · повторить» у самого сообщения не меняется.
- Поле служебное: на сервер не уходит и в архив `.bare` не пишется, как и `raw`.

## Следствия

- `clock_skew` наконец видно: расхождение часов объясняется словами, а не молчаливым «не отправлено».
- Текст переживает перезагрузку вместе с сообщением: он часть записи, а не состояние экрана.
- Причин у полосы над вводом становится три — нет соединения, ключ изменился, отказ отправки. Больше одной сразу не показывается: полоса одна.
