Commit Graph
2364 Commits
Author SHA1 Message Date
Sergey Matyunin c706f8a744 fix: remove stale decor catalog import
Issue: #434
User-Visible: no
2026-09-03 14:25:33 +03:00
claude[bot] bdba9f48ff docs: review document for #434
Issue: #434
User-Visible: no
2026-09-03 11:21:22 +00:00
Sergey Matyuninandclaude[bot] dbda64e89d test: catch stale danger locale gate
Issue: #434
User-Visible: no
2026-09-03 10:55:16 +00:00
Sergey Matyuninandclaude[bot] cba13621c8 fix: harden v1.71 audit boundaries
Issue: #434
User-Visible: yes
2026-09-03 10:55:16 +00:00
claude[bot] 4190db54ab docs: review document for #434
Issue: #434
User-Visible: no
2026-09-03 10:55:16 +00:00
Sergey Matyuninandclaude[bot] a2cdd360bc docs: bound smoke job in audit polish spec
Issue: #434
User-Visible: no
2026-09-03 10:55:16 +00:00
claude[bot] f383d8fd87 docs: review document for #434
Issue: #434
User-Visible: no
2026-09-03 10:55:15 +00:00
Sergey Matyuninandclaude[bot] 8a75c53eca docs: specify v1.71 audit polish
Issue: #434
User-Visible: no
2026-09-03 10:55:15 +00:00
Claude d1091b6d47 test(decor): путь загрузки картинки под автотестом
`src/backdrop-pick.ts` и `src/decor-image-editor.ts` не входили в
tsconfig.test.json — юнитов у них не было вовсе. Смок при этом подменял
`hass.callWS` целиком и до `uploadFromInput`, `upload`, `delete` не
доходил; в шапке файла это было честно написано. AC1 #51 обещал
доказательство «component unit + smoke» — не было ни того, ни другого.

Цена известна: #427 — файл тяжелее 2 МиБ нельзя было добавить ничем,
гасли обе кнопки диалога, включая «уменьшить копию», — прожил четыре
круга ревью именно потому, что этот путь не проверяло ничто.

Оба файла теперь в tsconfig.test.json (компиляция +6 с, без правок
продуктового кода) и покрыты 13 юнитами:

- классификация: проходной файл, тяжелее лимита источника (guard с
  probe.kind='safe' — предупреждение о размере, не об отказе), warn,
  hard, unknown, неподдерживаемый формат;
- состав кнопок диалога на трёх случаях. Декор свыше лимита: «Отмена» и
  «уменьшить копию», без «оставить оригинал» — это и есть #427. Подложка
  на том же файле сохраняет обе кнопки, hard остаётся с одной «Отмена»,
  unknown предупреждает, а не проходит тихо;
- uploadFromInput: сброс input.value, молчание на занятом, отказ формата,
  исключение классификации, передача флага замены в оба слота;
- upload: multipart-поле и URL, порядок каталога, палитра против замены
  ссылки в диалоге, восемь ответов бэкенда с разными текстами, отпускание
  busy на отказе, запрет второго запроса поверх незакончившегося;
- delete: ссылки на ассет, отказ в подтверждении, чистка каталога, карты
  и палитры, различение in_use, сохранность каталога на отказе сервера;
- loadCatalog: отбор валидных строк и тост на отказе.

Смок `smoke_decor_images.mjs` получил последний блок, который проходит
настоящие uploadFromInput → upload → delete в собранном бандле, подменяя
только транспорт: fetchWithAuth и одну ветку callWS.

