From 1f032d51bf61e557f5f5b53359a3fda8167a62c5 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Sat, 29 Aug 2026 08:44:54 +0000 Subject: [PATCH] docs: review document for #360 Issue: #360 User-Visible: no --- docs/reviews/CODE-REVIEW-360-r1.md | 158 +++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 docs/reviews/CODE-REVIEW-360-r1.md diff --git a/docs/reviews/CODE-REVIEW-360-r1.md b/docs/reviews/CODE-REVIEW-360-r1.md new file mode 100644 index 00000000..b095cc37 --- /dev/null +++ b/docs/reviews/CODE-REVIEW-360-r1.md @@ -0,0 +1,158 @@ +# CODE-REVIEW-360-r1 + +Issue: #360 «Основной default-цвет декора на главной панели» +Этап: код-ревью (PROCESS.md §2.7) +Заход: r1 · блокирующих циклов израсходовано 0/2 +SHA материала ревью: `f91b0ff51254fdf10aee1da56f20a307d7ea1e72` +Диапазон: `git diff origin/dev...HEAD` (один некоммит-мёрдж коммит `f91b0ff5`) + +## Вердикт + +**Зелёный.** High: 0, Medium: 0 (ни в скоупе, ни вне скоупа), Low: 0. + +## Скоуп диффа + +Один продуктовый коммит `f91b0ff5 feat: expose decor default color in main toolbar`, +трейлеры `Issue: #360` / `User-Visible: yes` на месте. + +Файлы: `src/houseplan-editor-runtime.ts` (+9 строк — новый постоянный +`hp-color-opacity` в `_renderDecorBar`), `test/color-picker.test.mjs`, +`demo/smoke_decor.mjs`, `docs/DECOR-EDITOR.md`, `docs/USER-GUIDE.ru.md`, +`docs/CHANGELOG.md`, `docs/CHANGELOG.ru.md`, `docs/images/07-background-editor.png` ++ `screenshots.json` (отпечаток документации), сгенерированные `dist/**` и +`custom_components/houseplan/frontend/**` (класс D, синхронны с исходником). + +Диффу соответствует ровно одна цель ТЗ: сделать существующий session-default +`_decorStyle.color`/`_decorStyle.opacity` видимым и управляемым с основной +панели редактора подложки при любом инструменте, ничего больше не меняя. +Правка не трогает геометрию, персистентную модель, i18n-ключи, миграции, +touch-контракт и любые другие редакторы — заявленный не-скоуп ТЗ выдержан +построчно. + +## Как проверялось + +Зелёного Validate на `f91b0ff5` нет, гейты прогнаны локально. + +| Гейт | Статус | Примечание | +|---|---|---| +| `npx tsc --noEmit` | 🟢 зелёный | без вывода | +| `npm test` | 🟢 зелёный | 1534 passed / 1 skipped / 0 failed | +| `npm run build` | 🟢 зелёный | `git status` после сборки чист — `dist/**` и `custom_components/houseplan/frontend/**` побайтово совпадают с закоммиченными (сверка проведена `diff -q` дополнительно) | +| `node scripts/check-docs.mjs` | 🟢 зелёный | «Documentation checks passed (7 files, 10 external links)» — diff трогает `src/**`, поэтому обязателен | +| `node scripts/smoke-select.mjs --base origin/dev --head HEAD` | выполнен | 3 «прямых совпадения» по символу `_decorStyle`: `demo/smoke_decor.mjs`, `demo/smoke_color_picker.mjs`, `demo/smoke_furniture.mjs` | +| `node demo/smoke_decor.mjs` | 🟢 зелёный | назван в тест-плане ТЗ (п.6) и это же смок расширен диффом; см. «тест умеет падать» ниже | +| `node demo/smoke_color_picker.mjs` | 🟢 зелёный | прямое совпадение из smoke-select | +| `node demo/smoke_furniture.mjs` | 🟢 зелёный | прямое совпадение из smoke-select (мебель — один из потребителей `_decorStyle`) | +| `node --test test/color-picker.test.mjs` | 🟢 зелёный | новые ассерты по `decor-default-color`; см. «тест умеет падать» ниже | +| `npm run golden:verify` | **не прогонялся** | ТЗ (план тестов, п.6) явно относит golden/screenshot-ревью к предрелизному гейту (AC6: «Доказательство: smoke + golden/screenshot review перед бетой»); это решение уже прошло зелёное ревью ТЗ (SPEC-REVIEW-360-r2). Локальный прогон дополнительно бессмыслен: правило §12/#13 принимает эталоны только `golden:accept -- --reviewed` по полному Linux-артефакту CI | +| `npm run invariants -- --config …` | **не прогонялся** | diff не трогает геометрию/`layout`/`marker.space`/`open_spans`/рёбра — только UI-state `_decorStyle` и его потребление существующими `decorStylePatch`/`_decorSaveShape`, которые сам diff не меняет | +| `python -m pytest tests_backend -q` | **не прогонялся** | `custom_components/**/*.py` не тронут | +| performance-профили | **не прогонялись** | не названы в AC, чувствительные к перфу пути (рендер геометрии, пересчёт масок) не тронуты — добавлен один статический biding в toolbar | + +### Дисциплина «тест умеет падать» + +Проверено исполнением, не только чтением: временно убран добавленный блок +`` из `_renderDecorBar` +(`src/houseplan-editor-runtime.ts`), пересобран бандл (`npm run bundle:sync`) +— `node demo/smoke_decor.mjs` упал (`Cannot read properties of null (reading +'dispatchEvent')` на обращении к main picker). Отдельно тем же способом +(без пересборки, тест читает `.ts`-исходник напрямую) `node --test +test/color-picker.test.mjs` упал на новом ассерте `defaultPickerStart >= 0`. +После проверки код и бандлы восстановлены (`git checkout -- +src/houseplan-editor-runtime.ts` + `npm run bundle:sync`), `git status` +чист. + +## Разбор по AC + +- **AC1 (постоянная доступность).** `_renderDecorBar` (src/houseplan-editor-runtime.ts:5324) + рендерит `.editbar-tools`, где новый `hp-color-opacity.decor-default-color` + безусловен — не зависит от `this.host._decorTool`, в отличие от контекстного + picker'а в `_renderDecorSecondary` (условие `draws`, строка 5252). В коде + ровно один экземпляр `class="decor-default-color"`. Проверено чтением и + смоком `defaultStyleVisibleForEveryDecorTool` (перебор всех 8 инструментов, + включая `select`/`erase`/`backdrop`) — **доказано**. +- **AC2 (все новые типы).** Смок `everyNewDecorKindUsesMainDefault`: после + смены основного default создаются line/rect/ellipse (через `_decorCommitDraft`), + text (через `_decorPointerDown`+`_decorSaveText`) и furniture (через + `_furnPlace`) — все получают записанный `color`/`opacity`. **Доказано + browser-смоком**, как требует AC. +- **AC3 (существующее неизменно).** Смок `mainPickerLeavesExistingObjectsUntouched` + сравнивает JSON контрольного объекта до/после смены default побайтово. + **Доказано**. +- **AC4 (заливка независима).** Смок `mainDefaultDoesNotOverwriteShapeFill`: + после смены default `fill_color`/`fill_opacity` новых rect/ellipse равны + ранее выставленным `#fedcba`/`0.23`, а не новому основному цвету. В коде + обработчик пишет только `{ ...e.detail }` (`color`, `opacity`), других полей + событие не содержит. **Доказано и кодом, и смоком**. +- **AC5 (единый state).** Смок `mainPickerUpdatesOneSessionDefault` (main → context) + и `contextPickerUpdatesMainPicker` (context → main) в обе стороны, плюс + `objectDialogRefreshesMainDefault` — сохранение properties-диалога линии + обновляет main picker по контракту `_decorSaveShape` (не менялся диффом). + Оба picker'а читают один `this.host._decorStyle`, что даёт единый источник + числа «текущий цвет/opacity» без дублирования (проверка на предмет «одно + число — один источник» пройдена чтением). **Доказано**. +- **AC6 (responsive/a11y).** Обычная ширина уже покрыта существующими + `colorPickerUsesTopLayer`/`colorPickerInsideViewport`. Добавлен отдельный + прогон на viewport 560×820: `narrowToolbarKeepsToolsAndCloseApart` (Undo/Redo + и все 8 кнопок инструментов не наезжают на закреплённый `.editbar-end`), + `narrowToolbarKeepsDefaultPickerUsable` (popover целиком в viewport), + `defaultPickerReadableInLightAndDark` (trigger 40×40 и `visibility: visible` + в обеих темах). Стилизация не потребовала правок `chrome.styles.ts`: уже + существующее правило `.decorbar hp-color-opacity { flex: 0 0 auto; }` + (chrome.styles.ts:124) действует на любой `hp-color-opacity` внутри + `.decorbar` по тегу, а не по конкретному call site — новый инстанс подпадает + автоматически. Golden/screenshot-ревью по AC6 — явно предрелизный гейт (см. + таблицу выше), здесь не требуется. **Доказано смоком + чтением; golden — по + плану ТЗ, не на этом этапе**. +- **AC7 (совместимость и гейты).** Новых persisted-полей и i18n-ключей нет — + переиспользованы `decor.color`/`space.opacity`, `_colorPickerLabels` (было + ранее). `_decorStyle` остаётся приватным полем класса с исходным значением + `{ ...DEFAULT_DECOR_STYLE }` (houseplan-card.ts:1006), нигде не пишется в + конфиг/localStorage — session-only, как и раньше. typecheck/test/build + зелёные (таблица выше). **Доказано чтением и гейтами**. +- **AC8 (документация).** `docs/DECOR-EDITOR.md` и `docs/USER-GUIDE.ru.md` + описывают постоянный main-bar picker и его связь с контекстным; оба + changelog (`docs/CHANGELOG.md`, `docs/CHANGELOG.ru.md`) правлены в том же + коммите со ссылкой на #360. `check-docs.mjs` зелёный — отпечаток + скриншотов документации пересчитан и совпадает. **Доказано**. + +## Что проверено и корректно + +- Единственная точка изменения продуктового кода — 9 строк в + `_renderDecorBar`, использующие уже существующий контракт `_decorStyle` и + компонент `hp-color-opacity` без второй модели цвета, без нативного + `` (unit-тест на отсутствие таких input по всем `src/**` + зелёный). +- Обработчик `@hp-color-opacity-change` у нового picker'а буквально совпадает + с обработчиком контекстного picker'а того же назначения (строки 5267-5268 и + 5378-5379 идентичны) — не новая логика, а тот же паттерн, что уже + используется в 10+ местах файла; дублирование стилистическое и не вводится + этим диффом впервые, вычленять абстракцию ради одной новой строки не по + задаче. +- Бандлы (`dist/**`, `custom_components/houseplan/frontend/**`) синхронны с + исходником побайтово после чистой пересборки. +- Откат из ТЗ подтверждён: удаление добавленного блока — единственное + необходимое действие, состояние и persisted-данные не завязаны на него + (проверено практически при тесте «умеет падать»). + +## Чего не проверял + +- `npm run golden:verify` и обновление golden-эталонов — по решению ТЗ (AC6, + п.6 плана тестов) это предрелизный гейт (PROCESS §8), а не гейт этого + ревью; сам выбор уже прошёл зелёное ревью ТЗ. +- Инварианты модели геометрии (`npm run invariants`) — diff не касается рёбер, + толщины, `layout`, `marker.space`, `open_spans`. +- Backend (`pytest tests_backend`) — `custom_components/**/*.py` не менялся. +- Производительность — не названа в AC, чувствительный к перфу код не тронут. +- Ручное визуальное тестирование в браузере (вне Playwright-смоков) — не + проводилось; вместо него отработаны целевой и два смежных browser-смока + плюс явная проверка «тест умеет падать» на живом бандле. + +## Итог + +Реализация соответствует контракту ТЗ дословно: один новый постоянный +`hp-color-opacity` на главной панели, никаких побочных изменений в +персистентной модели, заливке фигур, существующих объектах, i18n или touch/ +View-контракте. Все AC либо доказаны browser-смоком (с подтверждённой +способностью упасть), либо разобраны по коду. Дешёвые и целевые гейты +зелёные. Оснований для Medium/High нет.