17 KiB
SPEC-REVIEW-231-r1
- Issue: #231 — декоративный слой виден поверх заливок комнат
- ТЗ:
docs/specs/231-decor-layer-order.md@ commite023adb(dev) - Заход: r1 · блокирующих циклов израсходовано 0 из 4
- Вердикт: жёлтый · High: 0 · Medium: 1 (в скоупе, чинится в этом ТЗ)
Скоуп ревью
Первый заход, дельты нет — разбор ТЗ целиком: продуктовая рамка (docs/SCOPE.md),
обязательные разделы §7.1 PROCESS.md, однозначность и доказуемость каждого AC,
отсутствие догадок, выданных за решение, соответствие терминологии
docs/USER-GUIDE.ru.md, согласованность с канонической документацией
подсистемы (docs/BACKDROP.md, docs/DECOR-EDITOR.md, docs/CANVAS.md,
docs/SUN.md) и с фактическим кодом.
Как проверялось
- Прочитаны
docs/SCOPE.md,AGENTS.md,PROCESS.md§2.4/§7.1/§7.2/§2.9/§2.10. - Прочитано тело issue #231 и все 6 комментариев: два уточнения владельца по
целевой позиции слоя, аналитика, вопрос Q1 с default, решение владельца по
Q1, финальный хендофф со ссылкой на ТЗ. Открытых продуктовых вопросов на
момент ревью нет,
blockedснят. - Прочитано ТЗ
docs/specs/231-decor-layer-order.mdцеликом. - Сверено с фактическим кодом
src/houseplan-card.ts:- подтверждён текущий порядок вызова
_renderDecorLayer()(строка 16584) — он действительно предшествует рендеру заливок комнат (цикл с 16596), hover-заливке (16726), обычным тоннелям (16727), Glow-base комнат (16728), Glow-base тоннелей (16729),_renderGlowLayer(16730) и_renderSunRays(16731); стены (16747), символы проёмов (16763) иdevlayer(16794) идут ещё позже. Абсолютные номера строк в теле issue (:16042…:16238) разошлись с HEAD (там сейчас:16584…), но порядок элементов, который единственно имеет значение для ТЗ, подтверждается независимо чтением кода — не является дефектом ТЗ; - целевая позиция ТЗ (между обоими проходами тоннелей и
_renderGlowLayer) соответствует названным строкам 16729/16730; - проверено, что
.decorlayer .dshape { pointer-events: none; }(src/styles.ts:1235) и включается только в.stage.mode-decor— утверждение ТЗ §9/§13 «decor не перехватывает tap/click вне редактора декора» верно независимо от DOM-позиции слоя, не является догадкой; - проверено
.glow-pools-frame/.glow-pools/.glow-spot { isolation: isolate }(src/styles.ts:678) — комментарий у кода прямо говорит, что этот блок изолирует screen-blend от «room data fill, Glow base, paper and backdrop»; ТЗ §8.2 корректно описывает это как риск и явно требует не переносить decor молча, если целевая fixture покажет иной результат — не догадка, а обозначенное предположение (§19.2) с открытым эскейпом; - подтверждено, что
houseplan-space-cardне рисует decor вообще (grep decor src/space-render.ts— одно упоминание, к теме не относится); - подтверждено, что изометрический слой (
iso-shadows-svg/iso-walls-svg, 16774–16782) — отдельные<svg>после закрытия основного плана, поэтому перестановка decor внутри основного SVG не меняет его позицию относительно 3D-стен; риск в таблице §16 корректен.
- подтверждён текущий порядок вызова
- Проверено
docs/BACKDROP.md— «Layer order» там даёт грубую группировку («sun / walls / openings / rooms / decor» одним пунктом), которая не различает internal order и в этом и есть источник бага; ТЗ верно ставит её актуализацию в release-артефакты (§18). - Проверено
docs/DECOR-EDITOR.md— контракта видимого порядка в View там нет вообще (только editor-opacity), обновление не требуется, ТЗ не настаивает («при необходимости») — согласовано. - Проверено
docs/CANVAS.md(«who owns the pointer», «Architectural connection overlay») иdocs/SUN.md(four-phase background) — оба документа говорят о decor на уровне, который порядок внутри плана не меняет; актуализация не нужна, ТЗ их не трогает — корректно. - Проверена регистрация ТЗ в
docs/specs/README.md:71— присутствует. - Проверены существующие смоки:
demo/smoke_decor.mjs,demo/smoke_decor_text.mjs,demo/smoke_hide_layers.mjs,demo/smoke_backdrop.mjs,demo/smoke_glow.mjs(hoverLayerOrder, строки 244–261) — ни один не проверяет порядок decor относительно hover-заливки комнаты (см. находку ниже). - Прогон гейтов для ревью спецификации не требуется (диапазон правок —
документация ТЗ и issue, продуктовый код не менялся);
git diff --checkиnode scripts/check-docs.mjs --external, упомянутые автором в хендоффе, достаточны для этого этапа и не перепроверялись повторно — они не относятся к предмету ревью (корректность и доказуемость контракта), а к гигиене коммита ТЗ.
Находки
Medium (в скоупе — чинится в этом же ТЗ)
M1. Нормативная позиция decor относительно room hover fill не имеет привязанного AC/доказательства.
- Где:
docs/specs/231-decor-layer-order.md§8.1 (нормативный порядок слоёв, пункт «room hover fill» между room fills и opening tunnels) и §14 (AC1–AC8). - Суть: §8.1 явно требует: «любой
[data-hp="decor"]следует в DOM после room fill, hover fill, обоих видов тоннелей и Glow-base» — hover-заливка комнаты прямо включена в обязательный нижний контур. Однако ни один AC этого не проверяет:- AC1 говорит про «room fill» (заливку), не про hover;
- AC2 перечисляет ровно три вещи, после которых должен идти decor — «обычный тоннель, Glow-base комнаты и Glow-base тоннель» — hover fill в списке нет;
- AC3 описывает верхнюю границу (Glow/солнце/стены/символы/устройства), тоже
не про hover.
Значит Goal 5 из §5 («Защитить порядок… тестом, который падает при возврате
старого расположения слоя») в этой конкретной паре (decor vs hover fill) не
реализуется ни одним названным доказательством. Существующий
demo/smoke_glow.mjsуже умеет сравнивать DOM-позицию (hoverLayerOrder, строка 260:hoverFillLayer.compareDocumentPosition(glowLayer)), ноdecorlayerв нём не упоминается вовсе — расширить эту же проверку стоит недорого.
- Сценарий отказа: реализация вставляет decor куда-то между room fill и Glow-base (что удовлетворяет AC1/AC2/AC3 буква в букву — «после обычного тоннеля» и т.д. формально не нарушены только если decor вставлен после тоннелей, но ничего не мешает случайно вставить decor до hover fill, например прямо перед строкой рендера hover — тоннели и Glow-base всё ещё идут после него по факту кода, так что AC2 останется зелёным, а на реальном плане при наведении на комнату с decor внутри hover-подсветка ляжет поверх декоративной линии/фигуры, а не под неё, что расходится с §8.1 и остаётся недоказанным дефектом.
- Почему не High: это пробел в покрытии доказательства, а не неверное
продуктовое решение — сам порядок (decor после hover fill) уже прямо задан
диаграммой владельца в теле issue (позиции
:16202до целевой:16205→:16206) и корректно перенесён в §8.1; чинится добавлением одной фразы в AC2 (или отдельного AC) и одной строки в план тестов (§15.1/§15.2), без обращения к владельцу. - Что сделать: явно включить hover fill в формулировку AC2 (например:
«…после hover fill, обычного тоннеля, Glow-base комнаты и Glow-base
тоннеля…») и добавить в §15.2/§15.1 конкретное доказательство — расширение
smoke_glow.mjs/hoverLayerOrderили отдельный targeted-assert наcompareDocumentPositionмежду.room-hover-fill-layerи.decorlayer.
Что проверено и корректно
- Продуктовая рамка: сценарий, персона, «что человек увидит до/после» —
присутствуют, соответствуют
docs/SCOPE.md/аналитике владельца в issue (владелец сам отнёс задачу к J1 в комментарии-аналитике; повторно отдельно в ТЗ можно не обосновывать). - Все обязательные разделы §7.1 PROCESS.md на месте: сценарий, что увидит человек, проблема, скоуп/не-скоуп, контракт поведения (§8–§9), UX (§10), данные/миграция/i18n (§11), AC1–AC8 (кроме отмеченного пробела), план автотестов (§15), риски (§16), откат (§17), release-артефакты (§18).
- Явный блок «Принятые предположения» (§19) присутствует и корректно помечает
как assumption именно то, что действительно не было продиктовано владельцем
дословно (например, что Glow-base — часть пола, а live Glow/солнце — часть
света) — не выдаёт догадку за факт, ревьюер может её оспорить (не оспариваю:
подтверждается разделением функций
_renderGlowBaseRooms/_renderGlowLayerв коде). - Причина бага (§3) точно подтверждена чтением кода — вызов decor действительно предшествует рендеру комнат.
- Решение владельца по Q1 (без нового флага «под планом», единый порядок для старого и нового decor) корректно и полностью перенесено в §8.3/§19.1, без расширения скоупа.
- Открытый технический риск с Glow/CSS isolation (§8.2) не замалчивается: ТЗ прямо требует не переносить decor поверх live Glow «молча» и возвращать вопрос владельцу, если fixture покажет иное — правильная эскалация вместо догадки.
- «Не входит в задачу» (§7) корректно исключает per-object флаг, изменение геометрии старого декора, любые изменения заливки/Glow/солнца/стен, добавление decor в статическую карточку и в скрытую изометрию отдельным рендерером, новый UI/i18n/миграцию.
- Touch/UX (§10): корректно ссылается на
docs/TOUCH-SUPPORT.md, не создаёт новых focus targets/жестов; View/kiosk-контракт (блокирующий по TOUCH-SUPPORT.md) не расширяется и не сужается. - Данные/миграция/i18n (§11): корректно — рендер-порядок не персистентное
поле, миграция не нужна, что подтверждается отсутствием изменений в
custom_components/houseplan/validation.py/типах decor. - AC5 (documented mutant) явно требует, чтобы smoke падал по существу
(AC1/AC2), а не просто по отсутствию DOM-узла — соответствует духу
scripts/mutation-gate.mjsи извлечённому там же уроку про тесты, которые «ни разу не проверяли на способность падать». - Golden-план (§15.3) корректно ограничивает принятие эталона отдельным reviewed Linux-артефактом, Windows — только диагностика; согласуется с AGENTS.md.
- Регистрация ТЗ в
docs/specs/README.mdна месте.
Чего не проверял
- Не проверял и не мог проверить визуальный результат Glow-blend на decor в браузере — эта проверка относится к этапу реализации/код-ревью (targeted fixture, §8.2), на этапе спецификации нет кода, который можно запустить.
- Не прогонял тяжёлые гейты (typecheck/test/build/golden/smoke) — на этом этапе продуктовый код не менялся, они не относятся к предмету ревью ТЗ и будут частью код-ревью.
- Не проверял
docs/TESTING.mdна предмет уже существующей документации layer-order/mutant contract для decor — в текущей редакции ТЗ такого описания там нет, и ТЗ (§12) верно относит его актуализацию к зонам изменений реализации, а не к самой спецификации. - Не оценивал производительность фактически (нет кода) — только сверил, что §13 не описывает новых наблюдателей/таймеров/network calls, что достаточно для стадии ТЗ.
Резюме
Одна находка Medium в скоупе (M1 — отсутствует доказательство для одной конкретной, но явно нормативной, границы порядка: decor относительно room hover fill). High-находок нет. Остальной контракт — порядок слоёв, hide/editor parity, компат старого decor, touch/UX, данные/i18n, release-артефакты — точен, проверяем и обоснован чтением кода, а не заявлением автора. Вердикт: жёлтый, возврат автору на правку ТЗ (добавить hover fill в AC2 и тест-план), без обращения к владельцу.