## 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`).
