# Наблюдаемость поверхности не выводится из терминальности задачи - **Дата:** 2026-08-10 - **Источник:** openspec/changes/archive/2026-08-10-card-live-refresh/design.md ## Решение Веб-UI обновляет себя, пока задача **наблюдаема** — то есть её состояние ещё может измениться без участия человека, — а не пока она нетерминальна. Предикат `store.State.IsObservable()` живёт в домене рядом с `IsTerminal()` и даёт: все нетерминальные плюс `failed`, `target_missing`, `orphaned`. Замолкают `done`, `cancelled`, `reverted`, `deleted`. ## Почему Очевидный предикат — «обновляемся, пока задача не терминальна» — оказался неверным, и это выяснилось на ревью дизайна, до кода. Цитата из источника: > Терминальность в проекте значит «не активна», а не «навсегда»: фоновая сверка > двигает часть терминальных сама — `ListRecoverable` возвращает в поток > `failed`/`stuck` с кодами `magnet_timeout` и `stalled`, а `desyncStates` > переоценивает `done`, `target_missing` и `orphaned`. Карточка, застывшая по > `IsTerminal`, показывала бы «Ошибка» у задачи, которая уже качается, — ровно > тот дефект, ради которого затеян change. `done` в перечень наблюдаемых не вошёл, и это отдельное решение с ценой: > Переход `done → target_missing`/`orphaned` означает, что файлы удалили руками > мимо сервиса, — событие редкое, а карточек `done` в списке больше всех. > Платить за редкий случай постоянным фоновым запросом на каждую разложенную > задачу дороже, чем показать её новое состояние при следующем заходе. ## Рассмотренные варианты - **Наблюдать только нетерминальные** (как задумывалось изначально) — проще всего и не заводит второго предиката. Отвергнут: задача, оживлённая сверкой из `failed`, висела бы на экране с надписью «Ошибка» до перезагрузки, причём соседние карточки при этом обновлялись бы — застывшая читалась бы как достоверная. - **Наблюдать всё, терминальные — редким тиком** — снимает вопрос целиком. Отвергнут: список из сотни разложенных задач слал бы пустые запросы вечно, а критерий приёмки «завершённая карточка себя не опрашивает» пришлось бы отменить. ## Последствия - `+` смена состояния становится видимой независимо от того, кто её сделал: воркер, веб-UI, Telegram или фоновая сверка. - `+` условие обновления выражено одним доменным предикатом; второго перечня состояний в транспорте нет, и завести его нельзя не заметив. - `−` в домене стало два перечня состояний вместо одного, и второй выведен из поведения воркера (`desyncStates`, `ListRecoverable`) вручную. Расширение сверки новым состоянием молча вернёт застывшую карточку — связки, которая бы это ловила, нет. - `−` карточка `failed`, `target_missing` или `orphaned` опрашивает сервер, пока открыта вкладка: эти состояния живут долго и копятся (срока хранения нет).