Files
jellybit/docs/adr/ADR-2026-08-10-observability-is-not-terminality.md
T
av a5d873b62d web-ui: карточка и страница обновляются, пока задачу может двигать фон
- условие самообновления — доменный предикат store.State.IsObservable() вместо
  фазы catched; один поллер на поверхность, интервалы 5 с и 15 с
- отказ тика отвечает 200 и самозавершающимся фрагментом с корневым id цели
  вместо 404/500, который htmx не свопит
- заведён ADR-2026-08-10-observability-is-not-terminality, переписан раздел
  «Живой поллинг» в конвенции веб-UI
2026-08-10 14:02:38 +03:00

57 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Наблюдаемость поверхности не выводится из терминальности задачи
- **Дата:** 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` опрашивает сервер, пока
открыта вкладка: эти состояния живут долго и копятся (срока хранения нет).