Files
houseplan-card/docs/reviews/SPEC-REVIEW-592-r2.md
T
2026-09-18 16:15:53 +00:00

156 lines
14 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.
# SPEC-REVIEW-592-r2 — «Вынести четыре диалога настроек из houseplan-editor-runtime.ts в модули (шаг 0 эпика #591)»
Issue: [#592](https://github.com/Matysh/houseplan-card/issues/592)
Этап: spec
Заход: r2 (блокирующих циклов израсходовано 1 из 4 — израсходован жёлтым вердиктом r1; зелёный вердикт цикла не образует, §4)
## Вердикт
**Зелёный.** High: 0. Medium: 0.
## Скоуп разбора — по дельте (§2.10)
Предыдущий раунд (r1) — жёлтый, две находки: M1 (в скоупе) и L1 (снята с записью).
Документ: `docs/reviews/SPEC-REVIEW-592-r1.md`. Материал r1 объявлен его блоком
«Материал раунда»: ветка `dev`, коммит `01fe7350791e`, дерево материала
`0054c6622b79256b64b455ed786b46270fec9208`. SHA живой (это предок текущего
`HEAD` — `01fe7350` виден в истории репозитория), ре-резолвить по якорям не
потребовалось.
Дельта этапа spec — не код, а тело issue #592 (ревизия r2 против r1). По правке
автора в комментарии видно, что изменения локальны: заголовочная строка «Редакция
r2: правки по ревью ТЗ r1», таблица «Мера храповика/Запас» (4→3), формулировка
«трёх строках» вместо «нескольких», список эталонов AC2 (добавлен
`device-ripple-color-popover-mobile-ru`), новый абзац «Почему именно этот список
эталонов (правка по M1)» с таблицей покрытия по диалогам, и список смоков AC1
(добавлены `smoke_gear_tabs`, `smoke_esc_dialogs`, `smoke_dialog_footer_width`).
Остальные разделы ТЗ (Проблема кроме числа, Контракт К1–К5, Скоуп/не-скоуп, AC3–AC7,
Риски, Откат, Release-артефакты, «Принято предположительно») дельту не задевают —
это подтверждают обе реплики автора («обе находки закрыты», список правок
исчерпывающий) и сверка структуры документа r2 с r1: разделы совпадают дословно
за пределами перечисленных мест.
Дельта локальна: новый субъект не появился (та же подсистема — редакторский граф
диалогов), контракт поведения (К1–К5) не менялся, объём правки (несколько строк
и одна таблица) несопоставим с объёмом исходной задачи. Условия «разбор остаётся
полным» (ребейз, смена контракта, новая подсистема, сопоставимый объём) не
выполнены — сокращённый разбор оправдан.
Поскольку код ещё не менялся (шаг не начат, `User-Visible: no`, задача готовит
почву), дешёвые гейты (`typecheck`/`test`/`build`) в этом раунде не гоняю — они
относятся к материалу code-review, а не к телу issue на этапе spec; это не
пропуск, а неприменимость предмета.
## Закрытие раунда r1
| Находка r1 | Чем закрыта | Где это видно |
|---|---|---|
| **M1** (Medium, в скоупе) — AC2 не называет эталон `device-ripple-color-popover-mobile-ru`, хотя он единственный доказывает ветку `display === 'icon_ripple'` в переносимом `_renderMarkerDialog` | Эталон добавлен в список AC2 (выделен жирным в теле issue) | Тело issue, строка AC2: «…**`device-ripple-color-popover-mobile-ru`**…»; проверено независимо: `demo/golden/matrix.mjs:1084` регистрирует сценарий, `demo/golden/harness.mjs:1994-2013` (ветка `dialog === 'device-ripple-color'`) открывает `_openMarkerDialog`, ставит `display: 'icon_ripple'` и раскрывает `hp-color-opacity` с ярлыком `marker.activity_color`; baseline `demo/golden/baselines/device-ripple-color-popover-mobile-ru.png` существует |
| **L1** (Low, снята с записью) — шапка называла запас ядер «4», фактически 3 (`split('\n').length`, не `wc -l`) | Число исправлено на «3» в таблице «Мера храповика/Запас» и в тексте «Проблема» | Тело issue: таблица показывает `Запас: 3 / 3`; текст «Оба ядра стоят в трёх строках от жёсткого потолка»; проверено пересчётом: `src/houseplan-editor-runtime.ts` — 14096 строк по `wc -l`/`awk 'END{print NR}'`, `split('\n').length` даёт 14097 против потолка 14100 в `test/core-file-budget.test.mjs:36` → запас 3; `src/houseplan-card.ts` — 13728 строк, `split.length` = 13729 против потолка 13732 (`:32`) → запас 3 |
Обе находки закрыты фактом текста/кода, а не заявлением автора — проверено
независимо, не только пересказано.
## Что проверено в этом раунде (дельта)
1. **Новый абзац «Почему именно этот список эталонов»** — таблица покрытия по
диалогам (Устройство 7 / Комната 2 / Общие настройки 3 / Пространство 1)
пересчитана и совпадает с фактическим списком AC2: 3 `device-dialog-*` + 1
`device-help-popover-*` + 1 `device-ripple-color-*` + 2 `toggle-entity-dialog-*`
= 7 для устройства; 2 `room-temperature-dialog-*` для комнаты; `general-color-*`
+ 2 `settings-help-zoom-200-*` = 3 для общих настроек; 1
`space-room-color-popover-desktop-ru` для пространства. Итого 13 эталонов в
AC2 (12 из r1 + добавленный ripple) — сходится с телом issue.
2. **Три новых смока в AC1**, заявленные как компенсация единственного golden-кадра
пространства. Проверено чтением каждого файла:
- `demo/smoke_gear_tabs.mjs` — открывает `_spaceDialog` (строки 23-49),
проверяет режим `create` (`_spaceDialog.mode === 'create'`) — реально
задействует диалог пространства;
- `demo/smoke_esc_dialogs.mjs:67-68` — вызывает
`c._openSpaceDialog('edit', c._space)` и проверяет закрытие по Esc;
- `demo/smoke_dialog_footer_width.mjs` — вызывает `_openSpaceDialog('edit', …)`
дважды (desktop и narrow), измеряет `buttons`, `oneRow`,
`noHorizontalOverflow`, `insideViewport` (строки 87, 139, 201-217) — реально
проверяет структуру диалога пространства (число кнопок, отсутствие
переполнения), а не просто факт открытия.
Все три файла существуют, все три действительно открывают/используют
`_spaceDialog`/`_openSpaceDialog`, заявление автора подтверждено чтением
кода, а не принято на слово. Важная оговорка (не находка, а точность
формулировки): эти три смока — функциональные/структурные проверки
(число кнопок, переполнение, режим), не побайтовые сравнения кадра. Автор
сам явно не относит их к AC2 (побайтовое совпадение), а держит в AC1 —
формулировка в issue корректна и не выдаёт смок за замену golden-сравнения.
## Унаследовано из r1
Без повторной проверки в этом раунде, со ссылкой на `docs/reviews/SPEC-REVIEW-592-r1.md`
(материал: ветка `dev`, коммит `01fe7350791e`, дерево `0054c6622b79256b64b455ed786b46270fec9208`):
- Границы всех четырёх методов (`_renderMarkerDialog` 12884–13610,
`_renderSpaceDialog` 13611–13907, `_renderSettingsDialog` 10337–10502,
`_renderRoomDialog` 13984–14097) — дельта их не меняет, номера строк в теле
issue r2 идентичны r1.
- Прецедент `radar-section.ts`/`vacuum-maps-section.ts` (форма экспорта, отсутствие
`@state()`, кто импортирует) — К2 в r2 не менялся.
- Число мутационных патчей (33) с `file: 'src/houseplan-editor-runtime.ts'` и
направление `relocateEditorPatch` — К5 в r2 не менялся.
- Реальность доказательств AC5 (`bundle:budget`, `bundle-assets.test.mjs` разбирают
фактический вывод сборки) и AC6 (`mutation-gate.test.mjs` — уникальность якоря) —
тексты AC3–AC7 в r2 не менялись.
- Полнота обязательных разделов §7.1, отсутствие незаявленных допущений
(раздел «Принято предположительно» ограничен техническими решениями) —
структура документа вне перечисленных мест дельты идентична r1.
- Продуктовая рамка: задача — шаг 0 эпика #591, видимых изменений нет (К1),
сценарий и «что человек увидит» корректно формулируют нулевой видимый эффект
как факт, а не как отсутствие анализа.
- Trailers: `User-Visible: no` корректно, changelog не требуется — задача не
меняет ничего наблюдаемого пользователем.
## Чего не проверял
- Не повторял построчный аудит всех ≈1300 строк четырёх методов на предмет других
скрытых веток по образцу ripple, кроме уже закрытой M1 — дельта r2 не расширяла
зону риска (не добавляла новых диалоговых веток), только меняла список
эталонов/смоков; повторный полный аудит не относится к предмету раунда.
- Не проходил построчно содержимое `smoke_general_settings.mjs`/
`smoke_room_settings.mjs`/`smoke_color_picker_consumers.mjs`/
`smoke_static_icon.mjs`/`smoke_device_inbox.mjs`/`smoke_room_temperature_thresholds.mjs`/
`smoke_device_preview_parity.mjs` — эти семь смоков дельту не задели, их
разбор унаследован из r1 неявно (r1 их не проверял построчно и сам отметил
это в «Чего не проверял»; предмет этого раунда — не они).
- Не гонял `npx tsc --noEmit`, `npm test`, `npm run build`, `golden:verify`,
`bundle:budget` — этап spec, продуктовый код ещё не менялся под эту задачу;
единственная числовая проверка (`split('\n').length` против потолков
`test/core-file-budget.test.mjs`) сделана вручную пересчётом, сам тестовый
файл не запускался (не нужен: код диалогов ещё на месте, ratchet не может
измениться).
- Не читал повторно эпик #591 целиком — К1 подготовки к нему в r1 уже
подтверждён, дельта эпика не касается.
## Материал раунда
- Issue #592, тело на момент разбора (`gh issue view 592 --json body`),
ревизия r2 (после комментария автора от 2026-09-18T16:11:07Z).
- Заход r2, циклов ревью ТЗ израсходовано 1 из 4 (израсходован жёлтым
вердиктом r1; текущий зелёный вердикт цикла не расходует, §4).
- Предыдущий раунд: `docs/reviews/SPEC-REVIEW-592-r1.md`, материал —
коммит `01fe7350791e`, дерево `0054c6622b79256b64b455ed786b46270fec9208`.
- Код на момент разбора — рабочая копия на `HEAD` = `8ec85ac0f6f62e72f8ac43c95786080e02b3a8bf`
(продуктовый код задачи ещё не менялся; ссылки на строки/потолки относятся к
этому состоянию репозитория).
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `dev`, коммит `8ec85ac0f6f6` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `d7c95364e09b77282237c26d3917fc86f3a025bd`
```
git log --all --format='%H %T' | grep d7c95364e09b
```
- Тело issue: `b105f7b3eb3f70575ee5751d1a917940da949981400e342e9cb133153057f673`
- Вердикт конвейера: `green` · High 0