docs: review document for #762

Issue: #762
User-Visible: no
This commit is contained in:
claude[bot]
2026-10-01 17:53:24 +00:00
parent 0606a3664a
commit 9f695d8a5d
2 changed files with 175 additions and 1 deletions
+2 -1
View File
@@ -1,12 +1,13 @@
# Индекс ревью
Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 271, issue: 138. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`.
Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 272, issue: 139. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`.
| Issue | Документ | Этап · раунд | Вердикт | H | M | Находки | Файлы |
|---|---|---|---|---:|---:|---|---|
| бета v1.79.0-beta.1 | [SHIP-REVIEW-v1.79.0-beta.1.md](SHIP-REVIEW-v1.79.0-beta.1.md) | пакетное ревью ship · — | ⚪ — | 0 | 0 | — | — |
| #775 | [CODE-REVIEW-775-r1.md](CODE-REVIEW-775-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — |
| #772 | [CODE-REVIEW-772-r1.md](CODE-REVIEW-772-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — |
| #762 | [SPEC-REVIEW-762-r1.md](SPEC-REVIEW-762-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — |
| #761 | [CODE-REVIEW-761-r1.md](CODE-REVIEW-761-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | заявленная «красная» мутация не воспроизводится в этой среде | `scripts/process-metrics.mjs` |
| #757 | [CODE-REVIEW-757-r1.md](CODE-REVIEW-757-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — |
| #756 | [CODE-REVIEW-756-r1.md](CODE-REVIEW-756-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — |
+173
View File
@@ -0,0 +1,173 @@
# 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.
---
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `dev`, коммит `0606a3664a6c` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `2b4c828038177a9231a8b041da0dad7c60c54f9f`
```
git log --all --format='%H %T' | grep 2b4c82803817
```
- Тело issue: `43855b946e06e4cbd56d6890ba92b55ab76f4f3334fd8c10ac7b271d90344cee`
- Вердикт конвейера: `green` · High 0 · маршрут `fix`
<!-- hp:usage input_tokens=4063 output_tokens=35348 cache_creation_input_tokens=110554 cache_read_input_tokens=3296374 num_turns=42 -->