Единый источник полей отображаемого имени и один рендер полного ярлыка на всех путях (старт и «Обновить имя»/авто-перелив). Раньше старт давал полный «Название (режиссёр, год). Сезон 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>
5.5 KiB
5.5 KiB
1. Хранение контекста (миграция + store)
- 1.1 Миграция goose (
internal/store/migrations):ALTER TABLE download ADD COLUMN parsed_context TEXT NOT NULL DEFAULT ''(down — дроп колонки) - 1.2
store.Download: полеParsedContext string \db:"parsed_context"`; включить колонку в SELECT/INSERT (internal/store/download.go,list.go`) - 1.3 Метод
SetParsedContext(ctx, id, json string) error(best-effort апдейт) в store; добавить в интерфейс worker - 1.4 Обновить ER-схему
docs/specs/database.md(новая колонка)
2. Извлечение из контекста → persistent
- 2.1
internal/naming: экспортировать извлечённую структуру и её JSON (публичный тип полей + метод/функция, возвращающая структуру вместе с именем), не ломая текущийDeriveName - 2.2
worker.goшаг добавления: сохранять извлечённую структуру вdownload.parsed_context(best-effort; сбой логируется, добавление не валит); пустая структура → пустойparsed_context
3. Режиссёр из метабазы (решение A2)
- 3.1
metadata.Provider: метод выборки режиссёра по id (credits) — реализовать в клиентах TMDB и TVDB (best-effort); TVMaze → пусто/не поддержан - 3.2
recognize.Plan: полеDirector \json:"director,omitempty"``; LLM его не заполняет, в валидации/гейте/plan-санитайзинге не участвует - 3.3
Recognize/matchMetadata: при подтверждённом авто-матче вкладывать режиссёра вplan.Director(как уже вкладываются title/year), best-effort - 3.4 Интерфейс
Recognizer(worker): метод выборки режиссёра по(provider, id)— проброс к metadata-провайдерам (без прямой зависимости worker→metadata) - 3.5 Ручной путь ревью: новое override-поле
ovrDirector; добавить его вsourcePins;chooseCandidateLocked/AddManualSourcebest-effort тянут режиссёра выбранногоprovider:idи пишут вovrDirector(пусто → очищает пин) - 3.6
applyOverrides: кластьovrDirectorвplan.Director
4. Единый рендер ярлыка + слоистое разрешение
- 4.1 Вынести логику
seasonSummary(httpapi/files.go) в переиспользуемое место (recognizeилиnaming);httpapiзовёт общий хелпер (поведение карточки не меняется) - 4.2
internal/naming: публичная функция рендера полного ярлыка из эффективных полей (title/director/year + готовая строка сводки сезонов); удалить/перевестиFormatTitleYear - 4.3
worker: хелперeffectiveNameFields(download, plan, overrides)— первый непустой слой override → recognition(+match) → parsed_context на поле; сводка сезонов:seasonSummary(plan)при наличии episode-ролей, иначе fallback на контекстный скалярSeason→ «Сезон N»; director: override → plan → context - 4.4
refreshDisplayNameLocked: заменитьFormatTitleYear(...)на рендер по эффективным полям; сохранить best-effort qBit rename, no-op при пустом источнике - 4.5 Сверить, что старт (
DeriveName) использует тот же рендер (единый формат ярлыка на всех путях)
5. UI ревью: режиссёр в инфо-части
- 5.1
httpapiинфо-часть выбранного источника: показывать режиссёра из эффективного плана/кандидата, пустой → прочерк (без слома вёрстки)
6. Тесты и проверки
- 6.1 Юнит-тесты рендера ярлыка: полный формат, опциональность режиссёра/года, сводка сезонов (один/несколько/спецвыпуски), санитайзинг+лимит
- 6.2 Тест слоистого разрешения: контекст-режиссёр переживает распознавание без матча; матч-режиссёр бьёт контекстного; override бьёт оба
- 6.3 Тест persist
parsed_contextна старте + best-effort (сбой не валит добавление) - 6.4 Тест метабазного режиссёра: авто-матч TMDB/TVDB →
plan.Director; ручной выбор кандидата тянет режиссёра вovrDirector; недоступность credits → пусто, матч/выбор не падают - 6.5
task lintиtask testзелёные;openspec validate --strict - 6.6 Удалить закрытую беклог-задачу
docs/backlog/knopka-obnovit-imya-polnyj-format.mdи строку в индексе беклога