16 KiB
SPEC-REVIEW-374-r1
Issue: #374 — Feature request: optional light pools and wall shadows in houseplan-space-card
ТЗ: docs/specs/374-space-card-light-pools.md
Ветка: issue/374-space-card-light-pools, SHA материала ревью: c4f37986
Заход: r1 · блокирующих циклов израсходовано 0 из 4
Скоуп ревью
Дифф ветки против origin/dev:
docs/specs/374-space-card-light-pools.md | 434 +++++++++++++++++++++++++++++++
1 file changed, 434 insertions(+)
Только новый файл ТЗ, продуктовый код не тронут. Трек — полный (не small,
не trivial): лейблы issue — P2, feature, S4-spec-review, признака
лёгкого трека нет; аналитика в issue явно называет причину («появляется новый
публичный конфигурационный контракт, затрагиваются производительность и
touch/View, а каноническую световую модель надо разделить между двумя
рендерами»), что корректно по критериям §5 PROCESS.md (сложность/риск 8/10 —
далеко за порогом ≤3). Файл ТЗ в docs/specs/374-*.md — верное место.
Как проверялось
- Прочитан
docs/SCOPE.md— сверена персона и job (J1), закрытая задача. - Прочитаны
AGENTS.md,PROCESS.mdцеликом (жизненный цикл, §5 критерии трека, §7.1 обязательные разделы ТЗ). - Прочитано тело issue #374, все комментарии (аналитика + «ТЗ готово»), и связанный закрытый документационный issue #370 с ответом владельца — источник контекста, откуда взялся запрос.
- Прочитан
docs/LIGHT.mdцеликом — канон световой модели, включая раздел «Which surfaces render pools», прямо описывающий текущее ограничение static card, которое ТЗ снимает. - Прочитан
docs/USER-GUIDE.ru.md(раздел проlive_states) для сверки терминологии. - Прочитан сам ТЗ целиком (435 строк).
- Технические утверждения ТЗ о текущем поведении кода сверены с
исходниками, а не приняты на слово:
resolvedLightSources,selectSpatialGlowSource,resolveGlowAppearance,glowAlpha,GLOW_FALLOFF— существуют вsrc/devices.ts,src/logic.ts,src/houseplan-card.tsровно с той сигнатурой использования, что описана в контракте (раздел «Источники и видимость»).- Независимость Glow от
live_states(_renderGlowLayerне читаетlive_states,live_states === falseгасит только_syncActivityRuntime/_activityRuntime, т.е. иконки/пульс, но не сам слой pool) — проверено чтениемsrc/houseplan-card.ts:10500-10589иsrc/space-card.ts:363-467. Совпадает с заявлением ТЗ п.2.5. - Порядок слоёв («room/tunnel fills → Glow base/tunnels → radial pools →
стены/openings → labels/devices») — сверен с фактическим порядком
svgв_renderPlanBody/аналоге (src/houseplan-card.ts:11290-11317): room fills → opening tunnel fills → Glow base → decor →_renderGlowLayer→ sun rays → zero walls → wall bodies. Совпадает. - Кеш-ключи (
_glowClipCache=space.id|fingerprint|pos|R, barrier по geometry fingerprint + квантованной сигнатуре проёмов) — сверены сsrc/houseplan-card.ts:10586-10588и с разделом «Caching»docs/LIGHT.md. Совпадает дословно. - Утверждение «static renderer получает marker positions в plan
coordinates до процентного преобразования devlayer» — сверено:
src/space-geometry.tsстроит модели вNORM_W×NORM_W(план- координаты), аsrc/space-render.ts:399,435конвертирует их вleft:%/top:%только в момент рендера HTML-оверлея маркеров. Значит план-координаты действительно доступны раньше процентного шага — утверждение точное, не догадка. - Поведение неизвестного
space(«сохраняет текущую error card», AC1) — сверено сsrc/space-card.ts:812(_errorCard(t(..., 'space_card.not_found'...))). Существует уже сейчас. - Все файлы, упомянутые в «Затронутые файлы» и «План автотестов»
(
demo/smoke_space_card.mjs,demo/performance/budgets-large-house-glow-overlay.json,src/i18n/{en,ru,de,fr}.jsonс параллельными ключамиeditor.live_statesкак образец конвенции) — существуют.
- Проверено отсутствие открытых продуктовых вопросов и незакрытых меток
неопределённости (
?, «уточнить», TBD) в тексте ТЗ — не найдено ни одной вне markdown-разметки типаlight_pools?: boolean.
Гейты
Стадия — ревью ТЗ, продуктовый код в диффе отсутствует. typecheck/test/
build/check-docs/смоки/golden/performance/invariants — гейты код-ревью
(§8 PROCESS.md), к спек-ревью неприменимы и не запускались. Единственная
проверка этой стадии — чтение и сверка ТЗ с кодом и канонами, что сделано в
разделе выше.
Находки
Ни одной блокирующей (High) или Medium-находки, в скоупе или вне скоупа, не обнаружено.
Рассмотренные, но не подтвердившиеся кандидаты (для прозрачности разбора):
- AC3 явно не называет «room draft» как отдельный оккludер, хотя раздел
«Скоуп» и канон
docs/LIGHT.mdперечисляют draft отдельно. Проверка:docs/LIGHT.mdгруппирует draft вместе с partition как один класс «independent bodies», геометрически объединяемых в одно тело перед visibility sweep. AC3 и план автотестов покрывают «partition», которое по канону механически идентично draft. Не находка — терминологическое сокращение, а не пробел контракта. - Термин «semantic pixel witness» в доказательствах AC2–AC4 не определён
в
docs/TESTING.mdкак канонический термин проекта — он введён и уже использовался автором в предыдущем спеке (372-space-card-empty-title.md). В этом же документе термин раскрыт операционально («План автотестов» п.5–6: конкретные точки сэмплинга пикселей, свет/тёмная тема, DPR/ширины). Не находка — определён внутри документа, а не оставлен голой ссылкой на неписаный процесс. - Дублирование места переключателя в UI («UX и доступность»: «рядом с
live-state visual settings» вместо точного «рядом с
live_states», уточнённого только в блоке «Принято предположительно») — не противоречие, второе уточняет первое, оба текста согласуются.
Что проверено и корректно
- Оба обязательных продуктовых раздела (§7.1) — «Сценарий» и «Что человек
увидит до и после» — называют персону из
docs/SCOPE.md(домочадец/гость- киоск), поверхность (houseplan-space-cardкак основной визуальный элемент дашборда) и однозначно формулируют видимое изменение без терминов реализации. - Задача укладывается в J1
docs/SCOPE.md— прямое усиление «Show the whole home and what's happening right now» для отдельной карточки. Не пересекает «Out of scope» (не sunlight/window wedges — прямо исключено в «Не-скоуп» со ссылкой на независимостьdocs/SUN.md; не 3D/интерьер; не automations). - Все 13 обязательных разделов ТЗ по §7.1 присутствуют: сценарий · что увидит · проблема · скоуп/не-скоуп · контракт поведения · UX · модель данных и миграция · i18n · AC1…AC10 с доказательством · план автотестов · риски · откат · release-артефакты. Плюс необязательные, но полезные: архитектурный контракт, перф/bundle, touch/темы/размеры, затронутые файлы, блок принятых предположений.
- Каждый AC (AC1…AC10) сформулирован как проверяемое утверждение и несёт
явный способ доказательства (
unit/browser smoke/golden/performance artifact/CI checks/«ревью кода» через ссылку на п.5 архитектурного контракта). Ни одного AC без названного способа проверки. - Продуктовых вопросов владельцу не осталось — комментарий аналитики прямо
фиксирует это, и текст ТЗ подтверждает: единственная развилка
(
light_poolsvsshow_light_shadows) закрыта решением в пользу одного канонического ключа, без alias. - Технические решения, не наблюдаемые пользователем (имена shared-модулей, форма runtime API, конкретный smoke-фикстур, точные raster tolerances, место переключателя в форме редактора), явно вынесены в блок «Принято предположительно, поменять свободно» — именно туда, где им место по §7.1, а не разбросаны по тексту как скрытые решения.
- Не-скоуп корректно отсекает соседние риски: миграцию существующих карточек, визуальные изменения полной карточки, деградацию/лимиты источников (запрещены явно — важно, т.к. issue упоминал «возможно с warning», ТЗ не поддалось соблазну добавить скрытую деградацию), редакторы геометрии, повышение бюджетов без отдельного решения.
- Архитектурный контракт формулирует пять проверяемых инвариантов извлечения общего модуля (нет DOM/hass/приватных полей в shared-модуле, no module-level unbounded cache, full-card output regression-equivalent, единый источник истины по aperture classification/visibility/source guard/falloff/SVG field) — ровно то, что нужно ревьюеру кода на код-ревью, без диктовки конкретных имён файлов (эти имена сознательно оставлены реализации).
- i18n-раздел соответствует существующей конвенции проекта (
editor.<key>во всех четырёх словарях, без английского fallback для de/fr). - Откат описан на двух уровнях (пользовательский — снять флаг/false; кодовый — раздельный откат static-адаптера и shared-extraction) с явным критерием, когда откатывается всё целиком.
- Риски (8 штук) названы конкретно и с указанием, чем каждый снижается в самом контракте, а не общими словами.
Чего не проверял
- Реализуемость перформанс-цели (AC7) на практике — на этой стадии нет кода,
профиль
large-space-card-glow-overlay-v1кандидатный и явно помечен как подлежащий уточнению в реализации; численные бюджеты по правилу процесса утверждаются только полным Linux performance artifact, не на спек-ревью. - Точные имена shared-модулей и границы API — сознательно оставлены реализации согласно блоку «Принято предположительно», ревью не оспаривает.
- Гейты код-ревью (
typecheck,test,build,check-docs, смоки, golden, performance,model-invariants) — неприменимы на этой стадии, кода нет.
Унаследовано из r0
Не применимо — это первый заход (r1), предыдущего цикла нет.
Вердикт
Полный, детально проработанный ТЗ без блокирующих или Medium-находок.
Технические утверждения о текущем поведении кода выборочно, но
представительно сверены с исходниками и каноном (docs/LIGHT.md) и во всех
проверенных случаях подтвердились — включая нетривиальные детали вроде
точных ключей кэша и независимости Glow от live_states. Продуктовые
разделы отвечают на оба обязательных вопроса §7.1, открытых вопросов
владельцу не осталось, технические развилки корректно вынесены в блок
предположений вместо того, чтобы быть выданными за решённые факты.
Вердикт: зелёный.