Files
houseplan-card/docs/reviews/CODE-REVIEW-459-r1.md
T
2026-09-05 11:18:37 +03:00

16 KiB
Raw Blame History

Код-ревью #459 — заход r1

Настройка «Zigbee links»: подсказка о функции, её ограничениях и легенда цветов и пунктира.

Ветка issue/459-zigbee-links-help, HEAD 951cbd0174bbbc4cb069cf5f8832da8cc49f2ace, база origin/dev = b04e4aacce4ab1f13f320dd1dfe7501b78da571e.

Скоуп

Диапазон git diff origin/dev...HEAD — 41 файл. Продуктовый код:

  • src/hp-zigbee-topology-settings.ts — импорт hp-help, локальный _help(), кружок у заголовка секции;
  • src/i18n/topology.ts — новая hasTopologyTranslation(), зеркало hasTranslation основного словаря;
  • src/i18n/topology/{en,ru,de,fr}.json — два новых ключа (help, help_aria);
  • test/zigbee-topology.test.mjs — 7 новых тестов (AC1, AC2, AC3, AC3b, AC4, AC5, AC6);
  • scripts/mutation-gate.mjs — два мутанта;
  • docs/CHANGELOG.md / docs/CHANGELOG.ru.md — записи в том же коммите, что и фича;
  • golden-эталон general-color-popover-desktop-en принят вторым коммитом с Release:/Baseline-Reviewed:;
  • dist/**, custom_components/houseplan/frontend/**, docs/images/screenshots.json — производные сборки/скриншотов.

Оверлей (hp-zigbee-topology-overlay.ts), логика топологии (zigbee-topology.ts, zigbee-topology-runtime.ts), lqiColor (logic.ts) и hp-help.ts не тронуты — соответствует §5 контракта («что не меняется»).

Как проверялось

Материал — git log --oneline origin/dev..HEAD (2 коммита) и git diff origin/dev...HEAD. Читал код построчно и сверял с контрактом ТЗ (тело issue + все 9 комментариев, включая утверждённый r2 SPEC-REVIEW и финальный текст §4.1).

Validate на 951cbd01 зелёный (прогон 33953825960), поэтому npx tsc --noEmit, полный npm test и npm run build не перегонял. Дельта не трогает геометрию/модель (стены, layout, marker.space, open_spans), поэтому npm run invariants не требуется.

Что прогнал сам:

Гейт Результат
node scripts/bundle-sync.mjs (подготовка стенда для смоков — demo/srv/assets не в репозитории) наложил дистрибутив без изменений в git-дереве
demo/smoke_zigbee_topology_hover.mjs (назван в AC8) OK, все 12 проверок true — оверлей, цвета, дефолт-офф, ленивая загрузка не изменились
node scripts/smoke-select.mjs --base b04e4aac --head 951cbd01 НЕОПРЕДЕЛЁННОСТЬ — символы _help, hasTopologyTranslation, topologyT, DICTIONARIES, Lang, TopologyI18nKey, langOf не связаны ни с одним смоком доказуемо; кроме уже прогнанного smoke_zigbee_topology_hover (AC8), других смоков задача не называет, и диф — новый namespace-компонент без побочных эффектов на другие поверхности, широкого символа нет
node scripts/bundle-budget.mjs OK, initial View 297 476 Б (потолок 298000±2000, budget 300000) — подтверждает заявленные автором «на 2 байта меньше dev»; есть предупреждение о низком запасе, но это унаследованный долг #367, не новый в этой задаче
node scripts/check-docs.mjs --external OK, 7 файлов, 12 внешних ссылок
node scripts/mutation-gate.mjs --id=topology-help-renders-without-aria OK — мутант пойман, тест краснеет
node scripts/mutation-gate.mjs --id=topology-help-drops-arrow-legend OK — мутант пойман, тест краснеет
node --test test/zigbee-topology.test.mjs (полный файл, 18 тестов) OK, 18/18 pass
Дисциплина «тест умеет падать» для AC6 (гейт паритета словарей) вручную удалил help_aria из de.json, тест на паритет упал ожидаемо; вернул файл на место (git status чист)
Чтение general-color-popover-desktop-en.png подтверждаю глазами: единственное изменение — кружок «?» у «Zigbee links», остальное — сдвиг вниз ~14px без регрессии рендера
docs/images/screenshots.json, baselines-index.json дифф только sourceFingerprint/sourceSha256 и хэш одной сцены; imageSha256 во всех 10 скриншот-сценах документации не изменился — рекапча была из-за отпечатка, не из-за пикселей

Не прогонял: полный npm test, npx tsc --noEmit, npm run build, полный npm run golden:verify (153 сцены) — уже подтверждены Validate на этом SHA; python -m pytest tests_backend — custom_components/**/*.py не тронут; npm run invariants — геометрия/модель не задеты; performance-профили — не названы в AC и не тронуты чувствительные пути.

