config: включение Telegram разведено с ключом доступа

- в секции [telegram] заведён обязательный ключ enabled: умолчания у него нет,
  файл без него негоден; bot_token стал только ключом доступа и при
  enabled = false не читается вовсе, а пустой при enabled = true роняет старт
- выключенный вход даёт подъём одним входом без единого обращения к Telegram и
  записью INFO вместо прежнего WARN: это выбор владельца, а не отклонение
- отказ разбора файла настроек больше не пересказывает toml — её ParseError
  несёт в тексте разбираемое значение, и оборванная строка секретного ключа
  уносила его в журнал; теперь называются путь, строка, столбец и последний ключ
This commit is contained in:
av
2026-08-13 21:46:14 +03:00
parent 903941f587
commit cd57b68215
27 changed files with 1536 additions and 123 deletions
@@ -0,0 +1,67 @@
## Why
Сегодня пустой токен бота означает сразу две разные вещи: «вход Telegram
выключен намеренно» и «ключа доступа нет». Владелец не может сказать сервису
«бот мне нужен» отдельно от «вот ключ», а сервис не может отличить осознанный
отказ от входа от криво отрендеренного файла настроек — и в обоих случаях
поднимается без бота.
Цена расхождения падает на выкладку: файл настроек собирает Ansible, и потерянный
при сборке ключ выглядит для сервиса ровно так же, как решение владельца обойтись
одним входом. Бот молча перестаёт отвечать своим отправителям, а узнать об этом
неоткуда.
## What Changes
- В настройках входа Telegram появляется отдельный признак включения. Он и
объявляет намерение: нужен ли сервису этот вход вообще.
- Ключ доступа перестаёт нести второе значение. Он читается и проверяется
**только** при включённом входе, а при выключенном не смотрится вовсе.
- Включённый вход без ключа доступа становится ошибкой настройки: сервис
говорит, какого ключа не хватает, и не поднимается. Прежде такой файл давал
тихий подъём без бота.
- Выключенный вход перестаёт быть поводом для предупреждения в журнале: решение
владельца сообщается обычной записью, а предупреждение остаётся за тем, чего
владелец не выбирал, — недоступностью Telegram.
- Отказ разбора файла настроек перестаёт пересказывать библиотеку разбора и
говорит своими словами: где сломалось и на каком ключе, но не что там
написано. Прежде поломанная строка секретного ключа уезжала в журнал вместе со
своим значением.
- **BREAKING** для файла настроек: у секции Telegram появляется новый
**обязательный** ключ. Умолчания у него нет: файл без признака негоден, и
сервис выходит с ошибкой настройки. Решение владельца от 2026-08-13 — намерение
объявляют, а не угадывают по умолчанию, и файл, где его забыли объявить, не
должен работать «как-нибудь».
Прежние правила подъёма при включённом входе сохраняются целиком: Telegram
отвечает «такого бота нет» — старт кончается отказом; Telegram недоступен или
молчит дольше срока — сервис поднимается одним входом и говорит об этом
предупреждением. Признак поднятости входа наблюдателю виден во всех случаях.
## Capabilities
### New Capabilities
Новых нет: речь о том, с какими входами сервис вправе подняться, а это уже
нормировано.
### Modified Capabilities
- `intake`: требование «Недоступный или незаданный вход Telegram не мешает
подъёму» перестаёт выводить намерение из ключа доступа. Оно начинает опираться
на объявленный признак включения, получает два новых отказа старта — признака
в настройках нет и вход включён без ключа — и разводит уровни записей журнала
по тому, выбрал ли владелец это состояние.
## Impact
- Настройки: секция `[telegram]` в `config.toml` и в образце
`config.dist.toml`; структура настроек и умолчания в `internal/config`.
- Подъём: разбор случая при сборке входа Telegram (`telegram_build.go`) и вызов
проверки настроек в `main.go`.
- Выкладка: шаблон настроек в `pet-project-server` обязан получить признак
включения **до** накатки нового образа, иначе сервис не поднимется. Правит его
человек, здесь только называем.
- Документы: запрет на боевой токен в `CLAUDE.md`, конвенция настроек
`docs/conventions/config.md`, таблица отказов в `docs/architecture.md`.
- Приём записи из Telegram, белый список и доставка ответов не затрагиваются.