docs: перевод документации на канон av-dev
- Раскладка docs/ приведена к канону 2: заведены passport/architecture/ database/security/review и research; docs/specs, drafts, backlog, review/ и BRIEF.md разобраны и удалены, беклог переехал в docs/tasks (34 задачи, 6 целей, слаги на английский). - Нарративы specs удалены как дубли openspec-спек после поимённой сверки; остаток заведён задачами (редактор маппинга ревью, крайние случаи именования), отказ от сущности title промоутнут в ADR. - Проектные копии агентов и скиллов ревью/пайплайна удалены в пользу плагинов av-dev-pm и av-dev-pipeline; в task gate добавлен шаг canon вместо er-schema.
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
# Отдельную сущность «тайтл» не вводим
|
||||
|
||||
- **Дата:** 2026-07-02
|
||||
- **Источник:** черновик `docs/drafts/logical-title-model.md` (разбор от
|
||||
2026-07-01, переработан 2026-07-02; удалён при переводе проекта на канон,
|
||||
полный текст — в истории git). Первый производный change —
|
||||
[openspec/changes/archive/2026-07-02-ulid-identity/design.md](../../openspec/changes/archive/2026-07-02-ulid-identity/design.md).
|
||||
|
||||
## Решение
|
||||
|
||||
Логический тайтл (фильм или сериал, складывающийся из нескольких загрузок во
|
||||
времени) остаётся **вычисляемой группой**, а не хранимой сущностью: доменная
|
||||
идентичность — `download` (ULID + множество инфохэшей), связь с диском —
|
||||
`file_link` с владением целевым путём, а «второй сезон в ту же папку» решается
|
||||
**правилом сходимости папки** при построении плана раскладки.
|
||||
|
||||
## Почему
|
||||
|
||||
Разбор шёл от операций, и у тайтла их не нашлось:
|
||||
|
||||
> У `title` при разборе **не нашлось ни одной собственной операции**: сходимость
|
||||
> папки — правило при построении плана; merge докачивания — per-path логика;
|
||||
> удаление целиком — цикл по вычисляемой группе. Сущность без собственных
|
||||
> операций — это линза, а линзу достаточно вычислять, не хранить.
|
||||
|
||||
Второй аргумент — у папки уже есть дом, и вычисляемый якорь **корректнее**
|
||||
хранимого:
|
||||
|
||||
> «Папка — это title-уровневое состояние, ей нужен дом» разбивается о то, что
|
||||
> дом у папки уже есть — файловая система и `dst_path` живых `file_link`'ов.
|
||||
> Реестр дублировал бы то, что и так записано в БД в N экземплярах. Причём
|
||||
> вычисляемый якорь корректнее хранимого: если все файлы сериала снесли, живых
|
||||
> ссылок нет — и новая загрузка честно создаёт свежую папку; хранимый
|
||||
> `title.folder` указывал бы в пустоту.
|
||||
|
||||
Третий — отказ **устраняет**, а не решает хвост развилок: жизненный цикл тайтла
|
||||
(рождение, смерть, пустой тайтл), слияние тайтлов, ad-hoc тайтл без провайдера,
|
||||
обратная миграция существующих строк, отдельный title-лог.
|
||||
|
||||
## Рассмотренные варианты
|
||||
|
||||
- **L2 — `title` с ключом `(provider, provider_id)`.** Отвергнут: привязывает
|
||||
долгоживущую сущность к провайдеру, который может смениться.
|
||||
- **L2-min — `title` со своим ULID + `title_external_id`** (провайдерные id
|
||||
множеством-атрибутом, симметрично `download_infohash`). Схема красивая и
|
||||
решает смену провайдера, ad-hoc тайтлы и слияние. Отвергнут именно по
|
||||
аргументу выше: собственных операций нет, а сущность тянет жизненный цикл,
|
||||
миграцию и четыре развилки.
|
||||
- **L3 — title-центричная медиатека (модель sonarr).** Отвергнут осознанно: мы
|
||||
не ходим в индексеры, не мониторим тайтлы и не ведём профили качества —
|
||||
контент приносит пользователь. Это граница домена,
|
||||
[passport.md](../passport.md) → «Что целью не является».
|
||||
|
||||
## Последствия
|
||||
|
||||
- `+` Идентичность осталась одноуровневой: `download` — мост между раздачей в
|
||||
qBittorrent и файлами на диске, и каждая сущность цепочки отвечает на свои
|
||||
операции.
|
||||
- `+` Главная боль («второй сезон должен лечь в ту же папку») закрыта дешёвым
|
||||
правилом при построении плана — реализовано change'ем
|
||||
`2026-07-10-series-folder-convergence`, требования влиты в
|
||||
[openspec/specs/file-layout](../../openspec/specs/file-layout/spec.md).
|
||||
- `+` Устранён, а не отложен, хвост развилок вокруг жизненного цикла тайтла.
|
||||
- `−` Группировка тайтла в UI и «удалить тайтл целиком» придётся каждый раз
|
||||
**вычислять** по `(provider, provider_id)` и общей папке; дешёвого хранимого
|
||||
ключа для этого нет.
|
||||
- `−` Рассинхрон «несколько живых папок с одним `(provider, provider_id)`»
|
||||
разрешается только уходом в review — in-app лечения нет, чинится руками на
|
||||
диске.
|
||||
- `−` Слияние загрузок при перезаливе «той же вещи» осталось открытым: когда
|
||||
несколько инфохэшей считать одной загрузкой, а когда разными, — вопрос
|
||||
переехал в задачу про merge-раскладку.
|
||||
|
||||
## Триггер пересмотра
|
||||
|
||||
Записан отдельно, чтобы не гонять этот круг заново:
|
||||
|
||||
> Сущность `title` возвращается в обсуждение, только когда появится **операция
|
||||
> или состояние, которому реально негде жить** в `download` + `file_link` —
|
||||
> например, «переименовать сериал целиком с переносом ссылок» как регулярное
|
||||
> действие или заметки уровня группы. До того — вычисляем.
|
||||
Reference in New Issue
Block a user