Files
houseplan-card/docs/reviews/SPEC-REVIEW-374-r1.md
2026-08-29 11:14:50 +00:00

16 KiB
Raw Permalink Blame History

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 — верное место.

Как проверялось

  1. Прочитан docs/SCOPE.md — сверена персона и job (J1), закрытая задача.
  2. Прочитаны AGENTS.md, PROCESS.md целиком (жизненный цикл, §5 критерии трека, §7.1 обязательные разделы ТЗ).
  3. Прочитано тело issue #374, все комментарии (аналитика + «ТЗ готово»), и связанный закрытый документационный issue #370 с ответом владельца — источник контекста, откуда взялся запрос.
  4. Прочитан docs/LIGHT.md целиком — канон световой модели, включая раздел «Which surfaces render pools», прямо описывающий текущее ограничение static card, которое ТЗ снимает.
  5. Прочитан docs/USER-GUIDE.ru.md (раздел про live_states) для сверки терминологии.
  6. Прочитан сам ТЗ целиком (435 строк).
  7. Технические утверждения ТЗ о текущем поведении кода сверены с исходниками, а не приняты на слово:
    • 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 как образец конвенции) — существуют.
  8. Проверено отсутствие открытых продуктовых вопросов и незакрытых меток неопределённости (?, «уточнить», 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_pools vs show_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, открытых вопросов владельцу не осталось, технические развилки корректно вынесены в блок предположений вместо того, чтобы быть выданными за решённые факты.

Вердикт: зелёный.