Рефакторинг границ capabilities: цепочка загрузка→матч→ревью→раскладка (openspec)
Привёл набор capabilities в OpenSpec к цепочке обработки, чтобы имя capability отвечало одному поведению. Чисто по спекам, код и поведение системы не меняются. Change refactor-capability-boundaries (архивирован): - recognition разделён на recognition (разбор LLM) + metadata-match (сверка с базами) - review выделен из web-ui + мигрирован из docs/specs/review-ux.md - новые capability из docs/specs: file-layout, download-tracking, notifications - identity очищен до инфра-id; приём (инфохэши, дедуп, ядро приёма) — в ingest - уведомление о рассинхроне перенесено из state-reconciliation в notifications - дубль владения путём и безопасного undo оставлен в state-reconciliation Итог: 11 capabilities, openspec validate --strict проходит (+37/−11 требований). Источник истины по мигрированным темам переехал в openspec/specs (шапки в docs). Снят пункт беклога «Пересмотр набора capabilities». Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
## Why
|
||||
|
||||
Деление capabilities в OpenSpec сложилось стихийно по ходу миграции и смешивает
|
||||
разные заботы в одной спеке: `recognition` держит и разбор через LLM, и работу с
|
||||
внешними базами; поведение ревью размазано между `web-ui` и не перенесённым
|
||||
`docs/specs/review-ux.md`; ключевые звенья цепочки (раскладка, отслеживание
|
||||
загрузки, уведомления) в OpenSpec отсутствуют вовсе. На каждой задаче приходится
|
||||
гадать, какой capability трогать. Приводим набор capabilities к цепочке
|
||||
«загрузка → распознавание → матч → ревью → раскладка», где имя capability
|
||||
отвечает **одному** поведению.
|
||||
|
||||
Это чисто спецификационный рефакторинг: **поведение системы не меняется**, код не
|
||||
трогаем. Меняются только границы и расположение требований.
|
||||
|
||||
## What Changes
|
||||
|
||||
- **Разделяем `recognition`**: оставляем в нём только разбор сигналов LLM (план,
|
||||
тип, название, файлы→серии, модель уверенности, решение auto/review); всю работу
|
||||
с метабазами выносим в новую `metadata-match`.
|
||||
- **Вводим `review`** как отдельный capability: переносим поведение ревью из
|
||||
`web-ui` (единый список источников, ручное добавление источника, предпросмотр
|
||||
полей) и мигрируем `docs/specs/review-ux.md`.
|
||||
- **Подрезаем `web-ui`** до чистого оформления: статика, шрифты, дизайн-система,
|
||||
скелет страниц, бейджи, клиентские взаимодействия, превью через единую логику
|
||||
именования.
|
||||
- **Мигрируем в OpenSpec** три звена цепочки, живущие пока в `docs/specs`:
|
||||
`file-layout` (из `jellyfin-layout.md`), `download-tracking` (FSM/поллинг из
|
||||
`workflow.md`), `notifications` (из `workflow.md` + `architecture.md`).
|
||||
- **Чистим `identity`** до инфраструктуры id: переносим приёмные требования
|
||||
(инфохэши, дедуп, атомарный возврат в активное) в `ingest`.
|
||||
- **Собираем уведомления** в `notifications`: переносим «Уведомление о
|
||||
рассинхроне» из `state-reconciliation`.
|
||||
- Не-BREAKING: перенос требований (REMOVED в исходной спеке + ADDED в целевой),
|
||||
формулировки сохраняем эквивалентными.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `metadata-match`: поиск записи во внешних базах (TMDB/TVDB/TVMaze) по названиям,
|
||||
сбор кандидатов, подтверждение единичного сильного матча → `provider`/
|
||||
`provider_id`/каноническое имя/год, URL кандидата.
|
||||
- `review`: процесс ревью после распознавания и матча — петля «догадка → подсказка
|
||||
→ перераспознавание», команды (Применить/Уточнить/Распознать заново/Тип/Игнор/
|
||||
Позже/Отклонить/Undo/Привязать заново), подсказка vs override, единый список
|
||||
источников совпадения, ручное добавление источника, предпросмотр (превью=
|
||||
применение), разделение труда транспортов.
|
||||
- `file-layout`: целевые имена фильмов/сериалов, сопоставление источник→цель,
|
||||
хардлинки, санитизация пути и запрет выхода за библиотеку, never-overwrite,
|
||||
copy-fallback. Владение путём (`superseded`) и безопасный undo (`nlink<=1`)
|
||||
остаются в `state-reconciliation` (не дублируем — см. design.md).
|
||||
- `download-tracking`: поллинг qBittorrent и машина состояний загрузки —
|
||||
`downloading`/`completed`/`stuck`/`failed`, завершение (moving/checking),
|
||||
таймауты (`magnet_timeout`/`stuck_after`), усыновление по категории/тегу.
|
||||
- `notifications`: пинги автору загрузки — падения (`failed`/`stuck`, включая
|
||||
приёмный `qbit_add` мимо поллинга) с дебаунсом, вход в review и готовность,
|
||||
рассинхрон.
|
||||
|
||||
### Modified Capabilities
|
||||
- `recognition`: убираем требования по метабазам (уезжают в `metadata-match`);
|
||||
добавляем перенесённый из `docs/specs/recognition.md` разбор сигналов LLM
|
||||
(пред-парс, схема плана, провайдер LLM, модель уверенности).
|
||||
- `ingest`: принимает перенесённые из `identity` приёмные требования (множество
|
||||
инфохэшей, дедуп по любому хешу, атомарный возврат в активное состояние).
|
||||
- `identity`: убираем приёмные требования — остаётся инфраструктура id (ULID,
|
||||
нормализация/валидация, корреляция в логах, миграция).
|
||||
- `web-ui`: убираем ревью-специфику (уезжает в `review`) — остаётся оформление.
|
||||
- `state-reconciliation`: убираем «Уведомление о рассинхроне» (уезжает в
|
||||
`notifications`).
|
||||
|
||||
## Impact
|
||||
|
||||
- Затрагивает только `openspec/specs/**` и `openspec/changes/**` — **кода нет**.
|
||||
- Источник истины по мигрируемым темам переезжает из `docs/specs/`
|
||||
(`recognition.md`, `review-ux.md`, `jellyfin-layout.md`, `workflow.md`) в
|
||||
`openspec/specs/` (как пилот `ingest`); в исходных файлах ставим пометку о
|
||||
переезде, содержимое не дублируем.
|
||||
- CLAUDE.md и `docs/backlog.md`: снять пункт из беклога, при необходимости
|
||||
поправить перечисление capabilities.
|
||||
- Валидация: `openspec validate --strict` для change перед коммитом; после архива
|
||||
дельты вливаются в `openspec/specs/`.
|
||||
Reference in New Issue
Block a user