docs: review document for #664

Issue: #664
User-Visible: no
This commit is contained in:
claude[bot]
2026-09-26 10:25:12 +00:00
parent 40b73cc599
commit e53f9d4f77
+157
View File
@@ -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