# CODE-REVIEW-532-r2 Вердикт: **зелёный** · заход r2 · блокирующих циклов израсходовано 1 из 4 · High: 0 · Medium: 0 Материал: `1cfe7fa53c71b2ba595c92d1bdfc560f90242f40`. Ветка приведена к `dev` конвейером: поверх головы задачи (`a89bd1b8`, тот же коммит, что автор назвал хендоффом r2) легло 7 коммитов `dev` (релиз v1.74.0 и посторонняя задача #533), ветка перемотана на `a89bd1b8 → 1cfe7fa5`. Это другой код по §7.2 — разбор ниже полный, а не только по дельте, хотя `origin/dev..HEAD` содержит всего 3 коммита самой задачи. ## Скоуп Issue #532 (не изменился с r1): тройной `drop-shadow` внешнего контура плана (`.hp-paperg`) жил в общем композиционном слое с планом, поэтому любая перерисовка плана (ховер, панорама) заново прогоняла три прохода размытия по габариту всего листа — в Firefox владельца ~9 к/с, 23 МБ текстур/кадр. Правка: `will-change: filter` на `.stage.daycycle .hp-paperg, .hp-static-stage.daycycle .hp-paperg`, уводящее отфильтрованную бумагу в свой слой. Побочный эффект контракта (К2, принят спек-ревью r2): промоушен делит SVG на два слоя, отчего диагональная штриховка стен антиалиасится иначе — 4 golden-кадра `day-cycle-{dawn,day,dusk,night}-dark` расходятся и пересматриваются отдельным коммитом на кандидате беты. Продуктовая рамка (View-режим как продукт для двух персон, `docs/SCOPE.md`) не тронута этим раундом — перечитал `SCOPE.md`, вывод не изменился. Раунд r2 — это ровно исправление двух Medium-находок r1: оба чейнджлога и `docs/SUN.md`. Продуктовый код (`src/styles/plan.styles.ts`), смок (`demo/smoke_daycycle_raster.mjs`) и мутант (`scripts/mutation-gate.mjs`) байт-в-байт не изменились с r1 — доказано ниже, не заявлено. ## Что изменилось между r1 и HEAD (доказательство байт-в-байт для остального) ``` git diff bb04f8605f9003c0ec6643359fa47af9319247bc ced9b416 -- \ src/styles/plan.styles.ts demo/smoke_daycycle_raster.mjs \ scripts/mutation-gate.mjs docs/images/screenshots.json ``` → пустой вывод: коммит `ced9b416` (содержимое головы задачи после ребейза) идентичен коммиту `bb04f8605f90`, который разобрало r1, по всем файлам кроме самих чейнджлогов/`SUN.md`. Единственный новый коммит раунда — `1cfe7fa53c71b2ba595c92d1bdfc560f90242f40` («Say what the day-cycle layer change does to the picture...»), и он трогает только `docs/CHANGELOG.md`, `docs/CHANGELOG.ru.md`, `docs/SUN.md` (14 строк, `User-Visible: no`). Это не молчаливое доверие: равенство деревьев проверено мной командой выше, а не взято со слов автора. ## Как проверялось Validate на `1cfe7fa5` зелёный (https://github.com/Matysh/houseplan-card/actions/runs/34625301309) — `tsc`, `npm test`, `npm run build`+сверка бандла, `check-docs.mjs` не перегонял отдельно, кроме случаев ниже. Прогнал сам (диф трогает рендер CSS через `ced9b416`, хоть и унаследованный от r1 — golden/смок/мутант не покрыты Validate): | Гейт | Команда | Результат | |---|---|---| | Сборка + синхронизация 3 копий бандла | `npm run build && npm run bundle:sync` | чисто, `git status` пуст после — рабочее дерево воспроизводит закоммиченный `dist`/`custom_components/houseplan/frontend`/`demo/srv/assets` побайтово | | Смок-свидетель | `node demo/smoke_daycycle_raster.mjs` | OK, 8/8 (`ratio: 0.78`, другая машина, тот же порядок, что у автора 0.73–0.82) | | Мутант | `node scripts/mutation-gate.mjs --id=daycycle-outline-not-promoted` | «тест покраснел, как обязан» — поймано 1 из 1, рабочее дерево осталось чистым после | | Три копии бандла | `diff -q dist/houseplan-card.js custom_components/houseplan/frontend/houseplan-card.js` + `houseplan-assets.json` | идентичны | | `check-docs.mjs` | `node scripts/check-docs.mjs` | passed (7 files, 12 external links) | Golden-матрицу (169 сценариев) и построчный анализ 4 кадров дневного цикла **не перегонял** — код, который её результат определяет (`plan.styles.ts`), байт-в-байт тот же, что r1 уже прогнало полностью (ровно 4 `different`, bbox и средний цвет посчитаны для всех четырёх кадров самостоятельно, см. `docs/reviews/CODE-REVIEW-532-r1.md`). Замена входа исключена диффом деревьев выше — прогон на неизменных байтах дал бы тот же результат, а сама матрица не из дешёвых. Не прогонял: `pytest tests_backend` (бэкенд не задет), `npm run invariants` (диффа геометрии/модели/`layout`/`marker.space`/`open_spans` нет — раунд чисто документационный, а унаследованный код — чистый CSS), performance- профили Validate (не названы в AC), `smoke-select` заново (диф раунда — доки, не `src/**`; для унаследованного CSS-диффа r1 уже получило и задокументировало «НЕОПРЕДЕЛЁННОСТЬ» и обосновало решение не гонять смежные `smoke_glow*`/ `smoke_discovery_filters` кодом К3/К4 — не переоткрываю). ## Закрытие раунда r1 | Находка r1 | Чем закрыта | Где это видно | |---|---|---| | Medium-1: чейнджлоги утверждали «picture is unchanged, to the pixel» / «не изменилась ни на пиксель», что противоречит К2/AC3 (3.3–3.5 % пикселей расходятся) | Коммит `1cfe7fa5` переписал обе записи: «The view is the same: the outline around the plan matches pixel for pixel, and the hatch inside the walls is anti-aliased a shade differently — splitting the layer moves it by a sub-pixel» (и симметрично по-русски) | `docs/CHANGELOG.md:9-12`, `docs/CHANGELOG.ru.md:15-17` | | Medium-2: `docs/SUN.md` приписывал коэффициент «×15» профилю Firefox, хотя измерен в headless Chromium через CDP | Коммит `1cfe7fa5` разделил источники: «Measured in headless Chromium (CDP tracing, summed `RasterTask`) on a demo-stand pan, that cost about fifteen times…; the owner's Firefox profile that opened #532 showed the same cause as 23 MB of texture uploads per frame and about nine frames per second, without a comparable ratio of its own» | `docs/SUN.md:82-88` | Проверил не по заявлению автора, а построчным чтением обоих файлов после правки (см. выше) — формулировки соответствуют находкам r1 дословно, включая рекомендованную ревьюером r1 замену «a Firefox window» → «our Chromium/CI measurement». ## Унаследовано из r1 Без повторного прогона (дорогие гейты), на основании доказанного выше байт-в-байт равенства `src/styles/plan.styles.ts`, `demo/smoke_daycycle_raster.mjs`, `scripts/mutation-gate.mjs` между `ced9b416` (голова этого раунда) и `bb04f8605f9003c0ec6643359fa47af9319247bc` (материал r1): - AC1/AC2/AC4 (подсказка стоит только под `.daycycle`, отношение растеризации ≤ 2.0, статичный фон не платит) — доказаны в r1 смоком + мутантом; я независимо перепрогнал оба на текущем SHA (таблица выше) вместо чистого наследования. - AC3 количественно (полная golden-матрица 169 сценариев: ровно 4 `different`; средний цвет и bbox расхождения посчитаны r1 лично для всех четырёх кадров `day-cycle-*-dark`, не только `night-dark`; семь «шумных» кадров подтверждены контролем на базе `origin/dev` тем же Chromium) — наследую без повторного прогона матрицы, см. документ `docs/reviews/CODE-REVIEW-532-r1.md`, SHA `bb04f8605f9003c0ec6643359fa47af9319247bc`. - Структурные факты кодом: `demo/golden/matrix.mjs` содержит ровно 4 сценария с `bgMode: 'daynight'`; `svgScreenBlendSupported` (`src/glow-blend.ts`) не читает `bg_mode` (К4 вне скоупа подтверждено кодом); `.hp-paperg` — только бумажные силуэты (`src/houseplan-card.ts`), не меняется на ховере/панораме. Файлы не изменились с r1 — наследую вывод. - Риск 5 ТЗ (`smoke-select` не находит связь для чисто-CSS диффа) — подтверждён независимо в r1, код не изменился — наследую. - Трейлеры и три копии бандла коммита `ced9b416` (`Issue: #532`, `User-Visible: yes`, оба чейнджлога в одном коммите с поведением) — уже проверены в r1 и не менялись; коммит `1cfe7fa5` несёт свои корректные трейлеры (`Issue: #532`, `User-Visible: no` — меняется только формулировка, не поведение), проверено мной заново. ## Что проверено и корректно (этот раунд) - Оба чейнджлога и `docs/SUN.md` больше не содержат ни одного из двух утверждений, отмеченных r1 как противоречащих контракту задачи; новые формулировки проверяемы читателем и не смешивают источники чисел. - `1cfe7fa5` несёт `Issue: #532` и `User-Visible: no` — корректно: меняется только текст о поведении, не само поведение. - Рабочее дерево после `npm run build && npm run bundle:sync` совпадает с закоммиченными `dist/**`, `custom_components/houseplan/frontend/**`, `demo/srv/assets/**` побайтово (`git status` пуст) — сборка воспроизводима на этом SHA. - `docs/images/screenshots.json` не менялся в этом раунде (проверено диффом дерева) — отпечаток документации не поехал. - Продуктовый вопрос автора из хендоффа r1 («приемлема ли цена пересъёмки 4 эталонов») закрыт зелёным спек-ревью r2 и не переоткрывается: этот раунд не трогает К2/AC3 по существу, только их описание в публичных доках. ## Чего не проверял - `pytest tests_backend` — `custom_components/**/*.py` не задет. - `npm run invariants` — геометрия/модель/`layout`/`marker.space`/ `open_spans` не задеты; унаследованный код — чистый CSS без геометрии. - Полная golden-матрица заново — код, который её результат определяет, не изменился (доказано диффом деревьев); повторный прогон на тех же байтах не добавляет информации, а гейт дорогой. - Performance-профили Validate — не названы в AC. - `smoke-select` заново — диф раунда лежит только в `docs/**`, инструмент по документации не разрешает связей; для унаследованного CSS-диффа ответ r1 («НЕОПРЕДЕЛЁННОСТЬ») не переоткрываю. - Приговор по настоящему Firefox (профиль владельца до/после этой конкретной правки текста) — вне возможностей код-ревью и не AC этой задачи. --- **Материал раунда:** SHA `1cfe7fa53c71b2ba595c92d1bdfc560f90242f40`, `origin/dev..HEAD` = 3 коммита (`ced9b416` — голова задачи после ребейза, байт-в-байт равна материалу r1; `3322c20c` — публикация документа r1; `1cfe7fa5` — исправление по r1, единственный содержательный коммит раунда). Полный разбор по указанию конвейера (ребейз через 7 чужих коммитов, §7.2), с опорой на доказанное byte-for-byte наследование дорогих гейтов из r1. **Предыдущий раунд:** `docs/reviews/CODE-REVIEW-532-r1.md`, вердикт жёлтый, материал `bb04f8605f9003c0ec6643359fa47af9319247bc`. --- ## Материал раунда - Ветка: `issue/532-daycycle-raster`, коммит `1cfe7fa53c71` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала: `0da2d90f30f9e607782d065fe23fc1e770c7e676` ``` git log --all --format='%H %T' | grep 0da2d90f30f9 ``` - Тело issue: `12e66588332b94c78100156f01e4832881b8163fb6f8fdca83acfcb8e90f4545` - Вердикт конвейера: `green` · High 0