Files
houseplan-card/docs/reviews/CODE-REVIEW-609-r1.md
T
2026-09-23 00:51:34 +00:00

19 KiB
Raw Blame History

CODE-REVIEW-609-r1

Материал: 4b27268e2fa7278da70d01a5b0e55e366a2e078d (заход r1, HEAD в момент ревью). Коммиты в диапазоне origin/dev..HEAD:

  • 4c9e0132 fix(dialog): align HA settings form shell (#609) — продукт + доказательства, User-Visible: yes, оба changelog в том же коммите.
  • 4b27268e test(dialog): strengthen mobile fullscreen witness (#609) — усиление одного mutation-witness, User-Visible: no.

Скоуп

ТЗ (§10) требует привести оболочку пяти form-shell-диалогов (space/settings/room/marker/onboarding) в настоящем ha-dialog к оболочке референса #600: 560 px desktop, min(940px, 100dvh-48px), канва тела, один HA-скроллер, fullscreen ≤480 px, генерик-диалоги и нативная ветка не тронуты. Диапазон подтверждает: изменения ограничены src/hp-dialog.ts и src/styles/dialogs.styles.ts плюс тестовая/диагностическая инфраструктура (demo/**, scripts/**, test/**) и документация — ровно то, что заявлено в §4 скоупа ТЗ. Продуктовых файлов вне hp-dialog.ts/dialogs.styles.ts в диффе нет.

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

Дешёвые гейты (typecheck/test/build) уже зелёные на этом SHA в Validate (https://github.com/Matysh/houseplan-card/actions/runs/35801912206) — не перегонялись повторно. Ниже — то, что Validate на обычном push не покрывает (heavyGatesRequested включает смоки/golden только на pull_request, workflow_dispatch --full, schedule или коммите с трейлером Release: — ничего из этого здесь нет), и что выбрано по дифф/AC и прогнано мной лично.

Гейт Команда Результат
Выбор смоков по дельте node scripts/smoke-select.mjs --base origin/dev --head HEAD зарегистрированная связь → smoke_dialog_modal_recovery.mjs, smoke_ha_form_shell_parity.mjs
Дешёвый HA-подобный smoke (AC3/AC6, Validate-свидетель) node demo/smoke_ha_form_shell_parity.mjs OK, все проверки (560 px, canvas, fullscreen 480/390/1280×480, generic 580 px) прошли
Регресс native lifecycle node demo/smoke_dialog_modal_recovery.mjs OK, все 22 проверки true
Фокусные smokes 4 форм (AC4) node demo/smoke_space_settings_form.mjs, ..._general_settings_form.mjs, ..._room_settings_form.mjs, ..._device_settings_form.mjs все OK
Регресс 5 потребителей form-shell node test/form-shell-consumers.test.mjs pass 1/1; проверил, что тест умеет падать: временно снял form-shell с room-settings-dialog.ts → тест красный; откатил (git checkout --)
Тяжёлая диагностика на настоящем home-assistant-frontend==20260729.7 (AC1/AC2/AC5/AC7) npm run bundle:sync && node demo/verify_ha_form_shell_609.mjs OK — прогнал сам (сеть доступна): desktop 1600×1000 → панель 560×940, canvas ≠ card, один HA-скроллер (haBodyOverflowY:auto, formBodyOverflowY:visible, haBodyScroll подтверждает реальный скролл), footer внутри; 480×800 и 390×844 → fullscreen, radius 0px, без горизонтального overflow; 1280×480 → штатный HA fullscreen сохранён; pageErrors:[], externalRequests:[], websocketAttempts:[] (AC7)
Мутанты #609 (AC6, «чем краснеет») node scripts/mutation-gate.mjs --id=<id> × 3 все три поймал (таблица ниже)
Целостность реестра мутантов node scripts/mutation-gate.mjs --check exit 0, все find уникальны, включая три новых
Golden 13(+) сцен диалогов (AC4) npm run golden:verify passed на Linux, все сцены зелёные, включая device-dialog-*, room-temperature-dialog-*, room-discard-dialog-mobile-ru, toggle-entity-dialog-*, settings-help-zoom-200-*
Свежесть doc-скриншотов и ссылок node scripts/check-docs.mjs passed (7 файлов, 12 внешних ссылок); docs/images/screenshots.json — sourceFingerprint изменился (src/** тронут), но все 11 imageSha256 идентичны — визуально нативная ветка не изменилась
no-new-any node scripts/no-new-any.mjs --base origin/dev --head HEAD новых any нет (36 добавленных строк в 2 файлах)
Бюджет бандла npm run bundle:budget initial View 290460 B ≤ потолка 291400±2000; только предупреждение о низком запасе (существующий долг #367/#474, не новый)

Таблица «чем краснеет» (AC6, §2.7 обязательна для защитных AC)

AC Чем доказан Чем краснеет
AC6 (ширина 560 не деградирует до generic 580) node demo/smoke_ha_form_shell_parity.mjs мутант ha-form-shell-width-falls-back-to-generic (560→580px) — поймал: node scripts/mutation-gate.mjs --id=ha-form-shell-width-falls-back-to-generic → «покраснел на мутанте»
AC6 (канва не сливается с card) тот же smoke мутант ha-form-shell-loses-canvas (canvas=card background) — поймал
AC6 (mobile fullscreen не сохраняет desktop-инсет) тот же smoke мутант ha-form-shell-mobile-keeps-desktop-inset (−48px на min/max-height) — поймал
AC3 (пять потребителей несут form-shell) test/form-shell-consumers.test.mjs (чистый юнит, регекс по исходнику) не зарегистрированный мутант (не обязателен — юнит, не дорогой гейт), но проверил вручную: снял атрибут у room-settings-dialog.ts → тест красный, откатил

Находки

Medium (в скоупе) — AC5 не доказан ни одним добавленным свидетелем

ТЗ AC5: «Light/dark и 200% text не создают второй scroll, обрезанный footer или слияние карточек с канвой. Доказательство: адресные кадры/геометрические проверки диагностического сценария» — то есть доказательство обещано именно новым диагностическим сценарием этой задачи.

Прочитал оба добавленных файла целиком:

  • demo/verify_ha_form_shell_609.mjs — четыре вьюпорта (1600×1000, 480×800, 390×844, 1280×480), ни разу не переключает тему и не меняет размер шрифта;
  • demo/smoke_ha_form_shell_parity.mjs — та же картина: только resize вьюпорта, ни documentElement.style.fontSize, ни варианта темы.

Более того, сама фикстура структурно не может показать «светлую» тему: demo/srv/demo.html:9 жёстко прописывает --card-background-color:#1c2530 (тёмная палитра) независимо от параметра colorScheme фикстуры (тот управляет только prefers-color-scheme браузера, а не значениями токенов, которые задаёт демо-страница). Я прогнал verify_ha_form_shell_609.mjs сам: cardBackground во всех кадрах — rgb(28, 37, 48), то есть тот же жёстко заданный тёмный тон; светлая тема в этом сценарии физически не встречается ни разу.

Ни одна из двух половин AC5 (тема, 200%-текст) не имеет исполнимого свидетеля в этом дифф. Соразмерный оракул был дёшев и достижим: тот же уже открытый настоящий ha-dialog из verify_ha_form_shell_609.mjs можно было дополнительно проверить с documentElement.style.fontSize='32px' (соседний диагностический README для #505 уже описывает ровно такой приём — «Separate 32px root-font cases exercise enlarged text») и с переопределением --secondary-background-color/--card-background-color перед settle(), не трогая продукт.

По коду сама реализация читается безопасно для темы (все значения — только var(--токен-HA, …), литеральных цветов нет) и по аналогии с уже протестированным нативным путём (golden settings-help-zoom-200-en-light / -ru-dark покрывают тот же общий flex/scroll-контракт, только в нативной, а не HA-ветке) — риск разъезда невелик, но это довод «вероятно работает», а не доказательство по AC, и сама заявленная в ТЗ форма доказательства (диагностика) отсутствует. Это находка §2.7: «если соразмерный исполнимый oracle возможен, его отсутствие — находка», а не тождество отсутствующего теста провалу.

Воспроизведение: grep -n "fontSize\|dark\|theme" demo/verify_ha_form_shell_609.mjs demo/smoke_ha_form_shell_parity.mjs — пусто.

Единственный Medium в скоупе задачи → вердикт жёлтый; правка — добавить theme/200%-кейс в уже существующий диагностический сценарий, без нового issue (#202).

Low — некорректная ссылка на AC в mutation-registry.mjs

Два новых мутанта цитируют несуществующий критерий: because: '#609 AC1/AC8: …' и '#609 AC4/AC8: …'. В ТЗ issue критериев приёмки семь (AC1…AC7, раздел «10. Критерии приёмки»); «AC8» не существует. Похоже на путаницу с пунктом 8 раздела «6. Контракт поведения» («Светлая и тёмная темы используют переменные HA без фиксированных цветов») — в кодовой базе для таких ссылок принято обозначение «К» (пример — комментарий в hp-dialog.ts:196 про «(К6)»), а не «AC». Сами мутанты работают верно (см. таблицу выше) — это чисто трассируемость комментария, не функциональный дефект. Снимаю с запиской, цикл не тратит: scripts/mutation-registry.mjs, ключи ha-form-shell-width-falls-back-to-generic и ha-form-shell-mobile-keeps-desktop-inset.

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

  • AC1/AC2 (геометрия в настоящем HA) — доказано исполнением, не чтением: мой собственный прогон verify_ha_form_shell_609.mjs против закреплённого home-assistant-frontend==20260729.7 подтвердил 560×940 desktop, canvas ≠ card, один HA-скроллер, fullscreen на 480×800/390×844 (radius 0, без горизонтального overflow), сохранённый штатный HA-fullscreen на 1280×480.
  • AC3 (пять потребителей + generic не тронут) — smoke_ha_form_shell_parity.mjs прогоняет все 5 data-kind плюс отрицательный контроль (genericWidth 580/390/1280 соответственно вьюпорту, т.е. без изменений); test/form-shell-consumers.test.mjs зарегистрировал сам факт присутствия атрибута у всех пяти файлов и умеет падать (проверил вручную).
  • AC4 (нативная ветка неизменна) — golden:verify зелёный на Linux по всем сценам (включая все диалоговые), четыре фокусных smoke форм зелёные, docs/images/screenshots.json — 11/11 imageSha256 совпадают, несмотря на изменившийся sourceFingerprint (т.е. правка не меняет рендер нативной ветки при том же исходном коде, только его хэш).
  • AC6 (защитная проверка) — три заявленных мутанта существуют, каждый поймал заявленную им регрессию лично мной (таблица «чем краснеет» выше); mutation-gate.mjs --check подтверждает, что все find-паттерны уникальны в файлах.
  • AC7 (изоляция фикстуры) — подтверждено моим прогоном: pageErrors, externalRequests, websocketAttempts — пустые массивы; fixture.assertClean() выполняется в конце сценария и не бросил.
  • Трейлеры и changelog — 4c9e0132 несёт Issue: #609, User-Visible: yes и оба changelog (docs/CHANGELOG.md, docs/CHANGELOG.ru.md) в этом же коммите; 4b27268e — User-Visible: no, чисто тестовое усиление одного мутанта, дополнительного изменения продукта не несёт.
  • Классы риска §2.6 — geometry (границы 480/450/500, разобрано и исполнено), visual (промежуточный кадр — диагностика ждёт 250 мс после 200 мс WebAwesome-анимации, settle()), host/input (mouse/touch — новый код не меняет обработчики ввода, только CSS-геометрию); data/rights и async неприменимы (чистая презентационная правка, минимальны данные и переходы состояния не тронуты).
  • Бюджет бандла — прирост 500 Б задокументирован причиной в самом файле (scripts/bundle-budget.mjs), пересчитан и подтверждён прогоном.
  • --dialog-content-padding: 0 не создаёт двойной отступ — подтверждено реальным прогоном: haBodyPadding = 0px во всех кадрах, .body (light-DOM) сохраняет собственные 16 px из dialogs.styles.ts.
  • Просмотрел hp-dialog[form-shell][ha-dialog-shell] .body { min-height: 100%; } и toggle ha-dialog-shell в connectedCallback — атрибут выставляется синхронно до первого рендера, читается тем же селектором, что и в dialogs.styles.ts; для generic-диалогов ([form-shell] отсутствует) правило неприменимо — подтверждено smoke (genericWidth не сдвинулась).

Чего не проверял

  • Короткое содержимое формы (когда высота карточек меньше высоты .body HA) — во всех прогнанных сценариях (реальная диагностика открывает Room settings, смоук использует height:1200px) содержимое всегда выше контейнера, поэтому min-height:100% на .body (правило, добавленное специально для короткого случая — не оставлять голую поверхность HA под канвой) ни разу не оказалось определяющим ограничением. Не завожу как находку: ни один AC явно не требует именно этого кадра, а правило — чистый CSS min-height от процентной высоты явно заданного flex-родителя, что обычно ведёт себя предсказуемо; но это не исполненное доказательство, только чтение.
  • Полный npm run typecheck/npm test/npm run build заново не гонял — зелёный Validate на этом же SHA уже есть по ссылке в задаче ревью, а рабочая копия после npm run bundle:sync не изменила ни файла (git status пуст), то есть закоммиченный бандл и есть тот, что построен из этого исходника.
  • pytest tests_backend — не тронут custom_components/**/*.py, неприменимо.
  • Полная матрица demo/smoke_*.mjs (все ~90+ файлов) и performance-профили — вне названного диффом/AC объёма; smoke-select.mjs не назвал их, AC не называет performance.
  • Реальные версии home-assistant-frontend кроме закреплённой 20260729.7 — вне AC (риск §12 ТЗ явно называет это допустимым остаточным риском).

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

  • SHA: 4b27268e2fa7278da70d01a5b0e55e366a2e078d (совпадает с git rev-parse HEAD на момент вывода вердикта).
  • Дерево: чистое (git status — «nothing to commit, working tree clean»), включая после локальной пересборки npm run bundle:sync.
  • Коммиты диапазона: 4c9e0132, 4b27268e (см. таблицу выше).

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

  • Ветка: issue/609-ha-form-shell-parity, коммит 4b27268e2fa7 — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: e6ceae417ab48a2f16c3614c949acd96dadb6900
    git log --all --format='%H %T' | grep e6ceae417ab4
    
  • Тело issue: b08b9257ed688a47f3a0f422cdddc1bfc7cf7c511e81ada3ceeac8c2ce354d51
  • Вердикт конвейера: yellow · High 0