mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-04 13:48:57 +00:00
187 lines
16 KiB
Markdown
187 lines
16 KiB
Markdown
# SPEC-REVIEW-374-r1
|
||
|
||
Issue: [#374](https://github.com/Matysh/houseplan-card/issues/374) — Feature request: optional light pools and wall shadows in `houseplan-space-card`
|
||
ТЗ: [`docs/specs/374-space-card-light-pools.md`](https://github.com/Matysh/houseplan-card/blob/issue/374-space-card-light-pools/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, открытых вопросов
|
||
владельцу не осталось, технические развилки корректно вынесены в блок
|
||
предположений вместо того, чтобы быть выданными за решённые факты.
|
||
|
||
**Вердикт: зелёный.**
|