Сверка с метабазой промахивалась на иностранных фильмах с русским релиз-именем (кейс «Тёмный рыцарь»): поиск шёл по одной строке provider_hint||title и игнорировал original_title, а базы индексированы прежде всего по оригинальным названиям. - matchMetadata ищет по ключам original_title → title → provider_hint с ранним стопом на первом единичном сильном матче; пустые и нормализованно-дублирующие ключи пропускаются, кандидаты для review копятся из всех заходов. - Промпт требует всегда заполнять title и original_title (дублировать при отсутствии оригинала / российском контенте; при неуверенности дублировать, не выдумывать). Разбор остаётся мягким к пустому original_title. - TMDB-поиск передаёт language (по умолчанию ru-RU, настраивается [metadata.tmdb].language); original_title не зависит от локали. - Нормализация названий сводит ё→е. Инварианты не ослаблены: авто только при подтверждённом единичном матче + структурной валидации + согласованности сигналов. Capability recognition впервые перенесена в OpenSpec; change архивирован. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
7.4 KiB
Context
Сверка распознавания (internal/recognize/metadata.go, matchMetadata)
сейчас формирует один поисковый ключ searchTitle = provider_hint || title
и шлёт его всем включённым провайдерам. Гейт strongMatches сравнивает
нормализованные {plan.Title, plan.OriginalTitle} против
{cand.Title, cand.OriginalTitle} и требует год ±1. Базы TMDB/TVDB
индексированы прежде всего по оригинальным названиям, поэтому русское
релиз-имя часто не находится, а если original_title пуст — английская
сторона гейта вообще не работает. TMDB-поиск не передаёт language, так что
локализованный Title приходит в дефолтной локали.
Источник истины по recognition пока docs/specs/recognition.md (capability
ещё не перенесена в OpenSpec) — дельту синхронизируем с ним.
Goals / Non-Goals
Goals:
- Повысить попадаемость сверки на иностранных фильмах с русским релиз-именем, не ослабляя гейты авто-раскладки.
- Сделать оригинальное название всегда доступным для запроса и сравнения.
- Минимальные, локальные правки в существующих функциях.
Non-Goals:
- Не меняем модель уверенности и условия авто (матч в базе + структурная валидация + согласованность сигналов остаются как есть).
- Не вводим fuzzy-сравнение названий (только точечная нормализация
ё→е). - Не добавляем поле страны/языка происхождения в
Plan. - Не трогаем TVDB/TVMaze-клиентов по части локали (вне объёма).
Decisions
1. Стратегия поиска «оригинал → fallback», а не мёрж всех запросов.
Перебираем ключи [original_title, title, provider_hint] по порядку,
останавливаемся на первом, давшем единичный сильный матч. Оригинал —
сильнейший ключ баз, обычно хватает первого захода; меньше обращений к
API/квотам. Альтернатива — гнать все запросы и мёржить кандидатов — даёт чуть
полнее список для review, но дороже по обращениям; отвергнута как избыточная.
Кандидатов для review всё равно копим из всех фактически выполненных заходов.
Дубль-ключи (нормализованно равные уже выполненному) пропускаем.
2. provider_hint остаётся третьим фолбэком, а не удаляется.
Два канонических названия покрывают основной кейс, но hint иногда
сформулирован удачнее (очищен от мусора релиз-имени) — дешёвая страховка,
когда оба названия не нашлись. Удаление поля — лишняя правка схемы без явной
выгоды.
3. «Всегда заполнять оба названия» — через промпт, не через жёсткую схему.
Требование к модели: заполнять title и original_title, при отсутствии
отдельного оригинала или для российского контента — дублировать title; при
неуверенности — дублировать, а не выдумывать. Это и есть защита от
ложного авто-матча: «не знаю» схлопывается в безопасное дублирование русского
названия, а не в галлюцинацию английского, которая могла бы случайно
сматчиться с реальным фильмом и привести к авто-раскладке не того тайтла.
parsePlan остаётся мягким: пустой original_title не отбраковываем
(graceful-фолбэк на title), чтобы не плодить correction-ретраи и не уходить
в review зря.
4. language=ru-RU для TMDB, всегда, параметризуемо конфигом.
Поле original_title/original_name у TMDB не зависит от language —
английская сторона гейта не страдает. Локализованный Title приходит
по-русски: сходится русская сторона гейта и аккуратнее карточки кандидатов в
review. Деление на «российский/нероссийский» не нужно — ru-RU полезен
именно зарубежке, а для русского контента нейтрален. Дефолт ru-RU, поле
[metadata.tmdb].language.
5. ё→е в normalize, и только это.
Узкая правка под реальный класс расхождений написания. й→и и прочие
свёртки НЕ делаем — меняют смысл, риск ложных совпадений.
Risks / Trade-offs
- Модель всё же выдумывает оригинал вопреки промпту → гейт по-прежнему
требует год ±1 и единичность матча; авто только при подтверждённом матче.
Промпт явно предписывает дублирование при неуверенности. Остаточный риск
низкий и не выше текущего (галлюцинация
titleвозможна и сейчас). ru-RUдля контента без русской локализации → TMDB отдаёт fallback (оригинал/английский), хуже текущего поведения не становится.- Лишние обращения к базам при фолбэках → ограничены порядком из 1–3 запросов на провайдера, дубль-ключи пропускаются, ранний стоп на первом сильном матче. Ошибки провайдера по-прежнему не валят распознавание.
Migration Plan
- Изменения обратносовместимы по хранимым данным и API. Новое поле конфига
[metadata.tmdb].languageопционально (дефолтru-RU). - Откат — ревёрт; персистентных миграций БД нет.
- После apply синхронизировать
docs/specs/recognition.mdс дельтой.
Open Questions
- Нет.