44 KiB
Issue #146 — четырёхфазный фон «Следует за Солнцем»
Статус: ТЗ на ревью
Дата: 2026-08-14
Тип: feature · приоритет: P1 · пользовательская ценность: 7/10 · сложность/риск: 8/10
Issue: #146
Ветка: issue/146-four-phase-sun-background
Канонические документы: SCOPE, SUN,
UX-MODES, TOUCH-SUPPORT,
ARCHITECTURE,
CONFIG-COMPATIBILITY.
Текст issue имеет приоритет над приложенными к нему SPECIFICATION.md,
README.md и интерактивным прототипом. Решения владельца Q1–Q3 и все defaults
приняты 2026-08-14 в issue #146.
1. Сценарий и продуктовый контекст
Основная персона — человек, который ежедневно смотрит на дом в View либо на настенной kiosk-панели и должен одним взглядом узнавать сам план и текущее состояние дома. Фон вокруг плана даёт спокойный временной контекст, но не имеет права искажать цвета пола, стен, Glow, устройств или других данных.
Это часть J1 из docs/SCOPE.md: House Plan существует прежде всего как
правдивый пространственный обзор дома. Новая функция декоративна, поэтому она
не становится единственным носителем состояния и не меняет доступность
управления. View и kiosk остаются полностью поддержанными touch-поверхностями.
2. Что человек увидит до и после
До: режим daynight непрерывно интерполирует один сплошной цвет по высоте
Солнца, требует настроенный север, а ночью уменьшает яркость всего плана до
10 %. У новых установок и пространств режим не включён автоматически.
После: вокруг неизменного плана отображается одно из четырёх узнаваемых
окружений — рассвет, день, сумерки или ночь. Между фазами за 1100 ms плавно
меняются только градиент окружения, декоративный солнечный свет, внешняя
виньетка и alpha-aware контур плана. При доступном sun.sun состояние и свет
следуют реальному Солнцу; иначе работают по локальным часам браузера. Новые
установки и новые пространства начинают с режима «Следует за Солнцем», старые
неявные настройки сохраняют прежний статический вид.
3. Проблема и подтверждённая техническая база
src/sun.ts::dayPhase()возвращает непрерывный solid background,planDimи warmth. Это не четырёхфазная модель из issue.- Full card применяет ночной
brightness()к.zoomwrap, поэтому вместе с окружением меняются сам план и все его live-слои. bg_mode: daynightсейчас зависит отnorth_degи валидногоsun.sun; без компаса либо сущности молча возвращается статический фон.sunStateOf()читает только azimuth/elevation. Направление движения (attributes.rising) ещё не участвует в выборе dawn/dusk.- Full card и
houseplan-space-cardрассчитывают фон разными render-путями, а editor canvases намеренно остаются статическими. - Текущий fallback отсутствующего
bg_mode—static. Простая смена fallback наdaynightизменила бы уже существующие планы без согласия пользователя. - Уже существуют независимые солнечные лучи из окон, Glow/spill, room fills, hover, decor/backdrop, vacuum и mode-transition #101. Новый фон должен интегрироваться с ними, а не заменить или перекрасить их.
4. Решения владельца
- В диапазоне высоты между −6° и +6° признак
sun.sun.attributes.risingразличает рассвет и сумерки: rising —dawn, falling —dusk. Выше +6° —day, ниже −6° —night. - Если elevation или rising отсутствуют/некорректны, используется полный fallback по локальному времени браузера: dawn 05:00–07:59, day 08:00–17:59, dusk 18:00–20:59, night 21:00–04:59.
- При валидном
sun.sunи фаза, и положение декоративного фонового света следуют реальным elevation/azimuth. Часовая дуга прототипа используется только при полном fallback. Ночью отдельный световой круг скрыт. - Существующие пространства без явного выбора сохраняют прежний статический
вид через совместимую миграцию. Явный
daynightполучает новую четырёхфазную семантику. Новые установки и каждое новое пространство начинают сdaynight; явныйstaticавтоматически не меняется. - Сам план не затемняется и не тонируется. Существующие Glow/spill, солнечные лучи из окон, room fills/hover, decor/backdrop, vacuum и остальные live-слои сохраняют действующее поведение.
5. Scope
В задачу входят:
- дискретная модель
dawn | day | dusk | nightдляbg_mode: daynight; - реальный sun-source с полным локальным clock-fallback;
- четырёхфазный градиент окружения, декоративный солнечный свет, виньетка и alpha-aware контур по утверждённым visual tokens;
- переход фаз за 1100 ms и
prefers-reduced-motion; - одинаковая фаза и визуальные tokens в full View, kiosk и статической
houseplan-space-card; - совместимость с mode-transition View ↔ editor из #101;
- новый default для новой установки, ручного создания пространства и Floors/Areas onboarding;
- однократная совместимая миграция старого неявного global default;
- совместимость полного и per-space export/import;
- обновление существующих RU/EN строк режима и подсказок;
- unit, backend, production-bundle smoke, golden и performance coverage;
- пользовательская/архитектурная документация, оба changelog и три поставляемые bundle-копии.
6. Non-scope
В задачу не входят:
- новый публичный mode token вместо
static | daynight; - ручной phase selector, видимый QA-control или пользовательское расписание;
- геолокация, внешний weather API, сетевой астрономический расчёт либо новые HA service calls/entities;
- изменение существующей геометрии/порогов/цвета солнечных лучей из окон;
- настройка visual palette, длительности перехода или порогов −6/+6 в UI;
- окрашивание, затемнение, насыщенность, opacity либо blend самого плана;
- day/night окружение внутри Plan/Devices/Decor editors;
- пересмотр бумажного слоя, room fill, Glow, hover, decor, vacuum, isometric/Labs или View ↔ editor UX;
- сохранение текущей вычисленной фазы в config/storage;
- canvas/WebGL только ради фонового градиента;
- production-обработка URL-параметра
?time=HH:MM; - изменение touch-контракта desktop-first редакторов.
7. Контракт источника и выбора фазы
7.1. Валидный real-sun sample
Для окружения real-sun sample валиден, только если одновременно:
- существует live-state
sun.sun; attributes.elevation— конечное число;attributes.azimuth— конечное число, нормализуемое в[0, 360);attributes.rising— настоящий boolean.
Если любое условие нарушено, весь day-cycle — и фаза, и положение фонового
света — атомарно переходит на clock-fallback. Нельзя смешивать фазу от часов с
позицией из частично валидного sun.sun.
Это отдельная проверка только для окружения. Действующий sunStateOf() и
существующие оконные лучи продолжают использовать azimuth/elevation по
docs/SUN.md: отсутствие rising не должно выключить уже работающие лучи.
7.2. Фаза по реальному Солнцу
Границы детерминированы так:
| Условие | Фаза |
|---|---|
elevation <= -6 |
night |
-6 < elevation < 6 и rising === true |
dawn |
elevation >= 6 |
day |
-6 < elevation < 6 и rising === false |
dusk |
На точной верхней границе состояние уже day, на точной нижней — уже night.
Azimuth wrap 359°→0° не меняет фазу.
7.3. Полный clock-fallback
Используются часы и часовой пояс браузера через локальный Date, без серверного
времени:
| Локальные минуты | Фаза |
|---|---|
300 <= m < 480 (05:00–07:59) |
dawn |
480 <= m < 1080 (08:00–17:59) |
day |
1080 <= m < 1260 (18:00–20:59) |
dusk |
| иначе (21:00–04:59) | night |
DST и смену часового пояса даёт платформа Date. Интервал проверяет часы
каждые 30 s только пока используется fallback и вкладка видима. Дополнительно
состояние пересчитывается до первого видимого кадра, при pageshow и при
visibilitychange обратно в visible. Если фаза и позиционные tokens не
изменились, Lit/DOM update не запрашивается.
7.4. Переключение источника
Появление, исчезновение либо восстановление валидности sun.sun пересчитывает
весь day-cycle из одного snapshot. Текущая фаза не хранится как истина и не
может остаться от прежнего источника. Обычная смена источника получает тот же
1100 ms environment transition; fresh mount сразу начинает с правильного
состояния без вспышки default-day.
8. Контракт декоративного фонового света
Декоративный свет — pointer-inert слой окружения под планом. Он не является
оконным солнечным лучом и не использует north_deg: фон существует независимо
от ориентации дома.
8.1. Real-sun position
При валидном real-sun sample позиция вычисляется из реальных атрибутов:
x = 50 - sin(azimuth * pi / 180) * 42 // percent
y = 78 - clamp(elevation, 0, 90) / 90 * 64 // percent
opacityFactor = clamp((elevation + 6) / 12, 0, 1)
Так восток (около 90°) оказывается у левого горизонта, запад (около 270°) — у
правого, а северный и южный полдень проходят через центр без зависимости от
полушария. Отрицательная высота держит свет у горизонта; в night opacity
принудительно равна нулю.
8.2. Clock-fallback arc
Fallback повторяет дугу прототипа:
progress = (minutes - 300) / (1260 - 300)
x = 8 + progress * 84
y = 78 - sin(progress * pi) * 64
opacityFactor = max(.18, min((minutes - 300) / 120,
(1260 - minutes) / 120, 1))
Формулы применяются только в диапазоне 05:00 ≤ time < 21:00; вне его opacity равна нулю. Позиция обновляется той же 30-секундной fallback-проверкой, не пересчитывая план, стены, room geometry или устройства.
8.3. Вид и слой
Свет — мягкий radial gradient без жёсткой окружности, размером 250 CSS px в
эталонном desktop layout; на меньшей поверхности он ограничивается размером
окружения и не создаёт overflow/scroll. Цвет задаётся фазой, позиция и opacity —
источником выше. В night элемент может оставаться в DOM, но его вычисленная
opacity обязана быть 0 и ни один видимый световой круг не допускается.
9. Визуальный контракт четырёх фаз
Окружение строится из вертикального linear gradient и мягкого radial horizon у нижней части сцены. Значения ниже — канонические tokens прототипа; отклонение требует нового решения владельца, а не локального «подбора на глаз».
| Фаза | top | bottom | horizon | sun | vignette |
|---|---|---|---|---|---|
dawn |
#aabdd1 |
#e8c8b7 |
rgba(255,201,156,.56) |
rgba(255,188,125,.78) |
rgba(65,72,99,.21) |
day |
#dce9ef |
#cbdce3 |
rgba(255,245,220,.45) |
rgba(255,239,190,.72) |
rgba(65,91,105,.16) |
dusk |
#48536c |
#9a7380 |
rgba(242,156,114,.34) |
rgba(255,167,113,.55) |
rgba(20,26,44,.39) |
night |
#111a27 |
#1f2f3e |
rgba(79,120,151,.16) |
transparent | rgba(3,8,14,.58) |
Alpha-aware контур применяет три zero-offset drop-shadow либо визуально
эквивалентный эффект к одному каноническому plan-paper composite, не к
каждой комнате/стене отдельно:
| Фаза | near 0 0 1px |
mid 0 0 5px |
far 0 0 10px |
|---|---|---|---|
dawn |
rgba(74,57,61,.25) |
rgba(255,238,224,.40) |
rgba(255,224,202,.18) |
day |
rgba(45,62,71,.28) |
rgba(255,255,255,.42) |
rgba(255,255,255,.20) |
dusk |
rgba(238,219,225,.40) |
rgba(229,207,218,.26) |
rgba(215,190,205,.12) |
night |
rgba(218,238,249,.56) |
rgba(174,215,238,.30) |
rgba(136,194,226,.14) |
Контур повторяет внешний alpha-контур общего бумажного footprint, не имеет смещения, не создаёт внутренних швов между комнатами и не обводит устройства, labels, hover или live-эффекты. Для image-plan канонический footprint — его действующий opaque paper rect; для drawn-plan — объединённая по одному group совокупность room paper polygons. Пустой drawn space без комнат не получает ложный прямоугольный контур.
10. Инвариант неизменного плана
Во всех четырёх фазах к plan/content tree запрещено добавлять:
brightness,contrast,saturate,sepia,hue-rotateили иной color filter;- opacity родителя,
mix-blend-modeили цветной overlay поверх плана; - смену paper/floor/room fill цвета из-за фазы;
- изменение яркости/цвета devices, labels, decor/backdrop, vacuum, Glow/spill, hover или оконных солнечных лучей.
Действующий dayPhase().planDim удаляется из day-cycle render и из target
brightness mode-transition #101. Plan pixels внутри plan-paper alpha footprint
до и после смены фазы должны совпадать; разрешено меняться только внешнему
zero-offset outline за границей footprint.
11. Переходы и surfaces
11.1. Phase transition
При смене фазы ровно 1100 ms с easing
cubic-bezier(.22, .61, .36, 1) анимируются только:
- environment top/bottom/horizon;
- цвет/позиция/opacity декоративного света;
- внешняя vignette;
- три цвета alpha-aware outline.
Нельзя fade всего экрана или самого плана. Реализация обязана использовать
действительно интерполируемые CSS primitives либо environment-layer crossfade;
простая декларация transition на неанимируемом gradient не считается
выполнением. При prefers-reduced-motion: reduce длительность практически
нулевая (<= 0.01 ms либо transition: none).
11.2. Full View, kiosk и static card
Full View и kiosk используют один environment model. Статическая
houseplan-space-card получает ту же effective phase, palette, свет, outline и
fallback lifecycle; оконные wedges в static card не добавляются — действующее
ограничение docs/SUN.md сохраняется.
11.3. Editors и #101
Plan/Devices/Decor editors сохраняют действующий editor background и не получают четырёхфазное окружение. При View ↔ editor переходе #101:
- исходный и целевой кадр используют один атомарный phase/source snapshot;
- сам plan composite не меняет brightness/color;
- environment transition не перехватывает pointer/focus и не оставляет скрытый слой после commit/cancel;
- при возвращении в View актуальная фаза пересчитывается до целевого кадра, включая возврат после долгой паузы.
11.4. Существующие live-эффекты
Glow/spill, room fills/hover, decor/backdrop, vacuum, labels/devices и оконные
лучи сохраняют порядок слоёв, opacity, blend и lifecycle. north_deg продолжает
управлять только ориентационно зависимыми оконными лучами; daynight background
больше не выключается из-за отсутствия компаса.
12. Модель данных, defaults, migration и import/export
12.1. Persisted schema
Публичная schema не расширяется: global и per-space
settings.bg_mode: 'static' | 'daynight', per-space null/absence = inherit.
Вычисленная фаза, источник и позиция света не сохраняются. Backend продолжает
принимать отсутствие bg_mode ради legacy compatibility.
Runtime fallback отсутствующего effective token остаётся static; новая
семантика достигается материализованными defaults, а не переопределением
отсутствующего поля.
12.2. Новая установка и новые пространства
- Новый
DEFAULT_CONFIGматериализует globalsettings.bg_mode: 'daynight'. - Ручное Create space материализует per-space
bg_mode: 'daynight'. - Каждое пространство, созданное Floors/Areas onboarding, материализует
per-space
bg_mode: 'daynight'. - Открытие и сохранение существующего space dialog не меняет его mode без действия пользователя.
- Явный
staticна любом уровне никогда не переписывается автоматически.
Per-space materialization нужна даже при новом global default: добавленное
позднее пространство начинает с daynight, в том числе внутри старой
установки, чей global default мигрирован в static.
12.3. Однократная миграция существующего store
Backward-compatible storage migration выполняется один раз и идемпотентно:
- если в существующем config global
settings.bg_modeотсутствует либо невалиден, он материализуется какstatic; - валидный global
staticилиdaynightсохраняется; - все валидные per-space overrides сохраняются без переписывания;
- spaces без override продолжают наследовать уже материализованный global;
- migration сохраняет неизвестные поля, не меняет layout и не создаёт config-update storm;
- повторный старт не создаёт новую запись/revision.
12.4. Export/import
- Full export после миграции содержит явный global mode; legacy full import без
него материализуется как
staticдо preview/apply. - Per-space export материализует в экспортируемом space его effective mode, чтобы перенос не зависел от отсутствующего global settings блока.
- Legacy per-space import без mode материализуется как
staticдо merge. - Явные
static/daynightсохраняются при same-instance и foreign import. - Import preview показывает тот же итоговый mode, который будет применён; preview не пишет storage.
- Никакой импорт не превращается в «новое пространство по default»: импортированная семантика имеет приоритет над default ручного Create.
13. UX, i18n, accessibility и touch
Видимых новых controls нет. Действующий selector остаётся двухпозиционным:
static и daynight; color picker виден только для static.
Обновляются существующие RU/EN keys без добавления третьего режима:
gs.bg_daynight: «Следует за Солнцем» / “Follows the Sun”;gs.bg_daynight_hint: четыре фазы, real sun и локальный fallback, без требования компаса;gs.sun_missingиgs.north_hint: отсутствие sun/севера отключает оконные лучи, но не clock-driven background.
Фаза декоративна: она не добавляет announcement, focus target, toast или
semantic state; не меняет размеры сцены и не служит единственным носителем
информации. forced-colors сохраняет функциональную читаемость plan/devices;
декоративные environment layers могут быть упрощены либо отключены.
View, kiosk и static card полностью поддерживаются мышью, touch и без pointer:
новые слои имеют pointer-events: none, не перехватывают tap/swipe/pinch и не
меняют hit targets. Editor остаётся desktop-first и не получает новых действий.
14. Архитектурный и performance-контракт
- Один pure resolver возвращает phase, source (
sun | clock) и декоративные position/opacity tokens. Full/static surfaces не копируют пороги и формулы. - Palette хранится одной typed таблицей. CSS и тесты не получают расходящиеся hard-coded варианты.
- Real-sun resolver запускается только на релевантном изменении sun snapshot,
config/space или lifecycle catch-up; прочие
hassticks не меняют DOM. - Clock timer существует только в fallback, не чаще 30 s, не выполняет
необязательную работу в hidden document и очищается в
disconnectedCallback. - Не создаётся
requestAnimationFrameloop, canvas/WebGL, geometry/layout polling, новая сеть, service call или storage write. - Phase/source/position update меняет только bounded environment state/style. Rooms, walls, openings, Glow barriers, devices и backdrop geometry не пересчитываются.
- Alpha-aware outline применяется к одному plan-paper composite; per-room filter multiplication запрещён.
- Environment DOM count постоянен относительно rooms/devices и не растёт при каждой фазе или visibility cycle.
- #101 и cold-start #131 сохраняют первый полный кадр: не допускается второй пустой render ради вычисления локального времени.
- Таргетированный performance smoke доказывает отсутствие geometry/device rebuild на clock tick и обычном нерелевантном hass tick. Перед бетой на exact SHA обязательны существующие performance smoke и Full Performance без ослабления budgets.
15. Acceptance criteria
- AC1 (
unit; разработчик): real-sun resolver детерминированно выдаётnight/dawn/day/duskна обеих сторонах −6/+6, точных границах, при rising и falling; azimuth wrap не меняет фазу. - AC2 (
unit+ production-bundle smoke; разработчик): отсутствие/garbage любого из elevation/azimuth/rising атомарно включает clock-fallback с точными границами 05:00/08:00/18:00/21:00; валидность real sample восстанавливает весь sun-source без смешивания данных. - AC3 (
unit+ targeted smoke; разработчик): real-sun позиция следует elevation/azimuth, fallback — утверждённой дуге 05:00→13:00→21:00, а night имеет opacity 0. Ни один update не пересчитывает plan geometry. - AC4 (
golden+ computed-style smoke; владелец/ревьюер): dawn/day/dusk/ night используют точные palette и outline tokens раздела 9; ночью нет видимого светового круга, а светлый дневной и тёмный ночной план отделены от окружения. - AC5 (
pixel regression+ code review; разработчик/ревьюер): внутри plan-paper footprint пиксели plan, floors, room fills, Glow/spill, devices/labels, decor/backdrop, vacuum, hover и оконных лучей совпадают между четырьмя фазами; никакой phase-dependent plan filter/opacity/blend не остаётся. - AC6 (
targeted smoke; разработчик): смена фазы анимирует только environment и outer outline за 1100 ms с заданным easing; plan не мигает. Reduced motion завершает переход практически мгновенно. - AC7 (
production-bundle smoke+ golden; разработчик/владелец): full View, kiosk и static card получают одну effective phase/palette; editors остаются прежними, а #101 transition не оставляет stale/interactive environment layer. - AC8 (
unit+ smoke; разработчик):daynightработает безnorth_degи безsun.sunчерез clock fallback; оконные лучи по-прежнему требуют свои действующие sun/north gates и не меняют геометрию/пороги. - AC9 (
backend migration tests; разработчик): существующий отсутствующий global mode мигрирует вstaticровно один раз; валидные global/per-space modes и неизвестные поля сохраняются; повторный старт не пишет store/rev. - AC10 (
frontend unit+backend/import tests+ smoke; разработчик): новая установка, manual Create и Floors/Areas create материализуютdaynight; существующий Edit не меняет mode сам; явныйstaticостаётся static. - AC11 (
backend/import-export tests; разработчик): full/space export и legacy/current import выполняют контракт §12.4, preview совпадает с apply, а preview не пишет storage. - AC12 (
i18n test+ accessibility/touch smoke; разработчик): RU/EN тексты описывают четыре фазы и fallback; environment pointer-inert, не двигает focus, не меняет размеры/hit targets и не ломает tap/swipe/pinch в View/kiosk. - AC13 (
lifecycle smoke; разработчик): fallback пересчитывается сразу, каждые 30 s только в visible state, наpageshowи visible-return; timer и listeners очищаются при disconnect, повторное подключение не дублирует их. - AC14 (
performance smoke+ code review; разработчик/ревьюер): sun/clock update меняет bounded environment state без room/device/geometry rebuild, RAF-loop, canvas, сети, HA calls или storage writes; DOM/timer count bounded. - AC15 (
typecheck+unit+build+ docs review; разработчик): локальные implementation gates зелёные, обе пользовательские документации/changelog и три bundle-копии обновлены в одномUser-Visible: yesкоммите. - AC16 (
exact-SHA Linux gates; Claude/релиз-инженер): перед бетой зелёны Validate, полный smoke, reviewed golden и Full Performance на одном SHA без ослабления budgets; security/network/schema verdict явно записан в code review.
16. План автотестов и визуального review
16.1. Unit/frontend
Добавить pure-helper coverage:
- elevation
-6.1/-6/-5.9/5.9/6/6.1при обоих rising values; - NaN/infinity/string/missing для elevation, azimuth и rising;
- fallback минуты
299/300/479/480/1079/1080/1259/1260; - real position east/south/west/north и elevation below horizon/0/45/90;
- fallback position/opacity в 05:00, 07:00, 13:00, 19:00, 21:00;
- palette completeness и night opacity 0;
- mode inheritance с compatibility fallback
static; - отсутствие влияния нового rising requirement на sun-ray helpers.
16.2. Backend и compatibility
Покрыть storage migration: missing, static, daynight, mixed per-space, malformed legacy, unknown fields, idempotent second load и rev/event count.
Расширить import/export matrix: legacy full/space без mode, current full/space с обоими modes, inherited export materialization, same/foreign source, preview versus apply и import into target с противоположным global mode.
16.3. Targeted production-bundle smoke
Обновить sun/background smoke либо добавить отдельный four-phase smoke на собранном bundle:
- full View, kiosk и
houseplan-space-cardпроходят четыре deterministic real-sun phase; - отдельная matrix проходит clock fallback и source recovery;
- computed styles проверяют palette, outline, light visibility и transition;
- pixel probes/masked screenshots доказывают неизменность plan interior;
- existing window rays работают с north, а background — без north;
- editor и View↔editor transition не получают stale layer;
- visibility/pageshow/timer cleanup и reduced motion проверяются под fake clock;
- manual/Floors create и existing Edit проверяют persisted modes;
- counters доказывают отсутствие geometry/device rebuild и storage/network activity на fallback tick.
Targeted smoke пишется вместе с кодом; полный smoke-suite запускается перед бетой, не в implementation loop.
16.4. Golden
Нужны новые deterministic Linux golden-сцены full View для dawn, day,
dusk, night и static-card сцены для двух контрастных крайних состояний
day/night. Одинаковые fixture plan/live state/camera исключают посторонний
diff; reduced motion включён.
Golden artifact ревьюится владельцем/Claude как единый набор: соответствие
прототипу, отсутствие plan tint/dim, световой круг не виден ночью, outline не
создаёт per-room seams. Baseline принимается только штатной командой
golden:accept -- --reviewed из полного Linux-артефакта и отдельным коммитом с
обязательными release/baseline trailers по runbook; принять baseline ради
зелёного CI нельзя.
17. План реализации
- Ввести typed day-cycle resolver/palette рядом с sun pure logic, не меняя оконную ray geometry.
- Подключить единый environment model и lifecycle к full/static surfaces; убрать phase-dependent plan dim и compass gate background.
- Реализовать environment layers, decorative light, vignette, composite outline, 1100 ms/reduced-motion и интеграцию #101.
- Материализовать новые defaults, storage migration и import/export compatibility.
- Обновить selectors/hints i18n, документацию и changelog.
- Добавить unit/backend/targeted production-bundle smoke и deterministic golden scenes.
- Выполнить implementation-loop
typecheck,unit,build; остальные гейты — на пре-релизе по команде владельца.
Точные имена helper-функций, CSS classes и private fields не являются продуктовым контрактом.
18. Release-артефакты
Изменение пользовательское: implementation-коммит имеет User-Visible: yes и
в том же коммите обновляет:
docs/CHANGELOG.mdиdocs/CHANGELOG.ru.md;docs/SUN.md— новый источник истины по фазам, fallback, визуалу и независимости от компаса;docs/USER-GUIDE.ru.md— выбор режима, четыре фазы, defaults и fallback;docs/ARCHITECTURE.md— resolver/lifecycle/layers и full/static parity;docs/CONFIG-COMPATIBILITY.md— storage/default/import migration;docs/TESTING.md— targeted smoke/golden matrix;- RU/EN i18n и три поставляемые bundle-копии.
Перед бетой на exact SHA обязательны:
- Linux Validate;
- полный smoke-suite;
- reviewed/accepted golden artifact без необъяснённого diff;
- performance smoke и Full Performance без ослабления budgets;
- code review с явным negative security/network/HA-call verdict.
Новый отдельный security report не требуется: feature не принимает HTML/URL, не добавляет network/storage input или HA action. Публикация проходит через обычную бету до stable; issue закрывает владелец пачкой после опубликованной беты.
19. Риски и меры
| Риск | Вероятность / влияние | Мера |
|---|---|---|
| План незаметно остаётся dim/tinted старым filter | средняя / высокая | AC5 pixel mask, удаление planDim consumers, four-phase golden |
| Старый план без mode внезапно включит daynight | средняя / высокая | materialized storage migration в static, idempotence/backend tests |
| Новое пространство в старой установке наследует static | высокая / средняя | explicit per-space daynight в manual и Floors create, AC10 |
| Partial sun sample смешивается с clock position | средняя / средняя | атомарный resolver/source, garbage matrix AC2 |
| CSS gradient прыгает вместо перехода | средняя / средняя | проверяемые intermediate styles/pixels, animatable primitive/crossfade |
| Outline создаёт швы по комнатам или обводит devices | средняя / высокая | один plan-paper group, full/static golden и DOM assertion |
| 30 s timer течёт/дублируется | средняя / средняя | fallback-only lifecycle, disconnect/reconnect smoke |
| Background начинает зависеть от north и молчит | средняя / высокая | отдельные gates background/rays, no-north smoke |
| #101 оставляет stale слой либо pointer blocker | средняя / высокая | mode-transition targeted smoke, pointer-events none |
| Import наследует target mode вместо исходного | средняя / высокая | effective space export + legacy import materialization matrix |
| Visual layers ухудшают слабое устройство | низкая / высокая | bounded layers, один outline filter, performance exact-SHA gates |
20. Откат
Пользовательский немедленный откат — выбрать static глобально либо для
пространства; environment timer/layers становятся инертны без потери данных.
Технический откат — revert implementation-коммита вместе с тестами,
документацией, changelog и bundle-копиями. Миграция только материализует ранее
эффективный static, поэтому старая версия полностью читает результат; новые
явные daynight также являются старым валидным token. Обратная миграция и
удаление полей не нужны. Если default новой установки требуется временно
отключить без полного revert, вернуть creation defaults в static; сохранённые
пользовательские choices не переписывать.
21. Принятые технические предположения — можно менять без продуктового ревью
- Точная граница считается
<= -6 => night,>= 6 => day; только открытый интервал различает rising/falling. - Environment использует отдельный strict real-sun validator; ray API не
расширяется обязательным
rising. - Real decorative position использует формулы §8.1: horizontal проекция через
sin(azimuth), vertical — линейно по положительной elevation. Это декоративное отображение, не плановая координата и не зависит от north. - Размер light можно выразить через bounded
clamp()вместо ровно 250 px на маленьких карточках, сохранив desktop reference и visual intent. - Конкретный способ плавной смены gradient — registered custom properties или два bounded environment layers; AC важнее механизма.
- QA не читает production
?time: fake clock/sun внедряется только в unit, demo и smoke harness. Пользовательского QA-control нет. - Storage migration рекомендуется реализовать bump minor version с проверкой формы config-store document; точный helper свободен при соблюдении AC9.
- Per-space export может материализовать effective mode в копии export payload, не меняя live config.
- Один shared fallback ticker допустим вместо timer на карточку, если lifecycle, isolation нескольких карточек и bounded listener count доказаны тестами.
- DOM может хранить фазу как
data-day-cycleлибо typed class; публичной schema/DOM API это не становится. - Контур строится вокруг действующего канонического opaque paper composite: image rect либо общего group room papers; новый анализ alpha пикселей загруженного raster-файла не требуется.
- Открытых продуктовых вопросов нет; все Q1–Q3 и defaults приняты владельцем 2026-08-14.