mirror of
https://github.com/Matysh/houseplan-card
synced 2026-07-31 16:38:31 +00:00
v1.46.6: the detach promise, actually kept this time
v1.46.4 and v1.46.5 documented that detaching a plan leaves the image on disk,
added guards for it, and shipped tests. The guards were never reached: they sit
behind 'not superseded', and a file that left the configuration was called
superseded. From old_refs - new_refs alone, replacing a plan, detaching one and
deleting its space are indistinguishable — so all three deleted the file, at the
moment of the save, before any scheduled pass ever ran.
Every test I wrote for this called collect_plans(d, cfg, cfg): old config equal
to new, i.e. only the scheduled pass. The transition that mattered was never
exercised. Codex reproduced it in four lines.
Classification is by owner now:
space in both, plan A -> plan B : the user picked another image -> removed
space in both, plan -> none : detached -> kept
space gone : kept (the image was imported; a thirty-day
grace measured from file age is meaningless
anyway, it was uploaded months ago)
space has a plan, other file : rejected upload -> 1 h
Attachments follow the same shape: dropped from a device that still exists ->
removed (a trash button promises nothing); device gone -> kept; staging folder
-> 1 h.
Tests: a matrix per rule in the pure module, and — the part that was missing —
test_detaching_a_plan_keeps_the_file, which goes through real config/set calls:
attach, detach, assert the file is there, restart, assert again, re-attach,
replace, assert the replaced one is gone, delete the space, assert the plan
survives. Also strengthened the sweep/save race test to assert the save actually
succeeded and the config points at the specific expected file, per the report.
This commit is contained in:
+14
-6
@@ -214,14 +214,22 @@ we should not have removed cannot be brought back.** When the evidence is weak,
|
||||
keep the file. Owner's decision, 2026-07-28, after the one-hour rule applied to
|
||||
every unreferenced file destroyed two detached plans.
|
||||
|
||||
The classification is by **owner**, not by "is it referenced". A file leaving
|
||||
the configuration looks identical whether the plan was replaced, detached, or
|
||||
its space deleted — and only the first is a deletion the user asked for. Reading
|
||||
`old_refs - new_refs` and calling it "superseded" deleted a plan the moment it
|
||||
was detached, under documentation promising the opposite (HP-1465-01).
|
||||
|
||||
| Case | What it means | Rule |
|
||||
|---|---|---|
|
||||
| In the old revision, not in the new | a save replaced it | removed immediately |
|
||||
| Space exists, has **no** plan | detached, one click to undo | **never removed** |
|
||||
| Space exists, has a plan | its own rejected upload | `PLAN_ORPHAN_TTL_S` (1 h) |
|
||||
| Space no longer exists | deliberate deletion, but people misclick | `SCHEDULED_GRACE_S` (30 d) |
|
||||
| Attachment in `up_*` | a dialog that was never saved | `PLAN_ORPHAN_TTL_S` (1 h) |
|
||||
| Attachment in a marker folder | unreferenced, but may come back | `SCHEDULED_GRACE_S` (30 d) |
|
||||
| Space in both, plan A → plan B | the user picked another image | removed immediately |
|
||||
| Space in both, plan → none | detached; one click undoes it | **kept** |
|
||||
| Space gone | deliberate, but the image was imported and may be nowhere else | **kept** |
|
||||
| Space has a plan, plus another file of its own | an upload whose save was rejected | `PLAN_ORPHAN_TTL_S` (1 h) |
|
||||
| Marker in both, attachment dropped from its list | a trash button, promising nothing | removed immediately |
|
||||
| Marker gone | same call as a deleted space's plan | **kept** |
|
||||
| Attachment in `up_*` | a dialog that was never saved; no device owns it | `PLAN_ORPHAN_TTL_S` (1 h) |
|
||||
| Marker there, file it never listed | a rejected upload | `SCHEDULED_GRACE_S` (30 d) |
|
||||
|
||||
**Config writes are serialized** (HP-1454-03). `_writeConfig()` chains onto a
|
||||
single promise: one `config/set` in flight, each carrying the revision the
|
||||
|
||||
@@ -1,5 +1,20 @@
|
||||
# Changelog
|
||||
|
||||
## v1.46.6 — 2026-07-28 (the detach promise, actually kept this time)
|
||||
- **Switching a space to "draw" no longer deletes its image.** v1.46.4 and
|
||||
v1.46.5 said it did not, and the scheduled cleanup indeed left detached plans
|
||||
alone — but the save itself deleted the file the moment the reference was
|
||||
cleared, before any of those guards were reached. The cause: a file that left
|
||||
the configuration was called "superseded", and from that difference alone
|
||||
replacing a plan, detaching one and deleting its space are indistinguishable.
|
||||
Only the first is a deletion anybody asked for. The transition is now
|
||||
classified by the space that owned the file, and the same distinction applies
|
||||
to attachments: dropping one from a device that still exists removes it,
|
||||
deleting the device keeps its manuals.
|
||||
- **A plan whose space was deleted is kept**, rather than the thirty days
|
||||
v1.46.5 promised — thirty days measured from the file's age is meaningless
|
||||
anyway, since it was usually uploaded months earlier.
|
||||
|
||||
## v1.46.5 — 2026-07-28 (audit of every automatic deletion)
|
||||
- **A detached plan is never deleted, at any age.** v1.46.4 gave it a month;
|
||||
this makes it permanent and writes the reason down where the next change will
|
||||
|
||||
@@ -6,6 +6,21 @@
|
||||
> **Правило проекта:** оба файла пополняются в одном коммите с самим
|
||||
> изменением — как и остальная документация (см. docs/STATUS.md).
|
||||
|
||||
## v1.46.6 — 2026-07-28 (обещание про отцепление, теперь выполненное)
|
||||
- **Переключение пространства в «нарисовать» больше не удаляет его картинку.**
|
||||
v1.46.4 и v1.46.5 утверждали, что не удаляет, и плановая уборка действительно
|
||||
отцеплённые планы не трогала — но само сохранение удаляло файл в тот момент,
|
||||
когда снималась ссылка, ещё до всех этих проверок. Причина: файл, покинувший
|
||||
конфигурацию, считался «заменённым», а по одной этой разнице замену плана,
|
||||
отцепление и удаление пространства различить невозможно. Удалением, о котором
|
||||
просили, является только первое. Теперь переход классифицируется по
|
||||
пространству-владельцу, и та же разница применяется к вложениям: убрали файл у
|
||||
существующего устройства — он удаляется, удалили устройство — его инструкции
|
||||
остаются.
|
||||
- **План удалённого пространства сохраняется**, а не тридцать дней, как обещала
|
||||
v1.46.5: тридцать дней по возрасту файла всё равно бессмысленны — обычно он
|
||||
загружен месяцы назад.
|
||||
|
||||
## v1.46.5 — 2026-07-28 (ревизия всех автоматических удалений)
|
||||
- **Отцеплённый план не удаляется никогда, ни в каком возрасте.** В v1.46.4 ему
|
||||
давался месяц; теперь это навсегда, и причина записана там, где её увидит
|
||||
|
||||
+2
-2
@@ -15,12 +15,12 @@
|
||||
|
||||
| Item | State |
|
||||
|---|---|
|
||||
| Version | **v1.46.5** everywhere (manifest, const.py, package.json, CARD_VERSION); deployed to the home instance |
|
||||
| Version | **v1.46.6** 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 |
|
||||
| HACS | Custom repository works. **Inclusion PR: hacs/default#9004** — open, valid, labeled; ~864 older open PRs but merge rate ≈180/mo; realistic ETA 1–3 months (checked 2026-07-24) |
|
||||
| Home instance | ha.jbstudio.pro (SSH port 323, key `ha_jb`), deployed **v1.46.5** via direct copy (HACS custom repo also installed) |
|
||||
| Home instance | ha.jbstudio.pro (SSH port 323, key `ha_jb`), deployed **v1.46.6** via direct copy (HACS custom repo also installed) |
|
||||
| Localization | UI en/ru (src/i18n/*.json), everything user-visible localized incl. kiosk popover |
|
||||
| Tests | Four layers: frontend unit (`npm test`, node:test over `test-build/`), pure backend (`pytest tests_backend`, runs anywhere), HA-harness backend (same folder, CI only — needs py3.13 + pytest-homeassistant-custom-component), and browser smokes (`demo/smoke_*.mjs`, headless chromium). **Counts are not written down here** — they went stale within two releases while the version line beside them was kept current, which reads as less coverage than exists (review R5-2). Run `npm run inventory` for the current numbers, or read them off the last CI run |
|
||||
| Community | **Telegram chat: https://t.me/ha_houseplan** (created 2026-07-27) — the primary user-facing support channel; GitHub issues stay for bugs/features. Link it from any new release notes and posts |
|
||||
|
||||
+8
-5
@@ -239,11 +239,14 @@ Run the *core flows* (marked ★ below) in each environment at least once per mi
|
||||
on the plan after a reload. Same for each tap action and each fill mode
|
||||
[auto: backend test_every_display_mode_the_editor_offers_is_accepted and
|
||||
neighbours, test_a_marker_showing_its_value_can_be_saved]
|
||||
- [ ] Detaching a plan keeps the file (v1.46.4/v1.46.5): switch a space to
|
||||
"draw", restart, wait — the image stays in `config/houseplan/plans/`
|
||||
indefinitely and can be re-attached. Replacing a plan still removes the one
|
||||
it replaced, immediately
|
||||
[auto: unit: test_scheduled_collection_never_takes_a_detached_plan]
|
||||
- [ ] Detaching a plan keeps the file (v1.46.6): switch a space to "draw" and
|
||||
SAVE — the image is still in `config/houseplan/plans/` right afterwards,
|
||||
and after a restart, and can be re-attached. Deleting the space keeps it
|
||||
too. Replacing a plan still removes the one it replaced, immediately.
|
||||
Check straight after the save: the earlier bug deleted the file at that
|
||||
moment, while every scheduled-pass test passed
|
||||
[auto: unit: test_plan_collection_matrix, test_attachment_collection_matrix,
|
||||
backend test_detaching_a_plan_keeps_the_file]
|
||||
- [ ] Rebinding a device does not eat its manuals (v1.46.5): attach two files to
|
||||
a device, rebind it to another HA device — both are readable afterwards.
|
||||
If a copy failed, the file it failed on is still there rather than deleted
|
||||
|
||||
Reference in New Issue
Block a user