Files
houseplan-card/docs/reviews/CODE-REVIEW-525-r1.md
T
claude[bot] 8ba87b3ff7
Проверка (CI) / Классификация изменённых файлов (push) Successful in 1m47s
Проверка (CI) / Мутанты по диффу (1/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (2/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (3/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (4/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (5/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (6/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Предполётные проверки: документация, провенанс, процесс (push) Failing after 2m51s
Проверка (CI) / Hassfest: манифест интеграции (push) Failing after 1m23s
Проверка (CI) / HACS: валидация репозитория (push) Failing after 1m44s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 2m14s
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Failing after 4m45s
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Failing after 8m4s
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Skipped
Проверка (CI) / Смоки: все шарды зелёные (push) Skipped
Проверка (CI) / Golden-кадры против принятых эталонов (push) Skipped
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Skipped
docs: review document for #525
Issue: #525
User-Visible: no
2026-09-11 02:00:05 +00:00

165 lines
16 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-525-r1
Issue: #525 · Заход r1 · блокирующих циклов израсходовано 0 из 4
Материал ревью: `ab296302d179ff7a3bd047591db35ff67c92a683` (рабочая копия на нём).
Ветка приведена к `dev` конвейером до ревью (1 коммит dev поверх, `6bb34720` →
`ab296302` — это перебазирование тех же трёх коммитов, SHA сменились). Согласно
§7.2, после ребейза это другой код — разбор ниже полный, а не по дельте.
## Скоуп
Три коммита:
| SHA | Класс | Что |
|---|---|---|
| `9edef041` | A+B+C, `User-Visible: yes` | `_renderOpenings` и список маркеров переведены на `repeat(…, (x) => x.id, …)`; комментарий-ловушка в `plan.styles.ts`; новый смок `demo/smoke_space_switch_transitions.mjs`; два мутанта в `mutation-gate.mjs`; тест-линт AC5 в `test/smoke-harness-contract.test.mjs`; потолок `bundle-budget.mjs` 300 400 → 300 700; оба changelog; пересобранный бандл |
| `8d5bade6` | C | обновлён `docs/images/screenshots.json.sourceFingerprint` (фингерпринт по `src/**`, картинки не менялись) |
| `ab296302` | B | запись `_renderDevice`/`_renderOpenings` → `smoke_space_switch_transitions.mjs` в `scripts/smoke-links.mjs` |
Продуктовый диф минимален: `src/houseplan-card.ts` — две строки (`map` → `repeat`
в обоих списках), `src/styles/plan.styles.ts` — только комментарий. Совпадает с
ТЗ («Чего задача не трогает»): i18n, миграция конфига, touch, бэкенд и
публичные API диф не задевает — подтверждено чтением всего диффа, посторонних
изменений нет.
## Как проверялось
Дешёвые гейты Validate на этом SHA уже зелёные (ссылка в задаче ревьюеру),
поэтому `tsc`/`test`/`build` заново не гонял. Прогнал сам:
| Гейт | Команда | Результат |
|---|---|---|
| Смок-свидетель | `node demo/smoke_space_switch_transitions.mjs` | OK, все 12 проверок `true`, `unexpectedAnimations: []` |
| Мутант AC1 | `node scripts/mutation-gate.mjs --check` (id `openings-rendered-without-keys`) | `ok` — гейт сам собирает бандл в отдельном воркчисте, патчит `repeat`→`map`, смок красный, воркчист убран |
| Мутант AC2 | тот же прогон (id `device-markers-rendered-without-keys`) | `ok`, аналогично |
| Тест-линт AC5 | `node --test test/smoke-harness-contract.test.mjs` | 8/8 pass, включая новый `свидетель переходов при переключении меряет поэлементно (#525)` |
| Бюджет бандла | `node scripts/bundle-budget.mjs` | `initial View: 300059 B gzip (потолок 300700 ±2000, budget 301066, headroom 1007)` — совпадает с текстом коммита до байта |
| Документация | `node scripts/check-docs.mjs` | `Documentation checks passed (7 files, 12 external links)` |
| smoke-select по диффу | `node scripts/smoke-select.mjs --base origin/dev --head HEAD` | «Зарегистрированная связь»: `smoke_space_switch_transitions.mjs` ← `_renderDevice` — до третьего коммита была бы «НЕОПРЕДЕЛЁННОСТЬ», запись это чинит |
| Golden | `npm run golden:verify` | зелёный, 80/80 кадров `passed`, включая все `junction-*`, `openings-*`, `device-*`, `lighting-*` — риск переупорядочивания DOM из ТЗ не реализовался |
| Смежные смоки редактора | `node demo/smoke_device_position_history.mjs`, `node demo/smoke_drag_bounds.mjs` | оба OK (риск «идентичность в живом пути» из ТЗ) |
| Perf (AC6) | `npm run benchmark:large-house-interaction` (без базы) | завершился штатно, порядок величин (`spaceSwitch` max 636 мс, `switchCycle` max 623/total 1211 мс за 3 наблюдения) правдоподобен относительно заявленных медиан 524.8/1293.9 мс |
Не прогонял сам: `benchmark:compare` против базы `19e421b3` (нужен отдельный
воркчист на другом SHA для сборки базового отчёта — дорого при уже дважды
независимо сошедшихся числах, см. AC6 ниже), `npx tsc --noEmit`/`npm
test`/`npm run build` (взяты с зелёного Validate на этом SHA), HA-бэкенд
(`custom_components/**` не тронут), полный набор смоков (диф не задевает
ничего вне `_renderOpenings`/`_renderDevice`/стилей переходов).
## AC · чем доказан · чем краснеет (проверено, не только заявлено)
| # | AC | Доказательство | Чем краснеет | Проверил сам |
|---|---|---|---|---|
| AC1 | нет перехода на `.op-leaf`/`.op-arc` после переключения | `demo/smoke_space_switch_transitions.mjs` → `noOpeningTransitionOnSwitch` | мутант `openings-rendered-without-keys` | да, смок зелёный + мутант красный на отдельном прогоне |
| AC2 | нет перехода `box-shadow` на `.device-shell-frame` | тот же смок → `noMarkerTransitionOnSwitch` | мутант `device-markers-rendered-without-keys` | да, аналогично |
| AC3 | бегут только законные анимации после переключения | `onlyTheSwitchItselfAnimates` + `stillQuietOneFrameLater`, обход всего теневого дерева | любое новое переиспользование — красный список `unexpectedAnimations` | да, поле пустое на прогоне |
| AC4 | настоящая смена состояния двери внутри пространства по-прежнему анимируется | `aRealDoorOpeningStillAnimates` | удаление перехода — смок красный (не проверял мутантом отдельно, но логика симметрична AC1: тот же переход, инверсия проверки) | смок зелёный, чтением подтверждена симметрия проверки |
| AC5 | свидетель меряет поэлементно, не по документу | `test/smoke-harness-contract.test.mjs`, новый кейс | возврат `document.getAnimations()` — тест красный | да, 8/8 pass, код смока подтверждает поэлементный обход `shadowRoot` |
| AC6 | перф в пределах лимитов | таблица в хендоффе, лимиты пересчитаны ревьюером ТЗ независимо (SPEC-REVIEW-525-r1) | превышение лимита — job красный | частично: сам гейт не гонял A/B против базы, полагаюсь на сходящиеся независимые числа (см. «чего не проверял») |
AC4 не имеет отдельного мутанта в реестре — это не находка: симметрия
проверки («переход должен идти» вместо «перехода не должно быть») делает
ложноположительный смок маловероятным, а сам факт `aRealDoorOpeningStillAnimates: true`
воспроизведён прогоном.
## Находки
Находок нет. Три отступления от буквы ТЗ, названные автором в хендоффе,
рассмотрены и приняты:
1. **Комментарий-ловушка не в `houseplan-card.ts`, а в `plan.styles.ts`.**
Причина объективна и проверена: файл стоит ровно на потолке
`core-file-budget` (13649 строк при лимите 13650 — перепроверил `wc -l` и
тестовый лимит в `test/core-file-budget.test.mjs:26`). Перенос комментария
к самим переходам логичнее — это точка, которую откроет автор следующего
анимируемого свойства.
2. **`repeat` вместо `keyed`** — цена проверена автором (+241 Б против +373 Б),
решение соответствует контракту ТЗ буквально («Ключ проёма — `o.id`»,
упоминание `repeat` явно).
3. **Запись в `scripts/smoke-links.mjs`** вне первой редакции ТЗ, но устраняет
реальный пробел («НЕОПРЕДЕЛЁННОСТЬ» → «зарегистрированная связь», проверено
прогоном `smoke-select` до и по смыслу описано в AGENTS.md как штатный
инструмент). Класс B, тот же issue — правомерно.
Риски ТЗ («цена ключей», «golden», «идентичность в живом пути», «потеря
настоящей анимации») все закрыты проверкой, а не только словом автора: цена
ключей подтверждена гейтом бюджета бандла с точным числом, golden зелёный на
80 кадрах, `drag_bounds`/`device_position_history` зелёные, AC4 зелёный.
## Что проверено и корректно
- Диф продуктового кода ограничен двумя строками (`map` → `repeat`) плюс
стилевой комментарий — соответствует заявленному объёму и ТЗ.
- Единственные точки рендера списков проёмов (`_renderOpenings`, вызывается из
одного места, `:11741`) и маркеров (`:11787`) — оба переведены на `repeat`;
других мест, рисующих `.op-leaf`/`.op-arc`/`.device-shell-frame` через
списочный `map`, в `src/*.ts` нет (проверено `grep`). `src/space-render.ts` —
отдельный статический рендерер (`space-card.ts`), строит HTML-строку без
инкрементального Lit-diffing и под контракт AC1–AC3 не подпадает; ТЗ его и
не называет.
- Трейлеры: все три коммита несут `Issue: #525`; `9edef041` — `User-Visible:
yes` с правками обоих changelog в этом же коммите (проверено `git show
--stat`); `8d5bade6` и `ab296302` — `User-Visible: no`, что верно (docs- и
gate-правки без видимого поведения).
- Терминология changelog («пространства», «двери и окна», «створка») совпадает
с `docs/USER-GUIDE.ru.md`.
- Тело issue после зелёного ревью ТЗ менялось (добавлен абзац «чего не
трогает» и переписан черновик changelog) — автор сам назвал это в
комментарии до перехода в `S6`, повторно свежий текст сверен построчно с
реализацией, расхождений нет.
- `docs/images/screenshots.json`: все 11 `imageSha256` в диффе не изменились
(проверено `git diff` — строки без `+`/`-`), меняется только
`sourceFingerprint`/`sourceSha256` — соответствует правилу «фингерпринт
считается по всему `src/**`».
## Чего не проверял и почему
- `npx tsc --noEmit`, `npm test`, `npm run build` — сверены с зелёным Validate
на точном SHA `ab296302` (см. ссылку в постановке задачи ревьюеру).
- `npm run benchmark:compare` против базы `19e421b3` — не воспроизводил A/B:
потребовал бы отдельного воркчиста на другом коммите и полного цикла из 7
образцов на обеих версиях. Сам факт «работает без ошибок» и правдоподобие
порядка величин проверил (см. таблицу выше); числа AC6 дополнительно
сходятся с независимым пересчётом лимитов ревьюером ТЗ (`SPEC-REVIEW-525-r1.md`,
формула `max(база×(1+ratio), база+noise)` с `hardMaxMs`, совпадение до
сотых). Если это признать недостаточным — единственный пункт, который стоит
перепроверить отдельным прогоном.
- `python -m pytest tests_backend` — `custom_components/**/*.py` не тронут.
- Полный набор `demo/smoke_*.mjs` (240 файлов) — не запускал: диф ограничен
двумя рендерерами и стилевым комментарием, `smoke-select` дал ровно одну
«зарегистрированную связь», смежные риски (редактор, golden) проверены
прицельно.
- Инварианты модели (`npm run invariants`) — диф не трогает геометрию, толщину
стен, `layout`, `marker.space` или `open_spans`; это чисто слой отрисовки
(Lit-директива), гейт не применим.
## Материал раунда
- SHA ветки: `ab296302d179ff7a3bd047591db35ff67c92a683`
- Дерево материала: рабочая копия на этом SHA, детальный `HEAD` detached
- Диапазон: `origin/dev..HEAD` = `9edef041`, `8d5bade6`, `ab296302`
- ТЗ: тело issue #525, раздел `## ТЗ`, зелёное ревью
`docs/reviews/SPEC-REVIEW-525-r1.md`
## Вердикт
Зелёный. AC1–AC6 доказаны (AC6 — с оговоркой, см. «чего не проверял»), защитные
AC1/AC2/AC5 подтверждены собственным прогоном мутантов и тестов, риски ТЗ
закрыты проверяемо, находок High/Medium нет.
---
<!-- material-anchors: сгенерировано конвейером (#414) -->
## Материал раунда
- Ветка: `issue/525-space-switch-transitions`, коммит `ab296302d179` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
- Дерево материала: `2b749e6ac7af5d0cb523647be6fbf0bccce999ad`
```
git log --all --format='%H %T' | grep 2b749e6ac7af
```
- Тело issue: `786c461d9a358bfeb155d707363704ca5568415678b3d326d4240bed4ec75908`
- Вердикт конвейера: `green` · High 0