Свидетели (§2.7, #435). Девять мутаций прогнаны на собранном дереве,
каждая краснит свой тест: условие #427 → тест состава кнобок; снятие
лимита источника; input.value; флаг замены; too_large; busy в upload;
подтверждение удаления; used_by; проглоченный отказ каталога. Мутация
busy сначала вешала прогон и уносила пять тестов cancelledByParent —
тест переписан так, чтобы падать на сравнении, а не по таймауту.

В реестр добавлены три мутанта на продуктовый код: условие #427, потеря
флага замены, схлопывание кодов ошибок.

Гейты: npm test 1806 tests, 1805 pass, 0 fail (было 1791);
mutation-gate --check зелёный. Смок локально не прогнать — Chromium в
песочнице нет, проверит CI.

Issue: #433
User-Visible: no
2026-09-03 13:21:08 +03:00
claude[bot] a6a9757b6d docs: review document for #432
Issue: #432
User-Visible: no
2026-09-03 10:09:05 +00:00
Sergey Matyunin d8e67f530c test(assets): isolate HA asset fixtures
Issue: #432
User-Visible: no
2026-09-03 12:51:20 +03:00
Sergey Matyunin f3c32fb203 fix(assets): bound resolve integrity work
Issue: #432
User-Visible: yes
2026-09-03 12:48:08 +03:00
claude[bot] 58df908db2 docs: review document for #432
Issue: #432
User-Visible: no
2026-09-03 09:38:37 +00:00
Sergey Matyunin 17a1c10bef docs(spec): define bounded asset resolution
Issue: #432
User-Visible: no
2026-09-03 12:32:33 +03:00
claude[bot] 431b462a16 docs: review document for #431
Issue: #431
User-Visible: no
2026-09-03 08:46:43 +00:00
Sergey Matyunin 6559679b63 build: synchronize issue 431 artifacts
Issue: #431
User-Visible: no
2026-09-03 11:33:40 +03:00
Sergey Matyunin 58efb6a1b2 fix(geometry): canonicalize decor image coordinates
Issue: #431
User-Visible: yes
2026-09-03 11:26:31 +03:00
claude[bot] d97bf63feb docs: review document for #431
Issue: #431
User-Visible: no
2026-09-03 08:21:10 +00:00
Sergey Matyunin 260af7bfd2 docs(spec): define image coordinate canonicalization
Issue: #431
User-Visible: no
2026-09-03 11:16:08 +03:00
claude[bot] 34853ba32a docs: review document for #428
Issue: #428
User-Visible: no
2026-09-03 08:09:36 +00:00
Sergey Matyuninandclaude[bot] 972b0e0c0a test(import): account for space id remapping
Issue: #428
User-Visible: no
2026-09-03 08:09:36 +00:00
Sergey Matyuninandclaude[bot] 2c4dd3f638 fix(import): preserve missing decor asset round-trips
Issue: #428
User-Visible: yes
2026-09-03 08:09:36 +00:00
claude[bot] 7cf0105d62 docs: review document for #428
Issue: #428
User-Visible: no
2026-09-03 08:09:36 +00:00
Sergey Matyuninandclaude[bot] 6f8ce48e5b docs(spec): define missing decor asset round-trip
Issue: #428
User-Visible: no
2026-09-03 08:09:36 +00:00
Claude 8b9548775f test(backend): HA-зависимый тест объявляет это сам, а не именем файла
`python3 -m pytest tests_backend/` без Home Assistant обрывался НА СБОРКЕ:
`test_coordinate_canonicalization.py` тянет HA через `store`, а
`collect_ignore_glob` в conftest отсекает только `test_ha_*.py`. Ни один
из трёх сотен чистых тестов при этом не выполнялся, хотя CLAUDE.md и
PROCESS.md §8 обещают ровно обратное. В CI дефект невидим: там HA есть и
список игнора пуст.

Признак «нужен ли файлу HA» был подменён признаком «как файл назван» —
та же конструкция, которая в #389 уронила 85 тестов с голым assert False.

Вариант владельца — третий: `pytest.importorskip("homeassistant")` в
самом файле, до импортов, которые тянут HA. Теперь это честный скип
(«1 skipped» вместо «Interrupted»), остальные файлы прогоняются, а в CI
не скипается ничего.

Обещанная проверка остальных файлов сделана пофайловым collect: из
двадцати HA требует ровно один непоименованный — этот. Чтобы второй не
появился молча, добавлен статический гейт: он читает импорты (не
исполняет), строит множество модулей интеграции, тянущих HA, — с
замыканием по относительным импортам, потому что `import_export`
зависит от HA только через `store`, — и требует у такого теста либо имя
`test_ha_*`, либо importorskip.

Свидетели, каждый проверен отрицательным прогоном:
- снять importorskip → красный «файлам нужен HA, но они этого не
  объявляют»;
- новый чистый файл с импортом store → тот же красный;
- убрать замыкание → красный синтетический тест сканера;
- перестать исключать TYPE_CHECKING → красный он же;
- считать импорты внутри функций → красный он же.
Плюс два свидетеля самого сканера в теле гейта: `store` обязан быть
найден, `coordinate_canonicalization` обязан остаться чистым — иначе
«ничего не нашёл» выглядело бы как «всё в порядке».

Мутант `pure-backend-test-pulls-home-assistant` в реестре: добавляет
импорт store в чистый test_projection.py, guard — этот гейт.

Гейты: npm test 1791 tests, 1790 pass, 0 fail; pytest без HA
312 passed, 3 skipped (было: Interrupted, 0 выполнено);
mutation-gate --check зелёный.

Issue: #436
User-Visible: no
2026-09-03 11:06:25 +03:00
Claude bdf53dc482 docs: §2.7 требует таблицу «чем краснеет» у защитных AC
§2.7 уже требовал нужного: ревьюер обязан убедиться, что тест умеет
падать. Требование было, артефакта у него не было — в документе ревью
ничто не заставляло назвать, чем именно проверка краснеет, и «убедился»
писалось по впечатлению от чтения теста.

Цена известна по факту. Аудит v1.71.0-beta.1 нашёл пять защитных
контрактов #51 и #423, где снятие защиты не покраснило ни один тест
(#430). Все пять прошли код-ревью как доказанные; два теста попали в
закрытие coverage-ratchet под именами, обещавшими то, чего они не
проверяли.

Теперь у защитного AC три столбца: чем доказан, и отдельно — чем
краснеет, с результатом прогона. Пустой третий столбец — Medium.

Считаются защитные AC без свидетеля, а не мутанты на подсистему: у #421
мутанты были, и дыра всё равно проехала. Число мутантов остаётся
признаком — у #423 их ноль, и именно там нашёлся тест, спрашивавший
регулярку, находит ли она подстроку, которую сам же и вырезал.

Границы записаны явно, чтобы правило не стало ритуалом: AC без заявки на
защиту его не касаются, а «проверено чтением» остаётся законным — только
это видно во втором столбце.

Гейты: npm test 1791 tests, 1790 pass, 0 fail.

Issue: #435
User-Visible: no
2026-09-03 10:58:12 +03:00
Claude 1a8a51f2d9 fix(gates): ключ смоков покрывает оснастку и пробы гарда
Прогон #2371 (ee678352) добавил в demo/guard/verify-guard.mjs пробу
гарда benchmark — и job «Смоки в браузере» была ПРОПУЩЕНА как
переиспользованная. Причина в HARNESS.smoke: ключ держал ровно
demo/smoke_*.mjs, а `demo/serve.mjs`, `demo/guard/**` и benchmark, который
проба запускает, в него не входили. Файл исполняется только в этой job,
его правка её ключ не меняла — проба уехала в dev, ни разу не
запустившись.

Пропущенная проверка выглядит точно как пройденная: это тот же дефект,
против которого заведён #430, только этажом выше — не тест не умеет
падать, а job не запускается. Заодно это значит, что правки #404 в
serve.mjs и любой из четырёх проб гарда всё это время могли быть
реюзнуты.

Критерий ключа теперь один и читаемый: всё, что job исполняет.
Benchmark'и берутся все, а не по имени, — любой может быть подключён к
пробам позже, и лишний прогон дешевле молчания. demo/fixtures/** не
добавлен: он в корпусе sourceFingerprint, который уже подмешан в ключ.

Тест проверяет обе половины: файлы попадают в оснастку И правка каждого
меняет ключ. На прежнем предикате он краснеет (проверено).

Гейты: npm test 1791 tests, 1790 pass, 0 fail. Этот коммит меняет ключ
смоков, поэтому job со смоками на нём прогонится по-настоящему — вместе
с той пробой, ради которой всё и затевалось.

Issue: #430
User-Visible: no
2026-09-03 10:38:47 +03:00
Claude ee678352c7 test(gates): свидетели пяти защитных контрактов #51 и #423
Аудит v1.71.0-beta.1 (§3.2 M1/M2/M3/M6/M9) прогнал по мутанту на каждый
контракт: пять снятий защиты не покраснили ни один тест. Восьмой подряд
случай проверок, не умеющих падать, и первый — в бете, закрывавшей #421,
задачу ровно об этом.

Каждый свидетель ниже проверен отрицательным прогоном: мутант краснит
ровно свой тест и не задевает остальные.

1. Полное декодирование растра. `test_supported_raster_headers_and_full_decode`
   спрашивал w/h/mime — их даёт header-парсер; обрезка `PNG_1X1[:33]`
   теряет IEND и отбивается там же. No-op блока Pillow оставлял 35 pass.
   Новый свидетель: PNG с верными сигнатурой, IHDR, IEND, длинами и CRC,
   но с текстом вместо zlib-потока в IDAT. Оба прежних теста
   переименованы — их имена обещали то, чего они не проверяли.
   Пропуск без Pillow остался (validate_asset глотает ImportError
   осознанно), но в окружении с Home Assistant отсутствие Pillow теперь
   красное само по себе — иначе свидетель молча скипался бы в каноне.

2. Канонизация SVG. `ValidatedAsset(canonical,…)` → `ValidatedAsset(data,…)`
   не краснило ничего: все тесты смотрели w/h/mime, ни один — байты.
   Свидетель сверяет байты целиком: пролог и комментарий не переживают
   канонизацию, пустой элемент сжимается.
   Вторая половина — `_check_size(canonical)`. Экранирование `>` в тексте
   раздувает документ вчетверо: загрузка 1.84 МиБ канонизуется в 7.35 МиБ
   и до сих пор проходила входной контроль. Свидетель — ровно такая.

3. Гард внешних URL. Все три «внешних» кейса корпуса ловились другими
   правилами (тег не из словаря, атрибут не из словаря, ветвь href), и
   `if False:` не краснило ничего. Свидетель: разрешённый тег, разрешённый
   атрибут, пять токенов — сработать может только сам гард, сообщение это
   подтверждает.

4. Проекция декора. Единственный кейс задавал flip_h и opacity: 2 → 1;
   ожидание неотличимо от «opacity игнорируется», а flip_v не проверялся
   вовсе. Свидетели: четыре комбинации отражений, opacity 0.4 и 0 против
   заглушки, форма asset_id с согласованным url (прежняя строка ловилась
   сравнением url, поэтому регулярку id можно было удалить незаметно).

5. Гард benchmark из #423. Доказательство было циклическим: тест вырезал
   из текста подстроку и спрашивал регулярку, находит ли она её, — а
   регулярка искала именно её. Динамический режим `--guard-probe`
   существовал с #423 и не вызывался ни одним прогоном. Теперь он в
   `demo/guard/verify-guard.mjs` (умеет аргументы и файл выше каталога),
   а тест из обнаружения требует у нового page-benchmark режим пробы и
   запись в верификаторе.

Мутантов в реестре стало восемь новых: четыре бэкендных, три юнитных,
один на пробах гарда. У #423 их было ноль — единственная задача с
циклическим тестом и она же единственная без мутантов.

Гейты: typecheck зелёный; npm test 1790 tests, 1789 pass, 0 fail;
pytest без HA 310 passed, 2 skipped; npm run build зелёный, dist не
изменился (продуктовый код не тронут); mutation-gate --check применяет
все восемь якорей. Полный прогон новых мутантов — следующим шагом.

Issue: #430
User-Visible: no
2026-09-03 10:28:00 +03:00
claude[bot] c3eb225c8f docs: review document for #427
Issue: #427
User-Visible: no
2026-09-03 07:20:27 +00:00
Sergey Matyunin f71de89975 docs: refresh screenshot source fingerprint
Issue: #427
User-Visible: no
2026-09-03 10:07:25 +03:00
Sergey Matyunin b87e99f9a1 fix: keep decor downscale action available
Issue: #427
User-Visible: yes
2026-09-03 10:04:45 +03:00
Claude 4cabcbe828 chore(gates): убрать числовой храповик бюджета из #423
Проверка `assertSupportBundleOwnership` бросала при
`initialViewGzipBytes >= 291046` — «граф не стал больше, чем на момент
закрытия #423». Запас до порога: пятнадцать байт на бете 1.71.0, сто
четыре сейчас. Пятнадцать байт gzip меньше одной строки локали, поэтому
первый же посторонний коммит получил бы красный CI с сообщением про
копирайт формы поддержки — к которому не имеет отношения.

«Граф не вырос» — критерий приёмки на момент задачи, а не свойство
продукта. Свойство продукта охраняют `INITIAL_VIEW_GZIP_BUDGET` (300000)
и предупреждение о низком запасе: они судят размер целиком и не
привязаны к чужому номеру issue.

Долговечная половина того же контракта — владение графом (маркеры формы
отсутствуют в initial View, присутствуют в ленивом редакторе) — осталась
и по-прежнему падает в обе стороны. Новый тест закрепляет, что размер в
эту функцию вернуться не может: 0, 291046, 10 МБ и `undefined` проходят
одинаково, пока владение соблюдено.

Гейты: typecheck зелёный, npm test 1787/1786 pass 0 fail, npm run build
зелёный (dist побайтово не изменился — продуктовый код не тронут),
node scripts/bundle-budget.mjs зелёный: initial View 290942 Б, бюджет
300000 Б, запас 9058 Б плюс честное предупреждение о запасе.

Issue: #429
User-Visible: no
2026-09-03 09:56:54 +03:00
claude[bot] cc09e8f827 docs: review document for #426
Проверка (CI) / Классификация изменённых файлов (push) Successful in 24s
Проверка (CI) / Предполётные проверки: документация, провенанс, процесс (push) Successful in 50s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 45s
Проверка (CI) / HACS: валидация репозитория (push) Failing after 17s
Проверка (CI) / Hassfest: манифест интеграции (push) Failing after 24s
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Failing after 13m24s
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Skipped
Проверка (CI) / Смоки: все шарды зелёные (push) Skipped
Проверка (CI) / Golden-кадры против принятых эталонов (push) Skipped
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Skipped
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Failing after 6m56s
Issue: #426
User-Visible: no
2026-09-03 06:38:29 +00:00
Sergey Matyunin a6eb3d6cfa test: accept room tooltip settings golden
Issue: #426
User-Visible: no
Release: v1.71.0-beta.2
Baseline-Reviewed: https://github.com/Matysh/houseplan-card/actions/runs/33722471494
2026-09-03 09:25:14 +03:00
Sergey Matyunin 223951c042 chore: refresh config schema manifest
Issue: #426
User-Visible: no
2026-09-03 09:16:22 +03:00
Sergey Matyunin 9d1e5fdbba docs: refresh screenshot source fingerprint
Issue: #426
User-Visible: no
2026-09-03 09:12:50 +03:00
Sergey Matyunin 8013f7d052 feat: add room hover tooltip setting
Issue: #426
User-Visible: yes
2026-09-03 09:06:57 +03:00
claude[bot] ac99a2ff08 docs: review document for #426
Issue: #426
User-Visible: no
2026-09-03 05:52:52 +00:00
Sergey Matyunin 587c20699c docs: specify room hover tooltip toggle
Issue: #426
User-Visible: no
2026-09-03 08:47:07 +03:00
Sergey Matyunin a9fc2321a9 docs: accept v1.71.0-beta.1 screenshot fingerprint
Проверка (CI) / Классификация изменённых файлов (push) Successful in 30s
Проверка (CI) / Предполётные проверки: документация, провенанс, процесс (push) Failing after 53s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 52s
Проверка (CI) / HACS: валидация репозитория (push) Failing after 28s
Проверка (CI) / Hassfest: манифест интеграции (push) Failing after 16s
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Failing after 10m53s
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Failing after 13m16s
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Skipped
Проверка (CI) / Смоки: все шарды зелёные (push) Skipped
Проверка (CI) / Golden-кадры против принятых эталонов (push) Skipped
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Skipped
Issue: #425
User-Visible: no
v1.71.0-beta.1
2026-09-03 01:25:09 +03:00
Sergey Matyunin 694db13760 build: prepare v1.71.0-beta.1 candidate
Issue: #51
Issue: #417
Issue: #418
Issue: #419
Issue: #420
Issue: #421
Issue: #422
Issue: #423
Issue: #424
Issue: #425
User-Visible: no
2026-09-03 01:22:01 +03:00
claude[bot] ea01e3a683 docs: review document for #51
Issue: #51
User-Visible: no
2026-09-02 21:56:04 +00:00
Sergey Matyuninandclaude[bot] 44a38b3378 test: stabilize kiosk gear smoke
Issue: #51
User-Visible: no
2026-09-02 21:56:04 +00:00
claude[bot] ff42d650ca docs: review document for #51
Issue: #51
User-Visible: no
2026-09-02 21:56:04 +00:00
Sergey Matyuninandclaude[bot] 3a6ceeea54 test: cover custom image raster paths
Issue: #51
User-Visible: no
2026-09-02 21:56:04 +00:00
Sergey Matyuninandclaude[bot] a265830e3b chore: refresh custom image config schema
Issue: #51
User-Visible: no
2026-09-02 21:56:04 +00:00
Sergey Matyuninandclaude[bot] 294a70b6be docs: refresh custom image capture fingerprint
Issue: #51
User-Visible: no
2026-09-02 21:56:04 +00:00
claude[bot] cadcbcc5f1 docs: review document for #51
Issue: #51
User-Visible: no
2026-09-02 21:56:04 +00:00
Sergey Matyuninandclaude[bot] b3bcd3df8f chore: satisfy custom image backend lint
Issue: #51
User-Visible: no
2026-09-02 21:56:04 +00:00
Sergey Matyuninandclaude[bot] e56f0f297b refactor: type custom decor image contracts
Issue: #51
User-Visible: no
2026-09-02 21:56:04 +00:00