Files
houseplan-card/docs/reviews/CODE-REVIEW-229-r3.md
T
claude[bot] 619516806f
Validate / docs (push) Failing after 24s
Validate / changes (push) Successful in 1m10s
Validate / process-gate (push) Failing after 1m14s
Validate / provenance (push) Successful in 1m16s
Validate / reuse (push) Successful in 52s
Validate / hassfest (push) Failing after 33s
Validate / hacs (push) Failing after 47s
Validate / frontend (push) Successful in 7m12s
Validate / backend (push) Failing after 16m13s
Validate / golden (push) Failing after 11m40s
Validate / performance_smoke (push) Failing after 14m46s
Validate / smoke (push) Failing after 32m43s
docs: review document for #229
Issue: #229
User-Visible: no
2026-08-21 10:31:02 +00:00

14 KiB
Raw Blame History

Код-ревью #229 · заход r3

Вердикт: зелёный · заход r3 · блокирующих циклов 2/4 · High: 0 · Medium: 0

Скоуп разбора

Разбор — по дельте, правило §2.9/§2.10. Предыдущий раунд (r2) получен на SHA ed13b4a (документ docs/reviews/CODE-REVIEW-229-r2.md; SHA в самом тексте вердикта не назван — восстановлен по git log и по фразе автора «Коммит ed13b4a» в хендоффе, предшествующем вердикту). Правка по r2 — один коммит fab0c38 («refactor: one function owns the junction geometry of a space»).

Дельта: git diff ed13b4a..HEAD — 11 файлов, из них содержательные src/wall-merge.ts (+33/-0), src/houseplan-card.ts (-16 строк локально, вызов геометрии заменён на одну строчку), src/plan-optimizer.ts (аналогично -13), scripts/mutation-gate.mjs (2 мутанта перенацелены), test/wall-merge.test.mjs (+3 юнита). Остальное — docs/images/screenshots.json (только sourceFingerprint, автоматически из-за изменившегося бандла; imageSha256 не менялся, кадры те же) и коммит с документом ревью r2 (fe2fcef, не код).

Дельта локальна: одна находка (Medium-1 r2), один модуль, ни новая подсистема, ни смена контракта поведения не затронуты — User-Visible: no в коммите верен, продуктовое поведение не менялось ни на шаг, только внутренняя организация кода и тестов. Полный повторный разбор не требуется; объём проверки — сама правка плюс всё, до чего она дотягивается (оба вызывающих места и мутационное покрытие обоих путей).

Находка r2 и её закрытие

Medium-1 (r2, в скоупе, возвращена в задачу): дефект High-1 (двойное масштабирование roomPolygons, из-за которого T-стык партиции к середине комнатной стены не находился) был идентичен в двух местах — _mergeSpacePartitions (карта) и optimizePlans («Оптимизировать планы») — потому что каждый вызывающий строил геометрию примыканий самостоятельно. Регрессионное покрытие защищало только путь оптимизатора; путь карты, который r1 воспроизвёл вторым способом («в браузере через реальные клики»), не имел ни юнита, ни мутанта.

находка чем закрыта где это видно
Medium-1: однобокое покрытие двойного масштабирования room-полигонов, защищён только plan-optimizer.ts Геометрия примыканий (комнаты, колонны, концы черновиков) вынесена в одну функцию spaceMergeGeometry(space, { excludeDraftId }); оба вызывающих теперь однострочный вызов — масштаб можно ошибиться ровно в одном месте src/wall-merge.ts:278-295 (новая функция); src/houseplan-card.ts:6551-6557 и src/plan-optimizer.ts:503-506 (оба вызывающих — по одной строке, без собственного построения геометрии)
— регрессия для обоих путей Мутанты partition-merge-rescales-rooms и chain-merge-sees-own-draft перенацелены с plan-optimizer.test.mjs/смока на общий test/wall-merge.test.mjs, патчат теперь сам spaceMergeGeometry scripts/mutation-gate.mjs:721-741; юниты test/wall-merge.test.mjs:214-262

Закрытие проверено не по заявлению автора, а исполнением (см. «Как проверялось»): оба мутанта, применённые к текущему коду, красят гвард, а не только исходный.

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

Материал: git diff ed13b4a..HEAD и git diff origin/dev...HEAD (полный диапазон issue). Ручного тестирования в цикле нет — далее только то, что исполнено или разобрано по коду с явной пометкой.

Прочитано и разобрано по коду:

  • src/wall-merge.ts:278-295 (spaceMergeGeometry) — сопоставлено построчно со старыми телами обоих вызывающих (см. git diff выше): семантика идентична, включая то, что plan-optimizer.ts не передаёт excludeDraftId — как и раньше, там исключения черновика не было и не нужно (оптимизатор не выполняется во время активного рисования).
  • Проверено отсутствие циклического импорта: wall-merge.ts теперь импортирует roomPoly из ./logic; logic.ts не импортирует wall-merge.ts (grep — 0 совпадений). Компилируется без ошибок (см. ниже) — само по себе уже доказательство при бандлинге через rollup/tsc.

