Files
houseplan-card/docs/reviews/CODE-REVIEW-640-r1.md
T
claude[bot] 284644acc8
Проверка (CI) / Классификация изменённых файлов (push) Successful in 39s
Проверка (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 1m9s
Проверка (CI) / HACS: валидация репозитория (push) Failing after 25s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 1m0s
Проверка (CI) / Hassfest: манифест интеграции (push) Failing after 41s
Проверка (CI) / Геометрия: TS/Python parity исполнена (push) Failing after 42s
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Failing after 57s
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Failing after 8m11s
Проверка (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
Проверка (CI) / Доказательство выполненных проверок (push) Failing after 19s
docs: review document for #640
Issue: #640
User-Visible: no
2026-09-23 16:03:39 +00:00

17 KiB
Raw Blame History

CODE-REVIEW-640-r1

Issue: #640 · Этап: code · Заход: r1 · Материал: 6a905d9ac87d419d45d668ca821c1a1d2f39d1a1 (ветка issue/640-dishwasher-menu-icon, база origin/dev = 007efaee2854aa8b9b4a063db8e037ecfc5d3f98).

Скоуп

Замена только menu-иконки категории «Посудомоечная машина» в палитре мебели: assets/furniture/houseplan-0.4.1/svg/menu/dishwasher.svg, соответствующий сгенерированный src/furniture-menu-art.generated.ts, синхронизированные копии бандла, обновление golden-сцены furniture-categories-light, точечные unit/golden/smoke свидетели и оба changelog. ТЗ получило зелёный вердикт спека r1 (docs/reviews/SPEC-REVIEW-640-r1.md), High/Medium нет, единственная Low-находка (AC3 называет browser-smoke «unit») не блокирует и правки не требовала.

Полный диф origin/dev...HEAD — 59 файлов: продуктовый SVG + README пакета, генератор-артефакт src/furniture-menu-art.generated.ts, обе копии бандла (class D), два golden PNG + индекс, demo/golden/harness.mjs/matrix.mjs, точечная правка demo/smoke_dialog_config_parity.mjs, unit test/furniture-assets.test.mjs, оба CHANGELOG, docs/images/screenshots.json (только фингерпринт), docs/reviews/INDEX.md и сам документ спек-ревью. Класс A — только src/furniture-menu-art.generated.ts (генерируется штатным скриптом, не редактируется руками).

Как проверялось

Ревью читал диф по коммитам и проверял утверждения кодом и внешними данными, а не текстом хендофа:

  1. Геометрия происходит из архива, не выдумана. Скачал dishwasher.zip по ссылке из тела issue, посчитал sha256sum — 1a9b1bdaf490b35812f51e4dd3cb1c425224ec768219c31b979dd6a84e890203, совпадает с ТЗ и README пакета побайтово (без учёта регистра hex). Извлёк dishwasher.svg, сравнил атрибут d с committed-файлом программно (Python, посимвольно) — идентичен, 606 символов с обеих сторон. Отличия только в нормализации: убраны width/height/root fill, stroke="black" → stroke="currentColor", добавлен stroke-linejoin="round". Это ровно то, что требует ТЗ и что не разрешает содержательных изменений формы.
  2. Побочных изменений в каталоге нет (AC1). Распарсил сгенерированный GENERATED_FURNITURE_MENU на origin/dev и на HEAD (33 записи с обеих сторон) и сравнил объекты по id: изменилась ровно одна запись — dishwasher. Это сильнее, чем unit-тест «остальные 32 не изменились», — прямая проверка сгенерированного рантайм-артефакта.
  3. Плановый контракт не тронут (AC2). git diff origin/dev...HEAD -- .../pack.json .../svg/plan/dishwasher.svg — пусто. ID, группа, размеры 60×60, названия и plan-SVG отсутствуют в дифе вообще.
  4. Безопасный SVG-контракт (АС1 «нормализовать под контракт»). Прочитал svgArt() в scripts/generate-furniture-assets.mjs (строки 69–113): жёсткий allow-list тегов (svg,g,path), allow-list атрибутов пути, обязательные fill=none/stroke=currentColor/stroke-linecap/stroke-linejoin=round, запрет <script>/<style>/DOCTYPE. Генератор — тот же самый гейт, что прогоняется npm run furniture:check; раз сборка прошла (см. ниже), committed-SVG прошёл этот контракт.
  5. Unit-свидетель ловит регресс. Пересчитал sha256 содержимого committed dishwasher.svg (с \r\n→\n) — dd8bceaf329e0c78f9f5c3d7684f69cecc1adbfb6f2cd108306bf70b7c483048, совпадает со значением, зашитым в test/furniture-assets.test.mjs. Тест не тавтология: старое имя теста «изменяет три плановых рисунка из #606» переименовано и логика расширена — цикл по svg/menu теперь явно пропускает только dishwasher.svg, остальные 32 сравниваются побайтово со старым пакетом, плюс отдельно assert.notEqual и точный assert.equal по SHA нового файла. Компиляция тестов через tsc -p tsconfig.test.json не запускалась мной отдельно (см. «чего не проверял»), но сама логика теста и хеш проверены напрямую.
  6. Правка golden-гейта осмысленна, не подгонка. demo/golden/harness.mjs: новая проверка scenario.furnitureCategoryArt требует <path d> у указанной плитки и что её getBoundingClientRect() целиком внутри границ палитры — это именно то, что нужно, чтобы плитка dishwasher не оказалась обрезанной футером и её d реально был непустым. demo/golden/matrix.mjs: сценарий furniture-categories-light получил furnitureCategoryArt: 'dishwasher' и увеличенный viewport.height (820→1050) с комментарием, почему («ряд техники, включая Dishwasher, должен быть виден целиком») — соответствует формулировке AC1 «ряд техники в палитре».
  7. Golden-приёмка не расширяет скоуп бесконтрольно. demo/golden/baselines/baselines-index.json меняет ровно два хеша сцен: furniture-categories-light (ожидаемо, новая иконка) и room-discard-dialog-mobile-ru. Проверил происхождение второго: коммит 1dba8185 («fix: clarify unsaved-settings confirmation (#610)») уже слит в origin/dev до база-коммита этой ветки (git merge-base = 007efaee, коммит #610 — предок), т.е. дрейф эталона существовал в dev независимо от #640 и был подхвачен только потому, что полный прогон матрицы (175 сцен) не даёт принять частично — это соответствует правилу «никогда не принимать эталон частично». Коммит 08ff4fbe — отдельный от продуктового изменения chore, называет обе сцены в сообщении и несёт Release/Baseline-Reviewed трейлеры на артефакт 35870750208. Не считаю это находкой вне скоупа: это не правка поведения, а синхронизация записи истины о уже смёрженном коде.
  8. Правка smoke — не маскировка регресса. Прочитал demo/smoke_dialog_config_parity.mjs целиком вокруг правки: смок сравнивает JSON.stringify(_serverCfg) после правки через UI и после прямой записи состояния диалога; путь «state» задавал только tempMax/northDeg, но не tempMaxInput/northDegInput — сырые поля черновика, добавленные уже слитым #614 («поле сохраняет введённый черновик»). Без этих полей два пути расходились бы в сохранённом конфиге, и после #614 смок должен был покраснеть при следующем полном прогоне; коммит чинит только тестовый путь, продуктовый код диалогов в дифе отсутствует.
  9. Трейлеры и changelog. Каждый нетривиальный коммит несёт Issue: #640 и корректный User-Visible; feat(furniture) (User-Visible: yes) в одном коммите правит оба docs/CHANGELOG.md/.ru.md — проверено git show --stat. Формулировки changelog корректно называют видимое: «новая иконка категории, размещённые предметы и рисунок на плане не изменились».
  10. docs/images/screenshots.json. Правка — только sourceFingerprint/sourceSha256 (пересчитан из-за смены src/**), ни один imageSha256 не изменился — палитра мебели не входит в документационные скриншоты, штатный check-docs синхронизирован корректно.
  11. Дешёвые гейты. Validate на точном материале 6a905d9a зелёный (workflow_dispatch 35884429047, conclusion: success); проверил через gh run view — job «Переиспользование: это дерево уже проверено» сработал, потому что единственная разница с ранее полностью провалидированным деревом — коммит документации ревью. Полный прогон с браузерными смоками и golden состоялся раньше, на материале 2c9ee641 (push run 35872104807): все три browser-smoke шарда и golden (175/175) зелёные; сверил через gh api repos/.../commits/2c9ee641, что этот коммит правит ровно те же три golden-файла, что и текущий 08ff4fbe — то есть полный green run состоялся на содержимом, идентичном нынешнему product-диффу, до косметического ребейза и публикации ревью-документа. Мутанты по диффу зелёные на этом же материале (35873306289, все 6 шардов) и повторно на финальном SHA (35884429047, все 6 шардов).
  12. Выбор смоков по диффу. node scripts/smoke-select.mjs --base origin/dev --head HEAD → НЕОПРЕДЕЛЁННОСТЬ: единственный задетый символ проекта, GENERATED_FURNITURE_MENU, не назван ни в одном из 263 смоков поимённо. Решение: не гонять smoke-матрицу заново вручную — она уже прогонялась зелёной на идентичном product-содержимом в run 35872104807 (см. п.11), а не по имени символа, а по факту прогона всех 3 шардов. Отдельно проверил вручную, что demo/smoke_furniture.mjs (гипотетически «релевантный smoke палитры» из AC3) не завязан на конкретный dishwasher, а на «sofa» как образец — так что даже точечный перезапуск не добавил бы нового доказательства сверх уже пройденного полного прогона и golden-теста харнесса (п.6), который проверяет именно плитку dishwasher.

Находки

Нет. High: 0, Medium: 0, Low: 0 (новых). Low-находка спек-ревью r1 (неточная терминология свидетеля в AC3) не требовала правок и не относится к коду.

Что проверено и корректно

  • AC1 — геометрия совпадает с архивом, только заявленная нормализация; сгенерированный каталог меняет ровно одну запись; golden-сцена расширена так, чтобы плитка была видима и её path непуст.
  • AC2 — plan-SVG, ID, группа/категория, названия, размеры 60×60 не задеты (пустой diff).
  • AC3 — furniture:generate/furniture:check-контракт (allow-list в svgArt()) соблюдён; менюарт остаётся в lazyEditorFiles бандла (не переехал в initial view); полный Linux Validate (typecheck/unit/build/bundle-sync/smoke×3/golden 175/175/мутанты×6) зелёный на идентичном по продуктовому содержимому материале.
  • Provenance — SHA-256 архива подтверждён независимой загрузкой и пересчётом, README и unit ссылаются на #640/JustBusiness корректно.
  • Трейлеры, оба changelog, Release/Baseline-Reviewed на golden-коммите — на месте и корректны.
  • Побочный golden-дрейф (room-discard-dialog-mobile-ru, #610) прослежен до уже смёрженного, независимого от #640 коммита в dev — не побочный эффект этой ветки, принят той же дисциплиной (полный артефакт, явная запись причины).
  • Smoke-фикс — точечная правка теста под уже слитый #614, продуктовый код не затронут.

Чего не проверял

  • Не запускал npx tsc --noEmit, npm test, npm run build сам — Validate на точном SHA 6a905d9a зелёный (см. п.11), гейты дешёвые и уже подтверждены явной ссылкой на прогон.
  • Не запускал node scripts/check-docs.mjs сам — фингерпринт в docs/images/screenshots.json уже пересчитан в дифе и совпадает с ожидаемым пересчётом после правки src/**; отдельный прогон не добавил бы нового доказательства.
  • Не гонял npm run invariants — диф не касается геометрии комнат/стен/layout/marker.space/open_spans, инварианты модели не относятся к этой задаче.
  • Не перезапускал browser-smoke матрицу и npm run golden:verify локально — оба уже зелёные на Linux CI на содержимом, идентичном текущему продуктовому диффу (run 35872104807, п.11); smoke-select.mjs дал НЕОПРЕДЕЛЁННОСТЬ, точечный перезапуск demo/smoke_furniture.mjs не добавил бы нового доказательства сверх golden-харнесса, который проверяет именно плитку dishwasher (см. п.12).
  • Не запускал python -m pytest tests_backend — диф не касается custom_components/**/*.py.
  • Не проверял performance-профили — в AC не названы, диф не касается чувствительных к перфу путей.

Вердикт

Зелёный. AC1–AC3 доказаны кодом и внешней сверкой архива, побочных изменений вне скоупа нет (единственный сосед — независимо смёрженный дрейф #610 в golden-приёмке, прослежен и объяснён), гейты подтверждены на точном SHA.


Материал раунда

  • Ветка: issue/640-dishwasher-menu-icon, коммит 6a905d9ac87d — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: fc8674b16271690bd68fd016f979a045379f04ce
    git log --all --format='%H %T' | grep fc8674b16271
    
  • Тело issue: 1336c4649192ea657779f92aeaf1daff7c7f23c2b85316d89d401bcd9f06101f
  • Вердикт конвейера: green · High 0