fix(import): preserve missing decor asset round-trips

Issue: #428
User-Visible: yes
This commit is contained in:
Sergey Matyunin
2026-09-03 10:59:34 +03:00
parent 80a5a044c3
commit eef7ce129b
8 changed files with 238 additions and 11 deletions
+4
View File
@@ -2,6 +2,10 @@
## Unreleased
- Exports made while a reusable decor-image file is missing can now be imported
with the existing confirmation instead of rejecting the whole plan; full,
single-space and plan-only exports preserve the repairable image object
([#428](https://github.com/Matysh/houseplan-card/issues/428)).
- Oversized decor-image sources can now be added through the safe reduced-copy
action; House Plan hides only the forbidden original instead of hiding both
choices ([#427](https://github.com/Matysh/houseplan-card/issues/427)).
+5
View File
@@ -8,6 +8,11 @@
## Не выпущено
- Экспорт, созданный при отсутствующем файле пользовательской картинки декора,
теперь можно импортировать с обычным подтверждением вместо ошибки всего
плана; полный экспорт, одно пространство и режим «Только планировка»
сохраняют восстанавливаемый объект
([#428](https://github.com/Matysh/houseplan-card/issues/428)).
- Слишком большой исходник изображения декора теперь можно добавить через
безопасную уменьшенную копию: House Plan скрывает только запрещённый
оригинал, а не оба действия
+5
View File
@@ -249,6 +249,11 @@ It records content hash and source availability but never embeds file bytes or
signed URLs. The importer continues to accept v1. A matching verified local
hash is reused; otherwise import requires confirmation and preserves the image
record as an editor repair placeholder instead of removing its geometry.
When the source blob and metadata are already absent, the canonical row has
`exists_at_export:false` and may have `mime:null`; that exact missing state is
importable in full, single-space and plan-only documents. Missing MIME is not a
general validation bypass: the availability flag must be a literal boolean,
identity/hash remain exact, and every supplied non-null MIME must be supported.
Before a permanent downgrade, remove all image objects with a current card and
then explicitly delete their now-unused files from the palette.
+3
View File
@@ -782,6 +782,9 @@ Deleting or replacing a placed image leaves the reusable file in the palette.
The palette deletes a file only after all placed copies in all spaces are gone.
If a file is missing or fails its integrity check, View hides it; Background
shows a crossed placeholder that can be selected and repaired with Replace.
Exports still keep that image object without embedding the absent file. A later
import shows the existing missing-content confirmation and, once confirmed,
keeps the same repairable placeholder instead of rejecting the whole plan.
![Selected line in the Background editor](images/07-background-editor.png)
+4
View File
@@ -1412,6 +1412,10 @@ WebP и безопасный SVG; лимит 2 МиБ относится к со
Если файл исчез или не проходит проверку целостности, в просмотре он скрыт, а
в редакторе подложки остаётся перечёркнутая рамка. Её можно выбрать и указать
другой файл без потери позиции, размера, угла, отражения и порядка слоя.
Экспорт всё равно сохраняет такой объект, не встраивая отсутствующий файл.
При последующем импорте House Plan показывает обычное подтверждение
недостающего содержимого и после согласия оставляет ту же восстанавливаемую
рамку, а не отклоняет весь план.
## 15. Солнце: фон и оконные лучи
@@ -100,7 +100,7 @@ Exporter не восстанавливает MIME эвристикой и не
| literal `true` | отсутствует, `null` или неподдерживаемая строка | `ImportFailure("invalid_content")` |
| literal `false` | поддерживаемая строка | допустимо |
| literal `false` | отсутствует или `null` | допустимо: это исправляемый missing asset |
| literal `false` | неподдерживаемая непустая строка либо значение другого типа | `ImportFailure("invalid_content")` |
| literal `false` | любая неподдерживаемая строка, включая `""`, либо значение другого типа | `ImportFailure("invalid_content")` |
| поле отсутствует, `null`, `0`, `1`, строка, объект или массив | любое | `ImportFailure("invalid_content")` |
Во всех допустимых строках остаются обязательными:
@@ -162,7 +162,8 @@ MIME связано одновременно с exact image identity и literal
## Затронутые файлы и модули
- `custom_components/houseplan/import_export.py` — bounded validation
`decor_asset` в `_content_state()`;
`decor_asset` в `_content_state()`, полная image-проекция plan-only и её
ограниченный manifest allowlist;
- `tests_backend/test_ha_import_export.py` — положительный round-trip и
отрицательная матрица;
- `docs/CONFIG-COMPATIBILITY.md` — точное значение missing MIME;