Commit Graph
2183 Commits
Author SHA1 Message Date
Matysh 601e68e52d fix: six smokes never asked whether the card threw
Счётчик исключений внутри карточки живёт в demo/serve.mjs, и читала его одна
функция — finish(). Шесть смоков её не вызывали вовсе: у трёх своя развязка
(`if (!ok) process.exit(1)`), у двух throw из try/finally, у
smoke_entry_stale ни того ни другого. Необработанное исключение во время этих
шести проходило незамеченным всегда — в лог печаталось EXC, а прогон
оставался зелёным.

smoke_entry_stale был хуже остальных: он складывал неудачи в _failures через
check/checkAll, но их никто не печатал и код возврата не выставлял. То есть
смок не мог провалиться в принципе — ровно паттерн «печатали булевы значения
и всегда выходили нулём», который шапка serve.mjs описывает как исправленный
в 2026-07-27.

Добавлен reportPageErrors(): тот же вердикт, что у finish(), для смоков со
своей логикой выхода. Каждый из шести теперь вердикт запрашивает, а
smoke_entry_stale получил finish() и вместе с ним настоящий код возврата.

Вердикт обязан ОСТАНАВЛИВАТЬ, а не только помечать. Первый заход выставлял
process.exitCode, и отрицательный прогон напечатал «FAILED: 1 uncaught
exception(s)» и следом «OK deep-link: …»: код был верным, вывод
противоречивым, а читают вывод.

Доказано отрицательным прогоном, а не рассуждением: на ветке
experiment/407-negative smoke_deeplink получил намеренное исключение внутри
карточки, шард 2/3 упал с exit code 1, в логе FAIL и FAILED без строки
успеха. Ветка удалена.

Гейт против повторения — test/smoke-harness-contract.test.mjs: он падает,
если смок не запрашивает вердикт или запрашивает, не останавливаясь. На
origin/dev до починки он находил ровно шесть файлов, после — ноль.

