Рисование прямой стены в несколько кликов оставляло по записи на каждый
отрезок. Швы невидимы, пока их не тронешь: выделение хватает кусок,
перетаскивание ломает стену пополам, толщина задаётся пофрагментно. У стен
комнат этого давно нет — `normalizeWallIntervals` схлопывает каждый сплошной
участок одной толщины. Независимые перегородки жили по другому правилу.
Новый чистый модуль `src/wall-merge.ts` даёт им то же правило:
- `mergeCollinearPartitions` сращивает соседей одинаковой толщины и
направления до неподвижной точки, но только там, где узел никому не нужен.
Узел остаётся, если в него приходит третья перегородка, стена комнаты
(стороной, а не только вершиной), колонна или конец сохранённого черновика.
- Направление выжившей записи канонизируется лексикографически: иначе одна и
та же физическая стена выходила то a→b, то b→a в зависимости от порядка
входа, и каждый host.t вдоль неё переворачивался вместе с ней.
- `applyOpeningMoves` переносит проёмы на выжившую запись: и авторитетный
`host`, и legacy-проекцию `x/y/angle`, которую рисует старый читатель
конфига (docs/CONFIG-COMPATIBILITY.md, #132). Проекция здесь не кэш —
канонизация направления разворачивает угол на 180°.
Рисование сращивает только свою цепочку и то, чего она коснулась (§8.6 ТЗ):
молча править чужие швы в стороне оно не вправе — для этого есть
«Оптимизировать планы» с предпросмотром, отчётом и отменой. Оптимизация
проходит по всему пространству без seed-ограничения и отдельной строкой
сообщает, сколько записей исчезло.
Issue: #229
User-Visible: yes
A fully fictional house (plans, devices, states) used for README screenshots,
the demo GIF and headless smoke tests — so no real home data ever appears in
public materials.
srv/demo.html — self-contained host page: <ha-icon>/<ha-card> stubs and a
fake hass (registries, states, callWS, callService, floors).
srv/assets/ — generated plan SVGs and icons.js (node demo/gen_icons.mjs,
needs the repo's devDependencies). The card bundle is copied from dist/:
cp dist/houseplan-card.js demo/srv/assets/.
serve.mjs — playwright launcher (route interception, no web server).
smoke_*.mjs — feature smoke tests; run with a Chromium installed via
PLAYWRIGHT_BROWSERS_PATH=<dir> npx playwright install chromium-headless-shell.
Note for sandboxed sessions: /tmp does not survive; this directory is the
persistent home of the harness (docs/DEVELOPMENT.md has the LD_LIBRARY_PATH recipe).