Issue: #229 User-Visible: no
14 KiB
Код-ревью #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(SHA50a00e4); дельта 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(SHAed13b4a) не наследован вслепую: это и есть предмет дельты 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 закрыты по существу и перепроверены исполнением. Дефект устранён на уровне причины (общая функция геометрии), а не симптома — оба мутанта краснеют для обоих путей из одного патча. Задача готова к выходу из цикла ревью.