From 06bf9b69214ddf1fd60f4020615519aed2337398 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Wed, 16 Sep 2026 21:19:57 +0000 Subject: [PATCH] docs: review document for #584 Issue: #584 User-Visible: no --- docs/reviews/CODE-REVIEW-584-r2.md | 215 +++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 docs/reviews/CODE-REVIEW-584-r2.md diff --git a/docs/reviews/CODE-REVIEW-584-r2.md b/docs/reviews/CODE-REVIEW-584-r2.md new file mode 100644 index 00000000..b5eefa89 --- /dev/null +++ b/docs/reviews/CODE-REVIEW-584-r2.md @@ -0,0 +1,215 @@ +# CODE-REVIEW-584-r2 — #584: физический габарит мебели равен заявленным размерам + +- Issue: [#584](https://github.com/Matysh/houseplan-card/issues/584) +- Этап: `code` (PROCESS.md §2.7) +- Диапазон материала раунда: `9bf41ec3..62d86e0f` +- Материал ревью — ровно `62d86e0f8361a0ed4cc7b9af184252ab5ee63dd0`, рабочая копия уже на нём; + `git fetch`/`git checkout`/`git pull` на другой коммит не делал. +- Предыдущий раунд: [`CODE-REVIEW-584-r1.md`](CODE-REVIEW-584-r1.md), вердикт + **жёлтый**, материал `9bf41ec3`, комментарий-вердикт + `github-actions @ 2026-09-16T21:12:07Z`. +- Заход: **r2** — разбор по дельте (PROCESS.md §2.9, issue #214) +- Блокирующих циклов израсходовано: 1/4 (бюджет тратят жёлтый/красный; r1 был жёлтым) + +## Дельта раунда + +``` +git diff 9bf41ec3..62d86e0f --stat + docs/reviews/CODE-REVIEW-584-r1.md | 260 +++++++++++++++++++++++++++++++++++++ + 1 file changed, 260 insertions(+) +``` + +Между материалом r1 (`9bf41ec3`) и материалом r2 (`62d86e0f`) в дереве изменился +**ровно один файл** — сам документ ревью r1, положенный шагом публикации +конвейера. Продуктового кода, тестов, паков, генераторов, changelog — нулевая +дельта. + +`origin/dev` за это время продвинулся `7c5fd32a → e0b16c76`, но `e0b16c76` +уже был предком материала `9bf41ec3` (это чужой докс-коммит, влившийся в +`dev`), а не переписыванием истории — проверено `git merge-base --is-ancestor +e0b16c76 HEAD` (истина) и `git merge-base origin/dev HEAD == e0b16c76`. Значит +это не ребейз на ушедший вперёд `dev` (§7.2), ветка ветки просто линейно +впереди; полный повторный разбор по этой причине не требуется. + +Единственное действие раунда — комментарий автора +`Matysh @ 2026-09-16T21:13:28Z` «M1 закрыт: число названо», закрывающий +единственную блокирующую находку r1 (M1) без изменения кода. + +## Закрытие раунда r1 + +| Находка r1 | Чем закрыта | Где это видно | +|---|---|---| +| **M1** (Medium, в скоупе) — раздел «Производительность»/«Риски» ТЗ требует назвать рост ленивого чанка `furniture-plan-art.generated` числом; число не было названо ни в хендоффе, ни в коммитах, ни в CHANGELOG | Комментарий `Matysh @ 2026-09-16T21:13:28Z` называет число по официальному источнику — полю `bundle-manifest.mjs`, а не по блобам исходника: `lazyFurnitureArtGzipBytes` 10 254 → 23 338 Б (+13 084 Б, +128 %); заодно назван эффект на холодный старт (`initialViewGzipBytes` +47 Б, +0,016 %) и на весь ленивый набор (`lazyGzipBytes` +13 136 Б, +3,1 %) | Issue #584, комментарий 2026-09-16T21:13:28Z. **Числа проверены мной независимо, не на слово** — см. «Как проверялось» | + +## Как проверялось + +Материал ревью — ровно `62d86e0f`; `git checkout`/`fetch` на другой коммит не +делал. + +Дешёвые гейты на этом SHA уже подтверждены Validate (упомянуто в задании +ревью: прогон `35151230014`, `success`) — это тот же код, что и на `9bf41ec3` +(дельта раунда не трогает исходники), поэтому `npx tsc --noEmit`, `npm test`, +`npm run build`+сверка бандлов, `check-docs.mjs`, browser-смоки, +`golden:verify`, мутанты — повторно не гонял. Причина не «доверие», а +«нулевая дельта кода»: r1 эти гейты уже проверил на идентичном дереве +(`9bf41ec3`), а r2 к дереву ничего не добавил кроме доксового файла, который +эти гейты не касается. + +Единственное, что требовало самостоятельной проверки в этом раунде — +достоверность чисел из закрывающего комментария M1. Числа не входят ни в один +автоматический гейт как утверждение соответствия ТЗ (сам факт наличия числа в +отчёте гейтом не проверяется), поэтому свериться нужно было вручную: + +``` +python3 -c " +import json +d = json.load(open('custom_components/houseplan/frontend/houseplan-assets.json')) +for k in ['initialViewGzipBytes','lazyGzipBytes','lazyFurnitureArtGzipBytes']: + print(k, d.get(k)) +" +# HEAD (62d86e0f): initialViewGzipBytes 291158, lazyGzipBytes 433657, lazyFurnitureArtGzipBytes 23338 + +git show origin/dev:custom_components/houseplan/frontend/houseplan-assets.json > /tmp/dev-manifest.json +python3 -c "... тот же код на /tmp/dev-manifest.json ..." +# dev (e0b16c76, тот же код мебели что и 7c5fd32a): initialViewGzipBytes 291111, lazyGzipBytes 420521, lazyFurnitureArtGzipBytes 10254 +``` + +Результат совпадает с комментарием **побитно**: + +| поле | `dev` (было) | `HEAD` (стало) | дельта в комментарии | дельта, посчитанная мной | +|---|---|---|---|---| +| `lazyFurnitureArtGzipBytes` | 10 254 | 23 338 | +13 084 Б, +128 % | +13 084 Б, +127,6 % → округление до +128 % корректно | +| `lazyGzipBytes` | 420 521 | 433 657 | +13 136 Б, +3,1 % | +13 136 Б, +3,124 % → округление корректно | +| `initialViewGzipBytes` | 291 111 | 291 158 | +47 Б, +0,016 % | +47 Б, +0,0161 % → округление корректно | + +Источник чисел — реальный закоммиченный файл манифеста +(`custom_components/houseplan/frontend/houseplan-assets.json`, поле пишет +`scripts/bundle-manifest.mjs`, тот же источник, которым руководствуется +`scripts/bundle-budget.mjs` при проверке бюджета `INITIAL_VIEW_GZIP_BUDGET = +301 066`), а не отдельный ручной подсчёт по blob'ам, как было у меня в r1. +Значит число теперь официальное и воспроизводимое любым будущим ревьюером той +же командой, а не разовый расчёт ревьюера. + +Дополнительно проверено: `291 158 < 301 066` — initial-View бюджет не задет +(и не мог быть задет: арт мебели лежит в ленивом чанке, `initialViewFiles` его +не включает — подтверждено ещё в r1 чтением `lazyFurnitureArtFiles`). + +## Унаследовано из r1 + +Без повторной проверки в этом раунде принято всё, что установил +[`CODE-REVIEW-584-r1.md`](CODE-REVIEW-584-r1.md) на материале `9bf41ec3`, +поскольку дельта `9bf41ec3..62d86e0f` не касается ни одного из этих +доказательств (единственный изменённый файл — сам r1-документ): + +- **AC1** (границы `[0,artW]×[0,artH]` ±0.1) — `test/furniture-visual-bounds.test.mjs`, + мутант `furniture-symbol-may-keep-inner-padding` логически прослежен, красит + тест. +- **AC2** (одинаковые `w/h` → одинаковый габарит) — наследуется от AC1 + транзитивно. +- **AC3** (трансформ сохраняет бокс при угле/зеркалировании/масштабе) — + прямые углы точное равенство, 15°/37° вложенность и покрытие >97 %. +- **AC4** (склейка путей сохраняет относительные команды) — + `test/furniture-path-join.test.mjs`, мутант + `furniture-paths-joined-without-reset` логически прослежен; попутная находка + про `stairs`/`tv` подтверждена в исходном сгенерированном коде. +- **AC5** (`furniture:check` падает на нарушении пп.1/2/5) — прочитан код + `svgArt()`/`loadPack()`, три `fail()`-условия соответствуют контракту. +- **AC6** (golden пересняты, диффы объяснены) — 9 кадров, каждый объяснён в + коммите `9bf41ec3`, `Baseline-Reviewed` присутствует. +- **AC7** (скоуп ограничен паком/генератором/`furniture.ts`/тестами) — + `git diff --stat` не содержит редактора/hit-area/конфига/i18n. +- **AC8** (гейты зелёные на точном SHA) — два прогона Validate на `9bf41ec3` + проверены по `headSha` (`35149944216` light, `35145083038` full). +- Математика legacy `plant` (растяжение `1/0.96`), независимая сверка + `svg-path-bounds.mjs` с продакшен-парсером `parseSvgPath` до `1e-6`, + добросовестность приёмки дизайнерского пака, трейлеры и changelog обоих + коммитов, «одно число — один источник» (не применимо), touch/security + (без изменений) — все пункты раздела «Что проверено и корректно» r1. +- Раздел «Чего не проверял» r1 (визуальный осмотр PNG глазами, + `model-invariants`/`pytest` — не применимо, полный перф-профиль + `large-house-*`) остаётся в той же силе: дельта раунда их не касается. + +Новое в этом раунде, что r1 не мог проверить (числа появились только сейчас): +воспроизведение и проверка чисел M1 — выполнено выше, не наследуется, а +проверено заново. + +## Находки + +Не найдено. M1 (единственная блокирующая находка r1) закрыта комментарием с +числами, которые я сверил с закоммиченным манифестом бандла независимо и +получил точное побитное совпадение — не принято на слово. Нового кода, +который нужно было бы разбирать, дельта не вносит, поэтому новых находок по +построению взяться не может (AC не пересматривались, потому что дельта их не +задевает). + +### Low — не найдено + +## Что проверено и корректно + +- **Точность чисел M1** — см. таблицу выше, совпадение до последнего байта + между комментарием и полем `houseplan-assets.json` на `dev` (`e0b16c76`, + тот же код мебели, что и старый `7c5fd32a`) и на `HEAD` (`62d86e0f`). +- **Источник чисел — официальный, не разовый расчёт.** Комментарий ссылается + на поле, которое реально существует в производственном манифесте и + используется гейтом `bundle-budget.mjs`, а не на постороннюю метрику. +- **Смысл цифр в комментарии корректен**: холодный старт (`initialViewGzipBytes`) + практически не меняется (+47 Б — это запись имени нового чанка, не сам + чанк), рост сосредоточен в ленивом чанке мебели, который загружается только + при открытии мебели на плане — соответствует утверждению ТЗ «решение — за + владельцем, если рост окажется заметным» и корректно передаёт масштаб + (+128 % локально в ленивом чанке, но всего +3,1 % во всём ленивом наборе и + +0,016 % в критичном для UX холодном старте). +- **Отсутствие рецидива рабейза/дивергенции**: `origin/dev` продвинулся, но + остался предком материала — не §7.2 «другой код после ребейза». +- Всё унаследованное из r1 (см. раздел выше) остаётся в силе — дельта его не + подрывает: правка M1 не касается ни одного файла, участвующего в AC1–AC8. + +## Чего не проверял + +- **`npx tsc --noEmit`, `npm test`, `npm run build`+сверка бандлов, + `check-docs.mjs`, browser-смоки, `golden:verify`, mutation-gate** — не + гонял повторно: дельта раунда не меняет ни одного файла, участвующего в + этих гейтах (единственный новый файл — `docs/reviews/CODE-REVIEW-584-r1.md`, + сам по себе документация ревью, не код, не тесты, не арт). Эти гейты уже + зелены на идентичном дереве кода — на `9bf41ec3` в r1 (проверено там по + `headSha`) и на `62d86e0f` в актуальном Validate (`35151230014`, `success`, + указан в задании ревью). +- **Полный визуальный осмотр 9 golden-кадров глазами** — не открывал заново; + это уже было явным пунктом «чего не проверял» в r1 и дельта раунда кадры не + трогает. +- **`model-invariants.mjs`, `pytest tests_backend`** — не применимо, как и в + r1: дельта не трогает геометрию комнат/стен/backend, а в этом раунде вообще + не трогает исходный код. + +## Вердикт + +**Зелёный · заход r2 · блокирующих циклов 1/4 · High: 0 · Medium: 0 → в задаче.** + +Единственная блокирующая находка r1 (M1 — рост ленивого чанка мебели не был +назван числом, как того требует раздел «Производительность»/«Риски» ТЗ) +закрыта комментарием автора с числами по официальному источнику +(`bundle-manifest.mjs`/`houseplan-assets.json`). Числа проверены мной +независимо по закоммиченному манифесту на обоих концах диапазона и совпадают +с комментарием побитно: `lazyFurnitureArtGzipBytes` 10 254 → 23 338 Б (+128 %), +`lazyGzipBytes` +3,1 %, `initialViewGzipBytes` (холодный старт, критичный для +бюджета `bundle-budget.mjs`) +47 Б (+0,016 %) — бюджет `301 066` Б не +приближается. Продуктового кода в дельте раунда нет, `origin/dev` продвинулся, +но остался предком материала (не ребейз, §7.2 не применяется). AC1–AC8, +скоуп, трейлеры и changelog наследуются из r1 без повторной проверки — дельта +их не касается. Новых High/Medium/Low находок не появилось. + +--- + +--- + + + +## Материал раунда + +- Ветка: `issue/584-furniture-physical-bounds`, коммит `62d86e0f8361` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `894d037879b76147721b484c5c769dd32eba7383` + ``` + git log --all --format='%H %T' | grep 894d037879b7 + ``` +- Тело issue: `2b6d41955420844101142131ce4f789615f0ac788609ae654f4b416448b03b9b` +- Вердикт конвейера: `green` · High 0