Files
houseplan-card/docs/reviews/CODE-REVIEW-464-r2.md
T
claude[bot] afba49a3fa
Проверка (CI) / Классификация изменённых файлов (push) Successful in 29s
Проверка (CI) / Предполётные проверки: документация, провенанс, процесс (push) Failing after 1m9s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 42s
Проверка (CI) / HACS: валидация репозитория (push) Failing after 26s
Проверка (CI) / Hassfest: манифест интеграции (push) Failing after 31s
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Failing after 8m56s
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Failing after 11m56s
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Skipped
Проверка (CI) / Смоки: все шарды зелёные (push) Skipped
Проверка (CI) / Golden-кадры против принятых эталонов (push) Skipped
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Skipped
docs: review document for #464
Issue: #464
User-Visible: no
2026-09-05 22:44:26 +00:00

154 lines
16 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.
# CODE-REVIEW-464-r2
- **Issue:** https://github.com/Matysh/houseplan-card/issues/464
- **Ветка:** `issue/464-zigbee-topology-layer`
- **Материал:** `git diff origin/dev...HEAD` на SHA `87cab133ac345c2283050bbea27ce73534393794`
(= текущий `HEAD` детач-чекаута ревьюера, совпадение проверено `git rev-parse HEAD`)
- **Трек:** полный (не менялся с r1)
- **Заход:** r2 · блокирующих циклов израсходовано 1 из 4 (потрачен в r1, жёлтым;
зелёный вердикт этого раунда цикл не тратит — §4)
## Скоуп раунда
Разбор **по дельте** (PROCESS.md §2.9): предыдущий раунд (`CODE-REVIEW-464-r1.md`,
жёлтый, SHA `276bf193`) закрыт одной находкой High-1. Дельта этого раунда —
`git diff 276bf193..HEAD`, 2 коммита (`0f7b0dff` продукт+тесты+доки,
`87cab133` только `docs/images/screenshots.json`), локальна: правит один CSS-селектор,
расширяет один smoke и добавляет один mutation-gate мутант под уже найденный
дефект. Ребейза на ушедший вперёд `dev` не было, новая подсистема не задета,
контракт поведения не сменился (AC1 из ТЗ не переписан, только доказан) — полный
разбор не требуется, разбираю дельту плюс всё, до чего она дотягивается.
Файлы дельты (без `dist/**` и `custom_components/houseplan/frontend/**`,
класс D — сверены пересборкой, см. гейты):
- `src/styles/devices.styles.ts` — продуктовый фикс (класс A)
- `demo/smoke_zigbee_topology_hover.mjs`, `scripts/mutation-gate.mjs` — тесты (класс B)
- `docs/specs/464-zigbee-topology-layer-order.md`, `docs/TESTING.md`,
`docs/CHANGELOG.md`, `docs/CHANGELOG.ru.md`, `docs/images/screenshots.json` —
документация (класс C)
## Закрытие раунда r1
| Находка | Чем закрыта | Где это видно |
|---|---|---|
| **High-1**: реальный курсор мыши над hovered-source endpoint матчит старое правило `:host([data-pointer-hover]) .dev:hover { z-index: 5 }` (специфичность `(0,4,0)`) сильнее нового `.dev[data-hp-zigbee-topology-endpoint] { z-index: 8 }` (специфичность `(0,2,0)`); оверлей стоит на `z-index: 7` → `5 < 7`, линия рисуется поверх маркера-источника | Добавлено правило той же специфичности что и конфликтующее плюс атрибут endpoint плюс `:hover` — `(0,5,0)`, что строго выше `(0,4,0)` и решает каскад в пользу endpoint независимо от порядка объявления | `src/styles/devices.styles.ts:345` — `:host([data-pointer-hover]) .dev[data-hp-zigbee-topology-endpoint]:hover { z-index: 8; }`. Доказано исполнением: smoke добавил блок с настоящим `page.mouse.move` (не `dispatchEvent`) и `result.realPointerEndpointWins` (`demo/smoke_zigbee_topology_hover.mjs:555-579`); лично прогнан `node demo/smoke_zigbee_topology_hover.mjs` → `OK`, `"realPointerEndpointWins": true`. Тест умеет падать: новый мутант `zigbee-topology-hovered-endpoint-elevation-removed` (`scripts/mutation-gate.mjs:6067-6076`) занижает z-index новой строки до 1; лично прогнан `node scripts/mutation-gate.mjs --id=zigbee-topology-hovered-endpoint-elevation-removed` → «покраснел, как обязан» |
Других находок в r1 не было (Medium: 0).
## Унаследовано из r1
Принято без повторной проверки — делта их не задевает:
- **AC2 (ownership/lifecycle/single-projection)** и **AC3 (casing неизвестного
LQI)** — доказаны чтением и исполнением в `CODE-REVIEW-464-r1.md` на SHA
`276bf193a2bec40a3c2fc823d364cbda00ac10d5`; дельта r2 не трогает
`hp-zigbee-topology-overlay.ts`, `zigbee-topology-overlay-bridge.ts`,
`houseplan-card.ts` — файлы, где эти AC реализованы.
- **Ревью ТЗ** — `SPEC-REVIEW-464-r1.md`, зелёное, SHA спеки `aae9efb9`.
- **Гейты `typecheck`/`test`/`build`/`bundle`/`no-new-any`/`process-gate`/
`benchmark:zigbee-topology` на SHA `276bf193`** — зелёный Validate
(run 33994548645), зафиксировано в `CODE-REVIEW-464-r1.md`.
- **i18n, трейлеры структуры коммитов, cleanup-матрица (pointerleave/touch/
pen/mode/space/setting/disconnect)** — проверены в r1, дельта их не касается.
## Как проверялось в этом раунде
| Гейт | Статус | Как |
|---|---|---|
| `typecheck` / `npm test` / `npm run build` + 3 копии бандла | ✅ зелёный, не перегонял отдельно | Validate на точном SHA `87cab133`: https://github.com/Matysh/houseplan-card/actions/runs/33996034405 (success) — «дешёвые гейты на этом SHA уже подтверждены». Дополнительно лично прогнал `npm run bundle:sync` (`tsc --noEmit && rollup -c` внутри) для собственного воспроизведения — зелёный, `git status` после чист: пересборка байт-в-байт совпала с закоммиченным `dist/**`/`custom_components/houseplan/frontend/**` |
| `node scripts/check-docs.mjs` | ✅ зелёный | Прогнал сам: `Documentation checks passed (7 files, 12 external links)`; diff трогает `src/**`, отпечаток скриншотов обязателен — коммит `87cab133` обновляет только `sourceFingerprint`/`sourceSha256`, все `imageSha256` побайтно не изменились (сверено чтением диффа `docs/images/screenshots.json`) |
| `node demo/smoke_zigbee_topology_hover.mjs` (прямое совпадение `smoke-select.mjs`) | ✅ зелёный | Прогнал сам после `bundle:sync`: `OK`, включая новый `realPointerEndpointWins: true` |
| Мутант `zigbee-topology-hovered-endpoint-elevation-removed` | ✅ красный при повреждении, как обязан | Прогнал сам: `node scripts/mutation-gate.mjs --id=zigbee-topology-hovered-endpoint-elevation-removed` → «поймано 1 из 1» |
| `node scripts/smoke-select.mjs --base origin/dev --head HEAD` | ✅ выполнен | Прямое совпадение: только `smoke_zigbee_topology_hover.mjs` (уже прогнан выше). 29 слабых связей — все по одному распространённому символу `_mode`; дельта не трогает переключение режимов (только CSS-селектор hover/endpoint и тесты/доки) — решил не гонять, риска регрессии не вижу |
| `npm run golden:verify` | не гонял | В `demo/golden/**` нет Zigbee-topology-сценария (проверено чтением `demo/golden/matrix.mjs` и содержимого `demo/golden/`); дельта не расширяет видимый в golden рендер, а обновлённый скриншот-фингерпринт уже подтверждён `check-docs.mjs` и байт-в-байт сверкой `imageSha256` |
| Остальные 6 из 7 старых мутантов задачи + полный `mutation-gate.mjs --check` | не гонял | Не задеты дельтой (файлы мутантов для AC2/AC3 не менялись); наследую зелёный статус r1/хендоффа автора; полный `--check` — предрелизный объём, несоразмерен точечной правке |
| `npm run invariants` | не гонял | Дельта не трогает геометрию комнат/стен, `layout`, `marker.space`, `open_spans` — только экранный z-index topology-оверлея |
| `python -m pytest tests_backend` | не гонял | Диапазон не трогает `custom_components/**/*.py` |
| `npm run benchmark:zigbee-topology`, `bundle:budget`, `no-new-any`, `process-gate --issues` | не гонял | Не задеты дельтой; зелёный статус наследую из Validate на `87cab133` и хендоффа автора r2 (перечислены поимённо в его комментарии) |
## Что проверено и корректно
- **Специфичность CSS разрешает конфликт правильно.** Новое правило
`:host([data-pointer-hover]) .dev[data-hp-zigbee-topology-endpoint]:hover`
весит `(0,5,0)` — строго больше конфликтующего `:host([data-pointer-hover])
.dev:hover` `(0,4,0)` — независимо от порядка объявления в файле. Проверено
и расчётом, и (сильнее) реальным исполнением через `page.mouse.move`.
- **Нет скрытых конфликтов той же природы.** Перепроверил чтением все
`z-index`-правила `devices.styles.ts` (`grep`) — единственная другая
hover-зависимая пара (`.dev:focus-visible { z-index: 5 }`) реагирует на
клавиатурный фокус, а не на реальный курсор; топология активируется только
реальным mouse-hover (зафиксировано ещё в аналитике issue: «touch и kiosk не
меняются, топология доступна только admin + mouse hover»), так что этот путь
не достижим для endpoint-элементов и не относится к AC1.
- **Мутант защищает именно новую строку**, а не дублирует старый: `find`/
`replace` бьёт по селектору с `:hover`, отличному от базового
`zigbee-topology-endpoint-elevation-removed`; `id` уникален
(`grep -c` = 1 по всему файлу).
- **Регрессионный smoke использует настоящий курсор**, а не синтетический
`dispatchEvent` — то же средство, которым сам дефект был найден в r1;
ждёт до 5 c появления `:hover` + атрибута + отрисованной линии перед
сравнением `getComputedStyle(...).zIndex`, что исключает гонку с отрисовкой.
- **Документация и трейлеры.** `CHANGELOG.md`/`CHANGELOG.ru.md` в одном
коммите с `User-Visible: yes` (`0f7b0dff`), формулировка «including the one
under the pointer» / «включая маркер прямо под курсором» точно описывает
зафиксированное поведение и не расширяет сам контракт. `docs/TESTING.md` и
ТЗ `docs/specs/464-...md` получили по абзацу, описывающему именно этот
инвариант (реальный `:hover` vs синтетический `pointerover`) — согласуется
с находкой r1 дословно. `87cab133` несёт `User-Visible: no` — корректно,
видимых кадров это не меняет (imageSha256 не тронут).
- **Инварианты модели вне периметра** — дельта не касается геометрии,
подтверждено чтением диффа: единственный продуктовый файл — CSS-стили.
## Чего не проверял
- Полный `mutation-gate.mjs --check` (весь проект) и оставшиеся 6 старых
мутантов задачи — несоразмерно точечной правке, не задеты дельтой.
- `npm test` целиком и `npm run build` отдельным прогоном юнит-сьюта — положился
на зелёный Validate точного SHA `87cab133`; лично воспроизвёл только
`tsc --noEmit && rollup -c` через `bundle:sync`.
- 29 смоков со слабой связью по символу `_mode` — не гонял, дельта не трогает
переключение режимов; решение зафиксировано в таблице гейтов.
- Реальное touch/pen устройство за пределами эмуляции `pointerType` — тот же
довод, что и в r1: различие смок/реальное устройство здесь не той природы,
что в закрытой находке (`pointerType` — явное поле события, не завязано на
hit-testing браузера, в отличие от `:hover`).
- Визуальный скриншот итоговой сцены — числовой `getComputedStyle(...).zIndex`
уже является единственным источником, управляющим порядком отрисовки;
дополнительный кадр ничего не добавил бы.
## Единый источник числа
Дельта не вводит и не меняет пользователем видимую величину (числовое
значение, дублируемое в двух местах интерфейса) — правится исключительно
порядок отрисовки (`z-index`), самого числа/значения пользователю не
показывается. `test/single-source-numbers.test.mjs` не затрагивается дельтой
(файл не менялся, диапазон не относится к value-badge/подписям).
## Вывод
High-1 из r1 закрыт: причина (специфичность CSS `:hover` выше специфичности
endpoint-правила) устранена добавлением правила ещё большей специфичности,
доказано личным исполнением smoke с настоящим курсором и личным исполнением
нового защитного мутанта, который краснеет при откате правки. Других находок
не внесено. AC2/AC3 наследуются из r1 без повторной проверки — дельта их не
касается. Документация и трейлеры в порядке.
**Вердикт: зелёный · заход r2 · блокирующих циклов 1/4 · High: 0 · Medium: 0**
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/464-zigbee-topology-layer`, коммит `87cab133ac34` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `445cc106c18942021aa8209aeac33ac47f1ccbda`
```
git log --all --format='%H %T' | grep 445cc106c189
```
- ТЗ `docs/specs/464-zigbee-topology-layer-order.md`, блоб `043ada287e048ed9750080c342b2a2fdb869d9f0`
```
git log --all --find-object=043ada287e048ed9750080c342b2a2fdb869d9f0 -- docs/specs/464-zigbee-topology-layer-order.md
```