Проверено исполнением:

  • npx tsc --noEmit — чисто.
  • npm test — 1007/1007, без изменений к количеству от заявленного автором.
  • npm run build + сверка трёх копий бандла (dist/houseplan-card.js, custom_components/houseplan/frontend/houseplan-card.js, demo/srv/assets/houseplan-card.js) — идентичны побайтово (sha256 9dd1ec1a…), git status после сборки чист — закоммиченный бандл соответствует исходникам.
  • node scripts/check-docs.mjs — passed (7 файлов, 10 внешних ссылок); подтверждает, что изменение sourceFingerprint в screenshots.json легитимно и не требует новых кадров (imageSha256 не менялся).
  • node scripts/process-gate.mjs — гейт пройден, предупреждений 0.
  • node demo/smoke_wall_chain_merge.mjs — OK, все 9 проверок, включая chainMergesIntoTheWallItTouches, draftIsGone (путь §8.6 через реальные клики).
  • node demo/smoke_wall_junctions.mjs — OK, все 12 проверок (соседняя поверхность — T-стыки и геометрия примыканий).
  • node demo/smoke_optimize_coordinate_canonicalization.mjs — OK, все 13 проверок (путь «Оптимизировать планы»).
  • Дисциплина «тест умеет падать» — оба перенацеленных мутанта проверены вручную (штатный харнесс mutation-gate.mjs непригоден для юнит-гвардов до #235, независимо от этой задачи):
    • partition-merge-rescales-rooms (патч возвращает лишнее деление на 1000 внутри spaceMergeGeometry): наложен на src/wall-merge.ts, пересобран test-build (tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs), node --test --test-name-pattern="issue 229" test/wall-merge.test.mjs дал 2 падения (space geometry keeps rooms in the coordinates… и a junction on a room side survives…, 1 !== 0). Патч снят, повторный прогон — 19/19 зелёных.
    • chain-merge-sees-own-draft (патч заменяет исключение черновика на void exclude): тем же способом — 1 падение (the chain being finished is not its own junction). Патч снят, 19/19 зелёных.
    • После снятия обоих патчей полный npm test — 1007/1007, git status чист (никаких временных правок не осталось).

Не прогонялось и почему: полный набор из 127 смоков, golden:verify, pytest tests_backend, performance-профили — дельта этого раунда не задевает рендер, backend или перф-пути; полные наборы — предрелизный гейт (§8), не гейт ревью соразмерного изменения. Задетые поверхности (карта, оптимизатор, T-стыки, слияние цепочки) покрыты смоками выше и юнитами.

Унаследовано из r1/r2

Без повторной проверки в этом раунде, дельта не касается их доказательной поверхности:

  • AC1, AC3-AC7, AC9 — наследованы уже в r2 из документа docs/reviews/CODE-REVIEW-229-r1.md (SHA 50a00e4); дельта r2→r3 не затрагивает пересчёт host.t, материализацию x/y/angle, допуски, канонизацию направления, транзитивность/порядконезависимость слияния — их код не менялся.
  • AC8 (§8.6, слияние ограничено компонентой связности новой цепочки) — проверено в r1/r2 чтением и смоком; в r3 логика seedIds в mergeCollinearPartitions не менялась, изменился только источник геометрии примыканий, который seedIds не касается. Перепроверено попутно смоком smoke_wall_chain_merge.mjs (chainMergesIntoTheWallItTouches) в этом раунде — совпадает.
  • AC2 (T-стык партиции к середине комнатной стены) — критерий из документа docs/reviews/CODE-REVIEW-229-r2.md (SHA ed13b4a) не наследован вслепую: это и есть предмет дельты r3, перепроверено заново в этом раунде (юнит «a junction on a room side survives, through the shared geometry», исполнен, зелёный; мутант, умеет падать — см. выше).

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

  • spaceMergeGeometry — единственный источник геометрии примыканий для обоих путей; масштаб координат общий с партициями (без лишнего деления), исключение активного черновика — опционально и по умолчанию отключено (важно для пути оптимизатора, где активного черновика не бывает).
  • Новые юниты (test/wall-merge.test.mjs:214-262) покрывают три вещи по отдельности: масштаб полигонов (включая x/y/w/h-комнату и комнату без геометрии), исключение черновика (обе ветки), сам T-стык — и делают это на уровне модуля, не дублируя мутационное покрытие смоком.
  • Трейлеры коммита fab0c38: Issue: #229, User-Visible: no — верно, поведение продукта не меняется, правка рефакторит внутреннюю организацию; changelog не требуется и не тронут.
  • Импорт roomPoly из ./logic в wall-merge.ts не создаёт цикла зависимостей.

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

  • Полный набор смоков (127), npm run golden:verify, python -m pytest tests_backend, performance-профили — не задеты дельтой этого раунда (см. «Как проверялось»).
  • Сценарий «комната через реальные клики» в смоке — автор honestly сообщил, что не взлетел (_offerWallFaces не даёт цепочке завершиться штатно) и оставил покрытие на юнитах общего модуля. Не блокирует: AC2 доказан юнитом на уровне mergeCollinearPartitions/spaceMergeGeometry, что достаточно — геометрия примыканий и механика предложения стен (_offerWallFaces) — разные слои, и дефект r1/r2 жил именно в геометрии. Если понадобится клик-путь через реальную комнату — отдельная работа поверх _offerWallFaces, не предмет этой задачи.

Итог

Обе High из r1 и единственная Medium из r2 закрыты по существу и перепроверены исполнением. Дефект устранён на уровне причины (общая функция геометрии), а не симптома — оба мутанта краснеют для обоих путей из одного патча. Задача готова к выходу из цикла ревью.