Ревью: единый блок выбора источника, клик = выбор (review-unified-source-block)
Три секции экрана ревью (Догадка/Источник/Раскладка) слиты в один блок: список вариантов (радио) → инфо о выбранном → предпросмотр раскладки. Клик по варианту сразу выбирает и сохраняет источник и обновляет инфо+раскладку частичным htmx-свопом блока, без полной перезагрузки и без кнопки «выбрать». - httpapi: reviewBlockAction (htmx-aware, детект HX-Request) для candidate/nobase/source; вынос buildReviewView; поля SeasonSummary и BlockError; сводка сезонов (seasonSummary/seasonRanges) - тип movie↔series убран из UI (read-only); удалён веб-роут /type и handleSetType, метод SetType из интерфейса httpapi (worker/Telegram не тронуты) - шаблон: партиал review_source_block, ссылка «запись ↗» вне кликабельного label, фокус радио с клавиатуры; чистка мёртвого sourceView.Files/IsSeries - тесты: htmx-своп выбора, htmx-путь ошибки, юнит-тесты сводки сезонов - openspec: спеки review/web-ui синхронизированы, change заархивирован - беклог: сложные сериальные раздачи; oob-обновление панели действий Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,8 @@
|
||||
## Purpose
|
||||
Ревью раскладки человеком после распознавания и матча: петля «догадка →
|
||||
подсказка → перераспознавание», команды (Применить/Уточнить/Распознать заново/
|
||||
Тип/Игнор/Позже/Отклонить/Undo/Привязать заново), мягкие подсказки vs жёсткие
|
||||
Игнор/Позже/Отклонить/Undo/Привязать заново; тип — read-only, корректируется
|
||||
через «Уточнить»), мягкие подсказки vs жёсткие
|
||||
`override`, единый список источников совпадения с ручным добавлением и
|
||||
предпросмотром (превью = применение), разделение труда транспортов (веб —
|
||||
точные правки, Telegram — быстрые действия и эскалация в веб).
|
||||
@@ -28,13 +29,16 @@ LLM; нет матча в базе или несколько кандидато
|
||||
|
||||
Экран ревью SHALL предоставлять команды: **Применить** (создать хардлинки по
|
||||
эффективному плану), **Уточнить** (добавить подсказку → перераспознать),
|
||||
**Распознать заново** (повторный прогон без новой подсказки), **Тип** (переключить
|
||||
movie↔series), **Игнор файла**, **Позже** (`deferred`), **Отклонить**
|
||||
(`cancelled`), **Undo** (снять созданные ссылки → `reverted`) и **Привязать
|
||||
заново** (из `reverted`/`cancelled`/`target_missing` → перераспознавание с ручным
|
||||
подтверждением). Команды из любого транспорта SHALL сериализоваться worker'ом под
|
||||
единой блокировкой; применяется последняя валидная команда. Команды,
|
||||
которым нужен источник, SHALL проверять его наличие синхронно перед действием.
|
||||
**Распознать заново** (повторный прогон без новой подсказки), **Игнор файла**,
|
||||
**Позже** (`deferred`), **Отклонить** (`cancelled`), **Undo** (снять созданные
|
||||
ссылки → `reverted`) и **Привязать заново** (из
|
||||
`reverted`/`cancelled`/`target_missing` → перераспознавание с ручным
|
||||
подтверждением). Экран ревью MUST NOT содержать команду переключения типа
|
||||
movie↔series: тип показывается read-only, а его корректировка выполняется
|
||||
мягкой подсказкой через **Уточнить**. Команды из любого транспорта SHALL
|
||||
сериализоваться worker'ом под единой блокировкой; применяется последняя валидная
|
||||
команда. Команды, которым нужен источник, SHALL проверять его наличие синхронно
|
||||
перед действием.
|
||||
|
||||
#### Scenario: Применение создаёт раскладку
|
||||
|
||||
@@ -49,6 +53,13 @@ movie↔series), **Игнор файла**, **Позже** (`deferred`), **От
|
||||
- **THEN** задача уходит в `cancelled`, а затем снова на распознавание с ручным
|
||||
подтверждением (авто-раскладка не делается)
|
||||
|
||||
#### Scenario: Тип не переключается кнопкой
|
||||
|
||||
- **GIVEN** загрузка в `review` с распознанным типом
|
||||
- **WHEN** пользователь открывает экран ревью
|
||||
- **THEN** отдельной команды/кнопки переключения movie↔series на экране нет
|
||||
- **AND** тип показан read-only в инфо-части выбранного источника
|
||||
|
||||
### Requirement: Подсказка мягкая, override жёсткий
|
||||
|
||||
Подсказка (`hint`) SHALL быть мягким сигналом — её интерпретирует LLM при
|
||||
@@ -69,11 +80,15 @@ movie↔series), **Игнор файла**, **Позже** (`deferred`), **От
|
||||
списком**, в котором распознавание нейронкой (без базы) — такая же строка,
|
||||
как кандидаты метабаз (TMDB/TVDB/TVMaze), а не отдельный режим сверху.
|
||||
Ровно один источник в списке SHALL быть отмечен активным (эффективный
|
||||
матч). Экран SHALL позволять как операции над этим списком: выбрать
|
||||
кандидата базы, переключиться на другого кандидата и снять матч с базой
|
||||
обратно на нейронку («без базы»). Смена активного источника SHALL
|
||||
выполняться через раундтрип на сервер (форма/htmx), без клиентского
|
||||
пересчёта доменного состояния. Список источников SHALL показываться только
|
||||
матч). Активный источник SHALL выбираться **одним кликом/тапом по строке
|
||||
варианта** (радиокнопка), без отдельной кнопки подтверждения выбора. Выбор
|
||||
источника SHALL сохранять его как эффективный матч (persist) и SHALL
|
||||
выполняться через раундтрип на сервер (форма/htmx), без клиентского пересчёта
|
||||
доменного состояния; при этом инфо-часть и предпросмотр раскладки SHALL
|
||||
немедленно обновляться под выбранный источник (частичный своп блока, без полной
|
||||
перезагрузки страницы). Экран SHALL позволять операции над этим списком:
|
||||
выбрать кандидата базы, переключиться на другого кандидата и снять матч с базы
|
||||
обратно на нейронку («без базы»). Список источников SHALL показываться только
|
||||
при наличии плана распознавания.
|
||||
|
||||
#### Scenario: Нейронка — строка в общем списке
|
||||
@@ -85,16 +100,19 @@ movie↔series), **Игнор файла**, **Позже** (`deferred`), **От
|
||||
нейронкой» стоит наравне с кандидатами баз
|
||||
- **AND** активным отмечен ровно один источник (текущий эффективный матч)
|
||||
|
||||
#### Scenario: Переключение между кандидатами
|
||||
#### Scenario: Выбор кандидата одним кликом
|
||||
|
||||
- **GIVEN** на экране ревью выбран один кандидат метабазы
|
||||
- **WHEN** пользователь выбирает другого кандидата из списка
|
||||
- **THEN** активным становится выбранный кандидат, прочие — неактивны
|
||||
- **WHEN** пользователь кликает/тапает строку другого кандидата
|
||||
- **THEN** выбранный кандидат сохраняется активным, прочие — неактивны, без
|
||||
отдельного нажатия кнопки «выбрать»
|
||||
- **AND** инфо-часть и предпросмотр раскладки сразу обновляются под выбранного
|
||||
кандидата без полной перезагрузки страницы
|
||||
|
||||
#### Scenario: Снятие матча в пользу нейронки
|
||||
|
||||
- **GIVEN** на экране ревью активен кандидат метабазы с названием «Fargo»
|
||||
- **WHEN** пользователь выбирает строку «распознано нейронкой»
|
||||
- **WHEN** пользователь кликает строку «распознано нейронкой»
|
||||
- **THEN** матч с базой снимается (источник — нейронка, «без базы»), тег
|
||||
папки провайдера не проставляется
|
||||
- **AND** поля источника — из распознавания нейронкой, без унаследованных
|
||||
@@ -132,30 +150,41 @@ movie↔series), **Игнор файла**, **Позже** (`deferred`), **От
|
||||
- **THEN** экран показывает сообщение об ошибке и не меняет текущий активный
|
||||
источник
|
||||
|
||||
### Requirement: Предпросмотр полей источника до фиксации выбора
|
||||
### Requirement: Инфо и предпросмотр выбранного источника
|
||||
|
||||
Экран ревью SHALL показывать для рассматриваемого источника (нейронка,
|
||||
кандидат базы или добавленный вручную) **поля** результата — тип, название,
|
||||
год, с зарезервированным местом под режиссёра. Показ полей источника
|
||||
MUST NOT менять сохранённый матч загрузки и MUST NOT создавать хардлинки:
|
||||
сохранённый матч меняется только явным выбором источника, а раскладка —
|
||||
только действием «Применить». Совпадение целевых путей предпросмотра с
|
||||
результатом применения регулируется требованием «Превью раскладки через
|
||||
единую логику именования» (`web-ui`).
|
||||
В едином блоке выбора источника экран ревью SHALL показывать для **выбранного
|
||||
(активного)** источника две части: **инфо** — тип (read-only, movie/series),
|
||||
название, оригинальное название, год, для сериала — сводку сезонов (один сезон,
|
||||
диапазон/список для многосезонного пака или «Спецвыпуски»), с
|
||||
зарезервированным местом под режиссёра; и **предпросмотр раскладки** — целевые
|
||||
пути хардлинков этого источника. Обе части SHALL относиться именно к активному
|
||||
источнику и SHALL обновляться при смене выбора. Отрисовка блока (показ инфо и
|
||||
предпросмотра) MUST NOT создавать хардлинки: раскладка создаётся только явным
|
||||
действием «Применить». Совпадение целевых путей предпросмотра с результатом
|
||||
применения регулируется требованием «Превью раскладки через единую логику
|
||||
именования» (`web-ui`).
|
||||
|
||||
#### Scenario: Предпросмотр полей без фиксации выбора
|
||||
#### Scenario: Инфо и предпросмотр относятся к активному источнику
|
||||
|
||||
- **GIVEN** список источников на экране ревью
|
||||
- **WHEN** пользователь рассматривает источник, ещё не выбрав его активным
|
||||
- **THEN** показаны поля результата (тип, название, год) для этого источника
|
||||
- **AND** сохранённый матч загрузки не меняется, хардлинки не создаются
|
||||
- **GIVEN** в списке активен кандидат метабазы
|
||||
- **WHEN** пользователь смотрит инфо-часть и предпросмотр раскладки
|
||||
- **THEN** показаны тип, название, ориг. название, год (и сводка сезонов для
|
||||
сериала) именно этого источника и предпросмотр его целевых путей
|
||||
|
||||
#### Scenario: Просмотр блока не создаёт раскладку
|
||||
|
||||
- **GIVEN** экран ревью с показанным блоком выбора источника
|
||||
- **WHEN** пользователь только просматривает инфо и предпросмотр, не нажимая
|
||||
«Применить»
|
||||
- **THEN** хардлинки не создаются, файлы под `paths.movies`/`series` не
|
||||
меняются
|
||||
|
||||
#### Scenario: Зарезервированное место под режиссёра
|
||||
|
||||
- **GIVEN** режиссёр из метабазы пока не загружается
|
||||
- **WHEN** отображается предпросмотр полей источника
|
||||
- **THEN** в предпросмотре присутствует место под режиссёра, показанное
|
||||
пустым (или прочерком), не ломая вёрстку
|
||||
- **WHEN** отображается инфо-часть выбранного источника
|
||||
- **THEN** в ней присутствует место под режиссёра, показанное пустым (или
|
||||
прочерком), не ломая вёрстку
|
||||
|
||||
### Requirement: Разделение труда транспортов в ревью
|
||||
|
||||
|
||||
Reference in New Issue
Block a user