13 KiB
SPEC-REVIEW-307-r1
Issue: #307 · Этап: ТЗ (spec) · Трек: small · Заход: r1 · Вердикт: зелёный
Блокирующих циклов израсходовано: 0/2 (лимит лёгкого трека, §4)
Скоуп
ТЗ (в теле issue #307, small-трек, шаблон §5: проблема · контракт · AC · откат)
на исправление визуального дефекта инструмента «Стены» в редакторе плана: во
время рисования цепочки уже поставленные (персистнутые) сегменты теряют
осевую линию .pathline и узлы .vertex, потому что тело стены рисуется
поверх них, а снап-оверлей намеренно исключает активный драфт из своей
геометрии. Решение — вынести ось/узлы/rubber-band активной цепочки
(.pathline, .vertex, .active-axis, .active-vertex) из
_renderMarkupLayer в отдельный editor-слой между _renderWallBodies и
_renderPlanSnapOverlay, ничего не меняя в геометрии снапа.
Затронутая поверхность — Plan editor (src/houseplan-card.ts, один модуль),
только режим _markup/_editing; View не затрагивается. Персона — Home admin
(единственная, кто пользуется редакторами, docs/SCOPE.md), контекст —
задача J4/J6 («от нуля до плана» и «поддерживать план актуальным», два
встроенных редактора). Изменение чисто композиционное (порядок отрисовки уже
существующих DOM-узлов), без новых полей конфига, миграций, i18n-ключей.
Как проверялось
Ревью читал ТЗ и тело/комментарий issue без устных пояснений автора, состязательно — искал, где контракт невыполним или непроверяем, а не соглашался с текстом. Каждое фактическое утверждение о коде и документации проверено чтением, а не принято на веру:
docs/SCOPE.md— подтвердил, что задача обслуживает J4/J6 и не задевает инвариант View/lock; продуктового конфликта нет.docs/USER-GUIDE.ru.md:372-375— дословно подтверждает цитату ТЗ: «поверх уже нарисованных стен видны тонкие осевые линии и точки их концов». Значит ожидаемое поведение — не догадка автора, а уже зафиксированный контракт; исключение для «ещё не завершённой цепочки» нигде не оговорено.src/houseplan-card.ts— построчно сверил все технические утверждения ТЗ:_renderMarkupLayer(:19960) действительно эмитит.pathline(:20029),.active-axis/.active-vertex(:20032-20036) и.vertex(:20038);- вызов
_renderMarkupLayer(:17553) стоит до_renderWallBodies(:17565), которая, в свою очередь, стоит до_renderPlanSnapOverlay(:17582) — ровно та последовательность, что и в ТЗ; _renderPlanSnapOverlay(:19843) и геометрияbuildPlanSnapGeometry(src/plan-snap-overlay.ts:253) действительно пропускают активный драфт (if (draft.id === options.activeDraftId) continue) — второй заявленный механизм подтверждён, не выдумка;physical-geometry.ts:210-221подтверждает, что каждый персистнутый сегментroom_draftsнемедленно попадает в непрозрачные тела (draftSegments/drafts) без исключения активного драфта — то самое тело, которое перекрывает ось;- «hit-слой», упомянутый в контракте как остающийся на месте элемент
_renderMarkupLayer, — реален:_renderPhysicalEditorLayer()(:19711, вызывается на :20008) рисует.physical-hit(прозрачные линии/пути для перетаскивания драфтов/перегородок/колонн,pointer-events: noneвне инструмента «Выбор»,src/styles.ts:2256-2264) — контракт не подменяет несуществующим термином существующий механизм; - цвет
#ffc14dиз AC1 подтверждён как реальныйstroke/fill.pathlineи.vertex(src/styles.ts:1803-1857) — пиксельная проба технически осмысленна и отличима от штриховки масонри; - AC3 ссылается на существующий
demo/smoke_plan_snap_overlay.mjs— файл существует.
docs/specs/228-plan-drawing-problems.md— беглая проверка, чтоactive-axis/active-vertexдействительно история #228 (проекция оси активного отрезка), заявленная в issue как смежная, не пересекающаяся работа — согласуется, конфликта скоупа нет.- Сверил критерии лёгкого трека (§5 PROCESS.md) построчно: сложность/риск
≤3 (аналитика — 2/10), одна поверхность, без миграции конфига, поведение
уже описано в USER-GUIDE (не новый UX-контракт), перф/touch не задеты
(перестановка существующих DOM-узлов, ни одного нового элемента). Шаблон
ТЗ соответствует §5 буквально: проблема · контракт · AC · откат, файла в
docs/specs/нет — верно дляsmall. - Комментарии issue — один, аналитика владельца (S2→S4, метка
smallпоставлена и объяснена). Прежнего вердикта ревью ТЗ нет — это первый заход, раздел «Унаследовано из r0» не применяется.
Находки
Блокирующих (High/Medium) не найдено.
Один пограничный момент, не тянущий на находку, а не пропущенный молча:
контракт не называет позицию нового слоя относительно
_renderResizeMeasurements/_renderRoomHoverOutline/диагностического
оверлея скрытых стен/превью размещения проёма — всех элементов, которые
сейчас лежат между _renderWallBodies и _renderPlanSnapOverlay. Это не
продуктовый вопрос: перечисленные оверлеи активны для других инструментов
(resize/двери-окна) и не пересекаются по времени с активной цепочкой «Стены»,
кроме, возможно, подсветки наведённой комнаты (roomHover), которая может
сработать параллельно с рисованием. AC2 не требует конкретной позиции внутри
этого промежутка — только «тела → слой цепочки → снап-оверлей», и это
достаточно проверяемо смоком. Оставляю как техническую деталь на усмотрение
реализации, как и позволяет §7.1 («всё, чего пользователь не наблюдает,
агенты решают сами»); не блокирует и не снижает вердикт.
Что проверено и корректно
- Оба продуктовых вопроса (что видит пользователь, какой объём входит в задачу) не требуют обращения к владельцу: ожидаемое поведение уже зафиксировано в USER-GUIDE.ru.md, объём — один модуль, одна визуальная причина с двумя техническими механизмами, обе описаны и обе имеют решение. Владельцу вопросов не задавалось — и это оправдано, а не пропущено.
- Причина дефекта — не догадка, выданная за факт: каждое утверждение о коде
(номера строк, имена классов/функций, порядок вызовов, поведение
buildPlanSnapGeometry) подтверждено чтением текущегоdev(см. выше). - Контракт однозначен: что именно переносится (
.pathline,.vertex,.active-axis,.active-vertex), откуда, куда (между конкретными двумя существующими вызовами), что не меняется (геометрия/резолвер снапа, жёлтая стилистика, всё остальное содержимое markup-слоя). - AC1-AC3 — каждый проверяем и указывает способ доказательства (
smokeновый/существующий, ревью кода). AC1 задаёт конкретные пиксельные точки (середина оси первого сегмента, центр промежуточного узла) и конкретный ожидаемый цвет, отличимый от штриховки — тест способен упасть на текущемdev, что и заявлено явно («падает на текущем dev»). AC3 явно фиксирует границу:plan-snap-overlay.tsне входит в дифф. - Откат тривиален и назван верно: одиночный revert, ни новых полей, ни миграций, ни persisted-состояний — соответствует характеру чисто композиционного изменения.
- Критерии лёгкого трека выполнены все одновременно, метка
smallне оспаривается. - Не найдено расхождений ТЗ с
docs/SCOPE.md,docs/USER-GUIDE.ru.md,docs/UX-MODES.md: изменение целиком внутриhp-editor-only-layer, гейтитсяthis._markup, View не задет, инвариант блокировок (SCOPE.md, «The lock invariant») не касается геометрии стен.
Чего не проверял
- Не запускал код и не собирал бандл — на этапе ревью ТЗ кода ещё нет,
проверка была по чтению текущего
dev(git logпоказываетdevна489f68ee, что совпадает с SHA, названным в аналитике owner).typecheck/test/buildк этому этапу не относятся (это гейты код-ревью, §2.7). - Не проверял, как новый слой будет вести себя при одновременной подсветке
наведённой комнаты (
roomHover) во время рисования цепочки — отмечено выше как техническая деталь реализации, не блокирующая ТЗ. - Не оценивал производительность численно — оценка «перестановка тех же DOM-узлов» правдоподобна на глаз и совпадает с заявлением owner в аналитике, но замер не проводился (задача не требует его: §2.5 требует «влияние на производительность названо», а не измерено, когда оно очевидно нулевое).