mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-28 19:01:34 +00:00
docs: review document for #640
Проверка (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
Проверка (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
Issue: #640 User-Visible: no
This commit is contained in:
@@ -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`, запрет `<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.
|
||||
|
||||
---
|
||||
|
||||
<!-- material-anchors: сгенерировано конвейером (#414) -->
|
||||
|
||||
## Материал раунда
|
||||
|
||||
- Ветка: `issue/640-dishwasher-menu-icon`, коммит `6a905d9ac87d` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
|
||||
- Дерево материала: `fc8674b16271690bd68fd016f979a045379f04ce`
|
||||
```
|
||||
git log --all --format='%H %T' | grep fc8674b16271
|
||||
```
|
||||
- Тело issue: `1336c4649192ea657779f92aeaf1daff7c7f23c2b85316d89d401bcd9f06101f`
|
||||
- Вердикт конвейера: `green` · High 0
|
||||
@@ -1,10 +1,11 @@
|
||||
# Индекс ревью
|
||||
|
||||
Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 1004, issue: 349. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`.
|
||||
Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 1005, issue: 349. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`.
|
||||
|
||||
| Issue | Документ | Этап · раунд | Вердикт | H | M | Находки | Файлы |
|
||||
|---|---|---|---|---:|---:|---|---|
|
||||
| #640 | [SPEC-REVIEW-640-r1.md](SPEC-REVIEW-640-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | AC3 называет browser-smoke «unit»-тестом | `demo/smoke_furniture_lazy_art.mjs` |
|
||||
| #640 | [CODE-REVIEW-640-r1.md](CODE-REVIEW-640-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — |
|
||||
| #639 | [CODE-REVIEW-639-r1.md](CODE-REVIEW-639-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | Новая запись smoke-links.mjs для smoke_space_settings_form.mjs описывает проверку, кото… | `smoke-links.mjs` `smoke_space_settings_form.mjs` `scripts/smoke-links.mjs` `demo/smoke_space_settings_form.mjs` `src/editors/space-form.ts` `form-kit.ts` |
|
||||
| #639 | [CODE-REVIEW-639-r2.md](CODE-REVIEW-639-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — |
|
||||
| #637 | [CODE-REVIEW-637-r1.md](CODE-REVIEW-637-r1.md) | code · r1 | 🟡 жёлтый | 0 | 1 | ложный «—» вместо настоящего «0 ч» в медианах | `scripts/process-metrics.mjs` |
|
||||
|
||||
Reference in New Issue
Block a user