fix(editor): preserve residual wall identity when creating room

Issue: #804
User-Visible: yes
This commit is contained in:
Matysh
2026-10-06 12:52:59 +03:00
parent de2029b7f9
commit b3f5aefa20
17 changed files with 845 additions and 26 deletions
+6
View File
@@ -272,6 +272,12 @@ revision. Model and lineage: [`WALL-THICKNESS.md`](WALL-THICKNESS.md) §1;
migrations and stale-client guard: [`CONFIG-COMPATIBILITY.md`](CONFIG-COMPATIBILITY.md)
(model v8–v10); rationale: [`adr/282-wall-geometry-representation.md`](adr/282-wall-geometry-representation.md).
Room-face acceptance uses `wall-face-lineage.ts` to choose provisional carriers
and settle only new-room hints against the partitions left after reconciliation
(#804). A residual keeps its identity without colliding with the promoted room
edge. The common model barrier, host validation and atomic history remain the
authorities; this helper neither allocates IDs nor writes configuration.
Rooms may not partially overlap (lying on a shared wall is legal, a fully nested
island is supported). Merge/Split use **polyclip-ts** (not `polygon-clipping`,
see [`DEVELOPMENT.md`](DEVELOPMENT.md)): Merge accepts a pair only when the union
+5
View File
@@ -2,6 +2,11 @@
## Unreleased
- Fixed creating a room from part of a longer independent wall failing with
conflicting wall identifiers. The outside wall pieces retain their geometry
and thickness; no redraw or Optimize workaround is needed
([#804](https://github.com/Matysh/houseplan-card/issues/804)).
## v1.80.0-beta.4 — 2026-10-05
- Zigbee links to another space now name the destination device too. Device
+5
View File
@@ -8,6 +8,11 @@
## Не выпущено
- Исправлен отказ создания комнаты на части длинной отдельной стены из-за
конфликта идентификаторов. Продолжения стены сохраняют геометрию и толщину;
обводить стену заново или запускать оптимизацию больше не требуется
([#804](https://github.com/Matysh/houseplan-card/issues/804)).
## v1.80.0-beta.4 — 2026-10-05
- Подписи Zigbee-связей в другое пространство теперь содержат имя устройства.
+10
View File
@@ -1,5 +1,15 @@
# Development and deployment
## Room-face lineage regression (#804)
`node demo/smoke_wall_face_lineage.mjs` exercises creation from a partial
independent wall using synthetic geometry, without a second exact-span carrier
over the room edge. Adding that duplicate carrier would hide the original bug.
Run against a fresh demo bundle; private runtime writes are not a test API.
Pure lineage cases and shared frontend/backend candidates cover retained IDs,
partial/full promotion and the unchanged partition-opening host restrictions.
Never add a user's complete exported home configuration to the test fixtures.
## Input support contract
Read `docs/TOUCH-SUPPORT.md` before changing interaction code.
+1
View File
@@ -31,6 +31,7 @@ Everything computable from the tree and git; regenerate, never edit by hand
| Branches | `main` carries stable releases only; pre-release tags point at `dev`. Work lands on `dev`, which is equal to or ahead of `main`, never behind. |
| Zigbee routes | #798 replaces inferred neighbour trees with integration-reported end-parent and active coordinator next-hop evidence. Unknown/conflicting routes are not guessed; stale/partial snapshots remain labelled. Solid arrows have a separate 0–255 palette; ordinary device LQI colours are unchanged. |
| Zigbee caption layout | #802 adds remote destination names and keeps the matching pointer tooltip clear of diagnostic text; only an unplaceable tooltip yields in a small card. Focus/touch/actions and provider transport remain unchanged. |
| Partial wall promotion | #804 settles new-room lineage after reconciliation: surviving independent wall pieces reserve their IDs, preventing the Garderoba duplicate-ID failure without changing geometry or relaxing opening-host validation. |
| Zigbee scan lifecycle | #800 replaces #799's 10-minute total budget with integration-owned background jobs: closing the browser does not stop waiting; after 10 minutes an exact-job cancel becomes available. MQTT setup/publish caps and the retained-info check remain bounded. Tests cover 15-minute success, cross-client restore, cancel races, stale-cache retention and reload on a live HA connection. |
| LED regression acceptance | #788 covers mixed face/free and fractional-coordinate joins, winding-safe field unions, retained endpoints/acute vertices and circle–wall transition events. The actual owner export is exercised locally; public fixtures are synthetic. Pixel oracles, not just SVG counts, protect the visible falloff. |
| LED core colour | #790 makes the on core follow the resolved light colour with or without Glow. Off, unavailable and non-live static strips keep their neutral presentation; geometry and field brightness are unchanged. |
+8
View File
@@ -47,6 +47,14 @@ room deletion, opening edits, Undo/Redo/recovery, Optimize and import/export
apply the same lineage and validation rules before one atomic persistence write.
Initial legacy IDs are deterministic, so frontend, backend and repeated
migrations converge; only genuinely new segments get UUIDs.
Room-face acceptance settles its provisional partition lineage after coincident
carriers have been reconciled (#804). A surviving partition or residual reserves
its ID: only new room-edge hints that still claim that ID are cleared, preserving
their slots. The common model barrier allocates new room-wall IDs; fully consumed
carriers retain their usual promotion lineage. Existing room IDs and the global
duplicate-ID guard are not relaxed. Ordinary config writes still reject changes
to the kind or ID of a surviving partition-opening host; the narrowly proved
Optimize rehost capability is not granted to room creation.
`src/wall-segment-model.ts` and `custom_components/houseplan/wall_segment_model.py`
share `test/fixtures/282-wall-identity-parity.json`. Writer-bypass mutants in
`scripts/mutation-registry.mjs` guard every structural writer entrance. A `cm:0`
@@ -36,8 +36,8 @@ that transition events alone prove disposal.
| Paint, cascade and layer composition | 40 | The invariant depends on computed CSS, SVG paint, clipping, stacking or pixels produced by Chromium. |
| Pointer geometry and trusted interaction | 49 | The invariant depends on hit testing, pointer capture, touch/keyboard dispatch or live DOM geometry. |
| Responsive DOM layout | 39 | The invariant depends on measured element boxes, responsive breakpoints, native/HA dialog shells or focusable target size. |
| Custom-element and HA browser lifecycle | 103 | The invariant crosses Lit/custom-element lifecycle, browser storage/events, lazy loading or a complete HA-card state transition. |
| **Total** | **239 / 200** | Above the guideline `mutation-gate --check` warns rather than fails (#699); each guard above it is held by its own reason in this inventory and its `because`. |
| Custom-element and HA browser lifecycle | 104 | The invariant crosses Lit/custom-element lifecycle, browser storage/events, lazy loading or a complete HA-card state transition. |
| **Total** | **240 / 200** | Above the guideline `mutation-gate --check` warns rather than fails (#699); each guard above it is held by its own reason in this inventory and its `because`. |
## Measured effect
@@ -240,6 +240,11 @@ The invariant depends on measured element boxes, responsive breakpoints, native/
### Custom-element and HA browser lifecycle
`wall-face-lineage-skips-post-reconcile-settlement` (#804) needs the production room
dialog, post-reconciliation runtime wiring, history, asynchronous `config/set` and
reload. Pure lineage-helper tests cannot prove that the editor actually settles
residual-owned IDs before the strict wall-model barrier or rolls rejected writes back.
The invariant crosses Lit/custom-element lifecycle, browser storage/events, lazy loading or a complete HA-card state transition.
- `accepted-marker-rolled-back-by-layout-failure`
@@ -329,6 +334,7 @@ The invariant crosses Lit/custom-element lifecycle, browser storage/events, lazy
- `view-current-space-aria-removed`
- `volumetric-kiosk-ignores-setting`
- `wall-face-apply-skips-overlap-guard`
- `wall-face-lineage-skips-post-reconcile-settlement`
- `wallthick-hit-narrowed`
- `warm-late-resume-beats-user-mode`
- `warm-late-resume-crosses-space`