Files
houseplan-card/docs/reviews/CODE-REVIEW-528-r1.md
T
2026-09-11 07:09:35 +00:00

134 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CODE-REVIEW — issue #528, заход r1
**SHA материала:** `f37ccdcebc3f454cb03c8cd25f5081a45eb4e22f` (рабочая копия уже на нём)
**Ветка:** `issue/528-marker-identity-witness`
**Класс изменения:** B (`demo/smoke_space_switch_transitions.mjs`) — issue переиспользован, продуктовый код и реестр мутантов не тронуты (совпадает с заявленным «Ограниченный объём»).
## Скоуп
Свидетель #525 (`demo/smoke_space_switch_transitions.mjs`) ловил мутант
`device-markers-rendered-without-keys` через побочный признак: отсутствие
бегущего перехода `box-shadow` на `.device-shell-frame` после переключения
пространства. #524 убрал этот переход из стилей (перф-регрессия Firefox),
признак стал тривиально истинным, и позиционное переиспользование DOM-узлов
маркеров перестало ловиться — свидетеля ослепили не намеренно, а как
побочный эффект соседней задачи.
Задача #528 узкая: маркерная половина свидетеля должна судить по идентичности
узла (`data-id` привязанного к узлу до/после переключения), а не по анимации.
Дверная половина (`op-leaf`/`op-arc`) остаётся как есть — там переход часть
продуктового контракта (#525) и её не просили трогать.
## Диф (весь, 16 строк)
Один файл, `git diff origin/dev...HEAD --stat`:
```
demo/smoke_space_switch_transitions.mjs | 17 ++++++++++++++++-
```
Добавлено:
1. Перед первым переключением (`c._pickSpace(ids[0])`) собираются ссылки на
все узлы `[data-hp="device"]` вместе с их `data-id` (`markersBefore`).
2. `markersDrawnInTheFirstSpace = markersBefore.length >= 3` — страховка от
вырожденного сравнения на пустом множестве (сама тоже проверяется
`checkAll`, дефолт `true`).
3. После второго `_pickSpace` вычисляется `reused` — узлы из `markersBefore`,
которые остались подключены (`isConnected`) и сменили `data-id`;
`noMarkerNodeReusedForAnotherDevice` и диагностический список
`reusedMarkerNodes` (ожидаемо пустой, `checkAll(res, { ..., reusedMarkerNodes: [] })`).
4. Старая проверка `noMarkerTransitionOnSwitch` (по переходу оболочки) не
удалена — она просто перестала быть единственной, что безопасно (AC не
требовал её убирать).
## Как проверялось
**Дешёвые гейты этого SHA уже зелёные** (Validate
[34572622663](https://github.com/Matysh/houseplan-card/actions/runs/34572622663),
success): `typecheck`/`test`/`build` не перегонял — diff не трогает `src/**`,
`test/**` юнитов, конфиги сборки. `node scripts/check-docs.mjs` также не
требуется: diff не задевает `src/**`, отпечаток скриншотов не устаревает.
`node scripts/smoke-select.mjs --base 78bc76073ea2...(merge-base) --head HEAD`
подтвердил ожидаемое: «Исполняемого frontend-диффа нет (`src/**/*.ts` не
тронут)», browser-smoke по этому инструменту не выбираются — выбирать
нечего, изменённый файл сам и есть свидетель.
Главная проверка — не общий гейт, а прямое доказательство по AC, и оно уже
есть на этом самом SHA в логах Validate, job «Мутанты по диффу (1/6)»
(id `103177915852`):
```
07:05:52 ok чистый прогон: node demo/smoke_space_switch_transitions.mjs
07:06:16 ok device-markers-rendered-without-keys: тест покраснел, как обязан
```
Это ровно то, что требуют AC2 и AC3: чистый (немутированный) прогон смока
целиком зелёный, и на замутированном коде (`repeat(devs, (d) => d.id, ...)` →
`devs.map(...)` в `src/houseplan-card.ts:11787`, реестр
`scripts/mutation-gate.mjs:7325`) свидетель краснеет. Не заявление автора —
факт из лога CI на материале ревью.
Дополнительно прочтением (без исполнения):
- `demo/serve.mjs:68-78` (`check`/`checkAll`) — сравнение через
`JSON.stringify`, так что `reusedMarkerNodes: []` в `checkAll` действительно
требует пустой массив, а не просто «поле определено».
- `src/space-render.ts:607` — реальная разметка маркера несёт
`data-hp="device" data-id="${d.id}"`, соответствует селектору смока.
- `src/styles/devices.styles.ts:200-215` — `.device-shell-frame` сейчас имеет
только `transition: border-color .15s, opacity .2s` (без `box-shadow`),
подтверждает описанную в issue причину: старый переход правда убран #524,
и старая проверка правда стала тривиальной.
- Логика `reused` (строки 124-129): узел считается «переиспользованным
чужим id», только если он ещё подключён к дереву (`isConnected`) и его
`data-id` изменился относительно зафиксированного до переключения — именно
позиционное переиспользование, а не обычное удаление узла или сохранение
того же устройства между пространствами (когда `data-id` не меняется).
Разобрано корректно.
## Проверено и корректно
- AC1 — реализовано: сравнение по ссылкам на узлы, а не по CSS-переходу;
подтверждена и защита от вырожденного случая (`markersDrawnInTheFirstSpace`).
- AC2 — доказано логом CI на этом SHA (мутант красный), не голым заявлением.
- AC3 — доказано тем же логом («чистый прогон» = OK целиком); дверная
половина (`op-leaf`/`op-arc`, `noOpeningTransitionOnSwitch`,
`theTwoDoorsDifferInState` и т. д.) не тронута, дифф это подтверждает.
- Трейлеры: `Issue: #528`, `User-Visible: no` — верно, диф не меняет
видимое поведение продукта, changelog не требуется.
- Скоуп: ни продуктовый код, ни `scripts/mutation-gate.mjs` не изменены —
соответствует заявленному в issue ограничению.
## Чего не проверял и почему
- `npx tsc --noEmit`, `npm test`, `npm run build`, сверку бандла —
не требуется: diff не трогает `src/**`/`test/**`/конфиги сборки, а Validate
на этом же SHA уже зелёный.
- `node scripts/check-docs.mjs` — diff не трогает `src/**`.
- `npm run invariants` — diff не трогает геометрию/toplogy/marker.space.
- `npm run golden:verify` — diff не может изменить видимый рендер (только
тестовый файл).
- `python -m pytest tests_backend` — Python не тронут.
- Полный прогон `demo/smoke_*.mjs` вручную — не требуется отдельно: ровно тот
смок, который меняется, уже прогнан CI на материале ревью дважды (чистый и
замутированный), что сильнее локального прогона без мутанта.
## Вердикт
Зелёный. AC1–AC3 выполнены и подтверждены логом CI на самом материале
ревью, а не заявлением автора; изменение в границах заявленного скоупа,
трейлеры верны.
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/528-marker-identity-witness`, коммит `f37ccdcebc3f` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `3a16a24c59b27eac3280c63ce77f48ca13875750`
```
git log --all --format='%H %T' | grep 3a16a24c59b2
```
- Тело issue: `f178b89645d3d0967d356c110b81f4262fd676aa9b7bf30203cb8ffb9b63190b`
- Вердикт конвейера: `green` · High 0