mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
256 lines
20 KiB
Markdown
256 lines
20 KiB
Markdown
# Issue #203 — выключение названий скрывает все подписи комнат
|
||
|
||
- Дата: 2026-08-19
|
||
- Тип: bug · приоритет P2 · ценность 7/10 · сложность 3/10
|
||
- Issue: [#203](https://github.com/Matysh/houseplan-card/issues/203)
|
||
- Ветка: `issue/203-hide-room-names`
|
||
|
||
Канонические документы: `docs/SCOPE.md`, `docs/UX-MODES.md`,
|
||
`docs/STYLING-HOOKS.md`, `docs/USER-GUIDE.ru.md`, `docs/TESTING.md`.
|
||
|
||
## 1. Сценарий и персона
|
||
|
||
Администратор дома открывает настройки пространства, выключает «Отображать
|
||
названия комнат (перетаскиваются)» и сохраняет. Он ожидает чистый View без
|
||
постоянных подписей, например для маленького экрана, фонового чертежа с уже
|
||
нанесёнными названиями или плана, где достаточно интерактивных устройств.
|
||
|
||
Это штатная часть J4/J6: явно выключенный визуальный слой должен исчезнуть на
|
||
всех пользовательских представлениях одного пространства.
|
||
|
||
## 2. Что человек увидит до и после
|
||
|
||
**До:** draggable HTML-карточка исчезает вместе с температурой, влажностью,
|
||
LQI и состоянием света, но на нарисованном плане без фонового изображения
|
||
возникает другая SVG-подпись. Имя остаётся, перемещается в геометрический центр
|
||
комнаты и меняет стиль. Компактная карточка пространства повторяет дефект.
|
||
|
||
**После:** при выключенной настройке в View, Devices editor и компактной
|
||
карточке нет постоянной подписи комнаты ни в HTML, ни в SVG. В Plan editor имя
|
||
по-прежнему временно показывается как редактируемый объект. При повторном
|
||
включении возвращается прежняя draggable карточка с сохранённой позицией,
|
||
масштабом, HA Area icon и разрешёнными метриками.
|
||
|
||
## 3. Подтверждённая проблема и причина
|
||
|
||
Persisted значение и основной resolver исправны:
|
||
|
||
- `spaceDisplayOf()` возвращает `showNames: false` для явного
|
||
`settings.show_names: false`;
|
||
- `_saveSpaceDialog()` записывает `show_names: d.showNames` для существующего
|
||
пространства;
|
||
- основной `.devlayer` перестаёт рендерить `_renderRoomLabel()`, поэтому
|
||
HTML-карточка и её `.rlmetrics` действительно исчезают.
|
||
|
||
Ошибка находится в двух fallback-ветках. `_renderSvgRoomLabels()` полного
|
||
renderer при `!space.bg && !disp.showNames` создаёт `<text class="rlabel">`.
|
||
`renderSpaceCard()` независимо делает то же через `staticSvgLabels`. Они
|
||
инвертируют смысл настройки. Скрытая изометрическая ветка дополнительно
|
||
форсирует HTML-карточки при `iso && !space.bg`, даже если `showNames === false`.
|
||
|
||
Именно смена HTML-карточки на SVG-текст объясняет все детали репорта: имя
|
||
остаётся, метрики пропадают, сохранённая layout-позиция не используется, цвет и
|
||
типографика становятся другими. На пространстве с `bg` дефект маскируется,
|
||
потому что SVG-fallback уже запрещён условием `space.bg`.
|
||
|
||
## 4. Scope
|
||
|
||
- сделать `show_names: false` единым запретом постоянных room-labels в полном
|
||
flat/iso View, Devices editor и компактной карточке пространства;
|
||
- сохранить принудительную видимость редактируемой HTML-подписи в Plan editor;
|
||
- сохранить live-preview значения в открытом диалоге настроек пространства;
|
||
- при `show_names: true` не менять состав, позицию, масштаб, цвет, метрики,
|
||
HA Area icon, drag/resize и навигацию комнатной карточки;
|
||
- удалить или обезвредить ошибочные SVG-fallback renderer и актуализировать
|
||
больше не существующий `.rlabel` styling-hook;
|
||
- добавить browser regression, mutation gate, визуальное доказательство и
|
||
пользовательскую/тестовую документацию.
|
||
|
||
## 5. Non-scope
|
||
|
||
- изменение текста/назначения переключателя или добавление второго режима
|
||
«статические названия»;
|
||
- скрытие названия комнаты внутри tooltip, диалога настроек, HA Area или
|
||
accessibility-описания самой комнаты: настройка управляет подписями на плане;
|
||
- удаление либо сброс `layout.rl_<roomId>`, масштаба подписи или room metrics;
|
||
- изменение `show_borders`, room fill, Glow, openings, devices и room hover;
|
||
- изменение дефолта `show_names` для новых/legacy пространств — это отдельная
|
||
проблема #204;
|
||
- schema/backend/API, migration, импорт/экспорт и Optimize;
|
||
- публичное включение изометрии или изменение её геометрии;
|
||
- редизайн комнатной карточки, Plan gear/handles или compact space card.
|
||
|
||
## 6. Контракт поведения
|
||
|
||
### 6.1. Матрица видимости
|
||
|
||
| Поверхность | `show_names: true` | `show_names: false` |
|
||
|---|---|---|
|
||
| Full View, flat | Одна HTML `.roomlabel` на именованную комнату | Нет HTML/SVG room-label |
|
||
| Full View, hidden iso | Та же HTML `.roomlabel`, спроецированная существующей iso-логикой | Нет HTML/SVG room-label |
|
||
| Devices editor | Одна HTML `.roomlabel` | Нет HTML/SVG room-label |
|
||
| Plan editor | Одна редактируемая HTML `.roomlabel` | Та же editor-only `.roomlabel` |
|
||
| Compact space card | Одна HTML `.roomlabel` | Нет HTML/SVG room-label |
|
||
|
||
Условие `!space.bg` больше не создаёт альтернативный способ показать имя.
|
||
Наличие или отсутствие фонового изображения не влияет на матрицу.
|
||
|
||
### 6.2. Повторное включение
|
||
|
||
Выключение не удаляет `layout.rl_<roomId>` и room settings. После повторного
|
||
включения карточка возвращается в сохранённую позицию и с сохранёнными
|
||
`k/name_scale/label_scale`. Разрешённые `label_temp`, `label_hum`, `label_lqi`
|
||
и `label_light` снова отображаются по существующим правилам и данным.
|
||
|
||
### 6.3. Plan editor
|
||
|
||
Plan editor сохраняет исключение `_markup`: подпись нужна для drag, resize и
|
||
доступа к редактируемому имени. Это исключение не должно протекать в View после
|
||
выхода из редактора. Room gear и placeholder безымянной комнаты сохраняются.
|
||
|
||
### 6.4. Диалог настроек
|
||
|
||
При переключении `showNames` в edit-диалоге `_spaceDisplayForRender()` сразу
|
||
проецирует новое значение в затемнённый пользовательский View. Cancel возвращает
|
||
persisted значение, Save записывает boolean. Результат после повторного открытия
|
||
совпадает с сохранённым состоянием.
|
||
|
||
## 7. Данные, совместимость и styling hooks
|
||
|
||
Persisted-формат не меняется: `settings.show_names` уже валидируется и хранит
|
||
boolean. Миграция не нужна, конфигурация не переписывается при чтении.
|
||
|
||
`div.roomlabel[data-hp="room-label"]` остаётся каноническим hook видимой
|
||
подписи. `text.rlabel` существовал только в противоречащей настройке fallback-
|
||
ветке и после исправления не является доступным runtime hook; строка о нём в
|
||
`docs/STYLING-HOOKS.md` удаляется или заменяется честным описанием отсутствия
|
||
подписи. `data-hp`, `data-id` и `data-area` HTML-карточки не меняются.
|
||
|
||
Downgrade возвращает старый SVG-fallback, но не теряет данные. Пользовательский
|
||
CSS, намеренно показывавший `text.rlabel` при выключенных названиях, перестаёт
|
||
иметь target — это необходимое следствие исправления ложного поведения, а не
|
||
новая точка расширения.
|
||
|
||
## 8. UX, i18n, accessibility и touch
|
||
|
||
Новых строк и элементов управления нет. Существующий русский и английский
|
||
текст становится честным. Выключенная подпись не оставляет пустого DOM-узла,
|
||
focus target или невидимой pointer-зоны. Tooltip комнаты и room hover остаются
|
||
доступны по геометрии комнаты, поэтому получить сведения по комнате можно.
|
||
|
||
Touch/keyboard policy и события Plan editor не меняются. При включённых именах
|
||
существующие drag, resize handles, Area navigation и accessibility-описания
|
||
сохраняются.
|
||
|
||
## 9. Acceptance criteria и доказательства
|
||
|
||
| AC | Критерий | Обязательное доказательство |
|
||
|---|---|---|
|
||
| AC1 | На нарисованном пространстве без `bg`, при `show_names:false`, в flat View нет ни `.roomlabel`, ни `.room-svg-labels text`, ни `[data-hp="room-label"]`. | Targeted Playwright smoke через реальный space setting. |
|
||
| AC2 | AC1 выполняется в компактной карточке пространства. | Тот же smoke на `houseplan-space-card`. |
|
||
| AC3 | Hidden iso при `show_names:false` не форсирует подписи; при `true` сохраняет существующую projected HTML-карточку. | Расширенный isometric contract/live smoke + отдельный iso mutant. |
|
||
| AC4 | Plan editor показывает редактируемую подпись при `show_names:false`; после выхода View снова пуст. | Browser mode-transition smoke с DOM assertions. |
|
||
| AC5 | При `true` HTML-карточки, метрики, HA Area icon, сохранённая позиция/scale и текущие события не меняются. | Существующие room-card/link/parity smokes + focused regression. |
|
||
| AC6 | Toggle в edit-диалоге даёт live-preview, Save переживает повторное открытие, Cancel не пишет config. | Расширенный `smoke_space_settings.mjs` либо отдельный targeted smoke. |
|
||
| AC7 | `show_borders`, fills, Glow, devices, openings и room tooltip не меняются при выключении имён. | DOM snapshot/assertions targeted smoke + reviewed golden. |
|
||
| AC8 | Документация больше не обещает доступный `text.rlabel` hook и однозначно описывает переключатель. | Diff `STYLING-HOOKS`, user guide и `TESTING`. |
|
||
| AC9 | Ошибочный fallback доказан исполняемым мутантом. | `mutation-gate --check`, clean green / mutant red. |
|
||
| AC10 | Рабочие gates зелёные. | typecheck, unit, build и все затронутые targeted smokes. |
|
||
|
||
## 10. План автотестов
|
||
|
||
### 10.1. Unit/source contract
|
||
|
||
Новая pure-логика не требуется. Существующие unit `spaceDisplayOf` уже
|
||
доказывают чтение явного `false`. Если итоговая реализация вынесет общую функцию
|
||
матрицы видимости, добавить table-driven unit; иначе не дублировать Lit-template
|
||
в искусственном source test.
|
||
|
||
### 10.2. Browser smoke
|
||
|
||
Расширить `demo/smoke_space_settings.mjs` или создать небольшой именной smoke:
|
||
|
||
1. взять пространство без `plan_url/bg`, включить имена и зафиксировать одну
|
||
HTML-карточку с метрикой и сохранённой layout-позицией;
|
||
2. открыть edit-диалог и выключить имена, проверить live-preview;
|
||
3. Save и повторное открытие подтверждают `false` и отсутствие любых labels;
|
||
4. перейти в Plan — подпись и editor affordance видимы; вернуться в View —
|
||
снова скрыты;
|
||
5. повторить ключевую проверку в hidden iso и compact space card;
|
||
6. включить имена обратно и проверить восстановление карточки, позиции/scale и
|
||
метрики;
|
||
7. отдельно проверить Cancel и отсутствие `pageerror`/console error.
|
||
|
||
`demo/smoke_styling_hooks.mjs` меняет прежнее утверждение «SVG-label существует
|
||
при false» на честное отсутствие любого label; HTML hook при true остаётся.
|
||
Смежные `smoke_room_cards.mjs`, `smoke_room_link.mjs`, room-label parity и iso
|
||
smokes прогоняются до code review.
|
||
|
||
### 10.3. Golden и mutation gate
|
||
|
||
Добавить/переиспользовать focused light/dark golden для нарисованного
|
||
пространства: reviewed baseline при `false` не содержит имён, при `true`
|
||
содержит существующие HTML-карточки. Общий `golden:verify` и полный smoke идут
|
||
перед бетой, но затронутые focused кадры обязательны при реализации.
|
||
|
||
Mutation gate обязан независимо защищать все три места исходного дефекта:
|
||
|
||
| Mutant id | Обязательная поломка | Guard |
|
||
|---|---|---|
|
||
| `hidden-room-names-full-svg-fallback` | Вернуть SVG-fallback `_renderSvgRoomLabels()` полного flat renderer при `show_names:false`. | Targeted full-card smoke из AC1 обязан завершиться non-zero. |
|
||
| `hidden-room-names-compact-svg-fallback` | Вернуть `staticSvgLabels` компактной карточки при `show_names:false`. | Targeted compact-card smoke из AC2 обязан завершиться non-zero. |
|
||
| `hidden-room-names-iso-override` | Вернуть независимый `iso && !space.bg` override, который форсирует HTML `.roomlabel` вопреки `show_names:false`. | Isometric contract/live smoke из AC3 обязан завершиться non-zero. |
|
||
|
||
Все три entries регистрируются в `scripts/mutation-gate.mjs`; каждый якорь
|
||
встречается ровно один раз. На чистом коде все guards зелёные, на каждом мутанте
|
||
соответствующий guard красный. Объединять full/compact/iso в один мутант нельзя:
|
||
иначе исправленная ветка может маскировать непроверенную соседнюю.
|
||
|
||
## 11. Риски и меры
|
||
|
||
| Риск | Мера |
|
||
|---|---|
|
||
| Скрытие протечёт в Plan и лишит пользователя редактируемого имени. | Отдельная строка матрицы, AC4 и реальный переход режимов. |
|
||
| Исправится full card, но останется compact или iso override. | Независимые AC2/AC3 и mutants по renderer. |
|
||
| Повторное включение сбросит позицию/scale/metrics. | Запрет записи layout и round-trip AC5/AC6. |
|
||
| Вместе с label исчезнет tooltip/room pointer geometry. | Label DOM меняется отдельно от room shape; AC7. |
|
||
| Удалится документированный styling hook без объяснения. | Актуализация `STYLING-HOOKS` и compatibility note §7. |
|
||
|
||
Performance улучшается либо нейтрален: удаляются DOM/SVG nodes и map по комнатам
|
||
при выключенном слое, новых проходов/таймеров/network calls нет. Security/privacy
|
||
boundary не меняется; настройка не становится механизмом сокрытия данных.
|
||
|
||
## 12. Rollback
|
||
|
||
Frontend-изменение откатывается вместе с тестами и документацией одним
|
||
коммитом. Данные и schema не меняются. Откат возвращает только ошибочный
|
||
SVG-fallback/iso override и не требует восстановления config или layout.
|
||
|
||
## 13. Release-артефакты
|
||
|
||
- пользовательские записи в `docs/CHANGELOG.md` и `docs/CHANGELOG.ru.md` в
|
||
implementation-коммите с `User-Visible: yes`;
|
||
- обновления `docs/USER-GUIDE.ru.md`, `docs/STYLING-HOOKS.md` и
|
||
`docs/TESTING.md`;
|
||
- targeted full/compact/Plan/iso browser evidence, styling-hook regression и
|
||
executable mutation gate;
|
||
- focused reviewed light/dark golden и синхронные bundle snapshots;
|
||
- отдельные backend, schema, migration, performance и security artifacts не
|
||
нужны;
|
||
- полные golden/smoke/performance остаются предрелизным гейтом.
|
||
|
||
## 14. Принятые предположения
|
||
|
||
Принято предположительно, поменять свободно при ревью:
|
||
|
||
1. «Скрыть названия» управляет постоянными labels на плане, но не удаляет имя
|
||
из tooltip/диалогов и не является privacy-функцией.
|
||
2. Plan editor сохраняет текущую принудительную видимость независимо от
|
||
persisted `show_names`, потому что там имя является редактируемым объектом.
|
||
3. Hidden iso обязан соблюдать тот же user setting, несмотря на прежний
|
||
технический override `iso && !space.bg`.
|
||
4. Канонический styling hook видимой подписи — существующий HTML
|
||
`div.roomlabel`; отдельный статический режим и новый hook не добавляются.
|
||
5. Если удаление мёртвого `.rlabel` CSS увеличит визуальный diff только за счёт
|
||
отсутствующих nodes, это входит в задачу; прочая типографика не меняется.
|