18 Commits
Author SHA1 Message Date
Matysh 2e2d353b04 v1.45.2: hardening from the v1.45.1 review — R4-1, R4-2
R4-1: collecting superseded plan files runs after the configuration is already
durable, but an error listing the directory propagated out of config/set. The
client saw a failure for a revision the server had committed, and its retry
came back as a conflict. collect_plans now reports 0 instead of raising, and
config/set logs and proceeds — the event fires, the revision is returned.

R4-2: the pending set was cleared when a batch went out, not when it came back,
so every render during an in-flight content/sign queued another request: six
calls where one was needed, and unbounded on a socket that is slow rather than
busy. Queued and in-flight are separate states now; a failure backs off (2 s
doubling to 60 s) instead of retrying on the next frame; an in-flight entry
expires after 15 s so a promise that never settles cannot wedge retries; a late
answer after dispose() no longer renders.

Tests: test/signing.test.mjs — eight cases with hand-settled promises, verified
against a v1.45.1 checkout where four of them fail (2 sign calls instead of 1,
no backoff, a late answer rendering after teardown). Backend: a broken
collector still yields a successful save whose revision the next CAS accepts.
Pure collector: a disappearing directory returns 0.
Docs: CHANGELOG.md + CHANGELOG.ru.md + ARCHITECTURE.md + TESTING.md + STATUS.md.
2026-07-28 00:13:45 +03:00
Matysh c749b52a0d v1.45.1: follow-up review of v1.45.0 — R3-1, R3-2
R3-1 (high): v1.45.0 made the upload safe but left deletion to the client —
after a successful save the card asked the backend to remove everything but the
file it had just committed. Two open editors cannot be ordered: a delayed
request from one deleted the plan the other had just saved, leaving the
accepted configuration pointing at nothing, the exact damage copy-on-write was
introduced to prevent.

houseplan/plan/cleanup is removed. config/set collects inside its own write
lock from the two configurations that bracket the commit (plans.collect_plans):
a file the old revision referenced and the new one does not is superseded and
goes; any other unreferenced upload waits out PLAN_ORPHAN_TTL_S, because a
fresh one may belong to a transaction that has not committed yet. The collector
lives in a pure module so it can be reasoned about and unit-tested without the
HA harness.

R3-2: houseplan-space-card signed its plan url and threw the result away —
getCardSize() mutated a throwaway model while render() rebuilt its own from the
config, so the <image> requested the protected path and got 401 on every
render. Both cards now share ContentSigner (src/signing.ts), which also gives
the static card batching, expiry handling and periodic re-signing.  is
released in finally: one failed request no longer wedges a url for the life of
the page.

Tests: five backend interleaving cases from the report, six unit tests for the
pure collector, smoke_space_card_bg (verified to fail against a v1.45.0 build:
the raw url reaches the DOM and no retry happens). 57 smokes, 124 unit, 22
backend-pure.
Docs: CHANGELOG.md + CHANGELOG.ru.md + ARCHITECTURE.md + TESTING.md + STATUS.md.
2026-07-27 22:01:41 +03:00
Matysh 5d2dbb1009 v1.45.0: external review of v1.44.8 — R2-1, R2-2, R2-3
R2-1 (high): plan replacement committed filesystem state before the config CAS.
The upload wrote the final name and unlinked the other extension, so a rejected
config write left the live plan already replaced — or the stored config
pointing at a deleted file. Uploads now go to <space>.<token>.<ext> and delete
nothing; houseplan/plan/cleanup runs only after the config write is accepted.
The '.' separator is load-bearing: a space id cannot contain one, so cleaning
'f1' can never reach the files of 'f1-attic'.

R2-2: the backend signs at most MAX_SIGN_PATHS (200) per request and ignores
the rest silently, while the card sent its whole cache in one call and trusted
any cached entry forever — past 200 attachments the later ones stopped being
refreshed and expired for good. Requests are chunked to the shared constant,
entries carry their issue time (aging urls keep rendering while a replacement
is fetched, expired ones are dropped), and the cache is pruned to urls the live
config still references.

R2-3: areaClimate() rescanned the whole registry per room and per measurement.
areaClimateMap() classifies once and returns Map<area,{temp,hum}>, memoized on
hass identity so fresh states are always observed. Smoke measurement: 133
registry scans per update with 44 rooms before, 2 after, flat in room count.

Also: smoke_ux_fixes wrote its screenshot to a hard-coded /tmp path and could
not run on Windows.

