mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
@@ -0,0 +1,157 @@
|
||||
# CODE-REVIEW-664-r1
|
||||
|
||||
Issue: #664 · этап: code · заход: r1 · материал: `40b73cc5999be6fc8f06eb5cac63f74e6c41c4f6`
|
||||
(1 коммит поверх `origin/dev` `6cdcb1ea`) · трек: `trivial`, короткий · блокирующих циклов
|
||||
использовано 0 из 2 (бюджет тратят только жёлтый/красный, а этот вердикт зелёный).
|
||||
|
||||
## Скоуп
|
||||
|
||||
Регрессия #564 (v1.76.0-beta.2): общие стили маркеров открывают
|
||||
`pointer-events: auto` на `.dev::before` (44 px пол) и `.device-shell-frame`
|
||||
(капсула) — для интерактивного плана это нужно, но статическая карточка
|
||||
`houseplan-space-card` импортирует те же стили целиком, и потомки внутри
|
||||
`.hp-static-stage` (которая объявлена `pointer-events: none`) снова стали
|
||||
целью хит-теста: курсор-«рука» и клики, уходящие в никуда, на контрактно
|
||||
read-only поверхности.
|
||||
|
||||
Работа обслуживает J1/J3 (`docs/SCOPE.md`) косвенно — не ломает их, а убирает
|
||||
ложное приглашение к действию там, где действия по контракту нет; это
|
||||
починка нарушенного UX-контракта, а не новая функциональность.
|
||||
|
||||
Диапазон: `src/space-card.ts`, `demo/smoke_space_card.mjs`,
|
||||
`scripts/mutation-registry.mjs`, `docs/ARCHITECTURE.md`, `docs/CHANGELOG.md`,
|
||||
`docs/CHANGELOG.ru.md`, `docs/images/screenshots.json` (только отпечаток).
|
||||
7 файлов, +95/−14 — совпадает с хендоффом.
|
||||
|
||||
## Как проверялось
|
||||
|
||||
Прочитан весь дифф построчно (`git diff origin/dev...HEAD`), тело issue,
|
||||
оценка владельца и хендофф автора. Правило `.hp-static-stage *,
|
||||
*::before, *::after { pointer-events: none }` (`src/space-card.ts:952-963`)
|
||||
разобрано по каскаду: специфичность `.hp-static-stage *::before` и
|
||||
`.dev::before` из `devices.styles.ts:185` равна (0,1,1) — как и
|
||||
`.hp-static-stage *` против `.device-shell-frame` (0,1,0) — побеждает
|
||||
источник, идущий позже в массиве `static styles = [cardStyles, css\`...\`]`
|
||||
(Lit сохраняет порядок вставки правил, `cardStyles` первый); значит новое
|
||||
правило переопределяет оба opt-in на равной специфичности не случайно, а по
|
||||
объявленному порядку каскада. Проверено чтением, подтверждено
|
||||
исполнением (ниже).
|
||||
|
||||
Проверено исполнением (не только чтением):
|
||||
|
||||
1. `npm run bundle:sync` — сборка чистая (tsc + rollup + bundle-sync).
|
||||
2. `node demo/smoke_space_card.mjs` на материале — зелёный,
|
||||
`markerProbe.insideStage=false`, `stageGridHitsInside=0/63`,
|
||||
`stageGridPointerCursors=0` — совпадает с числами из хендоффа.
|
||||
3. **Мутация вручную**: вырезал правило `.hp-static-stage *, *::before,
|
||||
*::after {...}` из `src/space-card.ts`, пересобрал, прогнал тот же смок —
|
||||
`FAIL space-card smoke`, `markerProbe = {insideStage: true, element:
|
||||
"span.device-shell-frame", cursor: "pointer"}`, `stageGridHitsInside=1` —
|
||||
дословно совпадает с заявленным в таблице AC «чем краснеет». Файл
|
||||
восстановлен, пересобран (`git status` — чисто).
|
||||
4. `node scripts/mutation-gate.mjs --check` — весь реестр `ok`, включая
|
||||
новую запись `static-card-descendants-hit-testable` (это то же самое, что
|
||||
пункт 3, но через штатный гейт, а не только вручную).
|
||||
5. `node scripts/smoke-select.mjs --base origin/dev --head HEAD` —
|
||||
«НЕОПРЕДЕЛЁННОСТЬ», 0 символов проекта на изменённых строках — совпадает
|
||||
с тем, что назвал автор; связанный смок (`smoke_space_card`) назван и
|
||||
прогнан отдельно (пункты 2-3).
|
||||
6. `node scripts/check-docs.mjs` — passed (дифф трогает `src/**`).
|
||||
7. Разобрана таблица AC/доказательство/мутация из хендоффа автора — числа и
|
||||
имена элементов (`span.device-shell-frame`, `div.hp-static-body`)
|
||||
совпадают с моим независимым прогоном пункта 3, это не переписанное
|
||||
заявление автора, а воспроизведённый результат.
|
||||
8. Проверено (чтением), что фикстура смока не задевает AC1 в части
|
||||
пылесоса: `spaceId = window.__card._model[0].id` — первое пространство
|
||||
(`f1`); `d_mower` (единственное устройство-пылесос демо-конфига,
|
||||
`demo/srv/demo.html`) размещён в пространстве `garden`, а не `f1`. Условие
|
||||
«при наличии пылесоса в фикстуре» не наступает для карточки, которую
|
||||
рендерит этот смок — пропуск отдельной проверки пылесоса не является
|
||||
пробелом AC1, а корректным отсутствием применимого случая.
|
||||
9. Проверено (чтением), что `_renderRecoveryOverlay()` — сосед `stage`
|
||||
внутри `.hp-static-body`, а не потомок `.hp-static-stage`
|
||||
(`src/space-card.ts:914-917`), поэтому новое правило `.hp-static-stage
|
||||
*` не может случайно закрыть интерактивность overlay восстановления,
|
||||
если он когда-либо получит собственные контролы.
|
||||
10. Проверено (чтением) `git diff` на `docs/images/screenshots.json`: из 11
|
||||
изменённых блоков во всех меняется только `sourceSha256`/
|
||||
`sourceFingerprint` (хеш собранного бандла), ни одна строка
|
||||
`imageSha256` (хеш самого PNG) не входит в добавленные/удалённые строки
|
||||
диффа — 11 кадров действительно попиксельно идентичны, как заявлено.
|
||||
11. Трейлеры коммита: `Issue: #664`, `User-Visible: yes`; оба changelog
|
||||
(`docs/CHANGELOG.md`, `docs/CHANGELOG.ru.md`) правятся в этом же
|
||||
коммите — условие §3 п.10 выполнено.
|
||||
12. Единственное видимое пользователю число в дифф-тексте (Changelog) —
|
||||
ссылка на версию `v1.76.0-beta.2`, это ссылка на существующий релиз, не
|
||||
новое число с двумя источниками; отдельного «одно число — один
|
||||
источник» риска в этом диффе нет.
|
||||
|
||||
Дешёвые гейты (typecheck/test/build+bundle-policy) не перегонялись отдельно:
|
||||
подтверждены зелёным Validate на этом же SHA
|
||||
(https://github.com/Matysh/houseplan-card/actions/runs/36234983969), что
|
||||
совпадает с независимым прогоном `npm run bundle:sync` (build+tsc) в пункте 1.
|
||||
|
||||
## Находки
|
||||
|
||||
Нет ни одной находки High или Medium. Дифф закрывает ровно заявленный дефект,
|
||||
не трогает интерактивную карточку (`#564` там не отменяется), контракт
|
||||
`docs/ARCHITECTURE.md` обновлён вместе с кодом, оба changelog присутствуют,
|
||||
защитный AC3 доказан таблицей с непустым третьим столбцом и я независимо
|
||||
воспроизвёл его результат.
|
||||
|
||||
## Что проверено и корректно
|
||||
|
||||
- AC1 — ничто в `.hp-static-stage` не цель хит-теста: воспроизведено
|
||||
(`elementFromPoint` по маркеру и сетке 9×9 не находит ничего внутри сцены).
|
||||
- AC2 — курсор не `pointer`, кнопка кликабельна: воспроизведено (`cursor:
|
||||
auto` на цели хит-теста, `deepLink` содержит `#space=`, было и раньше).
|
||||
- AC3 — мутант красит AC1/AC2: воспроизведено вручную и штатным
|
||||
`mutation-gate.mjs`, результат совпадает с заявленным дословно.
|
||||
- Каскад CSS выбирает нужное правило по source order при равной
|
||||
специфичности — разобран по коду, не только принят на слово.
|
||||
- Область поражения — только статическая карточка; полная карточка
|
||||
(`#564`) не затронута дифф-текстом за пределами `src/space-card.ts`.
|
||||
- Документация (`ARCHITECTURE.md`) и оба changelog обновлены в одном
|
||||
коммите с трейлерами `Issue`/`User-Visible`.
|
||||
- `check-docs.mjs` зелёный.
|
||||
- Скриншот-снапшот — только отпечаток источника, изображения не менялись.
|
||||
|
||||
## Чего не проверял
|
||||
|
||||
- Полную матрицу смоков, `golden:verify`, perf-профили, `pytest
|
||||
tests_backend` — не названы в AC, диффа Python нет, перф не задет; это
|
||||
совпадает с тем, что назвал автор в разделе «не прогонял», и я с этим
|
||||
согласен: изменение — CSS-правило одной поверхности плюс тест, который его
|
||||
ловит.
|
||||
- `npm test` полным прогоном (все `node --test test/*.test.mjs` части) и
|
||||
`npm run build` со сверкой трёх копий бандла отдельно от Validate — принял
|
||||
зелёный статус Validate на этом же SHA как подтверждение (ссылка выше);
|
||||
`npm run bundle:sync`, который я прогнал сам, включает build+tsc и
|
||||
является независимым частичным повторением.
|
||||
- Ручное тестирование в браузере вне playwright-смока (реальный HA,
|
||||
реальный тачскрин) — вне рамок код-ревью на коротком треке; смок
|
||||
`elementFromPoint` — адекватная замена для контракта read-only-курсора,
|
||||
сам провёл его дважды (материал + мутация).
|
||||
|
||||
## Вывод
|
||||
|
||||
Все три AC доказаны исполнением, а не только заявлением автора; защитный
|
||||
AC3 закрашен воспроизведённой мутацией с совпадающими деталями. Скоуп,
|
||||
трейлеры, changelog, документация архитектуры и мутационный реестр — на
|
||||
месте. Находок нет.
|
||||
|
||||
**Вердикт: зелёный.**
|
||||
|
||||
---
|
||||
|
||||
<!-- material-anchors: сгенерировано конвейером (#414) -->
|
||||
|
||||
## Материал раунда
|
||||
|
||||
- Ветка: `issue/664-static-card-cursor`, коммит `40b73cc5999b` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
|
||||
- Дерево материала: `5086e070529bcf9e4aecf4936e3a68185f7b4385`
|
||||
```
|
||||
git log --all --format='%H %T' | grep 5086e070529b
|
||||
```
|
||||
- Тело issue: `02dc2f7bc5b0b56b6f6e007b39eeae8b17b7bef2ec66a7a1a8461dea63435dd3`
|
||||
- Вердикт конвейера: `green` · High 0
|
||||
Reference in New Issue
Block a user