v1.54.2: HP-1541-01 — vacuum selected_map fallback obeys the not-nullish map-id contract

The v1.54.1 contract (first not-None value wins, zero is a value) covered
the source entity but not the card's fallback on the vacuum's own
selected_map: _vacMapId still used truthiness, so selected_map: 0 became
'default' on the frontend while trails.py resolve_map_id stored the run
under '0'. Calibration and server trails split across two keys and the
recorded run never rendered after reload.

The fallback is now the shared pure helper vacMapIdWithFallback (nullish
check), mirroring resolve_map_id. Cross-runtime regressions added for
selected_map = 0, '0' and '' on both sides; the frontend cases fail on the
old truthiness code.
This commit is contained in:
Matysh
2026-07-31 13:44:10 +03:00
parent 909bb6fbc7
commit fad2e87ab5
14 changed files with 109 additions and 17 deletions
+17
View File
@@ -1,5 +1,22 @@
# Changelog
## v1.54.2 — 2026-07-31
Patch release: the one remaining finding of the v1.54.1 re-audit
(HP-1541-01), pinned by regression tests on both sides of the contract.
- **Fix: a vacuum whose own `selected_map` is `0` split calibration and
trail between two map ids.** The v1.54.1 map-id contract («the first value
that exists wins, and zero is a value») was applied to the source entity
but not to the card's fallback on the vacuum's `selected_map`: the
frontend still judged it by truthiness and turned `0` into `default`,
while the server recorder stored the run under `0`. Calibration was saved
under a key the recorder never used, and the recorded trail never rendered
after a reload. The fallback now follows the same not-nullish rule on both
sides (`vacMapIdWithFallback` in the card, `resolve_map_id` on the
server), with cross-runtime regressions for `selected_map` = `0`, `"0"`
and `""`.
## v1.54.1 — 2026-07-31
Patch release: everything the adversarial audit of v1.54.0 found
+17
View File
@@ -6,6 +6,23 @@
> **Правило проекта:** оба файла пополняются в одном коммите с самим
> изменением — как и остальная документация (см. docs/STATUS.md).
## v1.54.2 — 2026-07-31
Патч-релиз: единственная оставшаяся находка повторного аудита v1.54.1
(HP-1541-01), закреплена регрессиями с обеих сторон контракта.
- **Исправлено: пылесос с собственным `selected_map: 0` делил калибровку и
след между двумя id карты.** Контракт map id из v1.54.1 («побеждает
первое существующее значение, и ноль — значение») был применён к
source-сущности, но не к фолбэку карточки на `selected_map` самого
пылесоса: фронтенд по-прежнему судил по «истинности» и превращал `0` в
`default`, тогда как серверный рекордер писал уборку под `0`. Калибровка
сохранялась под ключом, которого рекордер не использовал, а записанный
след после перезагрузки не отображался. Теперь фолбэк живёт по тому же
правилу «не-null» с обеих сторон (`vacMapIdWithFallback` в карточке,
`resolve_map_id` на сервере), с кросс-регрессиями для `selected_map` =
`0`, `"0"` и `""`.
## v1.54.1 — 2026-07-31
Патч-релиз: всё, что нашёл adversarial-аудит v1.54.0 (HP-1540-01..06),
+1 -1
View File
@@ -15,7 +15,7 @@
| Item | State |
|---|---|
| Version | **v1.54.1** everywhere (manifest, const.py, package.json, CARD_VERSION); deployed to the home instance |
| Version | **v1.54.2** everywhere (manifest, const.py, package.json, CARD_VERSION); deployed to the home instance |
| Workflow | Since 2026-07-22: minor changes go to branch **`dev`** (build + smokes → deploy home → commit → push, NO release); releases are batched on the owner's command (merge dev→main, one tag, one release with a summary changelog, CI checked on dev beforehand) |
| GitHub | https://github.com/Matysh/houseplan-card — **`main` carries every published release, the latest tag is the current version above**; `dev` is where work lands and is merged into `main` at release time (so `dev` is normally equal to or ahead of `main`, never behind). Push via SSH key `ha_jb` (remote git@github.com:…); API releases via the fine-grained PAT in `~/.git-credentials` (Contents R/W, issued 2026-07-23) |
| CI | validate.yml (hacs + hassfest + frontend + backend) green; release.yml attaches the bundle on release publish |