Files
avandClaude Opus 4.8 02d4ecc2aa display_name: слоистое разрешение полей + сохранение режиссёра из контекста
Единый источник полей отображаемого имени и один рендер полного ярлыка на
всех путях (старт и «Обновить имя»/авто-перелив). Раньше старт давал полный
«Название (режиссёр, год). Сезон N» но выбрасывал структуру, а перелив по
распознаванию — усечённый «Title (Year)».

- Слоистое разрешение скаляров имени: override → recognition(+match) →
  новый базовый слой «контекст» (download.parsed_context, JSON naming.Fields).
- naming: публичные Fields/Label/Derive, вынесен единый рендер; удалён
  FormatTitleYear. Сводка сезонов вынесена в recognize.SeasonSummary.
- Режиссёр из метабазы (решение A2): TMDB/TVDB credits через опциональный
  metadata.DirectorProvider; авто-матч кладёт в plan.Director, ручной выбор
  кандидата тянет credits и пиннит ovrDirector. Метабаза бьёт контекст.
- refreshDisplayNameLocked строит полный ярлык из эффективных полей;
  инфо-панель ревью показывает загруженного режиссёра.
- Миграция 0011_parsed_context + ER-схема. Всё косметика: на пути/раскладку
  не влияет, приём/вывод имени не валятся (best-effort).

Закрывает беклог-задачу «Кнопка „Обновить имя“: полный формат ярлыка».
OpenSpec: archive/2026-07-11-field-resolution-display-name (ingest,
recognition, metadata-match, review).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 11:50:08 +03:00

9.8 KiB
Raw Permalink Blame History

ingest Specification

ADDED Requirements

Requirement: Сохранение извлечённой из контекста структуры имени

Система SHALL сохранять структуру имени, извлечённую LLM со структурированным выводом на шаге добавления (тип, название, оригинальное название, год, режиссёр, сезон), у загрузки (download.parsed_context, JSON), чтобы её поля могли переиспользоваться при последующем выводе имени без повторного вызова LLM. Алгоритмический фолбек структуры не даёт (его выход — только строка имени), тогда parsed_context остаётся пустым — это штатно (нижний слой отсутствует). Сохранённая структура SHALL быть базовым (наименее доверенным) слоем источника полей имени: её значения берутся, только если более доверенный слой (распознавание/матч, ручные правки) соответствующего поля не дал.

Сохранение SHALL быть best-effort и косметическим: неудача записи parsed_context SHALL NOT проваливать добавление загрузки, а сама структура SHALL влиять только на отображаемое имя и SHALL NOT влиять на пути файлов, распознавание или раскладку. Пустая/невыведенная структура (нет контекста и подсказки) SHALL приводить к пустому parsed_context (нечего сохранять).

Scenario: Извлечённый режиссёр сохраняется у загрузки

  • GIVEN контекст загрузки, из которого LLM извлёк режиссёра и год
  • WHEN система выводит имя на шаге добавления
  • THEN извлечённая структура (в т.ч. режиссёр) сохраняется в download.parsed_context
  • AND отображаемое имя формируется как и прежде (полный ярлык)

Scenario: Сбой сохранения структуры не валит добавление

  • GIVEN запись parsed_context завершается ошибкой
  • WHEN идёт шаг добавления загрузки
  • THEN загрузка всё равно добавляется в qBittorrent (с rename, если имя выведено)
  • AND ошибка логируется, приём/добавление не проваливается

Scenario: Пустой вход — пустая структура

  • GIVEN пойманная загрузка без контекста и без подсказки из полей источника
  • WHEN выполняется шаг добавления
  • THEN структура не выводится, download.parsed_context пуст

MODIFIED Requirements

Requirement: Обновление отображаемого имени по распознаванию

Система SHALL уметь обновлять отображаемое имя загрузки после того, как распознавание дало каноническое название, — переливая уже вычисленное имя (без нового вызова LLM) в download.display_name и в имя раздачи qBittorrent.

Источником имени SHALL быть эффективные поля имени, разрешённые по слоям сверху вниз (берётся первый непустой слой): (1) ручные правки override; (2) распознавание с вложенным подтверждённым матчем (recognition, куда матч метабазы уже вложил каноничные название/год/режиссёра); (3) сохранённая структура из контекста (download.parsed_context). Так каждое поле берётся из самого доверенного доступного источника, а данные из контекста (например режиссёр) не теряются, если распознавание/матч их не дали. Название из слоя распознавания SHALL совпадать с тем, что использует раскладка (эффективный title), чтобы отображаемое имя не расходилось с целевыми путями.

Формат SHALL быть тем же полным детерминированным ярлыком, что и на шаге добавления: «Название (режиссёр, год)», где режиссёр и год опциональны, а для сериала добавляется сводка сезонов («. Сезон N» для одного сезона; «. Сезоны …» для многосезонного пака; отметка спецвыпусков) — согласованная со сводкой сезонов на экране просмотра. Применяются та же очистка от управляющих символов и обрезка по ограничению длины. Пустой источник (нет ни распознавания, ни сохранённой структуры, дающих непустое название) SHALL приводить к отсутствию изменений (no-op).

Переименование раздачи в qBittorrent SHALL адресоваться по infohash своей раздачи и SHALL быть best-effort: сбой (раздача удалена, qBittorrent недоступен) SHALL NOT проваливать обновление — download.display_name обновляется в любом случае, ошибка внешнего вызова логируется. Как и на шаге добавления, отображаемое имя SHALL влиять только на отображение и SHALL NOT влиять на пути файлов, распознавание или раскладку.

Обновление имени SHALL иметь две точки входа: авто — при подтверждённом матче (см. capability review); ручную — по явному действию пользователя. Ручное действие SHALL перезаписывать текущее имя всегда; авто SHALL перезаписывать, когда выведенное имя непусто.

Scenario: Перелив имени в загрузку и раздачу

  • GIVEN загрузка с распознанным непустым каноническим названием и известным режиссёром (из матча или из сохранённого контекста)
  • WHEN запускается обновление отображаемого имени
  • THEN download.display_name устанавливается в полный ярлык «Название (режиссёр, год)» (для сериала — со сводкой сезонов)
  • AND раздача в qBittorrent переименовывается в то же имя (по infohash своей раздачи)

Scenario: Режиссёр из контекста переживает распознавание без матча

  • GIVEN загрузка, где режиссёр был извлечён из контекста, а распознавание прошло без подтверждённого матча (режиссёр из метабазы недоступен)
  • WHEN запускается обновление отображаемого имени
  • THEN в ярлыке используется режиссёр из сохранённого контекста
  • AND название/год берутся из распознавания

Scenario: Режиссёр из матча бьёт контекстного

  • GIVEN загрузка, где режиссёр есть и в контексте, и в подтверждённом матче
  • WHEN формируется ярлык
  • THEN используется режиссёр из матча (более доверенный слой)

Scenario: qBittorrent недоступен — имя у загрузки всё равно обновлено

  • GIVEN обновление отображаемого имени с выведенным непустым именем
  • WHEN переименование раздачи в qBittorrent завершается ошибкой (недоступен или раздача удалена)
  • THEN download.display_name всё равно обновлён
  • AND ошибка внешнего вызова qBittorrent логируется, операция не проваливается

Scenario: Нет источника имени — обновление ничего не делает

  • GIVEN загрузка без распознанного названия и без сохранённой структуры (пустой источник имени)
  • WHEN запускается обновление отображаемого имени
  • THEN ни download.display_name, ни имя раздачи не меняются (no-op)