From e53f9d4f775d55da1051a705f5a83b9b98fab711 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Sat, 26 Sep 2026 10:25:12 +0000 Subject: [PATCH] docs: review document for #664 Issue: #664 User-Visible: no --- docs/reviews/CODE-REVIEW-664-r1.md | 157 +++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 docs/reviews/CODE-REVIEW-664-r1.md diff --git a/docs/reviews/CODE-REVIEW-664-r1.md b/docs/reviews/CODE-REVIEW-664-r1.md new file mode 100644 index 00000000..e51e9040 --- /dev/null +++ b/docs/reviews/CODE-REVIEW-664-r1.md @@ -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, документация архитектуры и мутационный реестр — на +месте. Находок нет. + +**Вердикт: зелёный.** + +--- + + + +## Материал раунда + +- Ветка: `issue/664-static-card-cursor`, коммит `40b73cc5999b` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `5086e070529bcf9e4aecf4936e3a68185f7b4385` + ``` + git log --all --format='%H %T' | grep 5086e070529b + ``` +- Тело issue: `02dc2f7bc5b0b56b6f6e007b39eeae8b17b7bef2ec66a7a1a8461dea63435dd3` +- Вердикт конвейера: `green` · High 0