docs: review document for #457

Issue: #457
User-Visible: no
This commit is contained in:
claude[bot]
2026-09-05 10:50:19 +03:00
committed by Sergey Matyunin
parent a63aef0239
commit d13ecf1237
+180
View File
@@ -0,0 +1,180 @@
# SPEC-REVIEW-457-r1
- Issue: [#457](https://github.com/Matysh/houseplan-card/issues/457) — Топология
Zigbee: показывать направление связи стрелкой на конце линии
- ТЗ: `docs/specs/457-zigbee-route-arrows.md`
- SHA материала: `f3a1dd84` (ветка `issue/457-zigbee-route-arrows`, коммит
«docs: specify Zigbee route arrows»)
- Заход: r1 · блокирующих циклов израсходовано 0 из 4
- Трек: полный (issue помечен `feature`, `P2`, `S4-spec-review`; `small` не
назначен, и это соответствует критериям §5 — новый UX-контракт, производная
графовая модель, новые i18n-строки и browser-smoke)
## Скоуп ревью
ТЗ описывает дерево аплинков Zigbee-топологии к координатору (BFS от узла с
`role: coordinator`), стрелки на рёбрах этого дерева при hover-диагностике, и
parent bubble для случаев, когда следующий узел на пути нельзя показать на
плане (другое пространство / нет маркера у устройства / нет маркера у
координатора). Развивает существующий контракт #54
(`docs/specs/054-zigbee-topology-overlay.md`), который явно исключал
«вычисление либо изображение маршрута до координатора» из своего non-scope —
#457 законно открывает этот пункт отдельной задачей.
Я не пишу и не правлю ни ТЗ, ни продуктовый код — только оцениваю.
## Как проверялось
Ревью ТЗ на этом этапе не гоняет гейты (кода ещё нет — весь diff класса A/B/D
пуст, изменена только документация класса C). Работа состояла в очной сверке
каждого фактического утверждения ТЗ с реальным состоянием репозитория на SHA
`f3a1dd84`, а не с пересказом автора:
- прочитан `docs/SCOPE.md` — задача продолжает J7 («Is my Zigbee mesh healthy
here?»), конфликта со scope нет, это уже подтвердила и аналитика Codex в
issue;
- прочитан `PROCESS.md` §2.4, §2.9 (не применимо к r1), §5, §7.1, §7.2 — все
обязательные разделы шаблона проверены поимённо;
- прочитано тело issue #457 целиком и все 6 комментариев (аналитика владельца,
два уточнения владельца, финальные решения владельца, аналитика и оценка
Codex, хендофф на ревью) — сверено, что все продуктовые вопросы закрыты
решениями владельца **до** написания ТЗ, а не оставлены на усмотрение
реализации;
- прочитан `docs/USER-GUIDE.ru.md` (раздел про Zigbee-диагностику, строки
200–230) и `docs/USER-GUIDE.md` — терминология «Показывать связи Zigbee при
наведении на устройство», admin-only, mouse-only, «снимок соседства, а не
маршрут каждого текущего пакета» уже зафиксирована и ТЗ её не переизобретает;
- прочитан базовый контракт `docs/specs/054-zigbee-topology-overlay.md`
целиком — проверено, что #457 не противоречит и не дублирует его AC, а
расширяет ровно тот пункт non-scope, который #54 сознательно оставил открытым;
- построчно сверены все технические утверждения ТЗ с текущим кодом:
`src/zigbee-topology.ts` (модель `ZigbeeTopologyLink`/`ZigbeeHoverLine`,
`observation()` — `relationship` действительно принимает только `string`,
`resolveMappedTopologyHover`, `omittedCount` действительно нигде не
выводится, `mapTopologyNodes` — четыре причины `unmatched_device` /
`ambiguous_placement` / `provider_scan_failure` / `drawable()`),
`src/hp-zigbee-topology-overlay.ts` (`viewBox="0 0 100 100"
preserveAspectRatio="none"`, `.halo` радиус `1.22`, `remote` bubble, `pointer-
events: none`, `forced-colors` блок), `src/zigbee-topology-overlay-bridge.ts`
и вызов в `src/houseplan-card.ts` (нет проекции названий пространств в
overlay сегодня, но паттерн `space.title || space.id` уже существует в файле
и его перенос в bridge не требует нового конфига), `src/zigbee-topology-
settings.ts` (`enabled: false` по умолчанию);
- прочитана реальная анонимизированная фикстура
`test/fixtures/zigbee2mqtt-networkmap-real-anonymized.json` — подтверждено,
что координатор (`type: Coordinator`) присутствует, `relationship: 2`
(число) и `depth: 15` действительно в данных, как заявлено в ТЗ;
perf-бюджеты `normalize 80 ms / map 160 ms / first hover 180 ms / 20 repeated
hovers 120 ms` в §12 ТЗ дословно совпадают с `BUDGETS` в
`demo/benchmark_zigbee_topology.mjs`, а лимиты «1000 nodes / 6000 links» — с
`TOPOLOGY_MAX_NODES`/`TOPOLOGY_MAX_LINKS`;
проверено существование всех названных в AC инструментов доказательства:
`test/zigbee-topology.test.mjs`, `demo/smoke_zigbee_topology_hover.mjs`,
`demo/benchmark_zigbee_topology.mjs` — ни один AC не ссылается на
несуществующий или придуманный гейт;
- проверено, что backend Python не затронут: `grep` по `custom_components/`
на «zigbee» не находит ничего, provider-обращения (`zha/devices`) идут через
`hass.callWS` из фронтенда — подтверждает §16 «Backend Python не меняется»;
- сверен формат `docs/CHANGELOG.md`/`docs/CHANGELOG.ru.md` (секция
`## Unreleased`) с требованием §19 добавить одну пользовательскую запись.
Полный набор автотестов/typecheck/build на этом этапе не запускался — кода нет,
гонять нечего; это ожидаемо для ревью ТЗ и не является пропуском гейта.
## Находки
Блокирующих (High) и находок в скоупе (Medium) нет.
### Low — зафиксировано, без правки
1. **§8, «При недостатке места bubble может сместиться на противоположную
сторону marker»** не даёт алгоритмического критерия «недостатка места»
(порог, приоритет сторон). Это единственное место контракта, где решение
явно оставлено на усмотрение реализации, но не занесено в «Принятые
предположения» (§20). Не блокирует: AC9 всё равно требует, чтобы bubble
«оставался внутри видимой области overlay» и не обрезал текст, то есть
наблюдаемое поведение проверяемо независимо от конкретного алгоритма
позиционирования. Снимаю без правки: технический выбор компоновки внутри
уже описанного визуального инварианта — по §7.1 такие решения ревьюер вправе
не эскалировать, а просто отметить.
## Что проверено и корректно
- Обязательные разделы §7.1 присутствуют все и в порядке, продиктованном
процессом: сценарий → что человек увидит → проблема → скоуп/не-скоуп →
контракт → UX → данные/миграция → i18n → AC → тесты → риски → откат →
release-артефакты (§§1–19 ТЗ).
- Оба «первых» продуктовых раздела (сценарий, что человек увидит до/после)
называют персону из `docs/SCOPE.md`, поверхность и момент, без терминов
реализации в разделе 2 — соответствует требованию.
- Открытых продуктовых вопросов нет: все три развилки, которые обсуждались в
комментариях (смысл стрелки, поведение при недоступном endpoint, поведение
при неизвестном пути) закрыты явными решениями владельца **до** написания
ТЗ, и ТЗ им не противоречит ни в одном разделе.
- Технических догадок, выданных за факт и не помеченных как предположение, не
найдено: единственное место, где реализация имеет свободу (алгоритм
выбора родителя, имена типов, точный визуальный размер наконечника, formula
позиционирования bubble при недостатке места) либо прямо названо в §20
«Принятые предположения», либо (см. Low выше) не влияет на проверяемость
AC.
- Каждый AC1–AC12 — проверяемое утверждение с явным способом доказательства
(unit / resolver unit / browser smoke / benchmark / bundle-budget /
check-docs), без формулировок вида «работает корректно» без критерия.
Инвариант «по стрелкам приходишь в координатор» сформулирован как свойство
дерева (§6.4), а не как свойство итоговой картинки — ТЗ прямо проговаривает,
почему это важно (обрыв цепочки на неразмещённом/удалённом узле не должен
делать AC1 невыполнимым в обычном доме).
- Конструкция «дерево аплинков по полному графу, включая неразмещённые узлы,
рисуется только по размещённым» корректно закрывает реальный дефект текущего
кода: `omittedCount` в `resolveMappedTopologyHover` сегодня действительно
считается, но нигде не выводится (проверено чтением
`src/zigbee-topology.ts:307-333` и `src/hp-zigbee-topology-overlay.ts`) — ТЗ
не выдумывает проблему.
- Все построчные технические ссылки на код и фикстуры, использованные для
обоснования решений (числовой `relationship` у Z2M, `depth: 15`, отсутствие
проекции названий пространств в overlay, дефолт `enabled: false`,
perf-бюджеты, лимиты 1000/6000), подтверждены чтением соответствующих файлов
— расхождений с фактическим состоянием кода не найдено.
- Не-скоуп (§5) корректно исключает смежные, но посторонние задачи
(асимметрия LQI, постоянный mesh-граф, touch-жест, автоматическое размещение
координатора) и совпадает с явными решениями владельца в issue не заводить
их сейчас.
- Откат (§18) и release-артефакты (§19) содержательны и не формальны:
пользовательский откат — существующий тумблер, кодовый откат — конкретные
поверхности для удаления.
## Чего не проверял
- Реализуемость perf-бюджетов на **новом** коде (построение дерева) — это
предмет измерения на этапе код-ревью через
`npm run benchmark:zigbee-topology`, сейчас кода не существует.
- Полный typecheck/test/build/golden/check-docs — не применимо к этапу ТЗ, код
не менялся (diff — только `docs/specs/457-zigbee-route-arrows.md`).
- Фактическую компоновку bubble в браузере (описанный в Low пункт) — там нет
кода для запуска, только текст контракта.
- Backend-тесты (`pytest tests_backend`) — не применимо, Python не
затронут ни диффом, ни планом ТЗ.
## Вердикт
Полный, тщательно проверенный по коду и данным документ, без открытых
продуктовых вопросов и без непомеченных догадок. Единственное замечание —
Low, снято без правки с записью в этом документе.
`Вердикт: зелёный · заход r1 · блокирующих циклов 0/4 · High: 0 · Medium: 0`
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/457-zigbee-route-arrows`, коммит `f3a1dd84e19d` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `0c76f7e322a59f7e81bbae32a7b013d63584ca5f`
```
git log --all --format='%H %T' | grep 0c76f7e322a5
```
- ТЗ `docs/specs/457-zigbee-route-arrows.md`, блоб `2c8350e397b0192a8f0db3d1c3ee0bf9f5f6e1f6`
```
git log --all --find-object=2c8350e397b0192a8f0db3d1c3ee0bf9f5f6e1f6 -- docs/specs/457-zigbee-route-arrows.md
```