- Клиент бота собирается один раз и достаётся отправителю и транспорту; разрез прошёл по «ответил ли Telegram»: ответ «такого бота нет» роняет старт, недоступность даёт подъём без Telegram (ADR-2026-08-13). Ожидание при сборке ограничено сроком — иначе молчащий Telegram вешал подъём. - Недоставленный ответ не роняет шаг: пишется с job_id и считается метрикой, уровень по причине — WARN для неподнятого входа, ERROR для неназванного адресата. Заведены transcriber_intake_up и transcriber_undelivered_reply_count. - Закрыта утечка токена в журнал: отказ разбора адреса рождается раньше обращения к клиенту, то есть мимо чистки на его границе.
128 lines
11 KiB
Markdown
128 lines
11 KiB
Markdown
## 1. Отправитель, который не отправляет
|
||
|
||
- [x] 1.1 Завести среди контрактов значение отказа «канал доставки не поднят» —
|
||
рядом с «работы нет» и «захват потерян», узнаваемое тем же способом
|
||
- [x] 1.2 Завести в пакете отправителя Telegram заглушку, реализующую контракт
|
||
отправки: она ничего не отправляет и на всякий ответ возвращает это
|
||
значение
|
||
- [x] 1.3 Проверить тестом, что заглушка возвращает именно его и ничего не пишет
|
||
сама
|
||
|
||
## 2. Ответ отправителю в конвейере
|
||
|
||
- [x] 2.1 Научить ответ отправителю узнавать это значение: пишется запись уровня
|
||
`WARN` с идентификатором задачи и причиной, шаг завершается без отказа
|
||
- [x] 2.2 Свести к тому же исходу вторую причину недоставки — задачу источника
|
||
Telegram без названного чата: сегодня она даёт отказ шага на уже
|
||
завершённой работе, то есть ложный сбой в счётчике воркера и перезапись
|
||
служебных полей
|
||
- [x] 2.3 Проверить, что в записи нет ни текста расшифровки, ни сообщения
|
||
отправителя
|
||
- [x] 2.4 Тест конвейера: задача источника Telegram доходит до ответа через
|
||
заглушку — шаг без отказа, состояние задачи не откатывается, в повтор она
|
||
не уходит и в `failed` не переводится
|
||
- [x] 2.5 Тест: задача источника Telegram без чата даёт тот же исход
|
||
- [x] 2.6 Тест: задача, принятая по HTTP, до заглушки не доходит и записи о
|
||
недоставке не порождает
|
||
|
||
## 3. Сборка при старте
|
||
|
||
- [x] 3.1 Свести сборку клиента бота к одной: отправитель ответов принимает
|
||
готового клиента вместо токена, транспорт получает того же
|
||
- [x] 3.2 Поставить разрез в этом единственном месте: пустой токен даёт заглушку
|
||
и одну запись уровня `WARN` о неподнятом боте, любой другой отказ сборки
|
||
роняет старт
|
||
- [x] 3.3 Тест на непустой токен, с которым бот не заводится: старт роняется.
|
||
Живой Telegram не нужен — адрес подставляется, как в имеющемся тесте
|
||
клиента
|
||
- [x] 3.4 Проверить, что ни запись о неподнятом боте, ни текст отказа старта не
|
||
несут значения токена
|
||
- [x] 3.5 Проверить остановку: сигнал остановки на конфиге с пустым токеном
|
||
завершает процесс тем же кодом и в тот же срок, что и с токеном
|
||
- [x] 3.6 Удалить неупотребляемый тип отказа «токен пуст» в транспорте бота —
|
||
третье представление того же факта
|
||
|
||
## 4. Настройки и их образец
|
||
|
||
- [x] 4.1 Описать в образце конфига, что пустой токен означает подъём без
|
||
Telegram и что при этом перестаёт работать
|
||
- [x] 4.2 Назвать там же остальные секции, без которых сервис не поднимется:
|
||
настройки входа и Yandex требуют непустых значений, при локальном прогоне
|
||
годятся выдуманные, наружу при старте не ходит ни одна
|
||
|
||
## 5. Проверки
|
||
|
||
- [x] 5.1 Тест на сборку отправителя с непустым токеном: прежний путь сохранён
|
||
- [x] 5.2 Живой прогон: конфиг с пустым токеном и заполненными по 4.2 секциями,
|
||
`GET /health` отвечает `200`, в выводе есть запись о неподнятом боте
|
||
- [x] 5.3 `task gate` зелёный
|
||
|
||
## 7. Развилки ревью кода — решения владельца 2026-08-13
|
||
|
||
- [x] 7.1 Недоступность Telegram на старт не влияет: разрез перенесён на «ответил
|
||
ли Telegram». Ответ «такого бота нет» роняет старт, всё прочее даёт подъём
|
||
без Telegram с записью `WARN`
|
||
- [x] 7.2 Ограничить ожидание при сборке клиента сроком — без него недоступность
|
||
неотличима от подъёма; длинный опрос сроком не ограничен
|
||
- [x] 7.3 Признак поднятости входов метрикой и счётчик недоставленных ответов с
|
||
причиной меткой
|
||
- [x] 7.4 Развести уровни недоставки: неподнятый вход — `WARN`, неназванный
|
||
адресат — `ERROR` (симптом порчи записи)
|
||
- [x] 7.5 Проверки на все четыре ветки сборки и на оба уровня недоставки
|
||
|
||
## 6. Документы
|
||
|
||
- [x] 6.1 `CLAUDE.md`, раздел «Запреты»: рядом с запретом на боевой токен встаёт
|
||
способ подняться без него
|
||
- [x] 6.2 `docs/review.md`, подраздел «Недоступно проверке»: строка о живом
|
||
прогоне сужается **с остатком** — подъём и осмотр стали доступны, прогон с
|
||
пустыми ключами Yandex по-прежнему нет
|
||
- [x] 6.3 `docs/architecture.md`: перечень capability отражает, что нормируют
|
||
`intake` и `pipeline` после этого изменения
|
||
- [x] 6.4 `docs/architecture.md`, таблица отказов внешних зависимостей: строка
|
||
про Telegram сегодня обещает дежурному «бот не стартует, приложение
|
||
продолжает работу без него» — привести к новому разрезу ссылкой на
|
||
требование, не перенося поведение в обзор
|
||
|
||
## Критерии приёмки
|
||
|
||
Первые три — дословно из записи задачи `local-run-without-telegram-token`.
|
||
**Четвёртый переписан** решением владельца на чекпоинте 2026-08-13: в прежней
|
||
редакции он требовал, чтобы задача осталась пригодной к повтору либо перешла в
|
||
`failed`, а дизайн отверг оба исхода с ценой, и норма `pipeline` требует прямо
|
||
обратного. Прежняя редакция сделала бы приёмку зелёной на поведении, которое это
|
||
же изменение запрещает. Запись задачи поправлена тем же решением.
|
||
|
||
- Сервис поднимается с пустым токеном бота: HTTP отвечает, воркеры идут, бот не
|
||
создан. Оракул — запуск с конфигом без токена и запрос `GET /health`: код 200.
|
||
- Отсутствие бота названо в журнале один раз при старте, а не молчанием. Оракул —
|
||
тот же запуск: в выводе есть строка о том, что бот не поднят и почему.
|
||
- Поведение с настоящим токеном не изменилось. Оракул — тест на создание
|
||
отправителя с непустым токеном: прежний путь сохранён.
|
||
- Задача из Telegram, дошедшая до ответа при отсутствующем боте, не роняет
|
||
процесс и не теряется молча: она остаётся в достигнутом состоянии, в повтор не
|
||
уходит и в `failed` не переводится, а недоставка видна записью журнала с
|
||
идентификатором задачи. Оракул — тест конвейера с задачей источника Telegram и
|
||
заглушкой вместо отправителя.
|
||
- Задача источника Telegram без названного чата даёт тот же исход, а не отказ
|
||
шага. Оракул — тест конвейера на такой задаче: воркеру сбой не засчитан,
|
||
служебные поля завершённой задачи не переписаны.
|
||
|
||
Сверх записи задачи — из ревью дизайна:
|
||
|
||
- Непустой токен, с которым бот не заводится, роняет старт. Оракул — тест с
|
||
подставным адресом Bot API.
|
||
- Записей о неподнятом боте ровно одна. Оракул — живой прогон с пустым токеном:
|
||
отбор по журналу даёт одну строку, а не две.
|
||
- Клиент бота собирается в одном месте. Оракул — отправитель ответов принимает
|
||
клиента, а не токен, и `NewBot` зовётся из сборки при старте однажды.
|
||
|
||
Сверх ревью кода — решения владельца по трём развилкам:
|
||
|
||
- Недоступность Telegram подъёму не мешает, ответ «такого бота нет» роняет старт.
|
||
Оракул — проверки на четыре ветки сборки.
|
||
- Поднятость входов видна метрикой. Оракул — живой прогон с пустым токеном:
|
||
признак входа Telegram равен нулю, признак HTTP — единице.
|
||
- Неназванный адресат пишется уровнем `ERROR`, неподнятый вход — `WARN`. Оракул
|
||
— проверки конвейера на обе причины.
|