Tests: smoke_plan_upload_reject, smoke_sign_cap, smoke_climate_once (all fail
on v1.44.8), three backend tests for versioned plan names and cleanup scoping,
unit tests for chunk/referencedContentUrls and areaClimateMap.
Docs: CHANGELOG.md + CHANGELOG.ru.md + ARCHITECTURE.md + TESTING.md + STATUS.md.
2026-07-27 21:08:34 +03:00
Matysh 0fd0ba408d fix v1.43.0: external audit P0 — data loss, split geometry, auth, dialog zombies
L2 (silent data loss): debounce gains flush()/pending(); _reloadConfigOnly
flushes a pending write and defers while one is in flight; conflict path
forces; failed reload now toasts instead of an empty catch; teardown flushes.

G1 (split corruption): same-edge cuts carve the niche properly instead of
walking the outline twice; partition invariant (parts sum to the original)
rejects anything else; +1 unit test covering 5 niche shapes and both legacy
cut shapes.

B1 (unauthenticated content): plans and marker files move to
HouseplanContentView (/api/houseplan/content/..., requires_auth); only the
card bundle stays static; contentUrl() rewrites legacy URLs on read (no
storage migration); repairs.py accepts both prefixes; +1 unit test.

L3 (dialog zombies): all four save catch-blocks guard against a closed
dialog; the card no longer blanks when a save fails after Esc.

smokes: smoke_save_race, smoke_dialog_zombie; docs (TESTING/CHANGELOG/
ARCHITECTURE incl. the optimistic-UI note) same-commit
2026-07-27 10:44:58 +03:00
Matysh 19e19b5c5f feat v1.42.0: room settings — the third settings tier
- four-tier principle fixed in ARCHITECTURE: global > space > room >
  device, specific overrides general, unset inherits
- room.settings { fill_mode, temp_source, hum_source } with backend
  schema; pure roomFillModeOf + sourceValue (+2 test suites, 114)
- gear on room cards in the Plan editor opens Room settings: rename,
  re-area (current area included in the list), fill override (may opt
  out of glow darkness), explicit temp/hum source with a searchable
  device+entity dropdown; the same section in the creation dialog