Проверка по AC

  • AC1 (кружок у заголовка, наведение/фокус/клик) — подтверждено чтением: render() кладёт ${this._t('title')}${this._help()} в .section (строка 187), а не в .toggle. Открытие по наведению/фокусу/клику — поведение самого hp-help.ts, не тронутого этой задачей, доказательство ссылкой корректно.
  • AC2 (fail-closed без одного из ключей) — _help() проверяет hasTopologyTranslation(lang, 'help') и ...'help_aria', возвращает nothing. Тест кружок справки не рисуется без подписи для скринридера гоняет hasTopologyTranslation напрямую, включая случай no_such_key → false и англ. фолбэк для de. Мутант topology-help-renders-without-aria (правит резолв на ?? key, имитируя старую фиктивную проверку) пойман.
  • AC3 / AC3b (шесть+один пункт легенды по-русски) — тест проверяет 10 паттернов по нормативной ru-строке, все совпадают: LQI, 40, 180, пунктир, исходящая→координатор, входящие, «без стрелки», «подпись на конце стрелки», «отсутствие стрелки», «дерево маршрут», «не путь пакета». Мутант topology-help-drops-arrow-legend (вырезает предложение про стрелки) пойман.
  • AC4 (границы шкалы = lqiColor, не константа) — тест импортирует lqiColor из скомпилированного logic.js и берёт hue(40)=0, hue(180)=120 из функции, затем ищет те же числа в тексте. Подтверждено чтением logic.ts:8-10: hue = clamp(0..120, (lqi-40)/140*120) — ровно то, что описывает ТЗ.
  • AC5 (нет переносов строк) — проверено для всех четырёх словарей; строки help/help_aria непустые.
  • AC6 (паритет ключей+плейсхолдеров четырёх словарей) — новый гейт лежит в test/zigbee-topology.test.mjs, а не в test/i18n.test.mjs, как предполагали «Затронутые файлы» ТЗ (низкая находка ниже). Сам гейт работает: проверил падением при удалении ключа.
  • AC7 (ядро и бандл не растут) — core-file-budget.test.mjs следит только за houseplan-card.ts и houseplan-editor-runtime.ts — ни один не тронут. bundle-budget.mjs зелёный, инициальный чанк на 2 байта меньше dev.
  • AC8 (оверлей не изменился) — smoke_zigbee_topology_hover.mjs прогнан лично, все проверки true.

Контракт §2 («не переиспользуем _help() редактора») и §3 (плоские ключи help/help_aria) подтверждены построчно: основной _help() в houseplan-editor-runtime.ts:1228 типизирован I18nKey/t() основного словаря и требует пару <ключ>.help/<ключ>.help.aria — несовместим с namespace topologyT. Новый hasTopologyTranslation — точное зеркало hasTranslation (src/i18n.ts:38-41), включая англ.-фолбэк.

Перевод легенды на en/de/fr сверен вручную по всем шести пунктам плюс оговорке о приближённости — ни один язык не потерял смысловой блок (проверка ru тестами, en/de/fr — чтением, не исполнением).