Issue: #407
User-Visible: no
2026-09-01 17:19:41 +03:00
claude[bot] 2fae84af58 docs: review document for #402
Проверка (CI) / Классификация изменённых файлов (push) Successful in 27s
Проверка (CI) / Предполётные проверки: документация, провенанс, процесс (push) Failing after 47s
Проверка (CI) / HACS: валидация репозитория (push) Failing after 23s
Проверка (CI) / Hassfest: манифест интеграции (push) Failing after 18s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 1m10s
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Failing after 4m16s
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Failing after 6m14s
Проверка (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: #402
User-Visible: no
2026-08-31 14:14:43 +00:00
Codex ccd870ddf7 build: refresh bundle trees and the doc capture for #402
User-Visible: no
Issue: #402
2026-08-31 16:47:53 +03:00
Codex 00b6f41233 fix: the danger confirmation lives outside render()'s branches (#402)
hp-confirm sat at the end of a chain of early returns, so in onboarding
(«no spaces yet»), in the fixed-floor states and without a space it did
not exist at all: the trash button next to a saved plan was dead and the
promise hung forever, because the decision event had no source in the
DOM. An already open dialog vanished the moment the card slipped into
one of those branches, leaving the caller waiting for a resolution that
could never come. Before #32 a browser confirm() worked there.

render() is now a wrapper: it takes the body — the old chain, unchanged,
as _renderBody — and renders the confirmation beside it. That fixes the
class rather than the instance: a branch added later cannot lose the
dialog again. noChange and nothing are passed through untouched, since
neither may be wrapped in a template; in those states _confirmDanger
refuses the request outright instead of leaving it pending, which is the
honest answer while the card is not on screen and the user has pressed
nothing.

_tapConfirm and _vacCalConfirm deliberately stay where they are. They
share the same final branch, but they have no promise (a synchronous
exec, a dialog closed by hp-close), so the defect cannot occur there,
and their entry points require a drawn plan.

Proven by a separate smoke rather than an addition to
smoke_danger_confirmation: that file keeps deliberately incomplete
dialog fixtures open, and the extra re-renders this change needs make
them throw. The new smoke runs under touch emulation, because
TOUCH-SUPPORT § Safety floor forbids bypassing a destructive
confirmation and the broken branch pierced that floor on finger as
surely as on mouse. Reverting the wrapper reddens it.

User-Visible: yes
Issue: #402
2026-08-31 16:47:05 +03:00
claude[bot] 931e49e3d6 docs: review document for #402
Issue: #402
User-Visible: no
2026-08-31 13:28:51 +00:00
Codex 11959e4c85 docs: #402 spec revision 2 per SPEC-REVIEW-402-r1
User-Visible: no
Issue: #402
2026-08-31 16:22:50 +03:00
claude[bot] 9b29df28db docs: review document for #402
Issue: #402
User-Visible: no
2026-08-31 13:19:34 +00:00
Codex d94db87ee7 docs: specify the branch-independent danger confirmation (#402)
User-Visible: no
Issue: #402
2026-08-31 16:08:52 +03:00
Matysh 4794183114 build: prepare v1.70.0-beta.2 candidate
Package HA Area marker relocation, unified dangerous confirmations, camera and marker-history fixes, beta polish and backend gate hardening.

Issue: #32
Issue: #126
Issue: #396
Issue: #397
Issue: #398
Issue: #399
Issue: #400
User-Visible: yes
v1.70.0-beta.2
2026-08-31 15:03:22 +03:00
claude[bot] bc076d3f50 docs: review document for #126
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Failing after 5m43s
Проверка (CI) / Предполётные проверки: документация, провенанс, процесс (push) Failing after 45s
Проверка (CI) / Классификация изменённых файлов (push) Successful in 21s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 1m16s
Проверка (CI) / HACS: валидация репозитория (push) Failing after 38s
Проверка (CI) / Hassfest: манифест интеграции (push) Failing after 43s
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Failing after 6m40s
Проверка (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: #126
User-Visible: no
2026-08-31 09:51:46 +00:00
Matysh 26cb00db24 docs: refresh canonical screenshots for area relocation
Issue: #126
User-Visible: no
2026-08-31 10:21:53 +03:00
Matysh d5268086c2 fix: harden HA area relocation regressions
Issue: #126
User-Visible: no
2026-08-31 10:16:46 +03:00
claude[bot]andMatysh 61dd7ccb89 docs: review document for #126
Issue: #126
User-Visible: no
2026-08-31 09:45:53 +03:00
Matysh b319fc9548 docs: refresh canonical screenshots
Issue: #126
User-Visible: no
2026-08-31 09:45:53 +03:00
Matysh 633cb20e59 fix: follow Home Assistant Area marker moves
Issue: #126
User-Visible: yes
2026-08-31 09:45:53 +03:00
claude[bot]andMatysh c8ef4f19e4 docs: review document for #126
Issue: #126
User-Visible: no
2026-08-31 09:45:52 +03:00
Matysh cdd9588ca6 docs: address HA area relocation review
Issue: #126
User-Visible: no
2026-08-31 09:45:52 +03:00
claude[bot]andMatysh bce0ae97b2 docs: review document for #126
Issue: #126
User-Visible: no
2026-08-31 09:45:52 +03:00
Matysh 59546662e6 docs: update HA area relocation contract
Issue: #126
User-Visible: no
2026-08-31 09:45:52 +03:00
Sergey MatyuninandMatysh 84f9901ca0 docs: specify HA area marker relocation
Issue: #126
User-Visible: no
2026-08-31 09:45:52 +03:00
Matysh 5c8cb58e1f ci: prove the screenshot environment instead of trusting the place
Правило приёмки скриншотов было про место: снимать только в CI. Обоснование
измерено — съёмка в другом окружении переписывает файлы без содержательных
изменений, в #231 два из девяти на 7–8 байт, набор с беты все девять. Но
держалось правило на комментарии, а не на механизме: кандидат проверялся на
самосогласованность и принимался целиком, ни разу не сравниваясь с тем, что
лежит в репозитории.

Цена видна на #390: правка типов, которая физически не может сдвинуть
пиксель, потребовала прогона workflow, а затем правки одиннадцати полей
манифеста руками.

Теперь правило про доказательство, и оно то же, что у golden с #334: среда
доказана, если каждый кадр, который менять не собирались, совпал с
закоммиченным байт-в-байт. Расхождение растеризации спрятать нельзя — оно
задевает все кадры с текстом сразу. Снимать можно где угодно, включая WSL;
принять получится только оттуда, где кадры воспроизводятся, и перестанет
получаться в тот день, когда обновятся шрифты.

Остальное следует из того же правила: намерение объявляется
--expect-change, необъявленное расхождение останавливает приёмку,
объявленное без расхождения — тоже (ложная декларация обесценивает список),
заменяются ровно объявленные файлы, а тотальная перерисовка требует
--no-witnesses --reason, и причина уезжает в манифест.

Частый случай закрылся сам: ничего не объявлено, все кадры совпали —
принимается один манифест, руками ничего писать не надо.

Проверено шестью сквозными прогонами на подделанном артефакте, не только
юнитами: идентичный кандидат, необъявленное расхождение, объявленное,
молчаливая декларация, тотальная перерисовка без причины и с ней.

Issue: #401
User-Visible: no
2026-08-31 09:40:52 +03:00
claude[bot] 4683a493cc docs: review document for #400
Issue: #400
User-Visible: no
2026-08-31 05:31:46 +00:00
claude[bot] 6a0bb985e7 docs: review document for #400
Issue: #400
User-Visible: no
2026-08-31 05:22:03 +00:00
Codex bd6722ccd2 build: refresh bundle trees and the doc capture for #400
User-Visible: no
Issue: #400
2026-08-31 08:14:55 +03:00
Codex d153b20a1d fix: make the handle paint order a named decision and mutate it (#400)
CODE-REVIEW-400-r1 Medium: the registered mutant edited a comment, not
the order — it could not reproduce the regression AC1 exists to catch.
That is the same defect class this issue is fixing elsewhere, in my own
guard.

The order is now HANDLE_PAINT_ORDER, a named constant, because it IS the
hit priority rather than an accident of where the blocks sit in the
template. The mutant flips that constant, so it reproduces exactly the
behaviour the audit found.

Also: smoke_furniture picked the SE corner as handles[3], an index that
silently depended on the old paint order — CI shard 3 went red on four
checks. It now selects by role (corner handles, third of four), which is
what the test actually means.

User-Visible: no
Issue: #400
2026-08-31 08:14:55 +03:00
claude[bot] f07e3c54ff docs: review document for #400
Issue: #400
User-Visible: no
2026-08-31 05:06:43 +00:00
Codex 73ecfbd1d7 build: refresh bundle trees and the doc capture for #400
User-Visible: no
Issue: #400
2026-08-31 07:57:02 +03:00
Codex fe3b85c06b fix: the corner handle wins on small furniture, guides exclude the real drag (#400)
(1) Corner and edge handles carry the same hit radius (1.8 % of the
view), so on furniture narrower than 4·hr — a 40 cm cabinet — the two
circles overlap and whichever is painted last takes the tap. Edges were
painted last. Corners are now, because a side handle scales one axis
while a corner scales both, and the object is small exactly when
proportional resize matters most. The visible beads are unchanged.

The audit called this 'proportional resize becomes unavailable'; the
measurement says otherwise and the spec records the correction: the
corner centre lies outside the edge circle, so the corner was reachable
— its area was halved, not lost. A polish, not a bug, and worth fixing
because it is one line of ordering.

(2) Alignment guides in the devices mode excluded the dragged marker by
_drag, which has been null there since #74 moved device dragging into
_deviceDrag. So the marker being moved was among its own candidates.
Nothing looked wrong because a point always matches itself within
tolerance — the guide was drawn from the marker to itself, visually
identical to an honest one, and the smoke asserted only guides() >= 1.
The smoke now compares the candidate lists with and without the drag and
demands exactly one removed entry.

(3) The 38 settings-help strings stay in the initial chunk, and that is
now a recorded decision rather than an oversight: measured 2 654 B gzip,
0.9 % of the ceiling, against splitting a synchronous dictionary in two,
a second request on first hint, and a second source for the key type
derived from en.json (#391). docs/ARCHITECTURE.md says so, with the
number that would justify revisiting it.

Both mutants run by hand: reverting the paint order reddens the 40 cm
probe while the 160 cm one stays green; restoring _drag reddens the
guides smoke.

User-Visible: yes
Issue: #400
2026-08-31 07:56:27 +03:00
claude[bot] 532743b01c docs: review document for #400
Issue: #400
User-Visible: no
2026-08-31 04:45:04 +00:00
Codex 60c211c82a docs: specify the beta polish batch (#400)
User-Visible: no
Issue: #400
2026-08-31 07:36:44 +03:00
claude[bot] 6bf39ee9a7 docs: review document for #399
Проверка (CI) / Классификация изменённых файлов (push) Successful in 20s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 33s
Проверка (CI) / HACS: валидация репозитория (push) Failing after 15s
Проверка (CI) / Предполётные проверки: документация, провенанс, процесс (push) Failing after 44s
Проверка (CI) / Hassfest: манифест интеграции (push) Failing after 17s
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Failing after 4m55s
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Failing after 5m59s
Проверка (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: #399
User-Visible: no
2026-08-31 01:54:28 +00:00
Codex 5c4d8cba9e test: prove AC5 by running the scanner, not the predicate (#399)
CODE-REVIEW-399-r1 High: the test named after AC5 called
installsPythonDeps on string literals and never executed the directory
walk it was supposed to protect. The reviewer showed what that costs:
restoring the old hardcoded pair of real names and dropping a third
workflow with unpinned installs into .github/workflows left all ten
checks green — the exact scenario AC5 describes went undetected.

The walk is now a function taking the directory, so the test can run it
for real: it builds a temporary directory with three files (a pinned
installer, a workflow that installs nothing, and a rogue one) and
asserts on what the scanner returns. Reverting the walk to a list of two
real names now reddens this test, verified by hand.

The mutant is sharpened accordingly: it substitutes the two-name list
instead of a one-name list. The old form failed on an unrelated
assertion about directory size, so it proved nothing about the scan
itself — while the two-name form is indistinguishable from correct code
on today's tree, which is what makes it the likely regression.

User-Visible: no
Issue: #399
2026-08-31 04:48:41 +03:00
claude[bot] 8b2a146c6c docs: review document for #399
Issue: #399
User-Visible: no
2026-08-31 01:44:20 +00:00
Codex 98028a3093 ci: the backend gate now checks exactly what it promises (#399)
Three claims a green backend used to make, each slightly wider than the
truth — and #392 happened in exactly that gap.

The frontend pin said 20260826.1 next to homeassistant==2026.8.3, whose
package_constraints.txt requires 20260729.7: a combination that exists
in no HA release. It was never derived from anything — someone once
picked it. It is now taken from the constraints, the source is named in
the file, and a test holds both numbers together so raising HA cannot
quietly desync them.

ruff's include declared three trees while CI linted one. Narrowed the
declaration rather than widening CI: the debt in scripts/ and
tests_backend/ (56 findings, mostly E402/I001, plus 7 B023 and 5 B017)
has its own cost and its own decisions, and belongs in its own task, not
in a visibility fix. test/lint-scope.test.mjs now compares the two, so
they can only move together.

The pin check skipped a workflow when it found neither the package name
nor the requirements path — and both vanish together the moment someone
returns to Defaulting to user installation because normal site-packages is not writeable, i.e. the gate switched itself off
under precisely the change it exists to catch. It now walks the whole
.github/workflows directory and decides per file by a positive sign: if
a file installs python packages, it must install them from the pins
file. Verified by dropping a rogue workflow into the directory — it
reddens without touching any list.

Three mutants registered and each run by hand.

User-Visible: no
Issue: #399
2026-08-31 04:35:56 +03:00
claude[bot] cc44b28f3b docs: review document for #399
Issue: #399
User-Visible: no
2026-08-31 01:31:41 +00:00
Codex bb635298c1 docs: #399 spec revision 3 per SPEC-REVIEW-399-r2
User-Visible: no
Issue: #399
2026-08-31 04:26:14 +03:00
claude[bot] 6befe4168f docs: review document for #399
Issue: #399
User-Visible: no
2026-08-31 01:23:19 +00:00
Codex 6d229c66f1 docs: #399 spec revision 2 per SPEC-REVIEW-399-r1
User-Visible: no
Issue: #399
2026-08-31 04:16:18 +03:00
claude[bot] 627a5359c3 docs: review document for #399
Issue: #399
User-Visible: no
2026-08-31 01:14:10 +00:00
Codex a1d7e0da55 docs: specify the backend gate honesty fixes (#399)
User-Visible: no
Issue: #399
2026-08-31 04:06:40 +03:00
claude[bot] f7fb3369b7 docs: review document for #398
Issue: #398
User-Visible: no
2026-08-31 01:05:33 +00:00
Codex d9b6766362 test: the sys.modules guard now sees the write, not its spelling (#398)
The guard introduced by #394 matched the literal
sys.modules['custom_components... and therefore never looked at
pure_imports.py, which writes through a variable — the third instance of
the #389 class walked straight past the check created for it.

The guard now inspects the write itself and decides by the key: a whole
literal or the literal head of an f-string is safe unless it starts with
custom_components (that is how tests register homeassistant.*, hp_pure.*
and houseplan.trails); anything else — a variable, a concatenation,
setdefault/update — counts as a violation whenever the file is able to
name the package at all, i.e. contains a custom_components. literal. A
file that never names the package cannot poison it through a variable,
so restoring a snapshot stays legal.

load_pure now removes what it registered. Removing its own name is not
enough: relative imports pull neighbours in, so junction_limits leaves
wall_segment_model and coordinate_canonicalization behind. It removes
the whole custom_components difference accumulated during exec_module,
in a finally, and a repeated call still works.

pure_imports.py is a named exemption of the static guard precisely
because that guard cannot see the cleanup — so the cleanup is proven by
an executable test instead, and the mutant pure-imports-stops-cleaning
reddens it. Both mutants were run by hand.

User-Visible: no
Issue: #398
2026-08-31 03:56:01 +03:00
claude[bot] 2b3cabe7e0 docs: review document for #398
Issue: #398
User-Visible: no
2026-08-31 00:47:06 +00:00
Codex 9fde407e4e docs: #398 spec revision 3 per SPEC-REVIEW-398-r2
User-Visible: no
Issue: #398
2026-08-31 03:40:36 +03:00
claude[bot] 692e3b72f4 docs: review document for #398
Issue: #398
User-Visible: no
2026-08-31 00:38:50 +00:00
Codex 480d202fa5 docs: #398 spec revision 2 per SPEC-REVIEW-398-r1
User-Visible: no
Issue: #398
2026-08-31 03:30:10 +03:00
claude[bot] a4b686a7fe docs: review document for #398
Issue: #398
User-Visible: no
2026-08-31 00:26:38 +00:00
Codex 69dd09a7c9 docs: specify the sys.modules guard scope fix (#398)
User-Visible: no
Issue: #398
2026-08-31 03:17:55 +03:00
claude[bot] 037a19d093 docs: review document for #397
Issue: #397
User-Visible: no
2026-08-31 00:15:10 +00:00
Codex f4c66bed3f test: prove AC3 on the reconnect path, with a probe that can fail (#397)
CODE-REVIEW-397-r1 Medium: AC3 named the second reader of the same
value — _loadFromServer via _adoptStructuralResponses — and nothing
exercised it. Adding the scenario turned out to be less mechanical than
it looked, and both obstacles are worth recording:

The reconnect path reads BOTH answers, and a differing config clears the
history for its own reason (configChanged). The fake server now echoes
the config the card already holds, so the check answers the layout
question it claims to answer.

The first version of the probe used a round 0.42, which canonicalization
leaves untouched — the check passed with and without the fix, i.e. for
the wrong reason. The probe now starts from a non-canonical position
(0.024999999999999942, which snaps to 0.025), and the scenario runs
immediately after the write, before any reload can align the two sides.

Verified by removing the fix: five checks red, now including
reconnectKeepsHistory and deleteEchoKeepsHistory. Both were green in the
weaker version — which is exactly what the reviewer's Medium was about.

User-Visible: no
Issue: #397
2026-08-31 03:03:59 +03:00