- source feeds the room card, tooltip and temp fill; works for rooms
  without an HA area (user-feedback case #1)
- smoke_room_settings.mjs (10 checks); TESTING/CHANGELOG/ARCHITECTURE
  same-commit
2026-07-27 09:58:21 +03:00
Matysh b03ef70794 docs: catch STATUS/ARCHITECTURE/UX-MODES up to v1.41.0, kiosk recipe in README.ru
- STATUS.md: fresh snapshot (version, dev-branch workflow, PAT, HACS
  queue reality, test counts) + feature-surface digest since 07-17
- ARCHITECTURE.md: decor layer, glow clip model, open boundaries math,
  controls, island rooms, kiosk, nav persistence
- UX-MODES.md: kiosk as the fourth interaction surface
- README.ru.md: wall-tablet recipe (parity with English)
2026-07-23 21:24:58 +03:00
Matysh 70d3453f78 docs: catch all documentation up to v1.23.1
Validate / hacs (push) Has been cancelled
Validate / hassfest (push) Has been cancelled
Validate / frontend (push) Has been cancelled
Validate / backend (push) Has been cancelled
- READMEs (en+ru): doors/windows/locks section (openings tool, live rendering, drag,
  double-click properties), presence ripples + per-device icon size/rotation in the
  manual-marker section.
- ARCHITECTURE: room geometry rules (derived walls, no-overlap, merge/split via
  polyclip-ts and why not polygon-clipping), doors & windows model (space.openings,
  snapToWall, absolute coords, security), per-marker display fields + cell_cm ruler.
- DEVELOPMENT: gotchas — polygon-clipping ESM/types mismatch; same-version redeploys
  keep ?v so browsers cache the old bundle.
- STATUS: snapshot refreshed (releases to v1.23.1, dacha deployed v1.23.1), milestones
  v1.17–v1.23.1 incl. the lost-sources lesson (push right after building).
- ROADMAP: 8 shipped Quality-Scale items ticked (done since v1.12.0).
- TESTING: restored the v1.22.0 ripple checklist lost in the sandbox reset.
2026-07-17 07:53:16 +03:00
Matysh 65268a7985 feat v1.19.0: a line is never an entity of its own — walls are derived from rooms
A wall can only exist as an edge of a closed room:
- roomEdges(rooms) derives walls from room outlines, deduping shared ones, so deleting a
  room keeps the borders its neighbours still contribute and drops the rest — the rule
  falls out of the model instead of needing bookkeeping.
- Nothing is persisted while drawing: an outline you never close leaves no lines behind
  (previously every click pair was written to space.segments immediately).
- The 'Erase line' tool is gone; space.segments is stripped on every save (validation
  still tolerates it on read so a stale tab cannot fail a save).
- Dead code out: _addSegment/_removeSegmentByKey/_distToSeg/_pathSegs/_segKey.
Docs (ARCHITECTURE/TESTING/CHANGELOG) updated in the same commit. +2 tests (63).
2026-07-16 07:27:23 +03:00
Matysh 1847c7b8ed feat v1.16.0: new read-only houseplan-space-card (static single-space schematic, pointer-events:none, deep-link button) + #space=<id> deep-link in the full card. Shared space-geometry/space-render + module-level config-store cache. +6 unit tests, smoke_space_card & smoke_deeplink. Docs in same commit. 2026-07-08 19:38:31 +03:00
Matysh 34d073f484 chore v1.13.3: remove legacy assets/ with real-house plan sources (privacy; unused since server-side config) 2026-07-06 07:39:43 +03:00
Matysh 94fb4af14c feat v1.11.0: full English translation + en/ru UI localization
- All card UI strings moved to src/i18n.ts (en/ru); language follows the HA
  profile automatically, new 'language: en|ru' card option forces it; GUI
  editor localized and got the language dropdown; generated device names
  localized via BuildCtx.loc.
- English-only codebase: comments, docstrings, test names, backend error
  messages and logs. Russian remains only in the ru dictionary, ru.json,
  iconFor regexes matching Russian device names (+their fixtures) and README.ru.md.
- Docs English-first: README (EN) + README.ru.md, ARCHITECTURE/DEVELOPMENT/
  ROADMAP/CHANGELOG fully translated; translations/en.json had Russian - fixed.
- Removed obsolete RELEASE_NOTES_v1.9.3.md and scripts_publish.sh.
2026-07-05 21:43:58 +03:00
JB 96d3a182c6 fix v1.7.4: PDF upload via HTTP endpoint instead of WebSocket — root cause was WS message-size limit dropping the connection on real (>2-3MB) PDFs (which also closed the dialog via reconnect). New POST /api/houseplan/upload (HomeAssistantView, multipart, auth); verified 3MB(182ms)+10MB(446ms). Legible errors (_errText), no more [object Object] 2026-07-04 16:10:26 +03:00
JB aa4e3aed1d fix v1.7.2: mobile 'configuration error' on cold start — register card as Lovelace resource (awaited before render) instead of only add_extra_js_url (raced); idempotent version update + YAML-mode fallback; _loadFromServer retries (up to 8 hass ticks) so card doesn't stick on onboarding if WS not ready yet 2026-07-04 15:12:27 +03:00
JB 74640318e9 feat v1.6.0+v1.6.1 (phase 3): device edit mode — markers model (hybrid auto+manual), click info-card in view / edit dialog in edit; dialog: name/binding-picker(filter,exclude placed+name-dupes,+virtual)/mdi-icon/model/link/description/PDF-upload/room; toolbar + add device; backend MARKER_SCHEMA + file/set upload + files static 2026-07-04 13:16:16 +03:00
JB 08cd929b8d v1.4.3+v1.4.4: icon centers snap to markup grid (drag + one-time DB snap); CRITICAL: optimistic locking for config (rev/expected_rev/conflict), houseplan_config_updated event with live client resync, per-device layout updates instead of full set 2026-07-04 12:06:09 +03:00
JB b97b61a8e6 feat v1.4.0 (phase 2): room markup editor — dot grid, two-click lines with snap, closed contour enables save with HA area dropdown, polygon rooms, tools add/erase-line/delete-room, shared wall segments in space.segments 2026-07-04 11:03:51 +03:00
JB 18c0ea1703 feat v1.3.0 (phase 1): server-side config store (spaces/plans/rooms/overrides/virtual, normalized coords), WS config/get|set + plan/set upload, card resolved-model (server or legacy fallback), one-click migration — executed on dacha 2026-07-04 10:43:40 +03:00
JB 1d576164f4 docs+publish prep: docs/ (architecture, development, changelog, roadmap), CI validate (hacs action + hassfest + build sync check), brand icon, LICENSE 2026-07-04 10:30:40 +03:00