config: включение Telegram разведено с ключом доступа
- в секции [telegram] заведён обязательный ключ enabled: умолчания у него нет, файл без него негоден; bot_token стал только ключом доступа и при enabled = false не читается вовсе, а пустой при enabled = true роняет старт - выключенный вход даёт подъём одним входом без единого обращения к Telegram и записью INFO вместо прежнего WARN: это выбор владельца, а не отклонение - отказ разбора файла настроек больше не пересказывает toml — её ParseError несёт в тексте разбираемое значение, и оборванная строка секретного ключа уносила его в журнал; теперь называются путь, строка, столбец и последний ключ
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# Ревью кода — telegram-enabled-flag
|
||||
|
||||
Метка `medium`, режим по графу. Состав: `autotests`, `specs`, `code`, `basics`,
|
||||
`triage`. Проходы `adversary`, `ops`, `architecture` не запускались — живут с
|
||||
метки `large`.
|
||||
|
||||
## План с исходом по каждой теме
|
||||
|
||||
| Тема | Дом | Глубина | Кто закрывает | Исход |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| requirements | `openspec/specs/intake/spec.md` + дельта | разбор | specs | закрыта, 3 находки |
|
||||
| autotests | `CLAUDE.md`, «Гейт» | — | autotests | закрыта, 3 находки |
|
||||
| conventions | `docs/conventions/config.md` | разбор | code | закрыта, 3 находки |
|
||||
| architecture | `docs/architecture.md`, «Компоненты», «Единые точки» | разбор | basics | закрыта, находок нет |
|
||||
| security | `docs/security.md` | разбор | basics | закрыта, находок нет |
|
||||
| operations | `docs/architecture.md`, «Эксплуатация» | разбор | basics | закрыта, 2 находки |
|
||||
|
||||
Тем без отчёта нет, тем без дома нет, своих тем проекта нет.
|
||||
|
||||
## Состояние гейта
|
||||
|
||||
Зелёные: `build`, `vet`, `gofmt`, `tests` (`-race`, флака нет при `-count=1`
|
||||
трижды), `golangci-lint` (0 issues), `shell`, `dockerfile`, `go-version`,
|
||||
`migrations`, `openspec`, `vulns`.
|
||||
|
||||
Красные: `docs` и `tasks` — «проект приведён к раскладке версии 3, текущая — 4».
|
||||
Краснота **унаследована**: проход `autotests` воспроизвёл её в отдельном рабочем
|
||||
дереве на чистом `903941f` без диффа. Чинится операцией `upgrade` скилла
|
||||
`av-dev:canon` и к этой работе не относится.
|
||||
|
||||
`vulns`: единственная уязвимость `GO-2026-5932` в `golang.org/x/crypto/openpgp`
|
||||
недостижима из кода и уже названа в `CLAUDE.md`.
|
||||
|
||||
## Находки и что с ними сделано
|
||||
|
||||
15 сырых находок, после дедупликации по причине — 8 живых.
|
||||
|
||||
| № | Находка | Severity | Исход |
|
||||
| --- | --- | --- | --- |
|
||||
| — | `telegramFromConfig` не прогонялся с включённым входом (покрытие `2 0`) | major | починено до остальных проходов: два теста на связку «собрать клиента → разобрать исход» |
|
||||
| — | Ветка `decodeError` с пустым последним ключом не покрыта (`1 0`) | major | починено: тест на опечатку «незакрытая скобка секции» |
|
||||
| 1 | Раздел «Эксплуатация» предписывает обратный порядок выкладки — по нему сервис не поднимется вовсе | major | **принята**, `docs/architecture.md` переписан: порядок задаётся по ключу, а не по файлу, плюс два случая отката |
|
||||
| 2 | Сторож инварианта «секрет не покидает конфиг» зелен по построению | major | **принята**, проверка переписана честно; оракул триажа — мутация `Validate()` на утечку оставляла её зелёной |
|
||||
| 3 | Шапки `ErrEmptyToken` и `AbsentMessageSender` защищают снятое поведение | minor | **принята**, обе переписаны под новый разрез |
|
||||
| 4 | Признак поднятости входа не держится ни одной проверкой | minor | **принята**, утверждение о нуле добавлено в тест выключенного входа |
|
||||
| 5 | Новый абзац конвенции снимает с учёта непроверяемую границу `update_timeout` | minor | **принята**, утверждение сужено до двух ключей |
|
||||
| 6 | Норма «отказ разбора не несёт значения» живёт вне спек, дом не назначен | minor | **принята как развилка (а)**: дом назначен явно в `design.md` — инвариант плюс конвенция |
|
||||
| — | Смена версии библиотеки разбора могла бы вернуть утечку | гипотеза | действия не требует: ловится добавленными проверками, подтверждено мутацией |
|
||||
| — | Третий случай отката: образ старше 2026-08-13 | гипотеза | свёрнуто в находку 1, записано вопросом владельцу |
|
||||
|
||||
Проход `security` находок не дал: починку утечки он проверил по исходникам
|
||||
библиотеки независимо и признал разрез верным.
|
||||
|
||||
## Сигнал о заниженной метке
|
||||
|
||||
`review-code` подал сигнал: изменение вводит обязательный ключ настроек без
|
||||
умолчания, уже выложенный файл после этого не грузится, а имя ключа конфига
|
||||
проект числит необратимым. На метке `large` порядок выкладки и откат закрывал бы
|
||||
отдельный проход `ops`. Сигнал материализовался находкой 1 — её нашёл `basics`
|
||||
попутно, а не проход, для неё предназначенный. `review-basics` возражений по
|
||||
метке не подавал. Метка прогона не пересматривалась: правило запрещает.
|
||||
|
||||
## Границы покрытия
|
||||
|
||||
- **Три прохода не запускались** — `adversary`, `ops`, `architecture`. Уносят с
|
||||
собой враждебный разбор входов, отдельный разбор выкладки и отката, и
|
||||
независимый разбор архитектурного решения.
|
||||
- **Ни один из четырёх проходов не сообщил свой потолок и остаток за срезом.**
|
||||
Это находка о самом прогоне: без такой строки «находок больше нет»
|
||||
неотличимо от «больше не поместилось». У `basics` риск выше прочих — одна
|
||||
квота на три темы.
|
||||
- **Решения проекта не сверялись**: `docs/adr/` — процессный документ, прогон его
|
||||
не открывает. Расхождение с `ADR-2026-08-13-telegram-outage-does-not-block-startup`,
|
||||
который это изменение частично отменяет, ловит не ревью, а сверка документации.
|
||||
- **Записанные наблюдения не использовались**: `docs/research/` не открывался.
|
||||
- **Поимённая сверка с руководствами по стилю Go не задавалась никем** — в
|
||||
частности, для шва-параметра вместо интерфейса.
|
||||
- **Альтернативной реализации, с которой можно сдиффить решения, у конвейера
|
||||
нет** — проход независимой реализации снят по стоимости.
|
||||
- **Живьём проверяемо не всё.** Подъём, отказ старта, маршруты и остановка —
|
||||
проверены. Приём из Telegram, расшифровка и заливка — нет: боевым токеном
|
||||
запускаться запрещено, ключи Yandex выдуманы, распознавание подменяется в
|
||||
коде. Новый разрез при включённом входе с настоящим ботом не проверялся ничем,
|
||||
кроме подставной сборки клиента.
|
||||
- Шаблон настроек в `pet-project-server` лежит в чужом репозитории и во вход не
|
||||
входил ни одному проходу.
|
||||
@@ -0,0 +1,63 @@
|
||||
# Ревью дизайна — telegram-enabled-flag
|
||||
|
||||
Метка `medium`, назначена агентом `review-scope` (размер среднее, сложность
|
||||
знакомое). Режим по графу. Состав по метке: `specs` (режим «дизайн ДО кода») и
|
||||
`rubric`. Триажа на этой стадии нет — сток стадии — шаг отработки замечаний.
|
||||
|
||||
## Находки и что с ними сделано
|
||||
|
||||
| Проход | Находка | Severity | Исход |
|
||||
| --- | --- | --- | --- |
|
||||
| specs | У выключенного входа нет оракула: «бот не заведён, отказа нет» остаётся верным и когда ветка встала **после** обращения, а обращение ушло боевым токеном в живой Telegram | major | принята. Заведён шов `telegramFromConfig(cfg, newBot, logger)`, шаг 3.3 судит по счётчику вызовов, а не по исходу |
|
||||
| specs | `ADR-2026-08-13-telegram-outage-does-not-block-startup` утверждает, что старт роняет ровно один исход сборки клиента; после изменения их два | minor | принята. Шаг 4.7: новый ADR и парный статус прежнему |
|
||||
| specs | `docs/architecture.md` (перечень capability) и `docs/review.md` (рецепт живого прогона) останутся ложными: они учат поднимать сервис пустым токеном | minor | принята. Шаги 4.5 и 4.6 |
|
||||
| specs | Ошибочный `enabled = false` из шаблона выкладки — оставшееся русло молчаливой потери бота — в рисках не назван | minor | принята. Строка в `Risks / Trade-offs` |
|
||||
| rubric | Отказ разбора файла настроек может унести секрет в журнал: `toml.ParseError` встраивает разбираемое значение в текст | major | **снята из объёма, ушла в урожай.** Путь существует сегодня (`LoadConfig` заворачивает через `%w`, `main.go:49` печатает целиком) и этой работой не заводится; у починки своя цена — потеря подробности отказа |
|
||||
| rubric | Задача, принятая из Telegram до выключения входа, завершится, а ответ не уйдёт | major | **снята: ложноположительная.** Уже нормировано `openspec/specs/pipeline/spec.md`, «Недоставленный ответ не роняет шаг», сценарий «Вход отправителя не поднят»: `WARN`, метрика, идентификатор задачи. Проход читал только `intake`; `specs` пришёл к тому же выводу независимо |
|
||||
| rubric | Откат образа при `enabled = false` и непустом ключе тихо поднимает выключенного бота | minor | принята. Абзац в `Migration Plan` |
|
||||
| rubric | `docs/conventions/config.md`, раздел «Структура в коде», останется утверждать, что умолчание есть у каждого поля | minor | принята. Шаг 4.4 расширен на второй раздел |
|
||||
|
||||
## Правки, сделанные по урожаю
|
||||
|
||||
Дельта-спеки не менялись ни одной правкой — значит разметка не повторялась и
|
||||
метка осталась `medium`. Правки легли в `design.md` (шов сборки, два риска,
|
||||
абзац отката) и в `tasks.md` (шаги 2.2, 3.2, 3.3, 4.4, 4.5, 4.6, 4.7, рубрика в
|
||||
критерии приёмки).
|
||||
|
||||
## Сознательно не сделано
|
||||
|
||||
Сценарий «Вход выключен» не получил строки `**AND** признак поднятости входа
|
||||
Telegram равен нулю`. Её держит соседнее требование «Поднятые входы видны
|
||||
наблюдателю», чей сценарий стоит на премиссе «сервис поднялся без Telegram» и
|
||||
новое состояние покрывает. Правка изменила бы дельта-спеку и потребовала бы
|
||||
повторной разметки, не дав сегодня ничего.
|
||||
|
||||
## Границы спеки — что осталось неопределённым
|
||||
|
||||
- **Небулево значение признака** (`enabled = "yes"`) попадает в общий отказ
|
||||
разбора и имени ключа не называет, хотя оба соседних сценария отказа этого
|
||||
требуют.
|
||||
- **Несколько негодных секций разом**: `[auth]` и `[telegram]` проверяются
|
||||
порознь, и спека не говорит, обязан ли отказ перечислить все ключи.
|
||||
- **`update_timeout` при выключенном входе** — читается или игнорируется, не
|
||||
нормировано. Вреда нет, но вопрос стал видимым: сборка получает секцию целиком.
|
||||
- **Проба готовности при выключенном входе** ни одним требованием не связана с
|
||||
признаком. Граница существовала и до изменения.
|
||||
|
||||
## Границы покрытия стадии
|
||||
|
||||
- Кода нет по построению: направление `spec → code` недоступно, судилось только
|
||||
задуманное.
|
||||
- Рубрика составлена не открывая код и дизайн — иначе она подстроилась бы под
|
||||
увиденное.
|
||||
- Решения (`docs/adr/`) и измеренные числа (`docs/research/`) прогон ревью не
|
||||
открывает: расхождение изменения с записанным решением ловит не он, а сверка
|
||||
документации. Здесь оно всё же всплыло — проход `specs` наткнулся на ADR через
|
||||
ссылку из `design.md`, а не обходом каталога.
|
||||
- Ничего не запускалось: `openspec validate --strict` — единственная выполненная
|
||||
команда.
|
||||
- `review-architecture` на предложении не запускался: он живёт с метки `large`.
|
||||
Вопрос «не появился ли второй способ делать то же самое» на этом изменении не
|
||||
задавал никто.
|
||||
- Шаблон настроек в `pet-project-server` лежит в чужом репозитории и во вход не
|
||||
входил ни одному проходу.
|
||||
Reference in New Issue
Block a user