- в секции [telegram] заведён обязательный ключ enabled: умолчания у него нет, файл без него негоден; bot_token стал только ключом доступа и при enabled = false не читается вовсе, а пустой при enabled = true роняет старт - выключенный вход даёт подъём одним входом без единого обращения к Telegram и записью INFO вместо прежнего WARN: это выбор владельца, а не отклонение - отказ разбора файла настроек больше не пересказывает toml — её ParseError несёт в тексте разбираемое значение, и оборванная строка секретного ключа уносила его в журнал; теперь называются путь, строка, столбец и последний ключ
8.5 KiB
Ревью кода — 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лежит в чужом репозитории и во вход не входил ни одному проходу.