# SPEC-REVIEW-464-r1 - **Issue:** https://github.com/Matysh/houseplan-card/issues/464 - **Этап:** ТЗ (PROCESS.md §2.4), трек — полный - **ТЗ:** `docs/specs/464-zigbee-topology-layer-order.md` на ветке `issue/464-zigbee-topology-layer` - **Заход:** r1 (первый), блокирующих циклов израсходовано 0/4 - **Материал ревью:** ветка `issue/464-zigbee-topology-layer`, HEAD `aae9efb9ff251ef1471cab685dee2c8c785dea5c`, коммит «docs: specify Zigbee topology layer order» (`Issue: #464` · `User-Visible: no`). Диапазон изменений от `origin/dev`: только `docs/specs/464-zigbee-topology-layer-order.md` (новый, 455 строк) и `docs/specs/README.md` (+2/-1). Продуктовый код не тронут — соответствует хендоффу автора и статусу `S4-spec-review`. ## Скоуп ревью Задача переведена аналитикой с `trivial` на полный трек: причина названа явно (изменение публичного контракта слоёв, закреплённого в #54/#457, пересечение full-card compositor/lazy overlay/live-camera projection) — критерий §5 «нет нового UX-контракта» не проходит, и это названо, а не подразумевается. Продуктовых вопросов у владельца по существу два, и оба уже закрыты его же комментарием в issue до написания ТЗ: точный порядок трёх уровней и параметры окантовки серого пунктира (1 px, `#2e2e2e`, просветы сохраняются). ТЗ проверено на точное соответствие этому комментарию. ## Как проверялось 1. Прочитаны `docs/SCOPE.md`, `AGENTS.md`, `PROCESS.md` целиком (включая §2.4, §2.5, §2.10, §5, §7.1, §7.2), тело issue #464 и все пять комментариев (включая уточнение владельца, две редакции аналитики и хендофф автора). 2. Прочитан документ ТЗ целиком, сверен на присутствие всех разделов §7.1. 3. Проверены на согласованность с ТЗ канонические документы подсистемы — `docs/specs/054-zigbee-topology-overlay.md`, `docs/specs/457-zigbee-route-arrows.md`, `docs/ARCHITECTURE.md` (раздел «Contextual Zigbee topology»), `docs/UX-MODES.md`, `docs/USER-GUIDE.ru.md` (раздел про связи Zigbee). 4. Технические утверждения §3 (root cause) сверены построчно с текущим кодом `dev` — не как код-ревью, а чтобы отличить подтверждённый факт от догадки, выданной за решение: - место монтирования: `renderZigbeeTopologyOverlay(...)` вызывается прямо перед `
` в `src/houseplan-card.ts:11827` → `:11839` — подтверждает «overlay — sibling перед `.devlayer`»; - `z-index`: `:host` в `src/hp-zigbee-topology-overlay.ts:45` = `5`, `.devlayer` в `src/styles/plan.styles.ts:1306-1310` = `6` — подтверждает заявленный конфликт уровней; - двойная camera-проекция: `data-hp-live-layer="camera"` сейчас стоит и на host-теге оверлея (`src/zigbee-topology-overlay-bridge.ts:21`), и на `.devlayer` независимо, а `live-viewport.ts:101,155` перебирает оба совпадения `querySelectorAll` — подтверждает мотивацию §7.4 «убрать собственную camera-проекцию у вложенного overlay»; - контракт unknown-LQI сегодня: один `` без обводки (`src/hp-zigbee-topology-overlay.ts:237-238`), плюс глобальное `line { vector-effect: non-scaling-stroke }` (строка 47) — подтверждает, что план «второй совпадающий stroke шире, тот же non-scaling-stroke» технически реализуем без новых свойств; - `docs/specs/054-...md:154-155` действительно фиксирует «над архитектурой/decor, но под device markers» — старый контракт, который #464 заменяет, назван и процитирован верно. 5. Проверена реализуемость заявленного способа доказательства AC, а не только его название: raster-probe через `createImageBitmap`/`OffscreenCanvas`) — уже рабочий паттерн в `demo/smoke_device_icon_pixel_alignment.mjs`, `demo/smoke_active_chain_ink.mjs`, `demo/smoke_grid_scale_invariance.mjs`, `demo/golden/run.mjs`; `npm run benchmark:zigbee-topology` уже существует в `package.json`; `scripts/mutation-gate.mjs` уже содержит мутанты для `zigbee-topology*` (`zigbee-topology-zha-read-starts-scan`, `zigbee-topology-ambiguous-marker-selected` и др.) — расширение тем же инструментом, не изобретение нового. 6. Проверены трейлеры коммита (`Issue: #464`, `User-Visible: no` — корректно для документации без продуктового поведения) и двусторонняя связь issue ↔ ТЗ ↔ `docs/specs/README.md` (запись добавлена, ссылка на файл и issue на месте). 7. Дешёвые гейты не гонялись повторно: диапазон правок — только `docs/specs/**` (класс C), продуктовый код не менялся, `typecheck`/`test`/`build` не могут покраснеть от .md-файла. Указанный в контексте зелёный Validate на этом же SHA (`aae9efb9`) относится к предыдущему код-ревью, а не к этому документу; для спек-ревью он не требуется и не использовался как замена чтения. ## Находки Не найдено ни одной блокирующей (High) находки. Находок Medium/Low в скоупе задачи и вне его — нет. Ниже — что отдельно проверялось на «догадку, выданную за факт», и почему не стало находкой: - Три уровня z-порядка (§4, §7.1) — не придуманы автором, а дословно повторяют уточнение владельца от 2026-09-05 в комментарии issue. Совпадение точное. - Параметры окантовки unknown-LQI (§8: `#2e2e2e`, 4 px casing / 2 px core → 1 px с каждой стороны, сохранённые просветы) — арифметика прямо выводится из уточнения владельца («обводка 1 px», «сохранение прозрачных промежутков»), а не изобретена. - Технические причины, почему «просто поднять z-index» и «снять stacking context с `.devlayer`» не работают (§3) — подтверждены чтением реального кода, а не заявлены голословно (см. «Как проверялось», п.4). - Технические решения реализации (namespaced-атрибут на `.dev`, bounded `MutationObserver(childList)`, второй `` вместо SVG-фильтра, локальные уровни 7/8) вынесены в явный раздел §20 «Принятые технические предположения — можно менять на ревью» — это правильная граница §7.1: не продуктовый вопрос владельцу, а решаемая автором и оспариваемая ревьюером деталь. Возражений по существу к перечисленным пяти пунктам нет: способ (второй непрерывный `` той же геометрии) корректно даёт кромку без превращения зазоров в сплошную линию, а `childList`-only observer с отключением в `disconnectedCallback` соответствует уже описанному в §12 требованию «не создавать цикл/leak». - Открытых продуктовых вопросов к владельцу в тексте ТЗ нет, и в текущем виде они и не нужны: оба вопроса, которые вообще относятся к продуктовому классу (§7.1: что видно, какой объём изменений), уже закрыты его же комментарием до начала написания ТЗ. ## Что проверено и корректно - Все обязательные разделы §7.1 присутствуют: сценарий (§1) · что человек увидит до/после (§2) · проблема и подтверждённая причина (§3) · скоуп (§5) и не-скоуп (§6) · контракт поведения (§7-8) · режимы/touch/доступность (§9) · модель данных и миграция (§10) · i18n (§11) · AC1-AC3 с доказательством (§14) · план автотестов (§15) · риски (§17) · откат (§18) · release-артефакты (§19). - AC1-AC3 пронумерованы, каждый указывает способ доказательства (`smoke` + raster + ревью кода / `smoke` + mutation), формулировки однозначны — можно проверить по конкретным пиксельным точкам и computed stacking level, а не по общему впечатлению. - Не-скоуп (§6) корректно отсекает смежные темы (получение snapshot, adapters, состав incident links/route selection, цветовая шкала известного LQI, любые config/i18n/backend изменения, touch/kiosk/editors) и явно обязывает вернуть задачу в `S3-spec`, если потребуется их затронуть. - Откат (§18) конкретен: один продуктовый коммит убирает namespaced-атрибут, второй stroke и возвращает overlay в sibling-позицию; данных/config миграции нет, поэтому откат кода данных не касается. - Release-артефакты (§19) полны: оба changelog, оба User Guide, ARCHITECTURE.md, TESTING.md, явная пометка supersede в #54/#457, обоснование отсутствия нового постоянного golden-эталона (hover — не часть golden matrix), обязательность `golden:verify`, `bundle:budget`, mutation, полного Linux docs-screenshot цикла (поскольку меняется `src/**`). - Производительность (§12) и security/privacy (§13) описаны предметно и не содержат новых поверхностей: lazy-загрузка не расширяется, endpoint sync ограничен DOM текущего space, DOM-атрибут не содержит IEEE/entity id. - Трейлеры коммита корректны (`Issue: #464`, `User-Visible: no`), ветка и имя файла соответствуют конвенции, `docs/specs/README.md` обновлён и ссылается на файл, файл ссылается на issue. ## Чего не проверял - Не проверялся продуктовый код — его не существует в этой ветке на момент ревью (класс A не тронут ни одним файлом), что и требуется на этапе ТЗ. - Не прогонялись `npx tsc --noEmit`, `npm test`, `npm run build` — диапазон правок ограничен `docs/specs/**` (класс C), эти гейты не могут быть чувствительны к markdown-диффу, и запуск не дал бы дополнительного сигнала. - Не запускались браузерные смоки, `golden:verify`, `bundle:budget`, `benchmark:zigbee-topology`, `mutation-gate.mjs` — на этом этапе продукта, которого они проверяют, ещё нет; их реализуемость и совместимость с существующей инфраструктурой проверена чтением (см. «Как проверялось», п.5), а не исполнением, поскольку исполнять пока нечего. - Не проверялась реализация #457/#459 построчно за пределами тех фрагментов, что нужны были для сверки цитируемого контракта (§3, §6 «Связано»). ## Материал раунда - Ветка: `issue/464-zigbee-topology-layer` - SHA материала: `aae9efb9ff251ef1471cab685dee2c8c785dea5c` - ТЗ: `docs/specs/464-zigbee-topology-layer-order.md` (новый файл на этом SHA) - Предыдущего раунда нет — это r1, разделы «Закрытие раунда r0» и «Унаследовано из r0» не применяются. ## Вердикт Зелёный. Готово к разработке. --- ## Материал раунда - Ветка: `issue/464-zigbee-topology-layer`, коммит `aae9efb9ff25` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала: `0d024bed021c9e5afb86b77757195a1de1034813` ``` git log --all --format='%H %T' | grep 0d024bed021c ``` - ТЗ `docs/specs/464-zigbee-topology-layer-order.md`, блоб `fbefda4d5cf5acf53895d037cf7b0a5a1cf484f2` ``` git log --all --find-object=fbefda4d5cf5acf53895d037cf7b0a5a1cf484f2 -- docs/specs/464-zigbee-topology-layer-order.md ```