mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-02 21:01:21 +00:00
227 lines
19 KiB
Markdown
227 lines
19 KiB
Markdown
# Код-ревью #593 — «Заменить все иконки библиотеки и расширить каталог до 60 плановых символов»
|
||
|
||
Заход: **r1** · блокирующих циклов израсходовано **0/4** (после этого вердикта — 1/4)
|
||
Материал: `7df2740f1ccc3bf14caeca1ae824eed853dda50f` (рабочая копия), один коммит,
|
||
245 изменённых файлов. Ветка была ребейзнута на ушедший вперёд `dev` (влился #594)
|
||
уже на этой вершине — конфликт был только в `dist/**`, `custom_components/.../frontend/**`,
|
||
обоих changelog и `docs/images/screenshots.json`; исходный код мебели трогали одни только
|
||
изменения этой задачи.
|
||
|
||
## 1. Скоуп ревью
|
||
|
||
ТЗ — редакция 4 в теле issue #593 (§1–§12), 11 критериев приёмки (AC1–AC11). Ревью
|
||
полное: это первый заход code review, дельты от предыдущего раунда нет (спор
|
||
был только в рамках самой спецификации, r1–r4 которой уже закрыт владельцем).
|
||
|
||
## 2. Как проверялось
|
||
|
||
Дешёвые гейты на `7df2740f` уже зелёные (Validate run 35438169526: success), поэтому
|
||
`npx tsc --noEmit`, `npm test`, `npm run build` заново не гонялись. Пересобраны и
|
||
прогнаны:
|
||
|
||
| команда | результат |
|
||
|---|---|
|
||
| `npm run build && npm run bundle:sync` | бандл собран, три копии дерева совпали |
|
||
| `npm run furniture:check` | `Furniture pack OK: 60 plan symbols, 33 menu icons (generated files current)` |
|
||
| `npm run bundle:budget` | initial View 290836/291400 ±2000 · lazy editor 221927/222900 ±2000 · lazy furniture art 16943/17900 ±2000 — все три внутри полосы |
|
||
| `node scripts/check-docs.mjs --screenshots=strict` | `Documentation checks passed (7 files, 12 external links)` |
|
||
| `node scripts/smoke-select.mjs --base origin/dev --head HEAD` | прямое совпадение: `smoke_decor.mjs`, `smoke_furniture_lazy_art.mjs`, `smoke_furniture.mjs` |
|
||
| `node demo/smoke_furniture.mjs` | OK, все факты `true`, включая `paletteShowsThirtyTwoCategories`, `newCategoriesAreVisible`, `requiredCategoriesArePresent`, `menuOnlyCategoriesStayHidden` |
|
||
| `node demo/smoke_furniture_lazy_art.mjs` | OK, включая `failedChunkDrawsNothingAtAll: true` (Q2) |
|
||
| `node demo/smoke_furniture_polish.mjs` | OK (не в прямой выборке инструмента, но назван в AC6 автором — прогнан) |
|
||
| `node demo/smoke_decor.mjs` | OK (прямое совпадение по символу `FURNITURE`) |
|
||
| `npm run golden:verify` (полная матрица, Chromium 151.0.7922.34 — совпадает с каноном) | 3 сцены `different`, 1 `missing-baseline` (новая сцена), остальные `passed`; разбор — находка §4.2 |
|
||
| прямые вычисления по `pack.json` / `test-build` (см. §4.1) | AC1–AC4 проверены исполнением скрипта, а не чтением |
|
||
|
||
Ручной проверкой кода (без исполнения): состав мутантов в `scripts/mutation-registry.mjs`
|
||
(5 новых + 1 исправленный), провенанс-документ пакета, i18n-диффы, docs/CHANGELOG*,
|
||
`docs/STATUS.md`, `docs/USER-GUIDE.ru.md`, `docs/ARCHITECTURE.md`.
|
||
|
||
## 3. Находки
|
||
|
||
### Medium 1 — `docs/ARCHITECTURE.md` не обновлён, хотя ТЗ явно называет это условием
|
||
|
||
`docs/ARCHITECTURE.md:249` до сих пор говорит: «Designer furniture artwork follows
|
||
the same shape (#474): the catalogue (ids, groups, default sizes) stays eager,
|
||
**the 44 SVG drawings** live in `lazyFurnitureArtFiles`…». После задачи их **60**,
|
||
и союза с примитивами (12 retained) тоже больше нет — а абзац именно про этот
|
||
механизм (см. `git diff` — файл вообще не тронут этой задачей).
|
||
|
||
ТЗ §9 называет условие явно: «`docs/ARCHITECTURE.md` — если там названо число 44
|
||
или союз с примитивами». Условие выполнено (искал `grep -n "44\|primitive"
|
||
docs/ARCHITECTURE.md` — единственное релевантное вхождение это строка 249), правка
|
||
не сделана. Расхождение будет видно любому, кто читает архитектурный документ
|
||
после `docs/FURNITURE.md` (там число уже 60) — источники разойдутся.
|
||
|
||
**Воспроизведение:** `grep -n "44 SVG drawings" docs/ARCHITECTURE.md` → строка 249,
|
||
не изменена в `git diff origin/dev...HEAD -- docs/ARCHITECTURE.md` (диф пуст).
|
||
|
||
### Medium 2 — сцена `tray-narrow-palette-en` меняется, но не объявлена в списке golden-приёмки
|
||
|
||
ТЗ §8 объявляет ровно 10 сцен, которые разойдутся с эталоном («Объявляются заранее,
|
||
чтобы `--expect-change` был написан до прогона, а не подогнан под результат»).
|
||
`node scripts/rebase-on-dev.mjs`/хендофф этот список повторяют без изменений.
|
||
|
||
Прогнал `npm run golden:verify` на пересобранном бандле этой самой вершины,
|
||
Chromium 151.0.7922.34 (совпадает с каноном из `docs/images/screenshots.json`, то
|
||
есть это не шум чужой среды). Результат — **три** сцены `different`, а не две:
|
||
|
||
```
|
||
tray-narrow-palette-en different diffRatio 0.0022 ← НЕ в списке §8
|
||
furniture-categories-light different diffRatio 0.0034 (объявлена)
|
||
furniture-placement-preview-light different diffRatio 0.0031 (объявлена)
|
||
```
|
||
|
||
`tray-narrow-palette-en` (`demo/golden/matrix.mjs:616-618`) рендерит ту же
|
||
двухуровневую палитру категорий (`furniturePalette: 'categories'`) на узком
|
||
вьюпорте — те же новые 33 иконки меню и 32 категории, что и у объявленной
|
||
`furniture-categories-light`, просто в другой раскладке. Соседние `tray-*` сцены
|
||
(`tray-wide-selection-en`, `tray-medium-group-en`, `tray-medium-selection-ru`) —
|
||
все `passed`, то есть разница локализована именно в контенте палитры мебели, а
|
||
не в шуме раскладки/шрифта.
|
||
|
||
Это не абстрактный риск: `scripts/golden-acceptance.mjs` → `goldenAcceptanceRefusal`
|
||
буквально отказывает приёмке при необъявленной `different`-сцене («съёмка
|
||
разошлась с принятыми эталонами в сценах, которые менять не собирались... приёмка
|
||
запрещена»). Владелец планирует принимать эталоны отдельным шагом со своей машины
|
||
(§8, риск №4) — с текущим списком `--expect-change` эта команда откажет именно на
|
||
`tray-narrow-palette-en`, и раунд придётся повторить только из-за неполного списка.
|
||
|
||
**Воспроизведение:** `npm run build && npm run bundle:sync && npm run golden:verify`
|
||
на этой вершине → `artifacts/golden/golden-report.json`, `results[].id ==
|
||
'tray-narrow-palette-en'`, `status: 'different'`.
|
||
|
||
**Что делать:** дописать `tray-narrow-palette-en` в перечень §8 (и, соответственно,
|
||
в `--expect-change` будущей команды приёмки). Кода это не касается — только текста
|
||
объявленного списка, который передаётся владельцу.
|
||
|
||
Оба High отсутствуют. Обе находки — Medium **в скоупе** задачи (одна прямо названа
|
||
условием ТЗ §9, вторая — прямое следствие изменённого набора SVG меню, которое ТЗ
|
||
само описывает в §8). По правилу PROCESS.md §12 (2026-08-19, #202) отдельный issue
|
||
не заводится — обе чинятся в этой же ветке.
|
||
|
||
## 4. Проверено и подтверждено исполнением (AC1–AC11)
|
||
|
||
- **AC1** (пакет 33/60, идентичность): `npm run furniture:check` → `OK: 60 plan
|
||
symbols, 33 menu icons`; прямым JSON-разбором `pack.json` — `menu_icons.length
|
||
=== 33`, `symbols.length === 60`, `pack_version === '0.4.0'`, `author`/`license`
|
||
корректны.
|
||
- **AC2** (совместимость ID): вычислил множество старых публичных ID (44 дизайнерских
|
||
из `houseplan-0.3.0/pack.json` + 12 retained из `LEGACY_FURNITURE`/`RETAINED_IDS`
|
||
на `origin/dev`) против новых 60 — расхождение `missing: []`, `added: ['computer',
|
||
'hood', 'oven', 'cactus']`. Ровно как требует ТЗ.
|
||
- **AC3** (mapping/категории): `menu_icons` минус используемые `symbols[].menu_icon`
|
||
→ пустая ровно `exercise`; занятых категорий 32. `cactus.menu_icon === 'plant'`.
|
||
Подтверждено также смоком (`paletteShowsThirtyTwoCategories`,
|
||
`menuOnlyCategoriesStayHidden`, `newCategoriesAreVisible` — все `true`).
|
||
- **AC4** (сохранённые размеры): вычислил объединённые старые размеры (44 из
|
||
0.3.0 pack.json + 12 из примитивов на `origin/dev` `src/furniture.ts`) и сравнил
|
||
с новыми `width_cm/depth_cm` для тех же 56 ID — `mismatches: []`. Таблица
|
||
`BEFORE` в `test/furniture.test.mjs` подтверждена независимым пересчётом, а не
|
||
просто прочитана.
|
||
- **AC5** (inert-subset): `furniture:check` не ослаблен (генератор — тот же файл,
|
||
правки только в константах идентичности пакета, см. `git diff
|
||
scripts/generate-furniture-assets.mjs` — 3 строки).
|
||
- **AC6** (UX палитры): `demo/smoke_furniture.mjs` и `demo/smoke_furniture_polish.mjs`
|
||
— оба зелёные на пересобранном бандле этой вершины.
|
||
- **AC7** (видимость 60 вариантов): golden-сцена `furniture-new-symbols-light`
|
||
добавлена в матрицу (версия 63→64), содержит все 4 новых ID; статус в отчёте —
|
||
`missing-baseline` (ожидаемо, эталона ещё нет). Остальной мебельный срез
|
||
разобран в §3 (Medium 2). `test/pdf-scene.test.mjs`/`test/pdf-svg-path.test.mjs`
|
||
не менялись и не нуждались — уже параметризованы по каталогу, не по примитивам.
|
||
- **AC8** (lazy split, отказ чанка): `demo/smoke_furniture_lazy_art.mjs`
|
||
зелёный, `failedChunkDrawsNothingAtAll: true`, `foreignBuildFallsBackLikeNetworkFailure`
|
||
тоже смотрит на `furniture === 0`. `furnitureArtIsLazy` в `src/furniture.ts`
|
||
теперь `BY_ID.has(id)` — унифицировано для всех 60.
|
||
- **AC9** (бюджеты-гейты): `lazyGraphCeilingViolation` — новый экспорт,
|
||
используется в `assertBundleBudget`; `npm run bundle:budget` на собранном
|
||
бандле подтверждает обе новые проверки внутри полосы (лог в §2). Тест
|
||
`test/bundle-assets.test.mjs` сверяет и реальный `dist/houseplan-assets.json`,
|
||
и синтетику по обе стороны полосы, и «зазор > 500 Б» с обеих сторон — как
|
||
требует §7 ТЗ.
|
||
- **AC10** (провенанс/грант/лицензия): `assets/furniture/houseplan-0.4.0/README.md`
|
||
несёт ссылку на грант `issuecomment-5739841899`, имя архива
|
||
`houseplan-furniture-0.4.0.zip`, SHA-256 `69BA5E0C…`. Тест `release provenance
|
||
is normalized...` в `test/furniture-assets.test.mjs` — 6 assert (2 equal + 4
|
||
match) против 5 у версии на `origin/dev` (2 equal + 3 match): число проверок
|
||
**не уменьшилось**, требование ТЗ §4 п.10 выполнено буквально.
|
||
- **AC11** (доказательства/команды): хендофф от 2026-09-19 называет команды и
|
||
результат; после ребейза — второй хендофф с полным списком (`furniture:check`,
|
||
`npm test` 2787/2786/1 skipped, `bundle:sync`, `bundle:budget`,
|
||
`docs:accept -- --identical` 11/11, `mutation-gate.mjs --check`,
|
||
`process-gate.mjs`). Я independently повторил релевантную часть (см. §2) на
|
||
этой же вершине.
|
||
|
||
Ловушка союза `LEGACY_FURNITURE ∪ GENERATED_FURNITURE_CATALOG` (§5 ТЗ) закрыта
|
||
буквально: `LEGACY_FURNITURE`, `RETAINED_IDS`, тип `Prim`, `box()`,
|
||
`primitivePathD` удалены из `src/furniture.ts`, `FURNITURE` — прямое отображение
|
||
`GENERATED_FURNITURE_CATALOG`. Мутант `furniture-legacy-shadows-designer-art`
|
||
воспроизводит именно эту ловушку патчем на `src/furniture.ts` и ловится
|
||
`test/furniture-assets.test.mjs`/`test/furniture.test.mjs` (подтверждено автором
|
||
как «1 из 1» на этой же вершине после ребейза, и я не нашёл оснований сомневаться
|
||
— код мутанта соответствует описанию, `node --check
|
||
scripts/mutation-registry.mjs` синтаксически чист).
|
||
|
||
i18n: 7 ключей × 4 локали = 28 добавленных строк, посчитано `git diff` построчно —
|
||
ровно совпадает с §6 ТЗ. `furn.cat_exercise` не добавлен — верно, категория скрыта.
|
||
|
||
## 5. Чего не проверял и почему
|
||
|
||
- **`npm run typecheck` / `npm test` / `npm run build` "с нуля"** — не гонял:
|
||
Validate на этой же вершине (`7df2740f`) зелёный (run 35438169526), а рекомендация
|
||
задания прямо разрешает не повторять эти три гейта при зелёном Validate на
|
||
материале. `npm run build` я всё же выполнил (дважды) — но не ради этого гейта,
|
||
а чтобы получить свежий бандл для golden/smoke, поэтому неявно он подтверждён
|
||
тоже (чисто, без ошибок typecheck).
|
||
- **`npm run gate:small -- --smokes`, полный `demo/smoke_*` (250 файлов)** —
|
||
не требовалось: diff не «широкий» символ (11 попаданий на изменённых строках,
|
||
порог — 50), инструмент назвал 3 сцены прямого совпадения, все три прогнаны.
|
||
Дополнительно прогнал `smoke_furniture_polish.mjs`, названный в AC6 автором.
|
||
- **`python -m pytest tests_backend`** — diff не касается
|
||
`custom_components/houseplan/**/*.py` (`git diff --stat` подтверждает: ни одного
|
||
Python-файла в дифе).
|
||
- **`npm run invariants -- --config …`** — diff не касается геометрии/ссылок
|
||
(рёбра комнат, толщина, `layout`, `marker.space`, `open_spans`); мебель — decor
|
||
без геометрической модели (ТЗ и `docs/FURNITURE.md` это прямо фиксируют).
|
||
- **`node scripts/mutation-gate.mjs`** — не перегонял сам (это дорогой полный
|
||
прогон); полагаюсь на то, что диффовый mutation-gate — часть Validate на
|
||
review-кандидате (`.github/workflows/validate.yml`, шаг `mutation-gate.mjs
|
||
--changed=$base..$HEAD_SHA`), а он зелёный на этой же вершине, плюс автор
|
||
отдельно перепроверил ключевые мутанты после ребейза.
|
||
- **Приёмка golden-эталонов (`golden:accept`)** — вне досягаемости ревьюера
|
||
(нужна машина владельца с полным Linux CI артефактом), что верно и названо
|
||
в самом ТЗ (§8, риск №4). `golden:verify` (advisory, легален где угодно) я
|
||
прогнал — и это как раз дало находку Medium 2.
|
||
- **`node scripts/process-gate.mjs --issues`** — требует `gh` с правами записи
|
||
в контексте задачи; не относится к предмету код-ревью.
|
||
|
||
## 6. Вердикт
|
||
|
||
Одиннадцать AC доказаны — частично чтением, частично (там, где это имело смысл:
|
||
подсчёт множеств ID/размеров, смоки, бюджеты, golden) независимым исполнением на
|
||
этой же вершине, не только цитированием хендоффа. Явных дефектов поведения не
|
||
нашёл: ловушка союза каталогов закрыта, Q1/Q2/Q3 реализованы буквально, бюджеты
|
||
стали настоящим гейтом, провенанс не ослаблен.
|
||
|
||
Две находки Medium — обе в скоупе, обе не требуют выхода за пределы задачи:
|
||
пропущенная правка `docs/ARCHITECTURE.md` (условие ТЗ §9 сработало, но не
|
||
выполнено) и неполный список golden-сцен для будущей приёмки эталонов (реальный,
|
||
воспроизведённый на каноническом Chromium диф, который иначе откажет команде
|
||
`golden:accept`). High нет.
|
||
|
||
**Вердикт: жёлтый · заход r1 · блокирующих циклов 1/4 · High: 0 · Medium: 2 → в задаче**
|
||
|
||
---
|
||
|
||
<!-- material-anchors: сгенерировано конвейером (#414) -->
|
||
|
||
## Материал раунда
|
||
|
||
- Ветка: `issue/593-furniture-pack-0.4.0`, коммит `7df2740f1ccc` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
|
||
- Дерево материала: `4141dff7cb0ad45e725cc54b9fac4ce7a156a9cc`
|
||
```
|
||
git log --all --format='%H %T' | grep 4141dff7cb0a
|
||
```
|
||
- Тело issue: `3a8d99615191f61cc781ac873210df277ce0951d828113e3efa89700a5b7b6a3`
|
||
- Вердикт конвейера: `yellow` · High 0
|