diff --git a/docs/reviews/CODE-REVIEW-640-r1.md b/docs/reviews/CODE-REVIEW-640-r1.md new file mode 100644 index 00000000..52dc8d05 --- /dev/null +++ b/docs/reviews/CODE-REVIEW-640-r1.md @@ -0,0 +1,67 @@ +# 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`, запрет `