13 KiB
CODE-REVIEW-212-r2
- Issue: https://github.com/Matysh/houseplan-card/issues/212
- Спецификация:
docs/specs/212-device-icons-polish.md(зелёный SPEC-REVIEW-212-r1) - Диапазон ревью:
origin/dev...HEAD. Полная задача —ec6f77b(specify) ·5cae1fd(SPEC-REVIEW doc) ·120d413(fix: polish device icons and pointer feedback) ·b7bfc92(CODE-REVIEW-212-r1 doc) ·c5ba699(fix: address device icon review findings,Issue: #212,User-Visible: yes). Этот цикл — второй код-ревью, предметно новое по сравнению с r1 — только диапазонb7bfc92..c5ba699. - Ветка:
issue/212-device-icons-polish - Роль: ревьюер кода, свежая сессия без контекста написания ТЗ/кода.
Скоуп проверки
CODE-REVIEW-212-r1 (docs/reviews/CODE-REVIEW-212-r1.md) вынес жёлтый вердикт
с двумя находками Medium в скоупе, обе без High:
- M1 — три существующих regression-смока (
smoke_glow.mjs,smoke_room_settings.mjs,smoke_ux_fixes.mjs) остались на старомMouseEvent('mouse{enter,move,leave}')/удалённом_touchSeenи были красными на SHA120d413из-за миграции room/marker hover наPointerEvent. - M2 —
hp-device-preview.tsгейтировал.dev:hoverчерез:host([data-pointer-hover]), но карта не проставляла этот атрибут экземпляруhp-device-preview— hover z-index в Device preview был мёртв навсегда.
Задача этого цикла — проверить, закрыты ли обе находки по существу (не
просто «тест больше не падает», а поведение действительно восстановлено), и
что фикс не завёл новой регрессии. Весь остальной код задачи (AC1–AC16)
не тронут диапазоном b7bfc92..c5ba699 и повторно не пересматривался —
он был закрыт по существу в r1.
Как проверялось
| Гейт | Команда | Результат |
|---|---|---|
| Типы | npx tsc --noEmit |
зелёный |
| Юнит | npm test |
952/952 зелёных |
| Сборка | npm run build + md5sum dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js demo/srv/assets/houseplan-card.js |
зелёная; все три хэша идентичны (b238775be1735d550f2b95c1e268cfa1) |
| Документация | node scripts/check-docs.mjs --external |
«Documentation checks passed (7 files, 10 external links)» |
Целевые смоки, фиксившиеся в c5ba699 |
node demo/smoke_glow.mjs, node demo/smoke_room_settings.mjs, node demo/smoke_ux_fixes.mjs, node demo/smoke_device_preview_parity.mjs |
все 4 зелёные |
| Failing-before/passing-after для M1 | те же 3 смока прогнаны против бандла коммита b7bfc92 (пере-собран в отдельном git worktree, с символической ссылкой на существующий node_modules) |
smoke_glow → FAILED (3), smoke_room_settings → FAILED (1), smoke_ux_fixes → FAILED (8) — то же множество, что описано в CODE-REVIEW-212-r1 |
| Failing-before/passing-after для M2 | новый файл smoke_device_preview_parity.mjs (из HEAD, с ассертом previewHoverGatePropagates) прогнан против бандла b7bfc92 |
previewHoverGatePropagates: false → FAILED (1) — тест умеет падать именно на старом коде |
Смежные названные смоки той же hover-механики (не изменены диффом, но зависят от POINTER_HOVER_TARGET_SELECTOR) |
node demo/smoke_touch_tips.mjs, node demo/smoke_feedback_v2.mjs, node demo/smoke_help_affordance.mjs, node demo/smoke_device_icon_design.mjs |
все зелёные — расширение селектора не задело существующие цели |
| Mutation-proof | node scripts/mutation-gate.mjs --check (все зарегистрированные guard'ы) и отдельно node scripts/mutation-gate.mjs --id=device-touch-hover-gate-removed |
все guard'ы зелёные на чистом коде; device-touch-hover-gate-removed «покраснел, как обязан» на мутанте |
Геометрический вывод AC1/AC3 не пересматривался — диапазон b7bfc92..c5ba699
эти файлы не трогает.
Верификация находок r1
M1 — исправлено, доказано реальным поведением, не только тестом
src/houseplan-card.ts не менялся в части обработчиков — миграция на
PointerEvent уже стояла в 120d413. Фикс — только в трёх смоках:
MouseEvent('mouse{enter,move,leave}') заменён на
PointerEvent('pointer{enter,move,leave}', { pointerType: 'mouse' }), а
проверка touch-подавления тултипа (smoke_ux_fixes.mjs) перестала писать
удалённый статический c.constructor._touchSeen и вместо этого шлёт настоящую
последовательность pointerdown/pointermove/pointerup с pointerType: 'touch'.
Прочитано и прослежено по коду: pointerdown на .room всплывает
(bubbles: true, composed: true) до @pointerdown на stage-контейнере
(src/houseplan-card.ts:15808), который вызывает _notePointer(e) —
PointerModalityController переключает модальность в touch до
следующего pointermove. Обработчик tip на .room (строка 15907) на
pointermove вызывает _showTip → _notePointer(ev) → if (!this._pointerModality.hoverEnabled) return; — при модальности touch
_tip не устанавливается. Тест проверяет ровно это: c._tip === null
после реального касания, а не факт вызова удалённого статического флага.
Подтверждено экспериментально (не только чтением): все три смока красные на
бандле b7bfc92 (та же картина, что зафиксирована в r1) и зелёные на
c5ba699. Доказано — воспроизведена как первоначальная регрессия
стенда, так и её устранение.
M2 — исправлено, доказано смоком, который умеет упасть
POINTER_HOVER_TARGET_SELECTOR = 'hp-dialog, hp-help, hp-color-opacity, hp-device-preview' — новая единая константа, используемая и в
_syncPointerHoverTargets (полный проход по renderRoot.querySelectorAll
при смене модальности, подписка на строке 736), и в
_syncPointerHoverSubtree (обработчик MutationObserver на добавленные узлы,
строка 2017). hp-device-preview рендерится напрямую в шаблоне карты, то
есть попадает под оба механизма симметрично hp-dialog/hp-help/
hp-color-opacity, ранее уже подключённым тем же способом. Проверено
чтением, не исполнением, в части внутреннего механизма подписки.
Экспериментальная часть: новый ассерт previewHoverGatePropagates в
smoke_device_preview_parity.mjs диспатчит настоящий PointerEvent( 'pointerover', { pointerType: 'mouse' }) на <hp-device-preview> и
проверяет data-pointer-hover и у карты, и у preview. На c5ba699 —
true; при прогоне того же (нового) файла смока против бандла b7bfc92 —
false, тест падает. Это прямое доказательство, что ассерт способен
детектировать именно тот регресс, который описывала находка M2, а не
проверяет тривиально всегда истинное условие.
Юнит-контракт (device-marker-polish-contract.test.mjs) расширен: список
файлов naked-hover-selector сканирования теперь включает
hp-device-preview.ts, и отдельный regex требует, чтобы
POINTER_HOVER_TARGET_SELECTOR содержал hp-device-preview. Доказано.
Проверено и корректно
- Оба Medium из r1 закрыты по существу, не косметически: поведение восстановлено (подтверждено сравнением бандлов до/после фикса), а не просто подогнан ассерт под текущий результат.
- Три копии бандла идентичны; трейлеры
c5ba699корректны (Issue: #212,User-Visible: yes); оба changelog (docs/CHANGELOG.md,docs/CHANGELOG.ru.md) обновлены в том же коммите и формулировка («Device preview» — термин уже используется в этом написании вdocs/specs/212-device-icons-polish.md§5/§13, не изобретён заново). docs/images/screenshots.json— обновлён толькоsourceFingerprint/sourceSha256(бандл изменился),imageSha256не менялся — визуальный результат скриншотов не затронут точечным фиксом,check-docs.mjsподтверждает согласованность.- Расширение
POINTER_HOVER_TARGET_SELECTORне задело существующие цели гейта (hp-dialog,hp-help,hp-color-opacity) — смежные смоки (touch_tips,feedback_v2,help_affordance,device_icon_design) зелёные без изменений. - Diff
b7bfc92..c5ba699не расширяет скоуп: изменены только файлы, напрямую относящиеся к M1/M2 (1 продуктовый файл, 4 смока, 1 юнит-тест, 2 changelog, 1 fingerprint-файл) — без побочных правок «раз уж я здесь». - i18n и backend (
custom_components/**/*.py) не затронуты этим диапазоном.
Чего не проверял
- Полный
demo/smoke_*.mjs(127 файлов) не прогонялся — диапазонb7bfc92..c5ba699узко точечный (M1/M2), прогнаны все 4 напрямую изменённых смока плюс 4 смежных, зависящих от того жеPOINTER_HOVER_TARGET_SELECTOR/PointerModalityController. Остальные AC1–AC16-смоки уже прогонялись и разбирались в CODE-REVIEW-212-r1 и этим диапазоном не затронуты — повторный прогон не добавил бы информации. npm run golden:verify/golden:acceptне запускался в этом цикле — диапазон не меняет геометрию/разметку, только тест-стенд и подписку на DOM-атрибут; визуальный результат (см.imageSha256выше) не изменился. Финальная сверка на Linux CI — пре-релизный гейт (PROCESS.md §8, §13).performance_smoke,python -m pytest tests_backend,npm run inventoryне запускались — вне гейта код-ревью (PROCESS.md §8) и диапазон не трогает Python/производительность.- Геометрический вывод AC1/AC3 и полная AC-трассировка AC1–AC16 не пересматривались повторно — они не входят в диапазон этого цикла и были закрыты по существу в CODE-REVIEW-212-r1.
Вердикт
Обе находки r1 закрыты по существу и подтверждены экспериментально — демонстрацией, что тот же тест/смок красный на коде до фикса и зелёный после, а не только чтением итогового кода. Новых High или Medium в этом диапазоне не найдено; диапазон узкий и не расширяет скоуп задачи.
Вердикт: зелёный · цикл r2/4 · High: 0 · Medium: 0 → в задаче