Files
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

24 lines
3.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 1. Layout: приём унаследованной базы и разбор пути
- [x] 1.1 Добавить в `layout.Plan` опциональное поле `FolderBase string` (пусто → как прежде)
- [x] 1.2 В `BuildLinks`: если `FolderBase != ""` — использовать её как `base` (через `sanitizeComponent`) вместо `titleYear(Title, Year)`, применяя и к папке, и к именам файлов; тег складывать как прежде
- [x] 1.3 Экспортировать хелпер(ы): извлечь папку тайтла из `dst_path` (первый сегмент под корнем `movies`/`series`; не под корнем → пусто) и снять базу из папки (убрать хвостовой ` [...]`; пустой результат → пусто)
- [x] 1.4 Юнит-тесты layout: `FolderBase` перекрывает базу в папке и в именах файлов (movie и series); извлечение папки/базы из пути — с тегом, без тега, с чужим/старым тегом, не под корнем
## 2. Store: lookup живых ссылок тайтла
- [x] 2.1 Добавить `LiveTitleFolders(ctx, provider, providerID, excludeDownloadID) ([]string, error)`: `dst_path` ссылок со `status IN linked/copied/exists` загрузок с тем же `(provider, provider_id)` current recognition, кроме `excludeDownloadID`; пустой provider/id → пусто
- [x] 2.2 Юнит-тест store: возврат путей по матчу; исключение текущей загрузки; superseded/collision/удалённые не попадают; пустой provider/id → пусто
## 3. Worker: правило сходимости, рассинхрон, превью
- [x] 3.1 Чистый хелпер `resolveFolderBase(ctx, dl, provider, providerID, mediaType) (base string, desync bool, err error)`: нет матча → пусто; иначе `LiveTitleFolders` → свести к различным папкам тайтла (хелпер 1.3), отбросить несуществующие на диске (`os.Lstat`) и неразбираемые; 0 → пусто, 1 → база, ≥2 → desync. Без побочных эффектов.
- [x] 3.2 В `linkPlan` (из состояния `linking`, рядом с обработкой коллизии — `deferred→review` в графе нет): вызвать `resolveFolderBase`; `desync``transition(review, "title_folder_desync")`, раскладку не выполнять; иначе прокинуть `base` в `toLayoutPlan`/`layout.Plan`
- [x] 3.3 Превью раскладки на ревью (review.go ~921/981) зовёт тот же `resolveFolderBase` и наследует базу (инвариант «превью=применение»); `desync` в превью → база из распознавания, без перевода в review
- [x] 3.4 Тесты worker/integration: сходимость второго сезона в ту же папку; отсутствие якоря → свежая папка; переименование папки на диске у кандидата → не якорь (печать заново); смена провайдера → не склеивается; рассинхрон (2 живые папки) → review с причиной; превью совпадает с применением
## 4. Спеки и проверка
- [x] 4.1 `openspec validate --strict series-folder-convergence`
- [x] 4.2 `task test` и `task lint` — зелёные