Транзитная геометрия Resize теперь только вычисляет центр для текущего кадра и не удаляет сессионную позицию. Окончательная геометрия по-прежнему очищает точку, если она действительно вышла за комнату.
Issue: #645
User-Visible: yes
Кнопка сохраняет положение в пределах комнаты только на время сессии редактора,
корректно отменяется при pinch/cancel и учитывается подписями Resize.
Issue: #645
User-Visible: yes
- scripts/no-new-private-writes.mjs: смоки и demo/helpers/** не добавляют
записей в приватное состояние карточки (присваивание, ++/--, delete по
цепочке с сегментом _x; от this — нет) и вызовов _setMode/_openRoomEdit/
_openMarkerDialog/_openSpaceDialog. Зачёт правки по полю, перенос блока —
movedLinesByFile из no-new-any; исключение // private-ok: <причина>.
--count — остаток на HEAD. Подключён в gate:small и в шаг frontend рядом с
no-new-any, с той же базой.
- demo/helpers/hp-test.mjs: 10 операций через контрактные хуки и события
фикстуры (setMode, setTool, switchSpace, openRoomEdit, openMarkerDialog,
openSpaceDialog, setServerConfig, setLayout, input, close); ставится
launch*() из demo/serve.mjs. В бандле фасада нет.
- demo/srv/demo.html: доставка houseplan_config_updated/_layout_updated,
__pushServerConfig/__pushServerLayout; после доставки запись со старым
expected_rev — conflict, как у настоящего сервера.
- HP_SMOKE_CHECKS=1 печатает имена проверок в finish().
- smoke_area_relocation, smoke_glow, smoke_grid_snap переведены на фасад без
потери утверждений; новый smoke_test_facade доказывает каждую операцию.
- 7 мутантов, docs/TESTING.md (раздел + правило №6), PROCESS.md §2.7, AGENTS.md.
Issue: #629
User-Visible: no
General settings colour tiles (room fills and glow) paint their colour at
its opacity over the checkerboard again, so "No light sources" at 0 % no
longer looks like solid grey. The label ink is chosen from the visible
colour (hex mixed with the checkerboard by alpha). Colour plates
(flat-swatch without cover-swatch) stay solid — now witnessed by the
- hp-color-opacity: one `_solidSwatch` condition drives background and
opacity; cover-swatch keeps the checkerboard
- editors/color-tile-ink.ts: pure isLightHex/colorTileInk, unit-tested
- smoke_dialog_polish_605: tileAlpha, defaultsDiffer, noneInkDark,
liveAlpha, platesFlat, plateSolid; oneSurface drops the opaque check
- mutants M-615-tile, M-615-plate, M-615-label
- USER-GUIDE (ru/en): "Colour tile" row; both changelogs
Issue: #615
User-Visible: yes
На вкладках «На плане» и «Скрытые» — флажки строк, «Выбрать все (N)» по
всему отфильтрованному набору (включая строки за «Показать ещё»), панель
«Выбрано: K · Скрыть/Показать выбранные (K) · Снять выбор» в отдельном
контейнере .device-inbox-batch вне .device-inbox-filters.
- src/device-inbox.ts: чистые inboxVisibilityAllowed (один источник для
canHide/canShow и выбора), selectableInboxRows, effectiveInboxSelection,
applyInboxVisibility — свёртка одиночных действий; одиночное = пакет из
одной строки.
- src/device-inbox-batch.ts (новый, lazy editor): выбор, панель, строка-
флажок и writeInboxVisibility — одна запись houseplan/config/set с
expected_rev на пакет, busy='__batch__' (inert), откат маркеров при отказе,
выбор сохраняется и сужается. Одиночный _setInboxHidden рантайма — тонкая
обёртка над той же записью; рантайм стал короче базы на 14 строк.
- сброс выбора при смене вкладки (клик и стрелка), поиска и «Только новые».
- i18n en/ru/de/fr: 9 ключей по ТЗ §8.
- смок demo/smoke_device_inbox_batch.mjs (AC1–AC8, AC10), юниты
test/device-inbox.test.mjs (AC2, AC4), 4 мутанта в реестре.
- docs: USER-GUIDE ru/en, FILTERING.md, оба changelog.
- monolith-baseline: hostRefs 4948→4959, bundleBytes 2500387→2505569 —
новая фича (состояние выбора и запись идут через порт хоста).
- bundle-budget: LAZY_EDITOR_GZIP_CEILING 245 400 → 246 600 (замер 245 610,
+1 190 Б gzip от базы 244 420); initial View 289 449 → 289 765 (+316 Б,
строки en-словаря), в пределах потолка.
Golden device-inbox-* изменятся ожидаемо — пересъёмка предрелизным гейтом
на Linux CI (§11.4).
Issue: #618
User-Visible: yes
План уходил base64 в WebSocket-кадре: файл больше ~3 МиБ давал кадр больше
4 МиБ, HA закрывал сокет до обработчика, и обещанные 8 МБ были недостижимы.
- бэкенд: HouseplanPlanUploadView (POST /api/houseplan/plans/upload), потоковый
предел MAX_PLAN_BYTES (read_bounded), общий writer store_plan_upload для view
и ws_plan_set (контракт WS без изменений);
- карточка: stagePlanFile/uploadPlanFile/renderPlanBackdropGuard в
backdrop-pick.ts для обоих рантаймов; PlanFilePayload хранит Blob вместо b64;
SVG больше предела — тост при выборе, растр — диалог #39 только с уменьшенной
копией, копия больше предела не попадает в staging, 413 называет предел;
- i18n toast.plan_too_large, backdrop.over_limit_body (en/ru/de/fr);
USER-GUIDE ru/en, CHANGELOG ru/en, docs/testing-notes (#617);
- тесты: test/plan-upload-limit.test.mjs, tests_backend/test_plan_upload.py,
test_ha_upload.py (#617), smoke_plan_upload_limit.mjs; три смока переведены
с b64/plan/set на blob/fetchWithAuth; мутанты plan-upload-*;
- база монолита: hostRefs +3 (общий хелпер плана вместо двух копий в рантаймах,
новый тост уменьшенной копии).
Issue: #617
User-Visible: yes
smoke_danger_confirmation asked for a confirmation as soon as btn.cancel was
translated. With #627 the settings namespace of de/fr settles after the main
catalog; while it is pending the host gate is warm and #417 refuses the
request — the dialog never painted and the smoke crashed intermittently.
The switch now waits until the host drops aria-busy (the gate settled), and
the settings-de/fr chunks are delayed by 300 ms so the slower-namespace order
is deterministic instead of a CI-speed coincidence. New checks name the lost
dialog directly instead of a TypeError.
Issue: #627
User-Visible: no
- ru/de/fr трёх словарей пространств — девять ленивых чанков (по одному на
пару «пространство × язык»), английский статически как слой отката;
рантайм — тот же LanguageRuntime (две попытки, отпечаток сборки, fallback,
общий тост отказа), src/i18n/namespace-language.ts.
- Загрузчики рантаймов онбординга и редактора отдают поверхность в рендер
только после того, как словарь текущего языка осел; гейт хоста учитывает
словари загруженной на нём поверхности (смена языка на лету — ветка warm).
Оверлей Zigbee ждёт topology до первой отрисовки.
- bundle-manifest: граф lazyNamespaceLocaleFiles, девять retry-токенов со
строгим счётом «ровно один». bundle-budget: потолок онбординга 28 500
(замер 27 470), редактор 245 400 → 228 900 (замер 227 869), проверки
ленивости и владения по содержимому.
- Смок smoke_lazy_admin_locale (AC4–AC7); регресс-смоки, переключавшие язык
синхронно, ждут гейт вместо ослабления проверок; пять мутантов.
- monolith-baseline bundleBytes 2 500 387 → 2 508 676: +10 чанков (rollup intro
и export на каждый) и записи манифеста; gzip каждой поверхности при этом
уменьшился.
Issue: #627
User-Visible: no
Первый вынос из монолита по образцу live-*/RadarSetupController.
src/optimize-plans-dialog.ts: OptimizePlansDialogState, чистые
preflightDiagnostics/preflightVersionsDiffer и класс OptimizePlansDialog
(open/preview/toggleLivePositions/run/copyDiagnostics/
reportPreflightFailure/render, clipboardFallback) за портом из 18 членов.
Модуль не знает HouseplanEditorHostPort; импортирует его только рантайм,
карточка берёт тип.
Инлайн-фолбэк буфера обмена — WeakMap по объекту диалога
(CODE-REVIEW-295-r1 M2), дедуп dev-лога — поле класса: из карточки и порта
ушли _preflightClipboardFallback и _reportedPreflightFingerprint, пять
делегатов и две стрелки-заглушки. Харнесс (13 смоков, wall-draw-click,
golden) зовёт card._editorRuntime.optimizePlans.* — меняется только адрес.
11 текстовых утверждений i18n.test.mjs о разметке и тосте диалога и гварды
8 мутантов переехали в юнит test/optimize-plans-dialog.test.mjs
(test-build); новый мутант optimize-dialog-imports-host-port.
monolith-baseline: delegates 159→154, portMembers 350→348,
hostRefs 4948→4869, portPrivates 96→94, harnessPrivates 107→101,
bundleBytes 2499647→2499182. Потолки ядер опущены на выигрыш;
потолок lazy editor gzip пересчитан (+555 Б gzip при −465 Б сырых).
Issue: #642
User-Visible: no
Полный прогон для #640 выявил устаревший parity-свидетель после уже слитого #614: прямой путь теперь обязан задавать и сырой текст числовых полей.
Issue: #640
User-Visible: no
Extend the authentic pinned-HA diagnostic with explicit light and dark palettes, a 32 px root-font case, one-scroller geometry assertions, and reviewed evidence images. Correct stale AC references in the mutation descriptions.
Issue: #609
User-Visible: no
Use Home Assistant's public dialog tokens for the reviewed 560 px canvas, height cap, single scroller and mobile fullscreen layout. Keep generic dialogs and the native fallback unchanged, with authentic-HA evidence and mutation witnesses.
Issue: #609
User-Visible: yes
Reviewed the complete Linux Validate artifact 35606718247: one new furniture scene and eight expected dialog-polish changes; 166 other scenes remain unchanged.
Release: v1.77.0-beta.5
Baseline-Reviewed: https://github.com/Matysh/houseplan-card/actions/runs/35606718247
Issue: #603
Issue: #605
Issue: #606
User-Visible: no
Publish corrected 0.4.1 pack, preserve old cactus objects as a read-only alias, and cover the catalog, renderers, editor, PDF and visual scene.
Issue: #606
User-Visible: yes
Count the Optimize action by its label instead of the removed alignall layout class, so the clean mutation guard still protects the action after the polish.
Issue: #605
User-Visible: no
Make colour tiles solid, readable and fully clickable; align Data actions and device icon field with the form kit. Cover narrow Windows layouts and both icon-picker branches with a focused browser smoke.
Issue: #605
User-Visible: yes
Reviewed room settings desktop/mobile and the new 320px discard confirmation from Linux Validate 35566453055; 171 scenes unchanged and 106 environment witnesses.
Issue: #603
User-Visible: no
Release: v1.77.0-beta.4
Baseline-Reviewed: https://github.com/Matysh/houseplan-card/actions/runs/35566453055
С Linux CI Validate 35538133817 приняты ровно восемь визуально проверенных сцен: три базовых диалога устройства, три help/popover-сцены и два цветовых поповера. Остальные 165 сцен сохранены без изменений; строгий allowlist accept.mjs исключил необъявленные расхождения.
Issue: #602
User-Visible: no
Release: v1.77.0-beta.3
Baseline-Reviewed: https://github.com/Matysh/houseplan-card/actions/runs/35538133817
Съёмка — Linux CI, Validate 35515236776 на ec97fd95; приёмка — Windows
владельца с HP_ALLOW_FOREIGN_CAPTURE (#455).
Просмотрены toggle-entity-dialog-desktop-en и
space-room-color-popover-desktop-ru. Остальные 171 сцена совпали; accept.mjs
отказал бы при любом необъявленном расхождении.
Issue: #600
User-Visible: no
Release: v1.77.0-beta.3
Baseline-Reviewed: https://github.com/Matysh/houseplan-card/actions/runs/35515236776
Продолжение r1 M1: полные fill.* в RU («По силе зигби-сигнала», «По
температуре») не входили одной строкой в четыре колонки сегмента пространства
и переносились на вторую строку кнопками. Референс (§4.2 reference/app.js
fillOptions, §6.1) даёт короткие подписи Custom | Zigbee | Lights |
Temperature — они и стоят в обоих сегментах общими ключами ленивого словаря
fill.seg_* (en/ru/de/fr); room.fill_seg_* удалены. USER-GUIDE ru/en,
ACCEPTANCE.md и smoke_ux_fixes обновлены; changelog называет короткие подписи.
Три эталона меняются к лучшему и требуют повторной приёмки:
device-dialog-desktop-en и toggle-entity-dialog-desktop-en («Colour and
brightness» одной строкой вместо двух), space-room-color-popover-desktop-ru
(сегмент RU без разорванных слов); остальные десять сцен — passed на этом
дереве диагностически.
Issue: #600
User-Visible: yes
M1. Подпись сегмента больше не рвётся посреди слова: колонка `.hpf-seg label`
не сжимается ниже самого длинного слова (`min-width: fit-content`, для
браузеров без него — прежний `0` строкой выше), слова переносятся только по
пробелам (`overflow-wrap: normal`), не поместившийся сегмент переносится на
вторую строку целыми кнопками (`flex-wrap`). Новый свидетель
demo/smoke_dialog_segments_i18n.mjs — четыре диалога × en/ru/de/fr: у каждой
подписи число строк (по Range текстового узла: span — flex-элемент, у блока
один прямоугольник даже при переносе) не больше числа слов, текст внутри
кнопки. На разметке r1 краснеет на en/ru/fr комнаты («Temperature» в 2
строки, «По температуре» в 3). Мутант form-kit-segment-breaks-words
возвращает прежние две строки CSS. ACCEPTANCE.md — строка про подписи
сегмента переписана.
M2. Glow radius — не условие Save: как на dev, нечисло или неположительное
значение при сохранении молча становится общим радиусом. Удалены
glowRadiusValid, MarkerProblem marker.error_glow_radius, ключ в четырёх
локалях словаря settings, aria-invalid у поля; смок device_settings_form
утверждает обратное прежнему (badRadiusDoesNotBlockSave,
zeroRadiusKeepsSaveEnabled) и проверяет «Review N fields» на привязке в
create-режиме. Changelog EN/RU и USER-GUIDE ru/en больше не называют радиус
среди ошибок; таблица устройства говорит про молчаливый общий радиус.
M3. Свидетель дефекта №5 (поповер «?» обрезается границей диалога комнаты):
demo/smoke_dialog_help_clipping.mjs — короткое окно 900×620, диалог комнаты
скроллится, «?» нижней карточки прижат к краю; подсказка выходит за край
скроллера и остаётся hit-test'ируемой во всех пяти точках (elementsFromPoint
сквозь теневые корни — обрезанная часть не hit-test'ится). Четыре ветки:
нативный <dialog> и ha-dialog × Popover API и портальный fallback; ветка
ha-dialog — заглушка с ловушками настоящей mwc-поверхности (transform +
overflow: hidden + собственный скроллер), portal вне поверхности проверен
явно. Настоящий ha-dialog (#505, загрузка колеса HA-frontend) — отдельная
диагностическая приёмка владельца; так и записано в ACCEPTANCE.md, где
появилась таблица AC8 «девять дефектов — свидетель на каждый».
M4. ACCEPTANCE.md: эталонов 13, а не 11 — одиннадцать из ТЗ (список AC10
унаследован от #598 без комнаты) плюс две room-temperature-dialog-*.
L1. USER-GUIDE.ru.md: испорченная строка таблицы настроек пространства
(хвост удалённой строки про декоративный слой) — убран; пояснение «в
редакторе подложки остаются видимыми» вернулось в строку «Видимые слои»;
строка про солнце говорит «слой Двери, окна и ворота выключен» вместо
«Скрыть проёмы включено».
Фикстуры листа диалогов набора пересняты (панель — байт в байт).
Бюджет: initial 289 852 / 290 900; lazy editor 242 989 / 243 900.
Гейты: typecheck, build, bundle:sync (три копии), npm test 2794 pass по
четырём частям, no-new-any, mutation-gate --check, check-inputs --coverage,
смоки: segments_i18n, help_clipping, четыре формы, config_parity,
help_affordance, room_settings, settings_dialog_cards.
Issue: #600
User-Visible: yes
После #600 единственный скроллер диалога находится в shadow-root .content.
Съёмка продолжала менять scrollTop у старой .body, поэтому обычный кадр
устройства и кадр Display preview получались побайтово одинаковыми.
Тест фиксирует владельца скролла и запрещает возврат к неработающей .body.
Issue: #600
User-Visible: no
Съёмка — Linux CI, Validate 35504549764 на 504c1609; приёмка — Windows
владельца с HP_ALLOW_FOREIGN_CAPTURE (#455).
Объявлены ровно 13 сцен AC10; остальные 160 сцен совпали побайтово,
иначе accept.mjs отказал бы до записи.
Issue: #600
User-Visible: no
Release: v1.77.0-beta.3
Baseline-Reviewed: https://github.com/Matysh/houseplan-card/actions/runs/35504549764
Единственный красный смок полного набора Validate #3417 (шард 2/3 и гард
мутанта в шарде 5/6): проверка localizedControl искала строку «Show the room
information window on hover» как label.srcrow с чекбоксом. С серии 2 это
строка-тумблер набора #gs-room-tooltip: название в .hpf-toggle-title, подпись
отдельно, переключатель — нативный чекбокс. Смок утверждает то же самое на
новой разметке.
Issue: #600
User-Visible: no
demo/smoke_dialog_config_parity.mjs: для каждого из четырёх диалогов одни и
те же правки делаются дважды — контролами набора с нажатием Save и прямой
записью в черновик с вызовом save-метода (путь прежних обработчиков и
существующих смоков); JSON.stringify(_serverCfg) совпадает побайтово, и оба
отличаются от исходного конфига. Заодно числовое поле размера шрифта
карточек в «Пространстве» получило id (space-card-font) — подпись for
раньше указывала в пустоту.
Issue: #600
User-Visible: no
Завершение четырёх серий по референсу docs/design/600-settings-dialogs/:
- из eager-листов dialogs.styles.ts и chrome.styles.ts сняты стили прежней
разметки диалогов (.bindsel/.bindharow/.entcheck, .ctrlchip*, .markerhelp*,
.helpfieldlabel, .markerradios, .markerlightdisabled, .markerbadgetechnical,
.markerglowvalue, .fileupload, .descin, .pdfedit/.pdftag, .gsrow,
.ripple-*row, .radaradditional, .togglehint, футеры marker/room) — 5,8 КБ
исходника; с разметки сняты уже пустые классы;
- «Additional actions» карточки Details — подзаголовок и строка действий
набора, без раскрывашки (radar-section.ts, только additional-placement);
- Q3 уточнён по кадру: hp-device-preview стоит без обёртки — у него свой
заголовок «Display preview · Now», второй над ним удваивался; пустое
состояние — блок на тинте;
- §6.1: «?» у комнаты стоит у поля Home Assistant area, а не у заголовка
Basics; подписи сегмента заливки — None · Zigbee · Lights · Temperature ·
Custom (два коротких ключа room.fill_seg_*), источники — «Average of the
room’s sensors / Specific device or entity», режим свечения — «Colour and
brightness» (тексты прежних ключей укорочены под сегменты);
- подпись поля с «?» и без стоят на одной линии в сетке (min-height 32 по
кнопке hp-help); иконка внутри подсказки — inline;
- парные кадры: demo/capture_design_pairs_600.mjs снимает четыре диалога в
двух темах на 560 в состояниях макетов → docs/design/…/pairs/ (8 PNG,
палитра 256, ~0,5 МБ); ACCEPTANCE.md — статус по диалогам, расхождения с
референсом по каждому со ссылкой на пункт SPEC и принятые адаптации (шапка
hp-dialog по §3, тумблеры набора по К7, секции радара/пылесоса по §7.2);
- changelog EN/RU («Не выпущено»), USER-GUIDE ru/en: раздел «Как устроены
диалоги настроек», таблица настроек пространства по новым карточкам,
диалог комнаты, диалог устройства, ссылка «Как у пространства»;
- бюджет: стартовый граф 289 853 — потолок 291 600 → 290 900 (снятые стили);
ленивый редакторский 243 149 — итоговый потолок 243 900 с разбором по
сериям в bundle-budget.mjs.
Golden: 11 сцен диалогов (device-dialog-*, room-temperature-dialog-*,
toggle-entity-dialog-*, device-help-popover-light-ru,
general-color-popover-desktop-en, settings-help-zoom-200-*,
device-ripple-color-popover-mobile-ru, space-room-color-popover-desktop-ru)
прогнаны диагностически (capture, HP_ALLOW_FOREIGN_CAPTURE, только
artifacts/): харнесс проходит все пути без исключений, кадры «different» —
эталоны переснимаются на Linux CI / машине владельца по #455.
Скриншоты документации (06-device-editor, 06-device-display-preview и др.)
устарели по отпечатку — пересъёмка перед кандидатом беты (#479).
Гейты: typecheck, build, bundle:sync (три копии байт в байт), npm test
2793 pass по четырём частям, mutation-gate --check, check-inputs --coverage,
фокусные смоки четырёх форм и смоки диалога устройства.
Issue: #600
User-Visible: yes
§7 SPEC.md референса. Пять карточек #598 остались, менялось содержимое; все
ключи _markerDialog и все записи в них прежние (§7.2):
- Basics — баннеры привязки стали callout'ами; Name с подсказкой «Shown on
the plan»; привязка — сегмент [Virtual | From the HA list] (те же радио
bmode) и кнопка выбора #marker-binding с панелью в потоке (sourcePicker
набора), чекбокс «Show entities» — внутри панели рядом с поиском (решение
владельца Q8); Room селектом с подсказкой «по зоне / переопределяет»;
секции радара и пылесоса — своими модулями без изменений;
- Tap action — селект с подсказкой Target/Now, «Ask for confirmation» —
строка-тумблер только при toggle/run (Q8), Entity to toggle и What to run
теми же условиями (список целей — панель набора), «Controls other light
sources» — чипы набора и поиск с панелью в потоке;
- Light and glow — «Include the device temperature…» строкой-тумблером;
роль — сегмент [Auto | Always | Never] с подсказкой результата Auto;
Leading light entity по условиям; блок свечения (.hpf-block): подзаголовок
с «?», сегмент [From source | Set colour | Colour and brightness] с
отключёнными вариантами и aria-describedby на объяснение, плашка цвета
вокруг прежнего hp-color-opacity (Q5), яркость и радиус строками с
числом и единицей, при Never блок неактивен целиком (aria-disabled) с
callout'ом причины;
- Appearance — поле иконки с превью, очисткой и ссылкой Pin в подсказке;
Display селектом с подсказкой режима; пульс — плашка цвета и строка
размера; Value source по условиям; подраздел Value badge — компактный
тумблер, Value селектом с техническим идентификатором, Position сегментом
[Above | Right | Below | Left]; предупреждения бейджа — заметки и
callout'ы; Display preview — прежний hp-device-preview целиком в блоке на
тинте с тегом Now (решение владельца Q3); «Icon size and rotation» —
две строки range-line в сетке;
- Details — Model и Link в ряд, Description textarea набора, Manuals чипами
и строкой действий Attach…, «Additional actions» подзаголовком набора.
Футер: Hide и Delete слева, статус, Cancel и Save справа. К10: снимок
черновика при _openMarkerDialog (marker-form-state.ts поверх
dialog-baseline; транзиентные ключи — раскрытие и фильтры списков, busy,
объявление подсказки, autoIcon, uploadId); в edit Save только при
изменениях, закрытие с изменениями спрашивает через _confirmDanger. Прежние
запреты Save (busy, калибровка радара, привязка не выбрана/не подтверждена)
остались; привязка и радиус свечения названы словами под полем
(marker.error_binding, marker.error_glow_radius), «Review N fields» ведёт к
полю. Тумблеры диалога — строки набора (нативный чекбокс, К7), а не
ha-switch; слайдеры — прежний _rangeInput (ha-slider в HA).
Набор: sourcePicker получил toolbar и disabled; сегмент — value у радио,
disabled и describedBy у варианта; callout — role note и id; unitInput —
describedBy; rangeLine — id; новые классы .hpf-block/.hpf-disabled,
.hpf-toolbar/.hpf-check, .hpf-iconfield/.hpf-iconpreview, .hpf-mono,
.hpf-note, .hpf-hint-line, textarea.hpf-input. settingsCopy вынесен в
editors/settings-copy.ts (общий для пространства, комнаты, устройства).
Смоки переписаны осознанно, с пометкой #600: binding_ui (#marker-binding,
.hpf-panel, #marker-show-entities), tap_run (панель набора, #marker-tap-
confirm), value_face_source (.hpf-cand.sel), static_icon (callout'ы),
climate_temp (#marker-use-climate-temp), help_affordance (#marker-name,
.hpf-block.hpf-disabled вместо fieldset[disabled]; второй Escape в грязном
диалоге спрашивает — К10), size_angle_parity (сетка Appearance),
color_picker_consumers (подписи полей), device_preview_parity (сегмент
стороны), ha_controls (тумблеры набора — нативные чекбоксы по К7, ha-slider
прежний). Golden-harness device — .hpf-field/.hpf-block, скроллер .content.
Новый фокусный свидетель demo/smoke_device_settings_form.mjs: пять карточек
без старой разметки, оболочка, привязка/панель/Show entities, Q8, сегменты и
блок свечения, плашки, иконка, бейдж, превью на тинте, размеры, Details,
цели 44, Save/dirty/вопрос при закрытии, create-режим, семь полос экранов.
Мутанты: marker-save-enabled-without-changes, marker-discard-without-asking,
marker-confirm-row-shown-for-do-nothing, marker-never-keeps-glow-block-live,
marker-badge-position-forgets-touch; якоря same-binding-click-resets-source,
state-callout-hidden-under-help, form-kit-segment-drops-radio-semantics
переставлены на новую разметку.
Контрактные тесты: color-picker (два поля набора вместо flex-строк),
native-select-contract (сторона бейджа — сегмент), i18n dead-keys (34 → 38
подсказок), German=English (marker.name_label). Словарь i18n/settings: 21
ключ marker.* на четыре локали; в основном каталоге marker.name_label
«Name», marker.size_label «Icon size and rotation», удалены мёртвые
marker.room_override, marker.light_role_always/never. Фикстуры листа
диалогов набора пересняты намеренно (панель — байт в байт, AC11).
Бюджет: стартовый граф 290 489 (потолок 291 600 без изменений); ленивый
редакторский 243 173 — потолок 240 100 → 243 900 с разбором в
bundle-budget.mjs; старые стили диалога устройства снимаются в финале.
Гейты: typecheck, build, bundle:sync (три копии байт в байт), npm test
2790+ pass по четырём частям, mutation-gate --check, 39 смоков диалога
устройства + новый + три формы серий 1–3.
Issue: #600
User-Visible: no
§6 SPEC.md референса. Четыре карточки #594 остались, менялось содержимое:
- Basics — Display name и Home Assistant area в одну строку из двух полей
(#room-name, #room-area — контролы набора); подстановка имени из зоны при
пустом имени прежняя;
- Fill — «Как у пространства» стала строкой-тумблером (#room-fill-inherit,
решение владельца Q4): включена — подсказка «Следует за пространством:
режим»; выключена — сегмент из пяти режимов, который стартует с
действующего режима пространства, а не с «None». «Свой цвет» — плашка
вокруг прежнего hp-color-opacity (Q5): свотч, hex, число прозрачности,
Reset у своего цвета. Границы комфорта при эффективной «Температуре» —
два поля с единицей °C (#room-temp-min/-max) с плейсхолдерами границ
пространства, легендой Cold / Comfort / Hot, ошибкой под полями и ссылкой
«Как у пространства». Модуль room-temperature-controls.ts удалён — его
разметку заменили поля набора;
- Sensor sources — подзаголовки, прежний сегмент «среднее / конкретный», при
конкретном — кнопка выбора в стиле селекта и панель с поиском в потоке
карточки (sourcePicker набора, роль listbox/option; общая с диалогом
устройства в серии 4). Кандидаты и запись прежние;
- Font sizes — две строки «слайдер + число % + Reset to 100%» с концами шкалы,
подсказка про размер карточек пространства, образец карточки сохранён
внутри .hpf-tint (решение владельца Q2).
Футер: Cancel | статус | Save; в create — Keep as walls слева. К10: снимок
черновика при _openRoomEdit (room-form-state.ts поверх dialog-baseline),
в edit Save только при изменениях, закрытие с изменениями спрашивает через
_confirmDanger; в create Save по прежнему условию (имя или зона), отмена без
вопроса — она и раньше значила «не создавать» и возвращала контур на план.
Ошибки черновика: имя (edit) / имя-или-зона (create), нечисло в границах —
подпись под полем, «Review N fields» в футере ведёт к первому полю.
Из eager-листа dialogs.styles.ts удалены .roomtemprange*, .roomdialog .srcrow
и .dropbtn; `overflow-x: hidden` у .body убран — скроллер один (К3).
Смоки переписаны осознанно, с пометкой #600: smoke_room_settings (тумблер
вместо радио, #room-name/#room-area, .hpf-panel .hpf-cand, старт сегмента с
режима пространства), smoke_room_temperature_thresholds (.hpf-temprange,
ссылка сброса). Golden-harness room-temperature — те же селекторы. Новый
фокусный свидетель demo/smoke_room_settings_form.mjs: четыре карточки без
старой разметки, имя и зона в одну строку, оболочка 560 и один скроллер,
тумблер/сегмент/плашка/границы/источники/размеры пишут в свои ключи, Save и
вопрос при закрытии, create-режим, семь полос экранов.
Мутанты: room-save-enabled-without-changes, room-discard-without-asking,
room-fill-segment-starts-at-none, room-temp-min-writes-max. Якорь
form-kit-writes-to-a-neighbour-key прежний. smoke-links: символ
roomTemperatureControls заменён на renderRoomSettingsDialog.
Словарь i18n/settings: девять ключей room.* на четыре локали; в основном
каталоге room.area_label без «(unassigned)». Фикстуры листа диалогов набора
пересняты намеренно (панель — байт в байт, AC11).
Бюджет: стартовый граф 290 575 — потолок ОПУЩЕН 292 200 → 291 600 (ушли CSS
диалога комнаты и модуль границ); ленивый редакторский 239 391 — потолок
238 600 → 240 100 с разбором в bundle-budget.mjs.
Гейты: typecheck, build, bundle:sync (три копии байт в байт), npm test
2790+ pass по четырём частям, mutation-gate --check, смоки: room_settings,
room_settings_form, room_temperature_thresholds, editor_tabs, font_scales,
resize_labels, room_autoclose, binding_ui, color_picker_consumers,
lazy_editor_chunk, space_settings_form, general_settings_form, ux_fixes,
settings_dialog_cards, dialog_footer_width.
Issue: #600
User-Visible: no
§5 SPEC.md референса. Семь карточек #598 остались, менялось содержимое:
- Display — две полные строки с иконкой, подписью и тумблером справа; пояснение
радара по §5.2 стало подписью строки (текст прежний, ключ переехал в ленивый
словарь как gs.radar_show_live_hint, «?» у строки больше нет);
- Zigbee links — заголовок и «?» функции (topology.help) рисует карточка, а
блок hp-zigbee-topology-settings получил режим embedded: строка-тумблер,
callout «сохраните настройку», подзаголовки ZHA / Zigbee2MQTT, поле тем и
строки действий контролами набора. Заголовок больше не удваивается
(дефект 1). Лист набора вносится в теневой корень компонента; токены
--hpf-* наследуются с хоста. Прежний render без embedded не тронут — его
держит контракт #459;
- Room fill colors — три подзаголовка (Lights / Temperature / Zigbee signal,
Q6) и плитки цвета по три в ряд: название на свотче, hex, число
прозрачности; свотч — trigger прежнего hp-color-opacity (Q5);
- Light-source glow — две плитки и поле радиуса с единицей внутри рамки;
- Plan — плашка цвета стен, сегмент фона, при Static — плашка фона с Reset и
подсказкой (тема / свой цвет);
- Sun — gs.sun_missing остаётся callout'ом (К5); север: поле градусов с «°»,
ссылка Clear, «N» и компас 44 px справа — индикатор набора, но тянуть его
по-прежнему можно (smoke_sun гоняет настоящий drag; старый 120-px SVG и его
CSS в plan.styles.ts удалены); лучи — строка-тумблер с подписью; источник
лучей — сегмент (sun-settings-view.ts переписан с <select> на segmented,
логика та же);
- Data — подзаголовки с «?» и строки действий набора.
К10 (Q1): Save только при изменениях и без ошибок (радиус > 0, север 0–359),
статус в футере, вопрос при закрытии с изменениями; снимок при открытии —
editors/general-form-state.ts поверх общего editors/dialog-baseline.ts (на него
же переведён space-form-state.ts). _settingsDialog не получил новых ключей.
Удалено мёртвое: _renderColorRow (рантайм и карточка), .sunrow/.suncol,
ключи gs.wall_group, gs.bg_group, gs.bg_theme, gs.radar_show_live.help(.aria)
в четырёх локалях. Девять новых ключей — в i18n/settings.
Смоки переписаны осознанно, с пометкой #600: smoke_general_settings (инвентарь
по классам набора, подзаголовки .hpf-sub h4, пояснения под «?» и подписью,
ни одного .rhint), smoke_sun (сегмент источника лучей вместо select, поле
#gs-north, radius drag 18 px), smoke_backup_transfer (подзаголовок и строка
действий), smoke_settings_dialog_cards (callout вместо .rhint). Новый фокусный
свидетель demo/smoke_general_settings_form.mjs: семь карточек и отсутствие
старой разметки, один заголовок у Zigbee, десять плиток, компас 44, цели 44,
запись плиток/плашки/радиуса/севера/сегментов в свои ключи, Save/dirty/вопрос
при закрытии.
Мутанты: general-save-enabled-without-changes,
general-tile-opacity-writes-a-neighbour-key, general-north-clear-writes-zero,
topology-embedded-draws-its-own-heading; якоря state-callout-hidden-under-help
и dialog-card-loses-its-heading переставлены на новую разметку.
Контрактные тесты: houseplan-source.mjs приводит `host.` к `this.` и в телах
вынесенных диалогов; color-picker — три явных showOpacity=true (плитки, плашка
стены, цвет комнаты); счётчик производных .aria 35 → 34.
Бюджет: стартовый граф 290 711 — потолок ОПУЩЕН 292 500 → 292 200 (ушёл
120-px компас из eager-листа и мёртвые ключи); ленивый редакторский 237 929 —
потолок 236 300 → 238 600 с разбором в bundle-budget.mjs.
Гейты: typecheck, build, bundle:sync, npm test 2792 pass, mutation-gate
--check, семь смоков «Общих», smoke_color_picker_consumers без правок.
Issue: #600
User-Visible: no
§4 SPEC.md референса, четыре карточки: Basics (имя и масштаб в сетке 1fr/175,
подложка двумя choice-карточками, callout о пересчёте масштаба), Appearance
(строка-тумблер границ с иконкой и подписью, сегмент стиля стен с образцами
линии, плашка цвета с hex/прозрачностью/Reset, сегмент заливки с деталями
режима, компактный список «Видимые слои» с логикой «включено = видно» — К2),
Room cards (строка-тумблер названий, четыре плитки значений с отключением и
callout-ссылкой, слайдер размера с числом, концами и «Сбросить до 100%», образец
карточки внутри блока на тинте — Q2), Sun & light (сегмент фона, плашка цвета
фона, радио «свет через окна» в строку, север селектом с компасом 44 px и полем
градусов, строка-тумблер свечения).
Одна форма на два рантайма. `renderSpaceForm` в `editors/space-form.ts`
собирает тело и футер; редакторский вход (`space-settings-dialog.ts`) и
онбординг подают порт с тем, что у них различается, и сами рисуют
`<hp-dialog data-kind=…>` — контракт #489 требует литеральный kind. Копия
разметки онбординга на 300 строк удалена; локальные дубли CELL_CM_* и
strictNumber там же — тоже («одно число — один источник»).
К10 (решение владельца Q1): Save активен только при изменениях и без ошибок,
в футере «Есть несохранённые изменения» либо ссылка «Проверьте поля: N» к
первому ошибочному; «✕», Cancel и Escape с изменениями спрашивают через
`_confirmDanger`, без изменений закрывают сразу. Снимок делается при открытии
(`editors/space-form-state.ts`, WeakMap по хосту) — `SpaceDialogState` не
получил ни одного ключа. Валидация: имя, подложка без изображения, диапазон
температур, север 0–359 — с `aria-invalid` и текстом под полем.
Строки. 51 новый ключ живёт в ленивом словаре `i18n/settings` (приём
#423/#459), не в первом кадре: стартовый граф 291 260 при потолке 292 500.
Отдельный словарь, а не `support`, — иначе онбординг тянул бы весь словарь
редактора ради одной формы. 11 существующих ключей переименованы по Q6
(«Space name», «Appearance», «Room cards», «Draw it myself», «Zigbee signal
next to devices»…), 9 мёртвых удалены из четырёх локалей. `hp-color-opacity`
получил `hide-label`: подпись рисует плашка, `label` остаётся для title/aria и
`smoke_color_picker_consumers` проходит без правок (AC5).
Смоки. Переписаны осознанно (К6 снят), каждый — с пометкой #600 у правки:
smoke_hide_layers (компактные строки, инверсия К2 проверяется кликом),
smoke_ux_fixes (сегмент, строка-тумблер, поля °C, ширина 560 — Q7),
smoke_dialog_footer_width (560 для form-shell), smoke_temp_fill (два поля по
id), smoke_settings_dialog_cards (три сегмента), smoke_space_settings и
smoke_space_create_display_defaults и smoke_lazy_editor_chunk (choice-карточка
по смыслу, не по индексу — порядок §4.2 draw → file), smoke_space_scale_defaults
(поле с единицей). Новый фокусный свидетель demo/smoke_space_settings_form.mjs:
состав карточек и отсутствие старой разметки, оболочка 560 и один скроллер,
цели 44, запись каждого нового контрола в свой ключ, Save/dirty/вопрос при
закрытии, семь контрольных ширин (320…1920).
Мутанты: space-fill-segment-writes-a-neighbour-key,
space-save-enabled-without-changes, space-discard-without-asking,
space-layer-toggle-loses-inversion.
Контрактные тесты: `houseplan-source.mjs` дописывает общие модули диалогов к
логическому исходнику; коллектор i18n видит `help(...)` порта и `shelp(...)`
(заодно встал на учёт `radar.help`, проходивший мимо счётчика — 30 → 35).
Потолок ленивого редакторского графа 225 900 → 236 300 (замер 235 560) с
разбором в bundle-budget.mjs: словарь на четыре локали и подписи — большая
часть роста; промежуточно, итог в конце серий.
Гейты: typecheck, build, bundle:sync, npm test 2792 pass (красным был только
потолок — поднят с доводом), 10 смоков пространства зелёные,
smoke_color_picker_consumers без правок, mutation-gate --check.
Issue: #600
User-Visible: no
Съёмка — Linux CI, Validate 35454723038 на acf179e4; приёмка — Windows
владельца с HP_ALLOW_FOREIGN_CAPTURE (#455).
Объявлены ровно одиннадцать сцен AC8; необъявленных расхождений нет —
иначе accept.mjs отказал бы до записи.
Issue: #598
User-Visible: no
Release: v1.77.0-beta.1
Baseline-Reviewed: https://github.com/Matysh/houseplan-card/actions/runs/35454723038