mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-03 21:28:59 +00:00
181 lines
15 KiB
Markdown
181 lines
15 KiB
Markdown
# 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
|
||
```
|