Что проверено и корректно

  • Оба мутанта реально ловятся (не «зелёный на бумаге» — прогнал сам).
  • AC6-гейт умеет падать (тест на паритет специально сломан и восстановлен).
  • Единственная задетая golden-сцена соответствует заявленному визуальному изменению, остальные 152 сцены документации не изменили пиксели.
  • User-Visible: yes в коммите 040902fe сопровождается правкой обоих changelog в этом же коммите; коммит 951cbd01 (принятие эталона) несёт Release:/Baseline-Reviewed: и помечен User-Visible: no, что верно — сам golden-коммит не меняет видимое поведение сверх уже объявленного.
  • Геометрия/модель/провайдеры/конфиг не затронуты — соответствует §5 контракта.
  • Числа 40 и 180 в подсказке имеют один источник (lqiColor), а не отдельную константу — AC4 гейт это блокирует, а не полагается на честное слово.

Низкие находки (без блокировки, приняты с запиской)

  1. Расхождение отчёта с диффом: автор пишет «+22 утверждения в шести новых тестах», в дифе — семь новых тестов (AC1…AC6, AC3b отдельно). Чисто редакторская неточность в отчёте, не в коде; не влияет на проверяемость.
  2. data-help-key не проставлен. Оба существующих места, где строится <hp-help> (houseplan-editor-runtime.ts:1232, houseplan-onboarding-runtime.ts:58), кладут data-help-key=${key} — по этому атрибуту demo/smoke_help_affordance.mjs находит конкретный кружок. Новый локальный _help() в hp-zigbee-topology-settings.ts этот атрибут не ставит. Ни один AC его не требует, поведение кружка не страдает — но если когда-нибудь понадобится смок, целящийся именно в этот кружок, привычный селектор hp-help[data-help-key="..."] не сработает. Не блокирует, реализатор может добавить одной строкой при желании.
  3. Гейт паритета словарей уехал из плана. ТЗ ожидало «несколько строк в существующем тесте» (test/i18n.test.mjs), реализация — новый тест в test/zigbee-topology.test.mjs. Гейт работает (проверил падением), но заявленный в «Затронутых файлах» путь не совпал с фактическим — организационная, не функциональная деталь.

Ни одна находка не блокирует и не относится к Medium: ни AC, ни продуктовое поведение не задеты.

Чего не проверял и почему

  • Полный npm test, npx tsc --noEmit, npm run build, полный npm run golden:verify — Validate уже зелёный на 951cbd01 этой же веткой (ссылка в задаче), а диф не расширяет их сверх того, что покрыто точечными прогонами выше.
  • python -m pytest tests_backend — custom_components/**/*.py в дифе нет (только синхронизированная копия фронтенд-бандла).
  • npm run invariants — диф не касается стен, layout, marker.space, open_spans или иных геометрических ссылок.
  • Performance-профили — не названы в AC и не задеты диффом.
  • Остальные 222 браузерных смока — не выбраны инструментом (НЕОПРЕДЕЛЁННОСТЬ) и не относятся по теме к namespace-компоненту без побочных эффектов; единственный релевантный (smoke_zigbee_topology_hover, AC8) прогнан.

Итог

Все восемь AC доказаны — тестом с проверенной способностью падать (AC1–AC6) либо смоком, прогнанным лично (AC8), либо бюджетным гейтом (AC7). Два мутанта реально ловятся. Контракт §1–§5 ТЗ выполнен буквально, включая обе оговорки, которые владелец сознательно исключил из текста (координатор без исходящей стрелки, соседи вне пространства). Три находки Low не влияют на корректность и не блокируют.

Вердикт: зелёный.


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

  • Ветка: issue/459-zigbee-links-help, коммит 951cbd0174bb — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 0232ce77f553298708b5cdf4558455cc2ffd721d
    git log --all --format='%H %T' | grep 0232ce77f553