mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-06 06:38:57 +00:00
@@ -0,0 +1,260 @@
|
||||
# #448 — Единый бессрочный переключатель `hp_alpha`
|
||||
|
||||
- Issue: [#448](https://github.com/Matysh/houseplan-card/issues/448)
|
||||
- Приоритет: P1
|
||||
- Тип: feature
|
||||
- Решения владельца: 2026-09-04, Q1 — default; Q2 — без миграции прежнего `iso`
|
||||
|
||||
## Сценарий
|
||||
|
||||
Продвинутый пользователь или тестировщик House Plan открывает полную карточку
|
||||
на своём обычном Home Assistant origin и один раз включает скрытый alpha-режим
|
||||
через URL. После перезагрузок, перезапусков Home Assistant и обновлений House
|
||||
Plan ему по-прежнему доступны все экспериментальные функции этой сборки. Сейчас
|
||||
такой функцией является существующий объёмный вид плана.
|
||||
|
||||
## Что человек увидит до и после
|
||||
|
||||
До изменения прежний ключ `iso` истёк на версии 1.65, поэтому в актуальной
|
||||
сборке объёмный вид невозможно включить. После изменения `hp_alpha=1` один раз
|
||||
возвращает существующий переключатель «Плоский / 3-D» без срока действия;
|
||||
`hp_alpha=0` выключает весь экспериментальный набор. Старое включение `iso`
|
||||
автоматически не переносится — режим нужно активировать заново.
|
||||
|
||||
## Проблема
|
||||
|
||||
`src/labs.ts` сейчас предоставляет внешний реестр отдельных feature-id с
|
||||
`since`/`expires`, читает операции `hp-labs=iso` и хранит массив id в
|
||||
`houseplan_card_labs_v1`. Единственный зарегистрированный `iso` истекает перед
|
||||
версией 1.65.0, поэтому на линии 1.71 он всегда отфильтровывается, хотя
|
||||
изометрический renderer, выбор вида по пространству и его тестовые сценарии
|
||||
остались в продукте.
|
||||
|
||||
Такой контракт также требует придумывать пользователю новый внешний ключ и
|
||||
продлевать окно при каждой следующей экспериментальной функции. Решение
|
||||
владельца заменяет его одним browser-local переключателем способности.
|
||||
|
||||
## Скоуп
|
||||
|
||||
- Один внешний URL-параметр `hp_alpha` со значениями `1` и `0`.
|
||||
- Один бессрочный persisted switch на текущем browser/HA-origin.
|
||||
- Включение одним switch всех экспериментальных функций, присутствующих в
|
||||
текущей сборке; внутренние идентификаторы функций допустимы только как деталь
|
||||
реализации и диагностики.
|
||||
- Возврат существующего объёмного вида и его переключателя в полной карточке.
|
||||
- Сохранение текущих ограничений объёмного вида: редакторы и
|
||||
`houseplan-space-card` остаются плоскими, публичного UI включения нет.
|
||||
- Адаптация unit, browser smoke, golden и performance fixtures к новому
|
||||
внешнему контракту.
|
||||
- Актуализация документации Labs/изометрии и двух changelog.
|
||||
|
||||
## Не-скоуп
|
||||
|
||||
- Публичный запуск 3-D или обычная настройка alpha в интерфейсе.
|
||||
- Реализация Stage 3 из #160 либо изменение визуального результата Stage 1/2.
|
||||
- Отдельные пользовательские ключи для `iso` или будущих экспериментов.
|
||||
- Серверное хранение, синхронизация между браузерами или HA-пользователями.
|
||||
- Изменение схемы плана, backend API, HA-запросов, сохранения конфигурации,
|
||||
действий устройств или статической карточки пространства.
|
||||
- Перенос ранее сохранённого `iso` в новый переключатель.
|
||||
|
||||
## Контракт поведения
|
||||
|
||||
### Единый внешний переключатель
|
||||
|
||||
1. `?hp_alpha=1` включает alpha для текущего browser/HA-origin и запоминает
|
||||
включение.
|
||||
2. `#hp_alpha=1&space=<id>` делает то же, не ломая существующий выбор
|
||||
пространства из hash.
|
||||
3. `hp_alpha=0` в query или hash выключает alpha и запоминает выключение.
|
||||
4. URL не переписывается после чтения параметра.
|
||||
5. Если параметр указан и в query, и в hash, операции применяются в порядке
|
||||
query → hash: последнее распознанное значение в hash сильнее query. Внутри
|
||||
одной части URL последнее распознанное значение сильнее предыдущего.
|
||||
6. Только точные строки `1` и `0` распознаются. Явное иное значение не может
|
||||
включить alpha: для текущего разрешения оно даёт выключенное состояние и не
|
||||
перезаписывает storage. Отсутствие параметра читает сохранённое состояние.
|
||||
7. Отсутствующие или повреждённые persisted-данные дают выключенное состояние.
|
||||
8. Версия карточки не участвует в решении. Нет `since`, `expires` и
|
||||
автоматического выключения после beta/stable update.
|
||||
|
||||
### Доступные эксперименты
|
||||
|
||||
9. При включённом alpha внутренний runtime активирует весь известный этой
|
||||
сборке экспериментальный набор. В первой поставке набора ровно одна функция:
|
||||
`iso`.
|
||||
10. Потребители могут продолжать различать функции внутренними id, но URL,
|
||||
storage и пользовательская документация не позволяют выбирать их по одной.
|
||||
11. При выключенном alpha effective projection всегда Flat, даже если
|
||||
per-space preference хранит `iso`.
|
||||
12. Выключение alpha не стирает `houseplan_card_view_v1`: повторное включение
|
||||
возвращает ранее выбранную проекцию пространства. Это состояние вида, а не
|
||||
второй экспериментальный ключ.
|
||||
13. В полной карточке View включённый alpha возвращает существующий
|
||||
переключатель Flat ↔ 3-D. В kiosk применяется сохранённая проекция, но новый
|
||||
служебный контрол не появляется. В любом редакторе и
|
||||
`houseplan-space-card` объёмная проекция отсутствует.
|
||||
14. Любой сбой разрешения alpha безопасно оставляет публичный Flat и не влияет
|
||||
на данные или HA-команды.
|
||||
|
||||
## URL, storage и совместимость
|
||||
|
||||
- Новый storage key: `houseplan_card_alpha_v1`.
|
||||
- Канонические значения storage: строка `1` для enabled и строка `0` для
|
||||
disabled. Любое другое содержимое считается выключенным.
|
||||
- Legacy URL `hp-labs=iso`, `hp-labs=-iso`, `hp-labs=off` больше не управляет
|
||||
функциями.
|
||||
- Legacy key `houseplan_card_labs_v1` не читается, не мигрируется и сам по себе
|
||||
не удаляется. Даже точное прежнее значение `["iso"]` не включает alpha.
|
||||
- Старому тестировщику необходимо один раз открыть карточку с `hp_alpha=1`.
|
||||
- Per-space preference `houseplan_card_view_v1` сохраняет существующий формат и
|
||||
не мигрируется.
|
||||
- Состояние локально для origin и профиля браузера; private mode/quota ошибки
|
||||
не роняют карточку, но сохранение между сессиями в таком окружении не
|
||||
гарантируется.
|
||||
|
||||
## UX и диагностика
|
||||
|
||||
- Обычный пользователь не видит новой настройки, баннера или подсказки.
|
||||
- Способ включения остаётся намеренно скрытым и документируется только в
|
||||
материалах разработчика/изометрии.
|
||||
- Когда alpha включён и экспериментальный кадр действительно отрисован,
|
||||
dev-console один раз на фактический набор сообщает, что активен `hp_alpha`, и
|
||||
перечисляет внутренние функции с issue, но без срока истечения.
|
||||
- Когда alpha выключен либо не удалось разобрать, служебный лог не обещает
|
||||
активный эксперимент.
|
||||
- Диагностический browser hook должен однозначно позволять smoke-тесту отличить
|
||||
alpha enabled от disabled и увидеть фактически активный внутренний набор.
|
||||
|
||||
## Модель данных и миграция
|
||||
|
||||
План, backend и пользовательская конфигурация не меняются. Новое состояние —
|
||||
один локальный boolean-like переключатель браузера. Автоматической миграции нет
|
||||
по прямому решению владельца: legacy storage остаётся неактивным входом, а
|
||||
пользователь заново подтверждает участие явным `hp_alpha=1`.
|
||||
|
||||
Внутренняя модель может сохранить snapshot со списком активных возможностей,
|
||||
если это уменьшает дифф потребителей. Его источник обязан быть один: при alpha
|
||||
off список пуст, при alpha on он равен полному набору сборки. Внутренний список
|
||||
не является persisted или URL API.
|
||||
|
||||
## i18n и accessibility
|
||||
|
||||
Новых публичных строк и интерактивных элементов нет. Существующие
|
||||
локализованные названия Flat/3-D, `aria-label` и keyboard contract
|
||||
переключателя сохраняются без изменений. Kiosk и static card не получают новых
|
||||
focus targets.
|
||||
|
||||
## Критерии приёмки
|
||||
|
||||
- **AC1.** `hp_alpha=1` в query и hash включает alpha, сохраняет `1` и не
|
||||
переписывает URL. Доказательство: unit resolver/storage + browser smoke после
|
||||
reload.
|
||||
- **AC2.** `hp_alpha=0` выключает alpha, сохраняет `0`, немедленно возвращает
|
||||
Flat и убирает переключатель 3-D. Доказательство: unit + browser smoke.
|
||||
- **AC3.** Query применяется раньше hash; последнее распознанное значение
|
||||
детерминированно побеждает. Доказательство: табличный unit-тест конфликтов.
|
||||
- **AC4.** Отсутствующий storage, повреждённый storage и явное неизвестное
|
||||
значение не включают alpha и не вызывают исключений. Доказательство: unit.
|
||||
- **AC5.** Поведение одинаково на текущей beta, stable и произвольной будущей
|
||||
semver: version expiry отсутствует. Доказательство: unit с несколькими
|
||||
версиями и source-contract без `since`/`expires` в решении.
|
||||
- **AC6.** `houseplan_card_labs_v1: ["iso"]` и любой `hp-labs=...` не включают
|
||||
alpha и не переносятся. Доказательство: unit + browser smoke чистого профиля.
|
||||
- **AC7.** При alpha on существующий полный View предлагает Flat ↔ 3-D и
|
||||
отображает Stage 2; при alpha off публичный View остаётся Flat.
|
||||
Доказательство: targeted isometric smoke и существующие golden.
|
||||
- **AC8.** Сохранённая per-space проекция переживает alpha off/on, но без alpha
|
||||
никогда не отрисовывается. Доказательство: unit/browser smoke.
|
||||
- **AC9.** Редакторы и `houseplan-space-card` остаются плоскими, kiosk не
|
||||
получает служебный контрол. Доказательство: contract unit + smoke.
|
||||
- **AC10.** Все isometric golden-сценарии явно включают общий alpha и падают,
|
||||
если фактически получили Flat. Доказательство: matrix unit +
|
||||
`npm run golden:verify`.
|
||||
- **AC11.** Isometric performance profile включает alpha новым контрактом и не
|
||||
использует legacy storage/URL. Доказательство: source-contract + профильный
|
||||
запуск.
|
||||
- **AC12.** Диагностика однозначно показывает switch и активный набор без
|
||||
`expires`; повторный одинаковый кадр не спамит console. Доказательство: unit
|
||||
или targeted browser smoke.
|
||||
- **AC13.** Alpha не участвует в HA data/request paths, schema и writes.
|
||||
Доказательство: static contract tests и чтение границ импорта.
|
||||
|
||||
## План автотестов
|
||||
|
||||
### Unit и contract
|
||||
|
||||
- Переписать таблицу `test/labs.test.mjs`: `1`/`0`, query/hash precedence,
|
||||
повторные значения, storage persistence, corruption, future versions,
|
||||
private-storage failures и отсутствие legacy migration.
|
||||
- Зафиксировать один внешний URL/storage contract; запретить возвращение
|
||||
`hp-labs`, persisted массива и expiry как активирующих входов.
|
||||
- Обновить `test/isometric-contract.test.mjs` и golden-matrix contract: full
|
||||
card использует alpha, secondary card не знает про него, isometric scenarios
|
||||
объявляют его явно.
|
||||
|
||||
### Browser и visual
|
||||
|
||||
- Обновить `demo/smoke_isometric_contract.mjs`: clean off → URL on → reload →
|
||||
3-D → URL off → Flat → повторное on восстанавливает preference.
|
||||
- Обновить `demo/smoke_isometric_live_touch.mjs` и все fixtures, которые сейчас
|
||||
подменяют `hp-labs`/legacy storage напрямую.
|
||||
- Прогнать выбранные `smoke-select` сценарии и весь isometric smoke-контракт.
|
||||
- Прогнать `npm run golden:verify`; новые эталоны не принимаются, если пиксели
|
||||
Stage 1/2 не изменились.
|
||||
|
||||
### Производительность и основные гейты
|
||||
|
||||
- `npm run benchmark:large-house-isometric` с alpha fixture и существующим
|
||||
бюджетом; задача меняет gate, а не геометрию/рендер, поэтому новый бюджет не
|
||||
вводится.
|
||||
- Перед код-ревью: typecheck, unit, build + bundle-tree/budget,
|
||||
`check-docs`, `no-new-any`, выбранные smokes и golden.
|
||||
|
||||
## Затронутые файлы и модули
|
||||
|
||||
Ожидаемо: `src/labs.ts`, потребители Labs в `src/houseplan-card.ts`, unit и
|
||||
isometric browser/golden/performance harnesses, `docs/DEVELOPMENT.md`,
|
||||
`docs/ISOMETRIC.md`, архитектурные/ADR ссылки при необходимости, оба changelog.
|
||||
Backend, schema плана и secondary-card renderer изменяться не должны.
|
||||
|
||||
## Риски
|
||||
|
||||
- Legacy фикстура может продолжить принудительно подставлять `['iso']` и дать
|
||||
ложнозелёный тест, не проверяющий новый пользовательский вход.
|
||||
- Стирание projection preference при `hp_alpha=0` превратит временное
|
||||
выключение экспериментов в потерю пользовательского выбора.
|
||||
- Параллельные module instances могут зарегистрировать несколько listeners;
|
||||
существующий single-listener contract нужно сохранить.
|
||||
- Ошибка precedence query/hash сделает включение зависимым от порядка роутера HA.
|
||||
- Слишком широкая замена термина `iso` может затронуть внутренний renderer;
|
||||
меняется capability gate, а не имя проекции.
|
||||
|
||||
## Откат
|
||||
|
||||
Откат изменения возвращает старый истёкший Labs resolver; публичный Flat при
|
||||
этом остаётся безопасным. Новый storage key можно оставить неиспользуемым: он
|
||||
не является данными плана и не требует destructive cleanup. Нельзя откатывать
|
||||
через продление `iso` expiry или возвращение нескольких внешних ключей — это
|
||||
восстановит проблему задачи.
|
||||
|
||||
## Release-артефакты
|
||||
|
||||
- Записи со ссылкой на #448 в `docs/CHANGELOG.ru.md` и `docs/CHANGELOG.md` в
|
||||
коммите пользовательского изменения.
|
||||
- Актуальные `docs/DEVELOPMENT.md` и `docs/ISOMETRIC.md`; при изменении
|
||||
архитектурной границы — соответствующие ADR/`docs/ARCHITECTURE.md`.
|
||||
- Обновлённые unit, smoke, golden matrix и isometric performance fixtures.
|
||||
- Обычные синхронные release bundles; новая картинка документации или новый
|
||||
golden baseline не ожидаются, пока пиксельный результат Stage 1/2 не менялся.
|
||||
|
||||
## Принятые предположения — можно менять на ревью без решения владельца
|
||||
|
||||
- Storage key — `houseplan_card_alpha_v1`, значения — строки `1`/`0`.
|
||||
- Явное неизвестное URL-значение выключает alpha только для текущего разрешения
|
||||
и не портит ранее сохранённое значение; распознанные `1`/`0` записываются.
|
||||
- Legacy storage не удаляется автоматически: он просто перестаёт быть входом.
|
||||
- Внутренние feature-id можно сохранить для маршрутизации и диагностики, если
|
||||
снаружи существует только один alpha switch.
|
||||
- Отключение alpha скрывает эксперимент, но не стирает per-space projection
|
||||
preference.
|
||||
@@ -174,6 +174,7 @@ GitHub Issues и GitHub Projects (v2) остаются единственным
|
||||
| [#440](https://github.com/Matysh/houseplan-card/issues/440) Полиш аудита v1.71.0-beta.2 | [440-v171-beta2-polish.md](440-v171-beta2-polish.md) |
|
||||
| [#445](https://github.com/Matysh/houseplan-card/issues/445) Магнит мебели к физической поверхности стены | [445-furniture-wall-face-snap.md](445-furniture-wall-face-snap.md) |
|
||||
| [#447](https://github.com/Matysh/houseplan-card/issues/447) Наружная грань для мебели и сдвиг декора стрелками | [447-exterior-furniture-snap-keyboard-nudge.md](447-exterior-furniture-snap-keyboard-nudge.md) |
|
||||
| [#448](https://github.com/Matysh/houseplan-card/issues/448) Единый бессрочный переключатель `hp_alpha` | [448-alpha-switch.md](448-alpha-switch.md) |
|
||||
|
||||
## P3
|
||||
|
||||
|
||||
Reference in New Issue
Block a user