Files
avandClaude Opus 4.8 4fc8c41b3a Поиск по нескольким названиям при сверке с базой (recognition)
Сверка с метабазой промахивалась на иностранных фильмах с русским
релиз-именем (кейс «Тёмный рыцарь»): поиск шёл по одной строке
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>
2026-06-29 12:16:47 +03:00

93 lines
7.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 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
- Нет.