diff --git a/tasks/BACKLOG.md b/tasks/BACKLOG.md index 964bdce..64b09ed 100644 --- a/tasks/BACKLOG.md +++ b/tasks/BACKLOG.md @@ -29,6 +29,7 @@ - [✨ Заказать спекой крайние случаи именования: многофайловый фильм, редакции, двойная серия](items/naming-edge-cases.md) — стэкинг частей (part1/cd1), редакции [edition-…] и двойная серия SxxEyy-Eyy описаны нарративом, но в file-layout не заказаны — раскладка таких раздач не определена - [🐞 Не сносить раздачу, которой владеет другая активная загрузка](items/delete-checks-active-infohash-owner.md) — удаление старой закрытой задачи уничтожает файлы живой загрузки с тем же инфохэшем; воспроизведено падающим тестом на ревью bulk-delete-page - [🐞 Не оставлять задачу в done, когда ссылки сняты, а раздача не снесена](items/delete-leaves-stale-done.md) — при недоступном qBittorrent задача весь простой соседа показывает done, хотя тайтла в Jellyfin уже нет: сверка падает на первом шаге и до коррекции не доходит +- [🐞 Обновлять страницу загрузки при выходе из «распознаётся»](items/download-page-stale-in-recognizing.md) — на боевом umbar последней версии страница держит бейдж «распознаётся» после того, как задача ушла в review или done — состояние видно только по F5 - [🔬 Канон нумерации серий и порядок у провайдера тега](items/episode-numbering-canon.md) — Косметика/редкость: порядок просмотра ок, но у тайтлов со спорным порядком (Бибоп) Jellyfin подтягивает не те подписи серий, если канон файлов ≠ дефолтный порядок провайдера тега - [🔬 Тексты и формат уведомлений в Telegram](items/telegram-messages-audit.md) — зонтичный проход по всем текстам бота: полнота карточек, единый язык, оформление; порождает под-задачи - [🔬 guessit как сервис-спутник](items/guessit-sidecar.md) — go-ptn слабее питоновского guessit — если точности пред-парса не хватит, завернуть guessit в сервис-спутник рядом с бинарём diff --git a/tasks/items/download-page-stale-in-recognizing.md b/tasks/items/download-page-stale-in-recognizing.md new file mode 100644 index 0000000..ff81b43 --- /dev/null +++ b/tasks/items/download-page-stale-in-recognizing.md @@ -0,0 +1,66 @@ +# 🐞 Обновлять страницу загрузки при выходе из «распознаётся» + +- **Тип:** fix +- **Категория:** Ядро продукта +- **Зачем:** на боевом umbar последней версии страница держит бейдж «распознаётся» после того, как задача ушла в review или done — состояние видно только по F5 + +Спека `web-ui` («Самообновление живой задачи») заказывает: страница наблюдаемой +задачи обновляет себя сама, пока задачу может двигать фон. `recognizing` +наблюдаем (`State.IsObservable`), тик страницы объявлен `every 15s`, и разметка +покрыта тестом `TestDownloadPageSelfPoll` — а на боевом стенде страница +застывает. Расходится не разметка, а поведение живой страницы, и причина +неизвестна: тик либо не уходит, либо уходит и не свопит, либо гасит сам себя. + +Речь только о странице `/download/{id}`. Список загрузок ведёт свой поллер +(карточка опрашивает `/fragments/downloads/{id}/card`) и в эту задачу не входит: +на нём застывания не заявлено и оно не проверялось. + +## Воспроизведение + +1. Открыть `/download/{id}` на боевом umbar, пока задача в `recognizing`. +2. Дождаться, когда фон уведёт её дальше — в `review` или `done`. +3. Смотреть на страницу, не трогая её. + +Видно вместо ожидаемого: бейдж и вся главная область остаются на «распознаётся» +дольше одного тика (15 с) — сколько именно, не замерено. Нажатие F5 показывает +настоящее состояние сразу. Наблюдалось на umbar на последней выложенной версии, +то есть уже с самообновлением из коммита `a5d873b`. + +Замера «через сколько секунд перестало обновляться», журнала сети из браузера и +проверки на локальном запуске нет — первым делом их и надо снять. + +## Затрагивает + +- `web/templates/partials/download_main.html` — объявление тика: + `hx-get="/download/{id}"`, `hx-trigger="every …"`, `hx-select="#download-main"`, + `hx-swap="outerHTML"` и `hx-preserve` на «Опасной зоне»; +- `handleDownload` и `buildDownloadView` (`internal/httpapi/download.go`) — ответ + на тик, ветка `isHTMX` → `fragTickErr` и вычисление `SelfPoll`/`PollEvery`; +- `fragNote` (`internal/httpapi/live.go`) — самозавершающийся фрагмент, который + снимает поллер с поверхности; +- `State.IsObservable` (`internal/store/download.go`) — предикат, на котором + стоит тик; +- спеки `web-ui` («Самообновление живой задачи») и `live-status`; +- боевой рантайм: версия развёрнутого бинаря, раздача статики и заголовки + кэширования страницы `/download/{id}`. + +## Критерии приёмки + +- Причина названа и подтверждена: показано, на каком шаге тик теряется — запрос + не уходит, ответ не свопится или поллер снят (оракул: журнал сети браузера или + лог сервера с боевого стенда, приложенный к задаче). +- Страница, открытая в `recognizing`, показывает новое состояние без F5 не позже + двух тиков после перехода (оракул: ручной прогон на umbar с засечкой времени + перехода по логу сервера и времени смены бейджа). +- Найденная причина закрыта проверкой, которая падала бы до починки (оракул: + тест в `internal/httpapi`; причина не ловится тестом — сказано прямо, чем она + закрыта вместо теста). +- Тик по-прежнему замолкает на ненаблюдаемом состоянии (оракул: существующий + `TestDownloadPageSelfPoll` зелёный). +- `task gate` зелёный (оракул: сам гейт). + +## Рамки + +На SSE не переезжать — это отдельная задача `sse-live-updates`; чинится +существующий htmx-поллинг. Ветку `fragTickErr` не убирать: она стоит там, чтобы +отказ чтения не оставлял вкладку стучать вечно (ADR-2026-08-10-observability-is-not-terminality).