## Why

LLM возвращает названия с «грязью», из-за которой сверка с метабазой промахивается
и загрузка уходит в review без единого кандидата (реальный кейс — «Harold and the
Purple Crayon» с кириллической буквой-двойником вместо латинской: сырое название
ушло в query-параметр TVDB дословно, база не нашла, а гейт сильного матча кир/лат
двойники не сворачивает). Плюс год из плана уходит в запрос как жёсткий фильтр —
при ошибке модели в годе база не находит запись, которая на деле есть. Итог:
Jellyfin остаётся без официального id, а человек вбивает id руками. Цель — поднять
hit-rate кандидатов метабазы, не трогая инвариант авто-матча.

## What Changes

- **Санитайзинг названий от LLM** (`recognition`): на границе разбора плана, после
  unmarshal и ДО структурной валидации/сверки, чистим человекочитаемые поля
  `title`, `original_title`, `provider_hint`: (1) strip control/zero-width
  символов, (2) collapse пробелов + trim, (3) свёртка кирилло-латинских
  homoglyph-двойников по курируемой таблице (потокенно, только для смешанных
  токенов). `files[].src` не трогаем — они обязаны байт-в-байт совпадать с файлами
  торрента.
- **Homoglyph-fold в гейте матча** (`metadata-match`): нормализация названий при
  сравнении получает ту же свёртку двойников как defense-in-depth на случай грязи
  со стороны кандидата базы.
- **Ретрай сверки без года** (`metadata-match`): если поиск с годом не дал
  подтверждённого матча, второй проход тем же перебором названий×провайдеров, но
  без года. Гейт (exact-normalized название + год ±1) остаётся прежним — precision
  не падает, кандидаты копятся через оба прохода.
- Наблюдаемость: `slog.Debug`, когда санитайзинг реально переписал поле.

Не в scope (отдельные задачи при необходимости): fuzzy/edit-distance матч,
транслитерация ru↔en, срез подзаголовка после «:», санитайзинг входного контекста
и накопленных подсказок.

## Capabilities

### New Capabilities

_Нет._

### Modified Capabilities

- `recognition`: добавляется требование санитайзинга человекочитаемых полей плана
  (`title`/`original_title`/`provider_hint`) на границе разбора ответа LLM.
- `metadata-match`: нормализация названий при сравнении расширяется свёрткой
  кирилло-латинских homoglyph-двойников; сверка получает безгодовой второй проход
  как fallback, когда поиск с годом не дал подтверждённого матча.

## Impact

- Код: `internal/recognize` (новый шаг санитайзинга при разборе плана, `normalize`
  и `matchMetadata` в `metadata.go`). Провайдеры `internal/metadata/*` не меняются
  (год уже опционален в `Query`).
- Поведение: ранее промахивавшиеся из-за homoglyph/кривого года раздачи теперь
  находят кандидата (авто-матч при единичном сильном совпадении, иначе — заполненный
  список для выбора в review). Инвариант «авто только при подтверждённом единичном
  сильном матче» и неприкосновенность `files[].src`/источника не затрагиваются.
- Зависимостей не добавляется (таблица двойников — небольшой литерал в коде).
