Привёл набор 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>
81 lines
6.9 KiB
Markdown
81 lines
6.9 KiB
Markdown
## 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/`.
|