19 KiB
CODE-REVIEW-609-r1
Материал: 4b27268e2fa7278da70d01a5b0e55e366a2e078d (заход r1, HEAD в момент ревью).
Коммиты в диапазоне origin/dev..HEAD:
4c9e0132fix(dialog): align HA settings form shell (#609) — продукт + доказательства,User-Visible: yes, оба changelog в том же коммите.4b27268etest(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прогоняет все 5data-kindплюс отрицательный контроль (genericWidth580/390/1280 соответственно вьюпорту, т.е. без изменений);test/form-shell-consumers.test.mjsзарегистрировал сам факт присутствия атрибута у всех пяти файлов и умеет падать (проверил вручную). - AC4 (нативная ветка неизменна) —
golden:verifyзелёный на Linux по всем сценам (включая все диалоговые), четыре фокусных smoke форм зелёные,docs/images/screenshots.json— 11/11imageSha256совпадают, несмотря на изменившийся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%; }и toggleha-dialog-shellвconnectedCallback— атрибут выставляется синхронно до первого рендера, читается тем же селектором, что и вdialogs.styles.ts; для generic-диалогов ([form-shell]отсутствует) правило неприменимо — подтверждено smoke (genericWidthне сдвинулась).
Чего не проверял
- Короткое содержимое формы (когда высота карточек меньше высоты
.bodyHA) — во всех прогнанных сценариях (реальная диагностика открывает Room settings, смоук используетheight:1200px) содержимое всегда выше контейнера, поэтомуmin-height:100%на.body(правило, добавленное специально для короткого случая — не оставлять голую поверхность HA под канвой) ни разу не оказалось определяющим ограничением. Не завожу как находку: ни один AC явно не требует именно этого кадра, а правило — чистый CSSmin-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— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
e6ceae417ab48a2f16c3614c949acd96dadb6900git log --all --format='%H %T' | grep e6ceae417ab4 - Тело issue:
b08b9257ed688a47f3a0f422cdddc1bfc7cf7c511e81ada3ceeac8c2ce354d51 - Вердикт конвейера:
yellow· High 0