- локаль из [general].language применяется при разборе ответа /search, а в запрос не уходит: параметр language у TVDB — фильтр выдачи, а не селектор перевода (ADR-2026-08-07) - Title берётся из блока translations с тотальным фолбэком на primary name, OriginalTitle — из primary name; форма ответа сверена по документации и живым прогоном не подтверждена (docs/research) - неожиданная форма ответа даёт WARN: признак — отсутствие во всей выдаче ключей языка ожидаемого вида, а не неудача разбора блока
12 KiB
12 KiB
1. Разведка формы ответа
- 1.1 Записать
docs/research/tvdb-search-translations.md: формаSearchResult(name,translations,name_translated,primary_language), смысл параметраlanguageу/search, версия swagger, честный провенанс «сверено по документации, живым прогоном не подтверждено» - 1.2 Добавить запись в перечень
docs/research/README.md→ «Записи»
2. Клиент TVDB
- 2.1
TVDBConfig.Language— абстрактный кодru|en, комментарий по образцуTMDBConfig.Language - 2.2
tvdbLocale(lang string) string— тотальныйswitch,ru→rus, default →eng; имя ровно как у соседаtmdbLocale; комментарий называетconfig.validateисточником множества - 2.3
NewTVDBкладёт выведенный код в поле клиента - 2.4
tvdbSearchRespобъявляетtranslationsкакjson.RawMessageи раскладывает вmap[string]stringотдельно, с гашением ошибки: негодная форма косметического поля не должна ронять разбор всей выдачи - 2.5
SearchзаполняетTitleиз перевода (ключ ищетсяstrings.EqualFold, выбор среди совпавших детерминирован, значение — послеstrings.TrimSpace) с фолбэком наname, иOriginalTitleизname - 2.6 Убедиться, что параметр
languageв строку запроса/searchНЕ попал - 2.7 Сигнал на операцию, когда во всей выдаче не встретилось ни одного ключа
языка ожидаемого вида: подозрение на иную форму ответа отличается от
штатного «перевода нет». Уровень
WARN—DEBUGв проде выключен (правка по находке 1 ревью кода) - 2.8 Дописать третий маппер (
metadata.tvdbLocale) в перечень потребителей кода языка в комментарииinternal/config/config.go→validate
3. Проброс из точки входа
- 3.1
cmd/jellybit/serve.go—metadataProvidersпередаётLanguage: cfg.ContentLanguage()вTVDBConfig
4. Тесты
- 4.1 Стенд
fakeTVDBвtvdb_test.goотдаёт запись с блокомtranslations - 4.2 Табличный тест: перевод есть →
Titleлокализован; перевода на нужный язык нет; перевод из одних пробелов; ключ в другом регистре; блока нет; блок пришёл не картой. Во всех случаях, кроме первого,Title= primary name; во всех без исключенияOriginalTitle= primary name - 4.3 Тест на язык по умолчанию (
Languageне задан → берётсяeng) - 4.4 Тест: строка запроса
/searchне содержитlanguageни приru, ни при пустом языке, и совпадает в обоих случаях - 4.5 Тест: негодный блок переводов не проваливает
Search— кандидаты возвращаются - 4.6 Тест: на один
Searchуходит ровно один HTTP-запрос к/search(счётчик на стенде) — расход лимита ключа не растёт - 4.8 Тест на сигнал о неожиданной форме ответа: буфер логгера, 8 случаев, включая штатный «перевода нет» с ожиданием отсутствия следа
- 4.9 Тест на детерминизм выбора ключа перевода (200 прогонов на случай)
- 4.10 Тест
TestMatchMetadata_TranslationMakesTwoStrongвinternal/recognize/metadata_test.go: два кандидата совпадают с планом разными осями — подтверждённого матча нет, обе записи уходят в review - 4.7 Интеграционный тест в
integration_test.goзаTVDB_API_KEYпечатаетTitleиOriginalTitle. Пишется, но не запускается — живых обращений к TVDB в этой задаче нет
5. Учёт нерешённого
- 5.1 Записать вопрос человеку в
docs/tasks/items/tvdb-title-locale.md(раздел «Вопросы» + тегquestion) через скиллav-dev-pm:tasks: форма ответа TVDB не сверена живым API, нужен ручной прогон под ключом; плюс расхождение с критерием приёмки A1 про параметр языка в запросе; плюс двустороннее движение границы авто/review. Сделано иначе, чем написано: раздел «Вопросы» у задачи в спринте краснитtasks.py checkи через него шагcanonгейта, а закрытие задачи стёрло бы вопрос вместе с файлом. Вопрос вынесен отдельной задачей-разведкойdocs/tasks/items/tvdb-search-response-live-check.md
6. Гейт
- 6.1
openspec validate --strict tvdb-title-locale - 6.2
task gateзелёный
Критерии приёмки задачи
Пришли из docs/tasks/items/tvdb-title-locale.md; переписывать и занижать их
нельзя, исход по каждому идёт в доклад.
- A1 Запрос поиска TVDB содержит параметр языка, выведенный из
[general].language(оракул: тест наhttptest-сервере вtvdb_test.go). Отменён решением 1 design.md: параметр — фильтр выдачи, а не селектор перевода. Вместо него проверяется обратное — параметра в запросе нет (задача 4.4). Расхождение вынесено вопросом человеку - A2 При наличии перевода
Candidate.Titleприходит на языке настройки, при отсутствии — равен primary name (оракул: табличный тест 4.2) - A3
Candidate.OriginalTitleу TVDB непуст и равен primary name (оракул: тот же тест 4.2; интеграционный прогон заTVDB_API_KEYпечатает оба поля — написан, но не запущен, живых обращений к метабазе в задаче нет) - A4 Дельта-спека
metadata-matchзаказывает локаль TVDB и фолбэк на оригинал (оракул:openspec validate --strict)
Приёмочные критерии от рубрики (ревью дизайна, проход rubric)
Рубрика порождена до чтения кода и дизайна. Пункты 1, 5, 7 закрываются условно:
они опираются на форму ответа /search, взятую из публичной документации, — стенд
httptest проверит поведение кода на предполагаемой форме, а не истинность
предположения.
- R1 Фолбэк
Titleтотален по всем формам отсутствия перевода: блока нет; блок пуст; ключа нет; значение пустое. ПустогоTitleпри непустомnameнет ни на одной ветви. Оракул — строка табличного теста на каждую форму (условно) - R2 Строка запроса
/searchне содержит параметра языка ни при каком значении настройки: утверждение об отсутствии ключа плюс равенство URL приruиen - R3
OriginalTitle= primary name всегда, включая случай найденного перевода; значение настройки языка его не смещает - R4 Язык имеет один источник и один вывод диалекта: ни константы
tvdbDefaultLanguage, ни фолбэка в конструкторе, ни второго места переводаru/en→rus/eng - R5 Разбор устойчив к форме, а не только к содержимому: лишние поля,
отсутствующие поля,
translations: null,translationsне картой, усечённое тело — не паникуют и не проваливаютSearch; худший исход — фолбэк по R1. Негодный ответ поиска целиком по-прежнему остаётся ошибкой (условно) - R6 Пустота значения проверяется после
TrimSpace, а не до - R7 Ключ в неожиданной форме (иной регистр) не даёт молчаливого фолбэка: поиск ключа регистронезависимый, исход зафиксирован тестом (условно)
- R8 Число обращений к TVDB на одну сверку не растёт: один
Search— один HTTP-запрос, проверяется счётчиком на стенде - R9 Результат — функция ответа провайдера, а не порядка проходов: исход не
зависит от того, каким проходом пришёл кандидат; заполнение
OriginalTitleне заставляет следующий заход перебора искать по подменённому значению; на фолбэкеTitle == OriginalTitleдедупликация ключей перебора не схлопывает перебор до нуля запросов - R10 Секрет и контекст ведут себя как у остальных клиентов: ключ TVDB не
попадает в лог, в текст ошибки разбора и в сообщение с URL;
contextдоходит до запроса и отменяет его; таймаут из конфига - R11 У ответа есть предел (
maxBodyвrawGet), у выдачи — прежний потолок кандидатов; второго канала без предела не заводится - R12 Факт фолбэка наблюдаем, но не шумен: один чекпоинт на операцию,
отсутствие перевода — не
ERROR, недоступность опциональной метабазы состояние загрузки не двигает