mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
@@ -0,0 +1,155 @@
|
||||
# #460 — Детерминированное завершение кадра живого редактора
|
||||
|
||||
Issue: [#460](https://github.com/Matysh/houseplan-card/issues/460)
|
||||
|
||||
## Сценарий
|
||||
|
||||
Администратор дома размещает мебель мышью в редакторе подложки. Браузерные
|
||||
проверки воспроизводят тот же путь: входят в редактор, двигают указатель,
|
||||
сравнивают preview с сохранённой фигурой и убирают указатель с плана.
|
||||
|
||||
## Что человек увидит до и после
|
||||
|
||||
До исправления preview мебели после ухода указателя изредка остаётся на плане;
|
||||
после исправления он всегда исчезает, а внешний вид и результат обычного
|
||||
размещения мебели не меняются.
|
||||
|
||||
## Проблема
|
||||
|
||||
После #451 pointer-owned состояние редактора может отрисовываться отдельным RAF
|
||||
вне цикла Lit. `updateComplete` больше не доказывает, что этот кадр уже применён,
|
||||
а локальная эвристика из двух RAF в browser smoke иногда снимает старую
|
||||
физическую толщину preview. На чистом `dev` мебельный smoke упал 7 раз из 12.
|
||||
|
||||
Диагностика выявила ещё две части одного сценария:
|
||||
|
||||
- программный smoke мог начать жесты после завершения mode transition, но до
|
||||
завершения вызванного им refit viewport, поэтому сравнивал разные камеры;
|
||||
- terminal `null` для hover-состояния шёл через облегчённый live-маршрут. Если
|
||||
полный Lit-кадр до этого успел нарисовать preview в основном слое, очистка
|
||||
live-слоя оставляла этот settled preview видимым.
|
||||
|
||||
## Скоуп
|
||||
|
||||
- Внутренняя awaitable-точка завершения последнего уже запрошенного кадра
|
||||
`live-editor`.
|
||||
- Корректное завершение ожиданий при coalescing, полном Lit commit и dispose.
|
||||
- Полный Lit commit для terminal-null hover-состояния.
|
||||
- Переход трёх затронутых browser smoke с фиксированных RAF на внутренний
|
||||
контракт; мебельный smoke начинает жесты только после наблюдаемого завершения
|
||||
mode transition и refit viewport.
|
||||
- Детерминированные unit-, browser- и mutation-доказательства.
|
||||
|
||||
## Не-скоуп
|
||||
|
||||
- Изменение геометрии, магнита, размеров, толщины или opacity мебели.
|
||||
- Новый публичный API карточки либо Home Assistant.
|
||||
- Переписывание `live-viewport`, mode transition или общей архитектуры #451.
|
||||
- Новое поведение touch/pen, View или kiosk.
|
||||
- Изменение формата конфигурации, сохранённых данных или истории Undo/Redo.
|
||||
|
||||
## Контракт поведения
|
||||
|
||||
1. Вызов внутренней точки синхронизации сначала дожидается уже ожидавшегося
|
||||
полного Lit-кадра, затем фиксирует последнюю запрошенную ревизию live-editor.
|
||||
2. Promise этой ревизии не завершается раньше фактической покраски DOM.
|
||||
Несколько изменений до одного RAF объединяются, но ожидание покрывает всю
|
||||
объединённую ревизию.
|
||||
3. Если полный Lit commit заменил промежуточный live-кадр, этот commit считается
|
||||
корректным завершением. Dispose отменяет RAF и завершает все ожидания.
|
||||
4. Присвоение `null` свойствам hover-preview не маршрутизируется только в
|
||||
live-слой: полный Lit commit обязан убрать и live-, и settled-копию.
|
||||
5. Browser smoke не определяет готовность через `setTimeout`, sleep либо
|
||||
фиксированное число RAF. Отдельная подготовка мебельного сценария ждёт
|
||||
фактическое состояние mode/refit; RAF используется только как цикл доставки
|
||||
браузерного состояния с проверяемым условием выхода.
|
||||
|
||||
## UX
|
||||
|
||||
Новых контролов и текстов нет. Предпросмотр остаётся тем же полупрозрачным
|
||||
символом и очищается по уже документированным границам из `docs/FURNITURE.md`:
|
||||
pointer leave, Escape, смена палитры, инструмента, редактора, пространства и
|
||||
remount.
|
||||
|
||||
## Модель данных и миграция
|
||||
|
||||
Модель данных не меняется. Ревизии и ожидающие callbacks существуют только в
|
||||
памяти экземпляра live-editor и уничтожаются вместе с ним. Миграция не нужна.
|
||||
|
||||
## i18n
|
||||
|
||||
Новых строк интерфейса нет. Словари не меняются.
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
### AC1 — явная синхронизация
|
||||
|
||||
Управляемый unit-тест доказывает, что Promise не завершается до live paint,
|
||||
покрывает coalesced-изменения и не зависает после полного commit или dispose.
|
||||
|
||||
### AC2 — очистка terminal hover
|
||||
|
||||
Unit-тест доказывает, что terminal-null hover требует полного Lit commit, а
|
||||
`demo/smoke_furniture.mjs` после `pointerleave` не находит preview ни в live-,
|
||||
ни в settled-слое.
|
||||
|
||||
### AC3 — browser-путь без временной лотереи
|
||||
|
||||
`smoke_furniture.mjs`, `smoke_decor.mjs` и `smoke_decor_text.mjs` используют
|
||||
внутренний awaitable-контракт вместо локального двойного RAF. Мебельный smoke
|
||||
проходит не менее 10 последовательных запусков без падений; mode/refit завершён
|
||||
до первого программного жеста.
|
||||
|
||||
### AC4 — mutation-защита
|
||||
|
||||
Мутант, который разрешает Promise до live paint, и мутант, возвращающий
|
||||
мебельному smoke двойной RAF вместо контракта, детерминированно ловятся своими
|
||||
гейтами.
|
||||
|
||||
## План автотестов
|
||||
|
||||
- `test/live-editor.test.mjs`: fake RAF, coalescing, terminal-null, commit и
|
||||
dispose; статический контракт трёх smoke.
|
||||
- `demo/smoke_furniture.mjs`: preview/commit, pointer leave и минимум 10
|
||||
последовательных полных запусков.
|
||||
- `demo/smoke_decor.mjs`, `demo/smoke_decor_text.mjs`: по одному полному
|
||||
целевому запуску после замены ожидания.
|
||||
- `scripts/mutation-gate.mjs`: два адресных мутанта из AC4.
|
||||
- Обычные `typecheck`, unit, build, bundle sync/budget, `no-new-any` и
|
||||
`check-docs` перед код-ревью.
|
||||
|
||||
## Риски
|
||||
|
||||
- Потерянная ревизия могла бы завершить Promise слишком рано либо оставить его
|
||||
навсегда ожидающим; fake-RAF тест отдельно проверяет обе стороны.
|
||||
- Полный commit и dispose могут отменить RAF, поэтому они обязаны завершать ту
|
||||
же ревизию, а не просто очищать callback браузера.
|
||||
- Подготовка smoke не должна превращаться в ещё одну временную эвристику:
|
||||
условие выхода связано с mode/refit state, а не с числом кадров.
|
||||
- Terminal-null переводится в более дорогой полный render только на границе
|
||||
hover-сессии, не на каждом pointermove; горячий путь #451 сохраняется.
|
||||
|
||||
## Откат
|
||||
|
||||
Один revert возвращает прежнюю маршрутизацию и smoke-ожидания. Конфигурация и
|
||||
пользовательские данные не требуют обратного преобразования.
|
||||
|
||||
## Release-артефакты
|
||||
|
||||
- Одновременные записи в `docs/CHANGELOG.md` и `docs/CHANGELOG.ru.md`.
|
||||
- `docs/FURNITURE.md` уже содержит правильный пользовательский контракт очистки
|
||||
preview и не требует изменения.
|
||||
- Стабильный screenshot/golden не меняется: исправляется transient-состояние,
|
||||
которого после завершения жеста не должно существовать.
|
||||
- Любое изменение `src/**` требует актуального Linux-артефакта `Docs
|
||||
screenshots` и приёмки его fingerprint по общему процессу.
|
||||
|
||||
## Принятые технические предположения — можно менять на ревью
|
||||
|
||||
- Контракт остаётся методом lazy editor runtime и не становится API карточки.
|
||||
- Монотонная ревизия и список ожидающих Promise принадлежат `live-editor`, где
|
||||
создаётся и завершается RAF.
|
||||
- Синхронизация mode/refit остаётся частью setup мебельного smoke; отдельный
|
||||
публичный settlement API для viewport в этой задаче не вводится.
|
||||
- Изменение считается пользовательски видимым из-за исправления stale preview,
|
||||
поэтому коммит получает `User-Visible: yes`.
|
||||
@@ -180,6 +180,7 @@ GitHub Issues и GitHub Projects (v2) остаются единственным
|
||||
| [#451](https://github.com/Matysh/houseplan-card/issues/451) Фильтрация render и лёгкий live-слой взаимодействий | [451-render-performance.md](451-render-performance.md) |
|
||||
| [#456](https://github.com/Matysh/houseplan-card/issues/456) Копирование пространства без комнат и устройств | [456-copy-space.md](456-copy-space.md) |
|
||||
| [#457](https://github.com/Matysh/houseplan-card/issues/457) Направление Zigbee-связей к координатору | [457-zigbee-route-arrows.md](457-zigbee-route-arrows.md) |
|
||||
| [#460](https://github.com/Matysh/houseplan-card/issues/460) Детерминированное завершение кадра живого редактора | [460-live-editor-settlement.md](460-live-editor-settlement.md) |
|
||||
|
||||
## P3
|
||||
|
||||
|
||||
Reference in New Issue
Block a user