18 KiB
SPEC-REVIEW-762-r1
Issue: #762 — «Warm remount и отложенный режим: хвосты после #756»
Этап: spec (PROCESS.md §2.4) · Трек: ask (§5) · Заход: r1 · блокирующих циклов 0/4
Материал: тело issue #762, раздел ## ТЗ, сверено с рабочей копией на
0606a3664a6c819a501316f478840d6c3a5b456c (HEAD; совпадает с актуализацией,
заявленной в самом ТЗ — «Актуализация по dev 0606a366...»; Validate на
этом SHA зелёный). Код продукта в задаче ещё не писался — ревью судит только
текст ТЗ и его соответствие дереву, на которое он ссылается.
Route: fix.
Скоуп
Пять связанных регрессий «тёплого» пересоздания карточки с отложенным правом
записи (хвосты после #756/#95): (1) выход из отложенного редактора теряет
исходный zoom/центр Просмотра; (2) камера дёргается на промежуточных кадрах
отложенного восстановления без открытого диалога; (3) в warm-памятку
попадает смешанная пара hdrH/stageH от разных layout; (4) позднее
_resumePendingNavMode перебивает уже отданную пользователем новую команду
режима; (5) смена пространства не отменяет ожидающее восстановление
редактора старого пространства. Служит J1/J6 docs/SCOPE.md — «план остаётся
верным» и «продолжить ту же работу после технического пересоздания»; новых
UI-элементов, настроек и touch-жестов редакторов нет, View/выбор пространства
на touch — обязательная поверхность и явно покрыты AC5.
Как проверялось
Ревью ТЗ не включает выполнение гейтов — кода нет, этап его не требует.
Проверялись: наличие обязательных разделов §7.1; однозначность и способ
доказательства каждого AC; соответствие канону (docs/WARM-REMOUNT.md,
docs/CANVAS.md, docs/SCOPE.md, docs/USER-GUIDE.ru.md); и, так как и
ТЗ, и аналитический комментарий автора опираются на построчные ссылки на
код, — сверка каждой процитированной причины с реальным деревом на
материальном SHA, а не с заявлением автора.
Построчно сверено чтением (не исполнением) с текущим деревом:
| Утверждение ТЗ/комментария | Файл:строка | Проверено |
|---|---|---|
resumeWarmMode удерживает камеру только при _warmRevivePending, случай без черновика выходит раньше защиты |
src/warm-mode-adoption.ts:55 (фактически строка if (!host._warmRevivePending) return;, код в файле сейчас на строке 58) |
совпадает: ранний return действительно пропускает весь блок удержания _view/refit (строки 59–63), когда диалога нет |
_setMode при входе из Просмотра в редактор перезаписывает _viewModeSnap текущей камерой, а не сохранённым warm-снимком |
src/houseplan-editor-runtime.ts:986 (блок this.host._viewModeSnap = { ... zoom: this.host._zoom ... }) |
совпадает: присваивание читает this.host._zoom/this.host._view на момент вызова _setMode, т.е. временную камеру отложенного Просмотра, если вход идёт через resumeWarmMode → commit() |
Обработчик шапки пишет новую hdrH вместе с stage.clientHeight, снятым до следующего рендера |
src/houseplan-card.ts:4068 (сейчас строка 4080: this._warmPatch({ hdrH: t, stageH: stage.clientHeight })) |
совпадает: stage.clientHeight читается синхронно в том же колбэке, что и новое t, до того как layout успевает осесть под новой высотой шапки |
Новая команда редактора не отменяет _pendingNavMode синхронно |
src/houseplan-card.ts:737 (_requestMode) |
совпадает: по всему файлу _pendingNavMode читается/пишется только в четырёх местах (:3311 установка, :4164–4166 потребление в _resumePendingNavMode, :7368/:7439 disconnect-путь) — _requestMode его не трогает вовсе |
| Смена пространства не очищает pending | src/houseplan-card.ts:1414 (_commitSpace) |
совпадает: _commitSpace не ссылается на _pendingNavMode |
docs/NAV-PERSIST* на dev отсутствует |
— | совпадает: файла нет, упомянутое в исходном (внешнем) репорте название действительно устарело |
demo/smoke_nav_persist.mjs существует и упомянут как часть материала |
demo/smoke_nav_persist.mjs, docs/WARM-REMOUNT.md:6 |
совпадает |
| «View restores the saved same-space centre and zoom on exit» — контракт п. 2 ТЗ не противоречит канону | docs/CANVAS.md:104–113 |
совпадает дословно по смыслу |
| «Явная команда пользователя всегда сильнее ещё не применённой памятки» — контракт п. 5 — уже задокументированный принцип, ТЗ лишь уточняет его для окна загрузки модуля | docs/WARM-REMOUNT.md:148–166 |
совпадает |
Ни одно утверждение о текущем поведении кода не разошлось с деревом; все пять причинно-следственных связей, на которых строится ТЗ, подтверждены чтением, а не только ссылкой автора.
Дополнительно проверено: _canManageConfiguration (houseplan-card.ts:983)
фолбэчится на hass.user.is_admin до ответа сервера — значит окно AC4
«задержанный модуль» действительно достижимо пользователем (вкладки
редактора рендерятся раньше, чем приходит авторитетный can_write), а не
теоретическая гонка, которую невозможно воспроизвести через UI.
Находки
High и Medium нет.
Что проверено и корректно
- Обязательные разделы §7.1 присутствуют все: сценарий (персона «владелец умного дома», десктоп/touch), что человек увидит до/после (одной фразой, без терминов реализации — «план может дёрнуться... после исправления сохраняет прежний вид»), проблема с построчными ссылками, скоуп и не-скоуп (явно перечислено, что НЕ переписывается: lifecycle целиком, загрузчик редакторов, TTL, owner-слоты, геометрия), контракт поведения и UX (пп. 1–8), модель данных/миграция/i18n («нет» явным текстом, обоснованно), критерии приёмки AC1–AC6 с доказательством, план автотестов, риски, откат, release-артефакты.
- Каждый AC однозначен и снабжён конкретным, фальсифицируемым механизмом проверки: AC1 — числовые значения (1.6→3.4) и точка наблюдения (возврат после закрытия редактора); AC2 — rAF-запись каждого кадра перехода, а не только финала, явно запрещены «обязательные три кадра» как false floor; AC3 — наблюдение самой записи в памятку, а не только итоговых размеров; AC4/AC5 — конкурирующие исходы в обоих порядках (сервер раньше/позже модуля); AC6 — именованные существующие смоки, которые обязаны остаться зелёными, плюс проверка конечного состояния вместо поиска строк в исходнике.
- Защитные AC (камера не дёргается, memo не смешивает пару, устаревший resume не побеждает) доказываются по правилам §2.7 уже на стадии ТЗ: для каждого из пяти симптомов назван отдельный красный свидетель на исходном коде, а не общий «потом разберёмся». План автотестов прямо требует писать их независимо друг от друга, чтобы один провал не прятал остальные — это снижает риск, что пройдёт зелёным ТЗ, которое на самом деле чинит только часть симптомов.
- Термины согласованы с каноном:
_view/viewBox/«Просмотр»/«пространство» использованы в точности как вdocs/CANVAS.mdиdocs/USER-GUIDE.ru.md; описание warm-памятки, TTL, одноразового воскрешения диалога и приоритета явной команды не противоречитdocs/WARM-REMOUNT.md, а п. 3 контракта («наличие черновика не влияет на защиту камеры») точно закрывает несостыковку, которую сам канон констатирует словом «камера... возвращается бит-в-бит», а код — нет (см. таблицу сверки выше). - Технических утверждений, не подкреплённых ни кодом, ни каноном и не помеченных как предположение, не найдено — все пять причин проверены чтением и совпали; раздел «принято предположительно» (4 пункта) содержит только действительно нейтральные для пользователя технические решения (структура идентичности pending-запроса, разбиение тестов, отложенное измерение геометрии, тестовые значения zoom) и ни один не маскирует продуктовый вопрос.
- Продуктовых вопросов владельцу в тексте нет, и это обоснованно: все восемь
пунктов контракта либо повторяют уже принятое канон-решение (приоритет
явной команды, «воскрешаем черновик, не воскрешаем решение», one-shot
revive), либо являются прямым следствием того, что пользователь уже увидел
как баг (откат к старой камере, потеря выбора). Отдельно проверена
потенциально спорная граница — что происходит, если пользователь успевает
запросить другой редактор, пока ещё не разрешился
_editorRuntimeвнутри уже идущего resume (а не общийcan_write): это реальное, достижимое через UI окно (см. «Как проверялось», фолбэк_canManageConfigurationнаis_admin), и AC4 его покрывает явно, с обоими порядками разрешения гонки. - Touch покрыт в объёме, обязательном по
docs/TOUCH-SUPPORT.md: View и выбор пространства полностью поддержаны, AC5 отдельно требует проверки tap в touch-viewport; новые touch-жесты редакторов осознанно не добавляются и не требуются (редакторы — desktop-first). - Release-артефакты: issue/ветка названы,
User-Visible: yesобоснован (пользователь видел баг — пропадающий зум/самовольное переключение режима, значит и исправление видимо), оба changelog явно требуются в том же коммите, bundle/VERSION/теги не трогаются, перед S7 требуются ссылки на исходные красные и итоговые зелёные прогоны по каждому AC. - Трек
askобоснован критерием §5: несколько связанных async-путей, контракт камеры и риск 7/10, что выше рамокshow; соответствует уже установленной меткеtrack:askиci:golden(камера — визуальный риск даже без изменения статичного вида, значитci:goldenуместен).
Чего не проверял
- Исполнение гейтов (
tsc,npm test,npm run build, golden, браузерные smoke) — кода ещё нет, этап spec их не требует; «дешёвый» зелёный Validate на материальном SHA относится к существующемуdev, а не к ещё не написанной реализации этой задачи. - Фактическое поведение браузера на заявленных численных порогах (1.6→3.4, «не более 1 CSS px», «минимум 5 кадров») — это спецификация будущего теста, а не код, который можно прочитать и исполнить сегодня; проверено только, что похожий порог (1 CSS px, 48 CSS px и т. п.) — устоявшийся в проекте паттерн измерения (docs/CANVAS.md, docs/WALL-THICKNESS.md, docs/TOUCH-SUPPORT.md), а не произвольное число без основания.
- Состояние соседних задач #756 и #95 как таковых — они не являются
материалом этого ревью; ТЗ ссылается на их контракты корректно (черновик
едет по цепочке, приоритет явной команды), и это подтверждено чтением
docs/WARM-REMOUNT.md, а не повторным ревью тех issue. - Реализуемость предложенных точек изменения (
src/warm-mode-adoption.ts,src/houseplan-card.ts, при необходимостиsrc/houseplan-editor-runtime.ts) — список файлов правдоподобен (именно там найдены все пять причин), но фактический диф появится только на код-ревью.
Вердикт
Зелёный. Документ ТЗ полон по §7.1, все пять причинно-следственных связей проверены чтением и совпадают с деревом на материальном SHA, каждый AC однозначен и снабжён названным способом доказательства и отдельным красным свидетелем, открытых продуктовых вопросов нет, технических утверждений без основания не найдено. High: 0, Medium: 0.
Материал раунда
- Ветка:
dev, коммит0606a3664a6c— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
2b4c828038177a9231a8b041da0dad7c60c54f9fgit log --all --format='%H %T' | grep 2b4c82803817 - Тело issue:
43855b946e06e4cbd56d6890ba92b55ab76f4f3334fd8c10ac7b271d90344cee - Вердикт конвейера:
green· High 0 · маршрутfix