# 🐞 Обновлять страницу загрузки при выходе из «распознаётся» - **Тип:** 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).