From d13ecf1237c193f6c7432f246e6445145807659d Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Sat, 5 Sep 2026 06:50:50 +0000 Subject: [PATCH] docs: review document for #457 Issue: #457 User-Visible: no --- docs/reviews/SPEC-REVIEW-457-r1.md | 180 +++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 docs/reviews/SPEC-REVIEW-457-r1.md diff --git a/docs/reviews/SPEC-REVIEW-457-r1.md b/docs/reviews/SPEC-REVIEW-457-r1.md new file mode 100644 index 00000000..0d8d828e --- /dev/null +++ b/docs/reviews/SPEC-REVIEW-457-r1.md @@ -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` + +--- + + + +## Материал раунда + +- Ветка: `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 + ```