## Why Распознавание уже копит кандидатов метабазы (`recognize.Result.Candidates` → `metadata_candidate`), и веб даёт полный «единый список источников совпадения» для точного выбора. В Telegram же карточка подтверждения показывает лишь эффективный матч (строка «База: …» / «нет матча»), но **не даёт выбрать** между несколькими найденными кандидатами: когда единичного сильного матча нет (частый триггер ревью — «несколько кандидатов»), из бота нельзя быстро закрепить нужный, приходится открывать веб. Ядро для этого уже готово: команда `worker.ChooseCandidate` пиннит кандидата как источник (ручной матч), не запуская авто-раскладку. ## What Changes - **Карточка подтверждения (review)** в боте, когда для распознавания есть сохранённые кандидаты метабазы, показывает кнопку выбора базы. По ней карточка двухшагово (как подтверждение удаления) разворачивает **список кандидатов inline-кнопками** — быстрый выбор из готового короткого списка. - **Выбор кандидата** кнопкой вызывает `ChooseCandidate` (пиннинг источника, ручной матч) и обновляет карточку на месте. Активный (уже выбранный) кандидат помечается в списке. Кнопка «← Назад» возвращает карточку без изменений. - **Веб остаётся точкой точных правок** (ввод id/URL вручную, «без базы», предпросмотр путей): бот — только быстрый выбор из уже найденных кандидатов. - **Безопасность границы:** id кандидата приходит в `callback_data` — недоверенный вход; перед доменным вызовом он валидируется как ULID (`ident.Parse`), как это уже делает веб-транспорт. Выбор кандидата — ручной матч, авто-раскладку не запускает (нужно явное «Применить»), инвариант авто-раскладки не двигается. ## Capabilities ### New Capabilities Нет. ### Modified Capabilities - `notifications`: добавляется требование к **поверхности** бота — предлагать выбор среди сохранённых кандидатов метабазы в карточке подтверждения (inline-кнопки, двухшаговое разворачивание), с валидацией id кандидата из `callback_data` на границе и без авто-раскладки. Доменная механика выбора (`ChooseCandidate`, пиннинг источника) уже покрыта capability `review` — здесь не дублируется. - `review`: MODIFIED требование «Разделение труда транспортов в ревью» — быстрый выбор источника из готового списка кандидатов теперь и Telegram-действие; точный ручной ввод id/URL и «без базы» остаются за вебом. Снимает межспековое расхождение (прежде выбор источника целиком относился к веб-точным-правкам). ## Impact - **Спеки:** дельта `notifications` — ADDED «Выбор кандидата метабазы из карточки подтверждения бота»; дельта `review` — MODIFIED «Разделение труда транспортов в ревью» (быстрый выбор кандидата — Telegram-действие). - **Код:** `internal/tgbot/bot.go` (интерфейс `Reviewer` + `ChooseCandidate`; callback-и списка/выбора/назад), `internal/tgbot/render.go` (кнопка выбора базы в `reviewKeyboard`, клавиатура списка кандидатов). - **Тесты:** `internal/tgbot` — карточка с кандидатами содержит кнопку выбора; разворачивание даёт список; выбор зовёт `ChooseCandidate` с валидным id; невалидный id из callback отклоняется. - **Миграции БД:** нет (кандидаты уже в БД — таблица `metadata_candidate`).