mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-30 19:58:50 +00:00
@@ -0,0 +1,117 @@
|
||||
# ТЗ #369 — Пачка Low аудита 29.08 (а–ж)
|
||||
|
||||
- Issue: https://github.com/Matysh/houseplan-card/issues/369
|
||||
- Приоритет: P3, polish; полный трек (семь несвязанных поверхностей — критерий
|
||||
«одна поверхность» §5 не выполняется, при том что каждая правка тривиальна)
|
||||
- Ревизия: 1 (2026-08-29)
|
||||
|
||||
## Сценарий
|
||||
|
||||
Семь мелких шероховатостей, найденных аудитом beta.2/beta.3 — каждая по
|
||||
отдельности не тянет на issue, вместе дают заметный полиш. Пользователь видит:
|
||||
честное предупреждение в логе вместо молча пропавшего следа пылесоса; климат
|
||||
в старых конфигурациях без HA Area; отсутствие «живых» маркеров у сознательно
|
||||
отключённых устройств; превью мебели, реагирующее на Shift мгновенно; никаких
|
||||
случайных установок мебели правой кнопкой. **До**: семь тихих странностей.
|
||||
**После**: каждая либо починена, либо честно задокументирована.
|
||||
|
||||
## Контракты по пунктам
|
||||
|
||||
**(а) Undelete пылесоса теряет след — документируется.** Поведение осознанное
|
||||
(#335: purge tombstone-трейлов на `config/set`), правится документацией:
|
||||
абзац в `docs/VACUUM.md` («удаление маркера пылесоса стирает его серверный
|
||||
след немедленно; восстановление маркера начинает след заново») + зеркальная
|
||||
строка в USER-GUIDE (en/ru) в теме пылесосов. Кода нет.
|
||||
|
||||
**(б) NaN-калибровка молча прячет след.** `smoothVacPath` (`src/vacuum.ts`)
|
||||
отбрасывает сегмент с нефинитной точкой без следа в консоли. Добавить
|
||||
`console.warn('[houseplan] vacuum trail segment dropped: non-finite point', …)`
|
||||
**однократно на вызов** (не на сегмент — файл может содержать сотни), с
|
||||
идентификацией количества отброшенных сегментов. Функция остаётся чистой по
|
||||
возврату; warn — единственный побочный эффект, отключаемый параметром
|
||||
`warn = console.warn` (юнит подменяет).
|
||||
|
||||
**(в) Легаси-маркер с `area === undefined` не получает климат #317.**
|
||||
`markerClimateTarget` (`src/devices.ts:1406`) проверяет `marker.area === null`;
|
||||
экспортные/легаси конфиги несут отсутствие ключа (undefined). Заменить на
|
||||
`marker.area == null` (ловит оба) — существующий кейс «маркер в Area» не
|
||||
задет (`marker.area` строка). Юнит: маркер `{space, room_id}` БЕЗ ключа area
|
||||
получает `roomClimateKey`, как и с явным `null`.
|
||||
|
||||
**(г) «Живой» маркер при полностью отключённых сущностях.** #318
|
||||
(`controllerAvailability`, `src/device-presentation.ts:213`) считает
|
||||
entityless-active устройство доступным. Уточнение: если у устройства В
|
||||
РЕЕСТРЕ есть собственные сущности, но все они отключены пользователем
|
||||
(`d.entities` пуст, а `d.bindingStatus.kind === 'ha_disabled'` ЛИБО
|
||||
`allEntityIds` непуст при пустом enabled-ростере) — это не «нет свидетельств
|
||||
offline», а «пользователь сознательно выключил»: возвращать текущее поведение
|
||||
ДО #318 (unavailable/приглушён). Истинно безростерные контроллеры (#318,
|
||||
реестр пуст) остаются available. Юнит рядом с тестами #318 на оба случая.
|
||||
|
||||
**(д) Превью мебели не реагирует на Shift без движения мыши.** Пока палитра
|
||||
мебели активна и превью видимо, runtime держит keydown/keyup-слушатели
|
||||
(`Shift`) на `window` (снятие — вместе с деактивацией инструмента/палитры и в
|
||||
`disconnected`-очистке жестов), обновляющие `free`-флаг превью и
|
||||
`requestUpdate`. Паритет с кликом сохраняется — клик уже читает
|
||||
`ev.shiftKey`.
|
||||
|
||||
**(е) Правый клик ставит мебель/декор.** В точке принятия placement-жеста
|
||||
(`_stagePointerDown` → decor/furniture ветки) добавить фильтр
|
||||
`ev.pointerType === 'mouse' && ev.button !== 0 → return` — правая/средняя
|
||||
кнопка не ставит объект. Touch/pen (`button` 0/-1) не задеты; контекстное
|
||||
меню браузера над стейджем ведёт себя как раньше.
|
||||
|
||||
**(ж) Имя правообладателя furniture-pack.** Решение владельца 2026-08-29:
|
||||
автор — **Sergey Matyunin / Сергей Матюнин**. Исправить
|
||||
`assets/furniture/houseplan-0.3.0/LICENSE.md`, `README.md` и `pack.json`
|
||||
(поле author) с «Sergey Matyushin» на «Sergey Matyunin». Root `LICENSE`
|
||||
(JB/justbusiness) не трогается.
|
||||
|
||||
## AC
|
||||
|
||||
1. (а) VACUUM.md + оба USER-GUIDE содержат абзац; check-docs зелёный.
|
||||
2. (б) юнит: путь с NaN-точкой — warn вызван ровно один раз с числом
|
||||
отброшенных сегментов; чистый путь — warn не вызван; возврат функции
|
||||
байт-в-байт как сейчас (существующие юниты без правок).
|
||||
3. (в) юнит: маркер без ключа `area` + `space`+`room_id` → room-ключ климата;
|
||||
с `area: 'kitchen'` → 'kitchen' (регресс-защита).
|
||||
4. (г) юниты: (i) устройство с пустым реестром + active → available (как
|
||||
#318); (ii) устройство с непустым `allEntityIds`/ha_disabled при пустом
|
||||
enabled-ростере → НЕ available. Существующие тесты #318 зелёные без правки.
|
||||
5. (д) смок: палитра мебели активна, превью видимо — нажатие Shift без
|
||||
движения мыши меняет `free`-флаг превью (и обратно на keyup); слушатели
|
||||
сняты после закрытия палитры (счётчик addEventListener/removeEventListener).
|
||||
6. (е) смок: right-button pointerdown по стейджу с armed-мебелью — объект НЕ
|
||||
поставлен; левый клик — поставлен (регресс).
|
||||
7. (ж) grep «Matyushin» по репо пуст; pack.json/LICENSE.md/README.md несут
|
||||
«Sergey Matyunin»; SHA-256 архива-источника в README не пересчитывается
|
||||
(архив не менялся — меняются только метаданные пака; расхождение имени с
|
||||
внутренностями архива оговаривается строкой в README).
|
||||
8. Мутанты: (б) warn выброшен → юнит красный; (в) `== null` → `=== null` →
|
||||
юнит красный; (г) уточнение снято → юнит красный; (е) фильтр кнопки снят →
|
||||
смок красный.
|
||||
|
||||
## Риски
|
||||
|
||||
- (г) меняет видимое поведение недавнего #318 — сужение честное (реестр
|
||||
непуст ⇒ свидетельство есть), но требует внимательного ревью формулировки
|
||||
условия; откат точечный.
|
||||
- (д) слушатели на window — риск утечки; лечится симметричным снятием и
|
||||
проверкой счётчиком в смоке.
|
||||
- Остальные пункты — точечные, риск минимальный.
|
||||
|
||||
## Release-артефакты
|
||||
|
||||
- CHANGELOG en+ru: одна запись пачкой (User-Visible: yes — пункты в, г, д, е).
|
||||
- Документация: VACUUM.md, USER-GUIDE en/ru (пункт а).
|
||||
- i18n: не требуется (новых строк UI нет).
|
||||
- golden/performance: не задеты (проверить прогоном обычного гейта).
|
||||
- security: не затрагивается; (ж) — правка метаданных лицензии.
|
||||
|
||||
## Вне скоупа
|
||||
|
||||
Изменение семантики purge (а) кодом; любые новые пороги/поведение trails.
|
||||
|
||||
## Откат
|
||||
|
||||
Один revert; конфиг/схема/контракты не меняются.
|
||||
Reference in New Issue
Block a user