Files
jellybit/openspec/changes/archive/2026-07-10-series-folder-convergence/tasks.md
T
avandClaude Opus 4.8 5c3ef79496 Раскладка: сходимость папки сериала (второй сезон в ту же папку)
При подтверждённом матче база папки (имя+год) наследуется от живой
папки-якоря того же (provider, provider_id) вместо печати заново из выхода
LLM — так второй/последующий сезон ложится в ТУ ЖЕ папку, а не заводит
рядом почти одинаковую. Отдельная сущность «тайтл» не вводится.

- layout: Plan.FolderBase перекрывает базу в папке и именах файлов;
  TitleFolder разбирает dst_path в папку тайтла и базу (снятие тега).
- store: LiveTitleFolders — dst_path живых ссылок того же матча.
- worker: resolveFolderBase (живость якоря — по наличию папки на диске,
  os.Lstat, а не по статусу ссылки в БД) в linkPlan и в превью ревью
  (превью=применение); рассинхрон нескольких живых папок → review из
  linking (deferred→review в графе нет).

Схема БД не менялась. Change series-folder-convergence заархивирован,
требования влиты в openspec/specs/file-layout.

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

3.6 KiB
Raw Blame History

1. Layout: приём унаследованной базы и разбор пути

  • 1.1 Добавить в layout.Plan опциональное поле FolderBase string (пусто → как прежде)
  • 1.2 В BuildLinks: если FolderBase != "" — использовать её как base (через sanitizeComponent) вместо titleYear(Title, Year), применяя и к папке, и к именам файлов; тег складывать как прежде
  • 1.3 Экспортировать хелпер(ы): извлечь папку тайтла из dst_path (первый сегмент под корнем movies/series; не под корнем → пусто) и снять базу из папки (убрать хвостовой [...]; пустой результат → пусто)
  • 1.4 Юнит-тесты layout: FolderBase перекрывает базу в папке и в именах файлов (movie и series); извлечение папки/базы из пути — с тегом, без тега, с чужим/старым тегом, не под корнем

2. Store: lookup живых ссылок тайтла

  • 2.1 Добавить LiveTitleFolders(ctx, provider, providerID, excludeDownloadID) ([]string, error): dst_path ссылок со status IN linked/copied/exists загрузок с тем же (provider, provider_id) current recognition, кроме excludeDownloadID; пустой provider/id → пусто
  • 2.2 Юнит-тест store: возврат путей по матчу; исключение текущей загрузки; superseded/collision/удалённые не попадают; пустой provider/id → пусто

3. Worker: правило сходимости, рассинхрон, превью

  • 3.1 Чистый хелпер resolveFolderBase(ctx, dl, provider, providerID, mediaType) (base string, desync bool, err error): нет матча → пусто; иначе LiveTitleFolders → свести к различным папкам тайтла (хелпер 1.3), отбросить несуществующие на диске (os.Lstat) и неразбираемые; 0 → пусто, 1 → база, ≥2 → desync. Без побочных эффектов.
  • 3.2 В linkPlan (из состояния linking, рядом с обработкой коллизии — deferred→review в графе нет): вызвать resolveFolderBase; desynctransition(review, "title_folder_desync"), раскладку не выполнять; иначе прокинуть base в toLayoutPlan/layout.Plan
  • 3.3 Превью раскладки на ревью (review.go ~921/981) зовёт тот же resolveFolderBase и наследует базу (инвариант «превью=применение»); desync в превью → база из распознавания, без перевода в review
  • 3.4 Тесты worker/integration: сходимость второго сезона в ту же папку; отсутствие якоря → свежая папка; переименование папки на диске у кандидата → не якорь (печать заново); смена провайдера → не склеивается; рассинхрон (2 живые папки) → review с причиной; превью совпадает с применением

4. Спеки и проверка

  • 4.1 openspec validate --strict series-folder-convergence
  • 4.2 task test и task lint — зелёные