закрыта задача tvdb-title-locale

- вопрос о неподтверждённой форме ответа TVDB вынесен разведкой
  tvdb-search-response-live-check: закрытие задачи стёрло бы его вместе с файлом
This commit is contained in:
av
2026-08-07 15:17:29 +03:00
parent fdbc781197
commit 1d375f55ba
4 changed files with 73 additions and 64 deletions
+1
View File
@@ -24,6 +24,7 @@
- [✨ Переделать веб-UI в устанавливаемое PWA](items/web-ui-pwa.md) — текущий server-rendered UI функционален — PWA (устанавливаемое, удобное с телефона) это улучшение большого объёма, не блокер
- [✨ Править на ревью маппинг «файл → серия» и раскладывать вручную при провале LLM](items/review-mapping-editor.md) — правка S·E, «нумеровать подряд» и ручной режим при полном провале LLM были запланированы объёмом Ф5 и не заведены задачей — в ревью сегодня можно только подсказать текстом
- [✨ Заказать спекой крайние случаи именования: многофайловый фильм, редакции, двойная серия](items/naming-edge-cases.md) — стэкинг частей (part1/cd1), редакции [edition-…] и двойная серия SxxEyy-Eyy описаны нарративом, но в file-layout не заказаны — раскладка таких раздач не определена
- [🔬 Форма ответа поиска TheTVDB и семантика параметра language](items/tvdb-search-response-live-check.md) — форма ответа поиска TheTVDB принята по swagger 4.7.10 и живым прогоном не подтверждена — при иной форме разбор молча уходит в фолбэк, гейт зелёный, локализованное название не работает
- [🔬 Канон нумерации серий и порядок у провайдера тега](items/episode-numbering-canon.md) — Косметика/редкость: порядок просмотра ок, но у тайтлов со спорным порядком (Бибоп) Jellyfin подтягивает не те подписи серий, если канон файлов ≠ дефолтный порядок провайдера тега
- [🔬 Тексты и формат уведомлений в Telegram](items/telegram-messages-audit.md) — зонтичный проход по всем текстам бота: полнота карточек, единый язык, оформление; порождает под-задачи
- [🔬 guessit как сервис-спутник](items/guessit-sidecar.md) — go-ptn слабее питоновского guessit — если точности пред-парса не хватит, завернуть guessit в сервис-спутник рядом с бинарём
-1
View File
@@ -8,6 +8,5 @@
## Набор
- [✨ Брать у TVDB название на языке настройки и оригинальное название](items/tvdb-title-locale.md) — [general].language правит только TMDB и промпт LLM — TVDB отдаёт primary name, и при language=ru в карточку ревью и имя папки попадает 哪吒之魔童降世 вместо «Нэчжа»
- [✨ Узаконить confidence-гейт авто-раскладки в спеке и сделать его выключаемым (дефолт 0.7)](items/auto-link-confidence-gate.md) — Решено (B): гейт оставляем как доп. проверку на ревью — выключаемый порог, дефолт 0.85→0.7, записать в спеку
- [🐞 Тормозить опрос qBittorrent бэкоффом при недоступности и эскалировать устойчивый сбой](items/background-error-noise.md) — недоступный qBittorrent опрашивается каждые 5 с и даёт WARN на каждом тике: нужен экспоненциальный бэкофф до минутного потолка со сбросом по первому успеху и ERROR на устойчивой деградации
@@ -0,0 +1,72 @@
# 🔬 Форма ответа поиска TheTVDB и семантика параметра language
- **Тип:** research
- **Категория:** Ядро продукта
- **Зачем:** форма ответа поиска TheTVDB принята по swagger 4.7.10 и живым прогоном не подтверждена — при иной форме разбор молча уходит в фолбэк, гейт зелёный, локализованное название не работает
- **Теги:** goal:recognition-accuracy, sprint:2026-08-06
Задача `tvdb-title-locale` научила клиент TVDB брать локализованное название из
блока переводов ответа `/search` и заполнять `OriginalTitle` primary name'ом. Но
живым прогоном форма ответа не сверялась: `CLAUDE.md` → «Запреты» запрещает
ходить в боевые метабазы из отладочных прогонов и расходовать лимиты ключа.
Форма взята из публичной документации (swagger TheTVDB v4, версия `4.7.10`) и
записана в [docs/research/tvdb-search-translations.md](../../research/tvdb-search-translations.md)
как **условие, а не замер**.
Разведка нужна потому, что ошибка предположения **не наблюдаема**: разбор уйдёт в
тотальный фолбэк, `Title` станет равен primary name, то есть исход побайтно
совпадёт с поведением до задачи. Гейт зелёный, карточка ревью прежняя, фича не
работает. Единственный след — DEBUG-строка «в выдаче не разобрался ни один блок
переводов».
## Вопрос
Какова реальная форма блока переводов в ответе `/search` TheTVDB v4 — карта
«трёхбуквенный код языка → название» или иная, — и правда ли параметр `language`
этого эндпоинта сужает выдачу по основному языку записи, а не выбирает перевод?
## Куда ляжет ответ
- [docs/research/tvdb-search-translations.md](../../research/tvdb-search-translations.md):
предположения заменяются наблюдениями с датой прогона, а строка «живым
прогоном не подтверждено» — результатом. Условие пересмотра там уже записано.
- Решение по трём развилкам, оставшимся от `tvdb-title-locale`:
1. **Критерий приёмки про параметр языка в запросе.** Задача требовала, чтобы
запрос поиска содержал параметр языка из `[general].language`. При
реализации критерий отменён: по документации параметр — фильтр («Restrict
results to a specific primary language»), и его передача отсекла бы ровно
иноязычные записи, ради которых задача заводилась. Тест сейчас проверяет
обратное — что параметра нет. Критерий менял исполнитель, а не приёмщик;
нужно решение человека: переписать критерий под факт, отвергнуть решение
или подтвердить семантику прогоном и решить по факту. Рекомендация —
подтвердить прогоном, затем переписать критерий.
2. **Форма блока `translations`.** Подтвердить карту и трёхбуквенность ключей
либо починить разбор под реальную форму.
3. **Граница авто-раскладки сдвинулась в обе стороны.** Заполнение
`OriginalTitle` даёт кандидату TVDB два названия вместо одного. Логика
гейта не менялась, вход изменился: запись, которую отсекал иероглифический
primary name, теперь может пройти по переводу (review → авто), а две разные
записи могут совпасть с планом разными названиями (авто → review —
франшиза с одним русским названием и годами в пределах ±1). Рекомендация —
принять как есть: движение вниз ведёт к человеку, движение вверх и есть
польза задачи, и это ровно то, как уже работает TMDB. Альтернатива —
сравнивать у TVDB только по `OriginalTitle`, но тогда пропадает польза от
совпадения по переводу.
## Рамки
Оракул уже написан и лежит в репозитории — прогоняется вручную, человеком, под
своим ключом:
```
TVDB_API_KEY=… go test ./internal/metadata/ -run Integration -v
```
Он печатает `Title` и `OriginalTitle` для `Fargo` и для иноязычной записи
`Ne Zha` (movie 131155, primary name `哪吒之魔童降世`, русский перевод «Нэчжа»).
Расхождение `Title` и `OriginalTitle` у второй записи подтверждает форму;
совпадение означает, что перевод не доехал.
Автоматическим прогоном разведка не делается: лимиты ключа беречь, в гейт этот
тест не заводить. Кода менять не требуется — исход разведки это запись; правка
разбора, если форма окажется иной, заводится отдельной задачей.
-63
View File
@@ -1,63 +0,0 @@
# ✨ Брать у TVDB название на языке настройки и оригинальное название
- **Тип:** feature
- **Категория:** Ядро продукта
- **Зачем:** [general].language правит только TMDB и промпт LLM — TVDB отдаёт primary name, и при language=ru в карточку ревью и имя папки попадает 哪吒之魔童降世 вместо «Нэчжа»
- **Теги:** goal:recognition-accuracy
Кандидат от TVDB начинает приходить с названием на языке `[general].language`
и с отдельно заполненным оригинальным названием — как это уже делает TMDB.
Сегодня глобальная настройка до клиента TVDB не доезжает вовсе:
`TVDBConfig` (`internal/metadata/tvdb.go`) поля языка не имеет, `serve.go`
собирает провайдер без него, `Search` шлёт только `query`/`type`/`year`, а из
ответа разбирает единственное поле `name` — это primary name записи, то есть
название на языке оригинала. Блок переводов не читается, `OriginalTitle` TVDB
не заполняет вовсе, хотя это ось сравнения при матче. Наблюдаемый случай —
[movie 131155](https://www.thetvdb.com/movies/131155-): primary name
`哪吒之魔童降世`, русский перевод у записи есть («Нэчжа»), но до нас не доходит.
Что сделать:
- прокинуть локаль в `TVDBConfig` из `cfg.ContentLanguage()`, диалект вывести
внутри `tvdb.go` — знание диалекта принадлежит тому, кто на нём говорит
([ADR решения 2 в архиве](../../../openspec/changes/archive/2026-07-24-content-language-switch/design.md));
- разобрать переводы в выдаче поиска (точные имена полей — `name_translated` и
блок `translations`; форму сверить с живым API через `TVDB_API_KEY=… go test
./internal/metadata/ -run Integration`, наугад не писать);
- фолбэк на primary name, когда перевода на нужный язык нет, — молчаливой
пустоты в `Title` быть не должно;
- заполнить `OriginalTitle` primary name'ом;
- заказать поведение спекой: требование «Локаль запроса к TMDB»
([metadata-match](../../../openspec/specs/metadata-match/spec.md)) написано
только под TMDB — либо обобщается на провайдеров, либо получает соседа.
## Затрагивает
- `internal/metadata/tvdb.go``TVDBConfig` (поле языка), строка запроса
`Search`, разбор переводов и `OriginalTitle` в кандидате;
- `cmd/jellybit/serve.go` — сборка провайдера TVDB из конфига;
- `openspec/specs/metadata-match/spec.md` — требование «Локаль запроса к TMDB»:
обобщается на провайдеров либо получает соседа под TVDB;
- внешний контракт: поиск TVDB (`/search`) и его блок переводов — формат
сверяется живым прогоном под `TVDB_API_KEY`, наугад не пишется.
## Критерии приёмки
- Запрос поиска TVDB содержит параметр языка, выведенный из `[general].language`
(оракул: тест на `httptest`-сервере в `tvdb_test.go` — проверяет строку
запроса при `language = ru` и при незаданном, как это сделано для TMDB).
- При наличии перевода `Candidate.Title` приходит на языке настройки, при
отсутствии — равен primary name (оракул: два случая в одном табличном тесте на
фикстуре ответа).
- `Candidate.OriginalTitle` у TVDB непуст и равен primary name (оракул: тот же
тест; плюс интеграционный прогон за `TVDB_API_KEY` печатает оба поля).
- Дельта-спека `metadata-match` заказывает локаль TVDB и фолбэк на оригинал
(оракул: `openspec validate --strict`).
## Рамки
Матч и гейт авто-раскладки не трогаются — локализованное название косметическое,
сравнение идёт по оригинальному; менять из-за него поведение выборки нельзя.
Живой API дёргается только вручную под env-гейтом, лимиты ключа беречь. TVMaze
вне охвата — переводов не отдаёт.