mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-29 03:09:36 +00:00
docs: #44 spec revision 3 per SPEC-REVIEW-44-r1
User-Visible: no Issue: #44
This commit is contained in:
@@ -3,8 +3,8 @@
|
||||
- Issue: https://github.com/Matysh/houseplan-card/issues/44
|
||||
- Приоритет: P2, tech-debt; полный трек (discovery/UI/settings/i18n/tests —
|
||||
решение аналитики 2026-08-15)
|
||||
- Ревизия: 2 (2026-08-30) — policy v1 принята владельцем (вход в работу без
|
||||
возражений к записанной политике); конкретизация под инбокс v1.69
|
||||
- Ревизия: 3 (2026-08-30) — по SPEC-REVIEW-44-r1 (H1, H2); policy v1 принята
|
||||
владельцем, конкретизация под инбокс v1.69
|
||||
- Связано: device inbox #29, field registry/манифест #33 (паспорта
|
||||
`allow-extra` обоих ключей уже выданы), персист-паттерн #377
|
||||
|
||||
@@ -20,10 +20,11 @@
|
||||
|
||||
## Что человек увидит до и после
|
||||
|
||||
**До**: группировка света и исключение интеграций происходят молча; понять
|
||||
«почему этого устройства нет в списке» нельзя. **После**: обе настройки видны
|
||||
и объяснимы; у кандидата, скрытого фильтром, в инбоксе появляется причина
|
||||
«Исключена интеграция X»; ничего не меняется само — только по Сохранить.
|
||||
**До**: группировка света и исключение интеграций происходят молча; причина
|
||||
`excluded_integration` в инбоксе уже существует (#29), но безлична
|
||||
(«Интеграция исключена фильтрами»). **После**: обе настройки видны и
|
||||
управляемы; текст причины называет интеграцию по имени («Исключена
|
||||
интеграция {integration}»); ничего не меняется само — только по Сохранить.
|
||||
|
||||
## Проблема
|
||||
|
||||
@@ -66,13 +67,15 @@ discovery `devices.ts:1491`).
|
||||
Отмена — no-op. Undo — штатный именованный снапшот конфига (паттерн
|
||||
существующих правок настроек).
|
||||
|
||||
### 2. Причина «Исключена интеграция X» в инбоксе
|
||||
### 2. Причина с именем интеграции (H1 r1: факт исправлен)
|
||||
|
||||
Кандидат, отфильтрованный исключением, при показе на вкладке «Скрытые»
|
||||
несёт `DeviceInboxReason` нового значения `excluded_integration` с текстом
|
||||
«Исключена интеграция {integration}». (Сегодня такие устройства не попадают
|
||||
в инбокс вовсе — они появляются на «Скрытых» именно с этой причиной;
|
||||
объём выдачи ограничен существующей механикой вкладки.)
|
||||
Причина `excluded_integration` УЖЕ существует и рендерится на вкладке
|
||||
«Доступны» (#29, `houseplan-editor-runtime.ts:7637`,
|
||||
`device_inbox.reason_excluded_integration`) — но текст обобщённый. Скоуп
|
||||
этой задачи: тексту добавляется плейсхолдер `{integration}` с фактическим
|
||||
platform-именем кандидата; вкладка НЕ меняется (перенос категории — отдельный
|
||||
продуктовый вопрос, здесь не открывается). Значение reason и его механика не
|
||||
трогаются.
|
||||
|
||||
### 3. Registry/доки
|
||||
|
||||
@@ -93,6 +96,13 @@ discovery `devices.ts:1491`).
|
||||
|
||||
1. Конфиг без ключей → поведение байт-в-байт сегодняшнее (default-путь не
|
||||
меняется ни в одном потребителе).
|
||||
1a. (H2 r1) `roomClimateMap` (`devices.ts:1491`) — единственное место в
|
||||
`src/**`, хардкодящее `EXCLUDED_DOMAINS` мимо настройки, — переводится на
|
||||
тот же резолвер действующего набора исключений, что и discovery: климат
|
||||
комнаты следует за настройкой пользователя, а не за старым жёстким
|
||||
списком (иначе UI создаёт новый «третий вариант»). Явный climate-opt-in
|
||||
(галочка «этот датчик меряет воздух комнаты») по-прежнему сильнее
|
||||
исключения — существующая ветка `optClimate` не меняется.
|
||||
2. Explicit-маркер (живой или tombstone) НИКОГДА не исчезает из-за смены
|
||||
фильтров — фильтры влияют только на автоматических кандидатов и seed.
|
||||
3. Оба значения читаются из одного источника (`_settings`) всеми
|
||||
@@ -125,8 +135,13 @@ issue требует видимости и policy, не пере-схемиза
|
||||
список; «Вернуть рекомендуемые» + Сохранить → ключа нет.
|
||||
- **AC3** (смок): у явного маркера с binding исключённой интеграции ничего
|
||||
не меняется (живой остаётся на плане, tombstone не трогается).
|
||||
- **AC4** (смок): скрытый фильтром кандидат виден на «Скрытых» с причиной
|
||||
«Исключена интеграция X».
|
||||
- **AC4** (смок): кандидат исключённой интеграции виден на «Доступны» с
|
||||
причиной, называющей интеграцию по имени («Исключена интеграция demo_x»);
|
||||
вкладка и значение reason прежние (регресс-ветка).
|
||||
- **AC4b** (юнит, H2): `roomClimateMap` с настроенным `exclude_integrations`
|
||||
фильтрует по НЕМУ (интеграция вне списка даёт климат; продуктовая, вручную
|
||||
включённая в список — не даёт); без ключа — байт-в-байт сегодняшний
|
||||
результат; явный climate-opt-in побеждает исключение (регресс-ветка).
|
||||
- **AC5** (юнит): резолвер действующего набора: unset→продуктовый список,
|
||||
[]→пусто (валидная «ничего не исключать»), список→список; тумблер:
|
||||
unset→true.
|
||||
@@ -139,8 +154,8 @@ issue требует видимости и policy, не пере-схемиза
|
||||
|
||||
## План автотестов
|
||||
|
||||
- Юниты: резолверы (AC5), превью-контракт (AC6), регресс дефолта (AC7) —
|
||||
test/devices.test.mjs + test/device-inbox.test.mjs.
|
||||
- Юниты: резолверы (AC5), превью-контракт (AC6), регресс дефолта (AC7),
|
||||
климат-фильтр (AC4b) — test/devices.test.mjs + test/device-inbox.test.mjs.
|
||||
- Смок `demo/smoke_discovery_filters.mjs` (новый): AC1–AC4 на демо-стенде
|
||||
с моковым config/set (паттерн #377-смока).
|
||||
- Мутанты: м1 — превью-счётчики от копии логики (подмена вызова общего
|
||||
@@ -155,6 +170,9 @@ issue требует видимости и policy, не пере-схемиза
|
||||
- Реason-вкладка «Скрытые» получает новый класс записей — объём ограничен
|
||||
существующим механизмом вкладки; смок проверяет отсутствие дублей.
|
||||
- Гонка вкладок — штатный conflict #340.
|
||||
- Перевод roomClimateMap на резолвер (H2) меняет климат ТОЛЬКО при заданном
|
||||
пользователем ключе — default-путь передаёт тот же продуктовый список
|
||||
(AC4b регресс-ветка + существующие климат-юниты #317 не слабеют).
|
||||
|
||||
## Откат
|
||||
|
||||
|
||||
Reference in New Issue
Block a user