15 KiB
CODE-REVIEW-307-r1
Issue: #307 · «Рисование стен: осевые линии и узлы не видны на уже поставленных
сегментах цепочки до её завершения» · трек small (ТЗ в теле issue) · заход r1
(первый цикл) · бюджет циклов лёгкого трека 0/2 израсходовано.
Ветка приведена к dev конвейером до ревью (893a9aa0 → 11343454, +1 коммит
dev). Разбор полный (это первый заход, вопрос «дельта vs полный разбор» из
§2.10 к r1 не применяется).
Коммит под ревью: 11343454 — fix: keep the active chain axis and nodes above the wall bodies (#307). Единственный коммит в диапазоне
origin/dev..HEAD.
Скоуп
Симптом: во время рисования цепочки стен (Plan → «Стены») уже поставленные
сегменты не показывают осевую линию и узлы — их закрашивает непрозрачное тело
свежеперсистнутого драфта. Видна только резинка (.active-axis/
.active-vertex) активного отрезка. Причина зафиксирована в issue двумя
пунктами: (1) .pathline/.vertex рисовались в _renderMarkupLayer, который
вставлен в композицию до _renderWallBodies; (2) снап-оверлей рисуется
после тел, но намеренно исключает активный драфт из геометрии — это
осознанное решение, не трогается.
Заявленное решение (вариант A из issue): вынести разметку активной цепочки в отдельный editor-слой, вставленный после тел стен и до снап-оверлея.
Соответствует Core user job из docs/SCOPE.md: J6 «Keep the plan true as the
home evolves» (два редактора, drag/resize) — сам инструмент рисования стен;
чинится визуальная обратная связь редактора, не продуктовая функция. Вне
скоупа продукта задача не выходит: чисто editor-only правка рендеринга,
никакого нового поведения, конфига или контракта.
Как проверялось
| Гейт | Результат | Команда |
|---|---|---|
| typecheck | зелёный, без вывода | npx tsc --noEmit |
| unit-тесты | 1304 pass / 0 fail / 1 skipped | npm test |
| build | собран, 14 с | npm run build |
| сверка 3 копий бандла | идентичны после пересборки (md5sum совпал с закоммиченными dist/ и custom_components/.../frontend/, bundle:sync пересоздал недостающую demo/srv/assets/ копию) |
npm run build && npm run bundle:sync |
docs (docs job) |
зелёный, отпечаток скриншотов совпал | node scripts/check-docs.mjs → «Documentation checks passed (7 files, 10 external links)» |
новый смок demo/smoke_active_chain_ink.mjs |
OK (пиксельные пробы axisMidYellow: true, nodeYellow: true, RGB [255,193,77]/[129,87,23]) |
node demo/smoke_active_chain_ink.mjs |
тот же смок на коде до фикса (HEAD~1:src/houseplan-card.ts, пересобран) |
падает: inkAboveBodies: false, axisMidYellow: false, nodeYellow: false (пиксели [255,255,255] — фон вместо оси) — тест умеет ловить регрессию |
node demo/smoke_active_chain_ink.mjs на откаченном src, дерево затем полностью восстановлено до HEAD |
выборка смежных смоков (smoke-select.mjs, 14 прямых совпадений по _path/_cursorPt/_markup/_contourClosed/Axis) |
все 14 — OK | см. список ниже |
npm run golden:verify (полная матрица, 127 сценариев) |
все passed, включая 4 сценария из группы риска |
npm run golden:verify |
npm run invariants |
не прогонялся — не применимо, см. «Чего не проверял» | — |
python -m pytest tests_backend |
не прогонялся — diff не касается custom_components/**/*.py |
— |
Прямые совпадения smoke-select.mjs, прогнанные все 14 — все OK:
smoke_draw_wall_thickness, smoke_align_guides, smoke_editor_gestures,
smoke_plan_drawing_repairs, smoke_plan_snap_overlay (AC3 явно требует его),
smoke_room_autoclose, smoke_unified_wall_tool, smoke_wall_junctions,
smoke_edit_walk, smoke_merge_split, smoke_optimize_coincident_partition,
smoke_resize_audit_1550, smoke_room_resize, smoke_split_nonsnap.
«Слабую связь» (18 смоков, одно распространённое имя _path/_cursorPt) не
гонял — ни один не выглядит специфичным к слоям композиции плана, а прямые
совпадения уже покрывают draw/junction/snap/resize/merge-split поверхность.
npm run golden:verify запускался несмотря на то, что ТЗ его не называет,
по прямому предписанию процесса: diff — это переупорядочивание editor-only
SVG-слоёв (изменился z-order .pathline/.vertex/.active-axis/
.active-vertex относительно тел стен), то есть «может изменить видимый
результат: слои». Нашёл 4 golden-сценария в plan-режиме, которые выставляют
card._path/_tool='draw' поверх настоящей геометрии стен
(plan-snap-endpoint-light, plan-snap-line-gaps-dark,
wall-junctions-plan-preview-light, wall-junctions-plan-t-dark —
demo/golden/matrix.mjs:266-285, demo/golden/harness.mjs:965-1017) — это
ровно тот класс состояния (резинка/поставленные точки цепочки поверх
реальных стен), для которого правка меняет порядок отрисовки. Полная матрица
прошла зелёной без единого расхождения — риск проверен и снят, а не просто
предположен.
Находки
Отсутствуют. High: 0, Medium: 0, Low: 0.
Что проверено и корректно
AC1 (ось и узлы видны на поставленных сегментах). Доказано автотестом
(demo/smoke_active_chain_ink.mjs), тест умеет падать — прогнан на коде до
фикса, три проверки красные с ожидаемым фоновым цветом вместо жёлтого. На
текущем коде все проверки зелёные, включая точные RGB-пробы в середине оси
первого сегмента и в узле.
AC2 (слой цепочки между телами и снап-оверлеем, резинка не регрессирует). Доказано чтением кода и тем же смоком:
src/houseplan-card.ts:17565(_renderWallBodies) →:17585-17586(новый<g class="hp-editor-only-layer">вокруг_renderActiveChainInk()) →:17587-17588(_renderPlanSnapOverlay) — порядок в композиции совпадает с контрактом ТЗ «после тел, до снап-оверлея».- Смок проверяет тот же факт через
compareDocumentPositionв DOM (inkAboveBodies,inkBelowSnapOverlay) — оба true. - Резинка (
.active-axis/.active-vertex) перенесена в тот же новый метод_renderActiveChainInk(:20057-20074) без изменения условий рендера — идентичный JSX-блок, только другое место вставки; смок подтверждает присутствие обоих элементов при активном курсоре. - Инструмент «Split» использует свои собственные
.pathline/.vertexвнутри_renderMarkupLayer(:20033-20040) — их ТЗ явно оставляет на месте, и диф их не трогает: отдельный блок кода, не задет переносом.
AC3 (снап не меняется). src/plan-snap-overlay.ts не входит в diff
(проверено — пустой git diff по файлу). smoke_plan_snap_overlay зелёный.
Существующие юнит-тесты снапа входят в общий зелёный прогон npm test (1305
тестов, ни один не упал). Проверено чтением + существующим смоком, как и
требует AC.
CSS не завязан на структуру родителя. .pathline, .vertex,
.active-axis, .active-vertex — глобальные селекторы классов в
src/styles.ts:1803-1863, не скоупятся через потомство конкретного <g>.
Перенос элементов в новый <g class="hp-editor-only-layer"> (тот же паттерн,
что уже используют align-guides, hidden-wall-diagnostics,
opening-placement-preview, снап-оверлей — opacity="${modeVisual?.editorWeight ?? 1}") не требует правок стилей и не ломает editorWeight-затемнение в
неактивных режимах.
Трейлеры и changelog. Единственный коммит несёт Issue: #307 и
User-Visible: yes; оба docs/CHANGELOG.md/docs/CHANGELOG.ru.md правлены в
том же коммите (проверено git show --stat, git diff по обоим файлам —
согласованные формулировки на двух языках, ссылка на issue).
Формулировка ТЗ vs UI. ТЗ цитирует docs/USER-GUIDE.ru.md:372-374
дословно («поверх уже нарисованных стен видны тонкие осевые линии и точки их
концов») — сверено, совпадает буквально.
Откат. Один коммит, без новых полей конфига, миграций или
persisted-состояний — подтверждено диффстатом (только src/houseplan-card.ts
- сгенерированные копии + смок + changelog + отпечаток скриншотов).
«Одно число — один источник». Не применимо: диф не добавляет и не
меняет ни одной пользователю видимой величины (числа, площади, подписи) —
только z-order editor-only SVG-элементов. test/single-source-numbers.test.mjs
входит в общий зелёный npm test.
Чего не проверял
npm run invariants— не прогонял. Diff не касается геометрической модели: нет правокlayout, записей толщины,marker.space,open_spans,physical-geometry.ts,plan-snap-overlay.ts. Изменение — это переупорядочивание editor-only SVG-слоёв внутри одного компонента рендеринга; ни одна из трёх инвариантных проверок (запись толщины, разрешимость ссылок, ключ записи = ключ решёточного ребра) не имеет отношения к этому диффу.python -m pytest tests_backend— не прогонял. Diff не касаетсяcustom_components/houseplan/**/*.py(только сгенерированная копия фронтенд- бандла вcustom_components/houseplan/frontend/houseplan-card.js, класс D).- Полный набор
demo/smoke_*.mjs— не гонял все ~70+ смоков, только 1 новый + 14 прямых совпадений (см. таблицу и обоснование выше). Слабые связи (18 смоков с одним общим именем_path/_cursorPt) не прогонял — по выводу инструмента это решение ревьюера, и просмотр списка (drag/pan/split/ opening-preview на разных, не связанных с композицией плана поверхностях) не выявил кандидатов, специфичных именно к порядку SVG-слоёв. performance_smoke— не прогонял. Не назван в AC, диф не трогает чувствительные к перфу пути (рендер не добавляет новых вычислений — тот же шаблон переставлен в другое место композиции, число DOM-узлов не меняется).- Ручное тестирование в браузере — не проводилось (в цикле code-review ручного тестирования нет по регламенту); функциональность подтверждена смоком с пиксельными пробами и golden-верификацией композитного рендера.
Вердикт
Все 3 AC доказаны: AC1/AC2 — автотестом, который умеет падать (проверено на коде до фикса), AC3 — чтением кода (файл снапа вне диффа) плюс существующим зелёным смоком. Дешёвые гейты (typecheck/test/build/bundle-sync/docs) зелёные. Прямые смежные смоки (14) зелёные. Полная golden-матрица (127 сценариев, включая 4 сценария из группы прямого риска — резинка/точки цепочки поверх настоящих стен в plan-режиме) зелёная без единого расхождения. Трейлеры и оба changelog корректны. Находок нет.
Зелёный.