From 1df463d7cfe5df951475fbe9438acd68d32ddaa6 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Mon, 14 Sep 2026 20:24:25 +0000 Subject: [PATCH] docs: review document for #579 Issue: #579 User-Visible: no --- docs/reviews/CODE-REVIEW-579-r2.md | 155 +++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 docs/reviews/CODE-REVIEW-579-r2.md diff --git a/docs/reviews/CODE-REVIEW-579-r2.md b/docs/reviews/CODE-REVIEW-579-r2.md new file mode 100644 index 00000000..3473d95f --- /dev/null +++ b/docs/reviews/CODE-REVIEW-579-r2.md @@ -0,0 +1,155 @@ +# CODE-REVIEW-579-r2 + +Issue: [#579](https://github.com/Matysh/houseplan-card/issues/579) — «WebView pinch compositor churn» +Материал: `2c7abe7938ded08d63f277269d8b7e52c04e2d4d` (диапазон `origin/dev..HEAD`: продуктовый коммит +`216990e4` + служебные документы ревью + тестовый коммит `2c7abe79`) +Заход: r2 (разбор по дельте от r1, PROCESS.md §2.9) +Блокирующих циклов израсходовано: 1 из 4 (потрачен r1; зелёный вердикт бюджет не тратит, #227) + +## Скоуп раунда + +r1 (`docs/reviews/CODE-REVIEW-579-r1.md`, коммит `9bae4d28`, вердикт жёлтый на материале +`216990e4`) закрыл всё, кроме одной находки: **M1 — AC4 (матрица day cycle/Glow/room fills/ +hatching/фон) не имела тестового доказательства**. Между `216990e4` и `HEAD` лежит ровно один +новый коммит: + +``` +2c7abe79 test: cover live viewport effects matrix (#579) +``` + +`git diff 216990e4..HEAD --stat`: + +``` + demo/smoke_live_pan_coverage.mjs | 83 ++++++++++++++++- + docs/reviews/CODE-REVIEW-579-r1.md | 182 +++++++++++++++++++++++++++++++++++++ +``` + +Второй файл — служебный документ самого r1 (класс C, публикация предыдущего раунда), не +материал для разбора. Единственный содержательный файл дельты — `demo/smoke_live_pan_coverage.mjs` +(класс B). Продуктовый код (`src/live-viewport.ts`, `src/live-interaction-runtime.ts`) не тронут: +автор прямо заявляет это в хендоффе, и `git diff 216990e4..HEAD -- 'src/**'` пуст — проверено. + +Дельта локальна: правка только добавляет evidence к уже принятому продуктовому коду, не меняет +контракт поведения, не трогает новую подсистему и по объёму (один тестовый файл) несопоставима с +исходной задачей. Разбор этого раунда ограничен дельтой и AC4, которую она доказывает; остальные +AC унаследованы из r1 (раздел ниже). + +## Закрытие раунда r1 + +| Находка r1 | Чем закрыта | Где это видно | +|---|---|---| +| **M1** — AC4 (day cycle off/on × Glow off/on × room fills/hatching/фон) не имеет тестового доказательства | Добавлена исполняемая матрица 2×2 в `demo/smoke_live_pan_coverage.mjs`: `configureEffectMatrix()` (:161) включает/выключает `bg_mode:'daynight'`/`glow_enabled` на существующей fixture с добавленными стенами (`space.walls`, :406) и контрастным `bg_color:'#123456'`; `effects` (:64) снимает `dayCycle`/`glowPools`/`roomFills`/`hatchedWalls`/`customBackground` из живого DOM в `immediateState` и `heldState`; `expected()` (внутри `runPan`, вызывается для `effectsDay{0,1}Glow{0,1}`, :444-448) требует `roomFills>0 && hatchedWalls>0 && customBackground && dayCycle===expected && glowPools соответствует glow` в ОБОИХ кадрах | Я прогнал `node demo/smoke_live_pan_coverage.mjs` на свежесобранном бандле: все 4 строки матрицы (`effectsDay0Glow0…effectsDay1Glow1`) дают `EffectsVisible:true`, и diagnostics показывают реальные значения (`hatchedWalls:1`, `roomFills:1`, `customBackground:true`, `glowPools` 0/1 согласно строке) — не заглушку | + +## Унаследовано из r1 + +Без повторной проверки принято всё, чего дельта не касается — документ +`docs/reviews/CODE-REVIEW-579-r1.md` (коммит `9bae4d28`), выводы получены на дереве материала +`09aab0675828` (SHA продуктового коммита `216990e4`): + +- **AC1** (стабильная promotion-сессия), **AC2** (бюджет сохранён), **AC3** (сцена не пропадает в + представленных кадрах, `continuity:screencast`), **AC5** (паритет SVG/HTML ≤1px), **AC6** + (terminal cleanup), **AC7** (существующее покрытие края) — доказаны в r1 unit-тестами, двумя + мутационными свидетелями (`live-pinch-compositor-demoted-on-budget-refresh`, + `live-pinch-compositor-demoted-on-active-lit-commit`) и `continuity:screencast`; продуктовый код, + который они проверяют, в этом раунде не менялся — доказательства не протухли. +- **AC8** (нет регрессии управления) — `smoke_editor_gestures`, `smoke_smooth_zoom`, `smoke_tap_ctx`, + `smoke_long_press_gesture`, все зелёные в r1; ни один из этих смоков не в дельте. +- **AC9** (производительность) и **AC10** (полевой Companion-контроль) — в r1 честно отмечены как + предрелизные/beta-приёмка, не гейт ревью; дельта их не касается. +- Находка **L1** r1 (AC2 без именованного мутанта, Low, снята с записью) — вне дельты, повторно не + поднимаю. +- Трейлеры продуктового коммита `216990e4` (`Issue: #579`, `User-Visible: yes`, оба changelog), + документация (`docs/ARCHITECTURE.md`, `docs/TESTING.md`, `docs/images/screenshots.json`) — приняты + в r1, дельта их не трогает. + +## Как проверялось в этом раунде + +Дешёвые гейты уже подтверждены зелёным Validate на `2c7abe79` +(https://github.com/Matysh/houseplan-card/actions/runs/34891309797) — `typecheck`/`unit`/`build` +со сверкой бандла перегонять не стал. Диф этого раунда не трогает `src/**`, поэтому +`check-docs.mjs` и `npm run model-invariants` не в скоупе (не требуются самим дифом) и не +перегонялись повторно — вывод r1 по ним не протухает, т.к. они завязаны на `src/**`, а он не менялся. + +Дополнительно к зачёту CI лично прогнал: + +| Гейт | Команда | Результат | +|---|---|---| +| Свежая сборка (нужна браузерным смокам — Validate на плейн-push heavy-джобы пропускает) | `npm run bundle:sync` | зелёный, `tsc --noEmit` в составе `build` тоже прошёл | +| `smoke-select` по дифу | `node scripts/smoke-select.mjs --base 216990e4 --head HEAD` | «Исполняемого frontend-диффа нет» — ожидаемо, дельта не трогает `src/**`; сам изменённый смок разбираю напрямую, это он и есть предмет дельты | +| Изменённый смок | `node demo/smoke_live_pan_coverage.mjs` | `OK`, все 65 именованных проверок `true`, включая 20 новых (`effectsDay0Glow0…effectsDay1Glow1` × `ImmediateCoverage/HeldCoverage/UsesTemporaryOverflow/TargetStableWhileHeld/EffectsVisible`) | +| Селекторы матрицы против реальной разметки | чтение `src/houseplan-card.ts`, `src/glow-scene.ts`, `src/day-cycle-render.ts`, `src/space-render.ts` | `.wallbody:not(.solid)[fill^="url("]` (`:9549-9551`), `.room.filled` (`:11666`), `.glowlayer .glow-pool` (`glow-scene.ts:606-615`), `.hp-day-cycle-env .hp-day-cycle-bg.active` (`day-cycle-render.ts:32-38`) — все классы существуют в текущем рендере ровно с этими именами, не выдуманы под тест | +| Дисциплина «тест умеет падать» для изменённого файла | `node scripts/mutation-gate.mjs --id=live-pinch-compositor-demoted-on-active-lit-commit` | «заявленный тест покраснел на мутанте», поймано 1/1 — подтверждает, что изменённый смок остался работоспособным guard'ом после правки, не просто не упал по случайности | + +**Не прогонял:** полный `demo/smoke_*.mjs` (дельта не в src, `smoke-select` ничего не выбирает, +кроме самого изменённого файла, который прогнан напрямую); `golden:verify` (дельта не трогает +рендер-код, только тестовую fixture, и golden уже зелёный в r1 на продуктовом коммите); +`python -m pytest tests_backend` (диф не касается `custom_components/**/*.py`); +`npm run model-invariants` (диф не трогает геометрию/`layout`/`marker.space`); performance-профиль +(AC9 остаётся предрелизным гейтом, дельта его не касается); мутант +`live-pinch-compositor-demoted-on-budget-refresh` (его guard — `test/live-viewport.test.mjs`, не в +дельте, не перезапускал). + +## AC → доказательство в этом раунде + +| AC | Доказано | Чем краснеет | +|---|---|---| +| AC4 эффекты не отключаются | `demo/smoke_live_pan_coverage.mjs`, матрица `effectsDay{0,1}Glow{0,1}` (:406-448), я прогнал — зелёный, значения реальные (не 0/false по умолчанию) | `expected()` (внутри `runPan`) красит `*EffectsVisible`, если `roomFills`/`hatchedWalls`/`customBackground` пропадут или `glowPools`/`dayCycle` не совпадут с ожидаемым состоянием строки матрицы; отдельного `MUTANT_DEFINITIONS`-контрпримера на этот конкретный assert нет — это тот же класс пробела, что уже был снят как Low (L1, AC2) в r1 для соседнего assert'а того же файла, не новая находка | + +Все остальные AC — см. «Унаследовано из r1». + +## Что проверено и корректно + +- Матрица переиспользует уже существующую shared-fixture «coverage-room» (`space.rooms`/ + `space.settings`, настраивается один раз перед всеми `runPan`-сценариями файла), а не заводит + отдельный конфиг — `configureEffectMatrix` клонирует `card._serverCfg` и правит только + `settings`, не трогая `rooms`/`walls`. Это единственная точка, где дельта расширяет уже + используемый другими (не относящимися к #579) проверками в этом же файле объект: добавление + `space.walls` (:406) поначалу выглядит риском регрессии для более ранних проверок этого же + файла (`flatMouseRightEdge` и т.п., они используют ту же комнату) — прогон подтвердил, что все + 45 pre-existing проверок остались зелёными; стены добавлены только для получения штриховки, + сама fixture раньше стен не имела вовсе. +- `_cfgEpoch++` после подмены `_serverCfg` — не изобретённый в тесте API: то же поле и тот же + паттерн инкремента уже используется продуктовым кодом (`src/houseplan-card.ts:3294`) для + инвалидации кеша по конфигу. +- Трейлеры нового коммита корректны: `Issue: #579`, `User-Visible: no` — коммит меняет только + `demo/**` (класс B), продуктовое поведение не меняет, changelog не требуется. +- «Одно число — один источник»: дельта не добавляет и не меняет пользовательски видимую величину + (тестовые ассерты, не UI) — неприменимо. + +## Чего не проверял и почему + +- Полный набор `demo/smoke_*.mjs` — дельта не в `src/**`, единственный связанный с изменением + смок прогнан напрямую. +- `golden:verify`, `model-invariants`, `pytest tests_backend`, performance-профиль — не в скоупе + дельты (см. таблицу выше), их выводы из r1/из состояния `src/**` не протухли. +- Физический прогон HA Companion (AC10) — вне окружения ревью, остаётся beta-приёмкой (унаследовано + из r1, дельта не меняет это решение). + +## Вердикт + +Единственная находка r1 (M1, Medium в скоупе) закрыта исполняемым доказательством: селекторы +матрицы проверены чтением реального рендера и совпадают, прогон смока даёт нетривиальные (не +default-false/0) значения по всем 4 строкам, а изменённый файл остаётся рабочим mutation-guard'ом +для уже принятых в r1 находок AC1/AC6. Новых High или Medium находок в дельте не найдено. Зелёный. + +--- + +## Материал раунда + +- Ветка: `issue/579-webview-pinch-compositor`, HEAD `2c7abe7938ded08d63f277269d8b7e52c04e2d4d`. +- Продуктовый коммит остаётся `216990e469f2d123a81c03e99cdcb315ed756be0` (не менялся с r1). +- Предыдущий документ: `docs/reviews/CODE-REVIEW-579-r1.md`, коммит `9bae4d283a6156e39912e9c909c7afb7d59fa518`, вердикт `yellow`, High 0, Medium 1. + +--- + + + +## Материал раунда + +- Ветка: `issue/579-webview-pinch-compositor`, коммит `2c7abe7938de` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `723a78780b711457d23f95da0e1753e55361211a` + ``` + git log --all --format='%H %T' | grep 723a78780b71 + ``` +- Тело issue: `4545e4010a0a0d13588d41c73912f543b83f5091653de15127390b77630498a0` +- Вердикт конвейера: `green` · High 0