Files
2026-10-01 17:53:24 +00:00

18 KiB
Raw Permalink Blame History

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 — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 2b4c828038177a9231a8b041da0dad7c60c54f9f
    git log --all --format='%H %T' | grep 2b4c82803817
    
  • Тело issue: 43855b946e06e4cbd56d6890ba92b55ab76f4f3334fd8c10ac7b271d90344cee
  • Вердикт конвейера: green · High 0 · маршрут fix