Files
houseplan-card/docs/reviews/SPEC-REVIEW-457-r1.md
T
2026-09-05 10:50:19 +03:00

15 KiB
Raw Blame History

SPEC-REVIEW-457-r1

  • Issue: #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


Материал раунда

  • Ветка: 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