Files
houseplan-card/docs/reviews/CODE-REVIEW-176-r1.md
T
2026-08-19 13:24:29 +00:00

13 KiB
Raw Blame History

CODE-REVIEW-176-r1

Issue: #176 — удалить мёртвый код старого инструмента Partition после #173. Трек: small (лёгкий), тип tech-debt, User-Visible: no. Ревьюер ≠ автор, свежая сессия без контекста реализации.

Скоуп

Диапазон: git log --oneline origin/dev..HEAD → один коммит f66e671 refactor: remove dead partition tool state (Issue: #176, User-Visible: no), ветка issue/176-remove-dead-partition-tool.

git diff origin/dev...HEAD --stat: 16 файлов, +142/−127. Продукт: src/houseplan-card.ts, src/i18n/en.json, src/i18n/ru.json. Гейты/тесты: test/unified-wall-tool-source.test.mjs (новый), test/golden-matrix.test.mjs, demo/smoke_free_walls.mjs, demo/smoke_plan_snap_overlay.mjs, demo/golden/harness.mjs. Документация: docs/STATUS.md, docs/TESTING.md, docs/images/screenshots.json + два PNG. Сгенерированное: три bundle-копии. Состав в точности совпадает с разделом «Затрагиваемые поверхности» ТЗ — расширения скоупа нет.

ТЗ (лёгкий трек, тело issue) прошло SPEC-REVIEW-176-r1 зелёным цветом.

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

Гейт Прогнан Результат
npx tsc --noEmit да чисто, без ошибок
npm test да 908/908, совпадает с хендоффом автора
npm run build + сверка 3 bundle-копий да cmp dist↔frontend↔demo/srv — идентичны
test/unified-wall-tool-source.test.mjs изолированно, затем на дореформенном src/houseplan-card.ts+en.json+ru.json (снятых из origin/dev) да на новом коде: 2/2 green; на старом коде (до #176): оба подтеста падают (title.markup_partition присутствует, this._tool === 'partition' matches) — тест умеет падать
node demo/smoke_unified_wall_tool.mjs (назван в AC2) да все 19 проверок true, OK
node demo/smoke_free_walls.mjs (назван в AC2, тронут диффом) да все 13 проверок true, OK
node demo/smoke_plan_snap_overlay.mjs (назван в AC2, тронут диффом) да все 35 проверок true, OK
node scripts/check-docs.mjs (без --external) да «Documentation checks passed (7 files, 10 external links)» — проверяет ровно то, что тронул диффом screenshots.json
python -m pytest tests_backend нет диапазон не касается custom_components/**/*.py (проверено git diff --stat -- '*.py' — пусто)
npm run golden:verify нет диапазон не меняет golden-baseline (demo/golden/baselines/** не тронут) и не расширяет визуальный контракт: оба реальных planSnap-сценария в demo/golden/matrix.mjs уже используют tool: 'draw' — сужение допустимых значений в golden-matrix.test.mjs/harness.mjs не меняет поведение существующих сценариев. Отложено на предрелизный гейт по правилу «полные наборы — гейт релиза, не ревью»
Остальные 124 браузерных смока нет диапазон касается только draw/partition-веток Plan editor; названные в AC покрывают все тронутые файлы, остальные поверхности (View, Devices editor, sun/light, isometric и т.д.) не задеты диффом
Полный производительный профиль нет в AC не назван, диффом не затронут (изменение — вычитание мёртвых веток, не новый путь выполнения)

Проверка AC по пунктам

AC1 — «мёртвый tool-state удалён». Подтверждено чтением и исполнением. grep по src/houseplan-card.ts не находит ни одного сравнения this._tool с 'partition' в любом порядке, самого MarkupTool/MARKUP_TOOLS без 'partition', метод _partitionClick отсутствует. Диспетчер клика (_markupClick, ветка после 'column', строка ~6826) падает в единственный default-путь Walls, ровно как заявлено в контракте №1. Источник доказательства — test/unified-wall-tool-source.test.mjs, который я прогнал и на новом, и на дореформенном исходнике: тест умеет падать (см. таблицу выше). Доказано.

AC2 — «совместимость и существующие независимые стены сохранены».

  • Legacy warm-token: normalizeUnifiedWallTool('partition') === 'draw' (src/wall-face-graph.ts:53-55) не тронут этим диффом; покрыт существующим (неизменённым) test/wall-face-graph.test.mjs:21 и я прогнал npm test зелёным. Проверено чтением цепочки normalizeMarkupTool → normalizeUnifiedWallTool, вызываемой из _restoreViewport при this._tool = normalizeMarkupTool(vp.tool) (строка 2651) — единственная точка присвоения _tool из внешнего/сохранённого значения.
  • Persisted-модель: space.partitions, PartitionCfg, kind: 'partition' у selection/drag/opening-host, _partitionDeleteDialog, _limitReached('partition') (лимит на количество, не tool-state), история history.partition_add, physical.partition_properties — все на месте, я перечислил их grepом и ни один не зависит от this._tool.
  • Создание независимой стены через завершение открытой Walls-chain, snap первого/второго клика, pan/pinch/pointercancel, свойства и удаление — подтверждено исполнением smoke_unified_wall_tool, smoke_free_walls, smoke_plan_snap_overlay (все green, см. таблицу). Доказано.

AC3 — «удалены только осиротевшие тексты и тестовый старый API». En/ru сверены построчно (grep по обоим locale): отсутствуют title.markup_partition, markup.hint_partition, physical.partition_size_title — ровно три ключа из ТЗ, включая самостоятельно найденный автором третий; при этом markup.partition, physical.partition_properties, history.partition_add присутствуют. Дополнительная проверка вне репозитория подтвердила, что удалённые ключи не используются больше нигде (grep по *.ts/*.mjs/*.json/*.md — только исторические документы ревью). Golden matrix/harness теперь принимают только 'draw'; я проверил, что оба реальных planSnap-сценария в demo/golden/matrix.mjs уже были на 'draw', так что визуальный результат не меняется (подтверждено чтением, не golden:verify). npm run build и cmp трёх bundle-копий — зелёные. Доказано.

Побочная находка — не дефект

docs/images/06-device-editor.png и 06-device-display-preview.png изменили imageSha256 (не только sourceSha256) — на первый взгляд странно для User-Visible: no рефактора Plan editor, раз эти два скриншота относятся к Device editor. Извлёк оба PNG из origin/dev и HEAD, сравнил пикселями (PIL.ImageChops.difference): разница ограничена одним пикселем на координате (1141,18)-(1142,19), отклонение ±1 только по одному каналу — это шум рендеринга/антиалиасинга при пере-захвате скриншотов, обязательном из-за смены sourceFingerprint (хеш всего src/**, а не только тронутых строк), а не видимое изменение продукта. Остальные 7 скриншотов вообще не изменили imageSha256. Не является находкой — зафиксировано, чтобы объяснить бинарный diff, а не оставить его без разбора.

Находки

Нет находок уровня High или Medium. Low не заведено — не найдено ни одного предмета, который стоило бы фиксировать как Low.

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

  • Все обязательные быстрые гейты зелёные (typecheck/test/build+cmp).
  • AC1–AC3 доказаны либо автотестом с проверенной способностью падать, либо прямым исполнением названных в AC браузерных смоков, либо чтением с явной пометкой.
  • Трейлеры коммита корректны: Issue: #176, User-Visible: no; при no changelog не требуется и не тронут — соответствует правилу.
  • Имя ветки issue/176-remove-dead-partition-tool соответствует трейлеру.
  • Скоуп диффа совпадает с «Затрагиваемые поверхности» ТЗ файл-в-файл; попутных правок «раз уж я здесь» не найдено.
  • Граница «мёртвый tool-code vs живая persisted-модель независимых стен» выдержана по всему файлу — ни одно использование kind: 'partition' / space.partitions не привязано к this._tool.
  • docs/TESTING.md обновлён точно: новая строка про legacy-токен ссылается на wall-face-graph.test — этот тест существовал и до #176 (диффом не тронут), проверил утверждение assert.equal(normalizeUnifiedWallTool('partition'), 'draw') напрямую в файле.
  • docs/STATUS.md корректно добавляет #176 в описание текущего цикла бета-4.

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

  • Полный HA-бэкенд-харнесс (python -m pytest tests_backend) — диапазон не трогает custom_components/**/*.py, гейт не применим.
  • npm run golden:verify — не прогонял; аргументация в таблице выше (сужение контракта не задевает реальные сценарии, подтверждено чтением demo/golden/matrix.mjs). Это сознательное решение, а не молчаливый пропуск; выполнится штатно на предрелизном гейте.
  • Оставшиеся 124 из 127 браузерных смоков — не относятся к тронутым draw/ partition-путям Plan editor; полный набор не запускался, т.к. задача не задевает все поверхности.
  • Performance-профили — не названы в AC и не затронуты диффом (чистое вычитание недостижимого кода не меняет hot path).
  • node scripts/check-docs.mjs --external (сетевые ссылки) — прогнан без --external, сетевую часть не гонял, чтобы не делать внешние вызовы из ревью-сессии; она не зависит от этого диффа (никакие ссылки не менялись).
  • Ручного тестирования в браузере не было — по процессу его нет в цикле; роль ручной проверки здесь выполняет прогон именованных в AC смоков.

Вердикт

Зелёный. Цикл r1/2 (лёгкий трек, лимит код-ревью — 2). High: 0. Medium: 0. Находок для возврата или для отдельного issue нет.