Поиск по нескольким названиям при сверке с базой (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>
This commit is contained in:
av
2026-06-29 12:16:47 +03:00
co-authored by Claude Opus 4.8
parent cc7e51b3a4
commit 4fc8c41b3a
15 changed files with 611 additions and 58 deletions
@@ -0,0 +1,32 @@
## 1. Конфигурация TMDB language
- [x] 1.1 Добавить поле `language` в конфиг TMDB (`[metadata.tmdb].language`), дефолт `ru-RU`; проброс в клиент TMDB
- [x] 1.2 Безопасный дефолт `ru-RU` при пустой локали (в `Default()` и фолбэком в клиенте — отдельная валидация-реджект не нужна); обновить `config.example.toml`
## 2. Локаль в TMDB-клиенте
- [x] 2.1 В `internal/metadata/tmdb.go` передавать `language` в `Search` (`params.Set("language", ...)`)
- [x] 2.2 Тест: запрос содержит `language=ru-RU`; `OriginalTitle` не зависит от локали
## 3. Нормализация названий
- [x] 3.1 В `internal/recognize/metadata.go` `normalize` сводить `ё``е`
- [x] 3.2 Тест: «Тёмный рыцарь» и «Темный рыцарь» нормализуются одинаково
## 4. Многозапросный поиск в matchMetadata
- [x] 4.1 Сформировать упорядоченный список ключей `[original_title, title, provider_hint]`, отбросив пустые и нормализованные дубли
- [x] 4.2 Перебирать ключи: для каждого — поиск по всем провайдерам, ранний стоп на первом единичном сильном матче (`strongMatches`)
- [x] 4.3 Кандидатов для review копить из всех выполненных заходов (дедуп по `provider:id`, потолок `maxCandidates`)
- [x] 4.4 Тесты: матч по original при пустом совпадении по title; фолбэк на title; фолбэк на provider_hint; пропуск дубль-ключа
## 5. Контракт LLM на названия (промпт)
- [x] 5.1 В `internal/recognize/prompt.go` усилить правила: всегда заполнять `title` и `original_title`; дублировать при отсутствии оригинала / российском происхождении; при неуверенности дублировать, не выдумывать
- [x] 5.2 Убедиться, что `parsePlan` остаётся мягким к пустому `original_title` (нет отбраковки/лишнего correction-ретрая); тест на graceful-фолбэк
## 6. Синхронизация спеки и проверка
- [x] 6.1 Синхронизировать `docs/specs/recognition.md` с дельтой (конвейер сверки, контракт названий, локаль TMDB, нормализация)
- [x] 6.2 `task test` и `task lint` зелёные
- [x] 6.3 `openspec validate recognition-multi-title-match --strict` проходит