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

163 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Код-ревью #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 закрыты по существу и
перепроверены исполнением. Дефект устранён на уровне причины (общая функция
геометрии), а не симптома — оба мутанта краснеют для обоих путей из одного
патча. Задача готова к выходу из цикла ревью.