Files
jellybit/openspec/changes/archive/2026-07-03-refactor-capability-boundaries/proposal.md
T
avandClaude Opus 4.8 512567c8ba Рефакторинг границ 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>
2026-07-03 21:17:51 +03:00

6.9 KiB

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/.