review: убрать явный переключатель типа movie↔series из всех транспортов

Кнопка «Тип» была только в Telegram (доменная SetType = жёсткий override
media_type + хинт + перераспознавание), в вебе её нет. Это создавало
расхождение поверхностей и внутреннюю противоречивость спеки review.
Решение: смена типа — редкий случай, для него достаточно «Уточнить»
(перераспознавание с явным указанием типа). Явный переключатель не нужен
ни на одной поверхности.

Снято: Telegram-кнопка и callback type:, worker.SetType, ставший мёртвым
override-плумбинг media_type (ovrMediaType, ветка applyOverrides, хелпер
oppositeType) и стейл-хвосты в тестах httpapi. Спека review — три MODIFIED
требования (запрет на все поверхности, «фиксация типа» убрана из команд и
из быстрых действий Telegram, иллюстрация override заменена на закрепление
источника). Синхронизирован docs/specs/review-ux.md.

Change заархивирован: openspec/changes/archive/2026-07-18-review-remove-type-switch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
av
2026-07-18 16:50:43 +03:00
co-authored by Claude Opus 4.8
parent 023fdacda5
commit 1d6f8f3449
13 changed files with 252 additions and 123 deletions
+24 -19
View File
@@ -33,11 +33,12 @@ LLM; нет матча в базе или несколько кандидато
**Позже** (`deferred`), **Отклонить** (`cancelled`), **Undo** (снять созданные
ссылки → `reverted`) и **Привязать заново** (из
`reverted`/`cancelled`/`target_missing` → перераспознавание с ручным
подтверждением). Экран ревью MUST NOT содержать команду переключения типа
movie↔series: тип показывается read-only, а его корректировка выполняется
мягкой подсказкой через **Уточнить**. Команды из любого транспорта SHALL
сериализоваться worker'ом под единой блокировкой; применяется последняя валидная
команда.
подтверждением). Никакая поверхность ревью — ни веб-UI, ни Telegram — MUST NOT
содержать команду переключения типа movie↔series: тип показывается read-only, а
его корректировка выполняется мягкой подсказкой через **Уточнить**
(перераспознавание, где пользователь явно указывает тип). Команды из любого
транспорта SHALL сериализоваться worker'ом под единой блокировкой; применяется
последняя валидная команда.
Команда **Позже** (`Defer`) SHALL парковать задачу в `deferred` из любого
не-терминального состояния, у которого уже есть раздача в qBittorrent, и SHALL
@@ -51,9 +52,9 @@ movie↔series: тип показывается read-only, а его корре
Терминальные состояния Defer SHALL отклонять как и прежде (`ErrConflict`).
Команды, которым нужен источник (**Применить**, **Уточнить**, **Распознать
заново**, **Привязать заново**, а также фиксация типа), SHALL синхронно (без
дебаунса) проверять перед действием, что источник не только присутствует в
qBittorrent, но и **готов к раскладке** — раздача в готовом классе состояния
заново**, **Привязать заново**), SHALL синхронно (без дебаунса) проверять перед
действием, что источник не только присутствует в qBittorrent, но и **готов к
раскладке** — раздача в готовом классе состояния
(`uploading`/`stalledUP`/`pausedUP`/… с учётом различий имён qBit v4/v5),
т.е. файлы докачаны. Если источник ещё качается (любое `downloading`-подобное
или переходное `moving`/`checking` состояние), команда SHALL отказывать с
@@ -78,12 +79,14 @@ qBittorrent, но и **готов к раскладке** — раздача в
- **THEN** задача уходит в `cancelled`, а затем снова на распознавание с ручным
подтверждением (авто-раскладка не делается)
#### Scenario: Тип не переключается кнопкой
#### Scenario: Тип не переключается командой ни в одном транспорте
- **GIVEN** загрузка в `review` с распознанным типом
- **WHEN** пользователь открывает экран ревью
- **THEN** отдельной команды/кнопки переключения movie↔series на экране нет
- **AND** тип показан read-only в инфо-части выбранного источника
- **WHEN** пользователь открывает ревью в вебе или в Telegram
- **THEN** отдельной команды/кнопки переключения movie↔series нет ни на одной
поверхности
- **AND** тип показан read-only; для смены типа пользователь уточняет
распознавание («Уточнить», явно указав тип)
#### Scenario: Позже паркует задачу из ревью
@@ -107,7 +110,7 @@ qBittorrent, но и **готов к раскладке** — раздача в
- **GIVEN** загрузка припаркована в `deferred`, а её раздача в qBittorrent ещё
качается (`downloading`, файлы не докачаны)
- **WHEN** пользователь выбирает «Распознать заново» (или «Уточнить»/«Привязать
заново»/фиксацию типа)
заново»)
- **THEN** команда отклоняется с конфликтом и причиной «торрент ещё качается»
- **AND** загрузка остаётся в `deferred`, хардлинки не создаются, авто-раскладка
не запускается
@@ -129,9 +132,11 @@ qBittorrent, но и **готов к раскладке** — раздача в
#### Scenario: Override переживает перераспознавание
- **GIVEN** пользователь зафиксировал тип `series` как override
- **GIVEN** пользователь закрепил источник (кандидат метабазы) как эффективный
матч
- **WHEN** запускается перераспознавание по новой подсказке
- **THEN** в новом эффективном плане тип остаётся `series`
- **THEN** в новом эффективном плане закреплённые название/год/провайдер
остаются
### Requirement: Единый список источников совпадения на ревью
@@ -331,10 +336,10 @@ SHALL относиться именно к активному источнику
Состояние ревью SHALL быть единым (в SQLite) для всех транспортов. Веб-UI SHALL
быть поверхностью точных правок (маппинг файлов, ручной ввод/выбор источника по
id или URL, «без базы», предпросмотр). Telegram SHALL давать быстрые действия
(одобрить, подсказать, переключить тип, **быстрый выбор источника из готового
списка кандидатов метабазы**, «Позже»/«Отклонить») и эскалацию в веб deep-link'ом
на ту же страницу; точечные правки, не помещающиеся в чат (ручной ввод id/URL,
маппинг файлов), SHALL делаться в вебе.
(одобрить, подсказать, **быстрый выбор источника из готового списка кандидатов
метабазы**, «Позже»/«Отклонить») и эскалацию в веб deep-link'ом на ту же
страницу; точечные правки, не помещающиеся в чат (ручной ввод id/URL, маппинг
файлов), SHALL делаться в вебе.
#### Scenario: Эскалация из Telegram в веб