Commit Graph
2228 Commits
Author SHA1 Message Date
Codexandclaude[bot] f36ded7fc2 feat(relay): receive support reports on the project stand (#43)
User-Visible: no
Issue: #43
2026-09-02 00:05:36 +00:00
claude[bot] 4bdd266fbb docs: review document for #43
Issue: #43
User-Visible: no
2026-09-02 00:05:36 +00:00
Sergey Matyuninandclaude[bot] 65e0c2deed docs: address support spec review
Issue: #43
User-Visible: no
2026-09-02 00:05:36 +00:00
claude[bot] 5bab93c421 docs: review document for #43
Issue: #43
User-Visible: no
2026-09-02 00:05:36 +00:00
Sergey Matyuninandclaude[bot] 8074612f6b docs: rewrite support feedback spec
Issue: #43
User-Visible: no
2026-09-02 00:05:36 +00:00
claude[bot] 319b25c281 docs: review document for #411
Issue: #411
User-Visible: no
2026-09-01 21:16:15 +00:00
Sergey Matyunin 9d5c0357b0 test: keep grid scale static fixture coherent
Issue: #411
User-Visible: no
2026-09-02 00:08:02 +03:00
Matysh 2d143b570f ci: stop truncating the numbers a failing smoke printed
smoke_grid_scale_invariance сообщает, НАСКОЛЬКО разошлись кадры: строка
pixel-diffs с changed, maxDelta и meanDelta по каждой паре. Введена в #302
ровно затем, чтобы падение не было голым boolean.

В логе прогона её не видно: шаг шарда печатает tail -20, а диагностика идёт до
вердикта и срезается. На #411 это и вышло — в логе осталось только «expected
true, got false», а числа, по которым видно, превышение порога это или
расхождение слоя, пришлось бы искать в артефакте.

Строки достаются адресно, перед хвостом лога. Они и есть разница между
«чинить» и «гадать».

Issue: #411
User-Visible: no
2026-09-01 23:52:36 +03:00
Matysh 4fa670e873 docs: accept deterministic documentation screenshots
Accept the canonical Linux capture after rasterisation flags and whole-pixel clipping changed every frame.

Issue: #410
User-Visible: no
2026-09-01 23:36:05 +03:00
Matysh ca0b318e5e ci: make the stability measurement a gate, not a printout
Замер сделал свою работу — теперь он остаётся как проверка. Если кадр снова
начнёт зависеть от времени, шаг упадёт, а не напечатает число в лог. Стоит
перед съёмкой набора: публиковать артефакт, снятый недетерминированной
съёмкой, смысла нет.

Issue: #410
User-Visible: no
2026-09-01 23:20:09 +03:00
Matysh ed700c8c8e fix: crop the documentation frames on whole pixels
Замер снял главное: три снимка подряд в одном состоянии страницы совпадают
побайтово у всех десяти сценариев. Значит рендер детерминирован, а плавает то,
что приходит на вход съёмке.

Обрезка считается из живого DOM через getBoundingClientRect и приходит
дробной. Дробная обрезка заставляет Chromium ресемплить кадр — и тогда сдвиг
раскладки на десятую пикселя переписывает границы всех элементов на единицы
уровней. Ровно эта подпись в #410: 76 пикселей, максимум 2 уровня, alpha не
тронута, всё на сглаженных границах полей.

Рамка расширяется наружу, а не округляется к ближайшему: обрезка обязана
содержать цель целиком.

Issue: #410
User-Visible: no
2026-09-01 23:13:59 +03:00
Matysh d945b03208 test: measure whether the frame drifts inside one page state (#410)
Флаги растеризации убрали один кадр из трёх, но device-editor и device-info
плавают по-прежнему. Дальше гадать нельзя: нужен ответ, плавает ли кадр внутри
одного состояния страницы или разница копится между подготовками сценария.

Режим --stability=N делает N снимков подряд без единой правки состояния и
сравнивает их попиксельно в самой странице — тем же приёмом, что у golden.
Печатает число различающихся пикселей, максимум по RGB, задета ли alpha и
bbox.

Ветка временная.

Issue: #410
User-Visible: no
2026-09-01 23:09:05 +03:00
Matysh 823fc316b2 fix: pin rasterisation for the documentation capture
Съёмка скриншотов документации запускалась вообще без флагов детерминизма,
тогда как golden имел их с самого начала. Отсюда и плавающие кадры: включённое
субпиксельное сглаживание даёт разный результат от прогона к прогону, а
дельта — единицы уровней в RGB на сглаженных границах при неизменной alpha —
это его подпись, а не изменение продукта.

Измерено до починки: два прогона канонического workflow на одном и том же
dev SHA 184e0098, одном Chromium 151.0.7922.34 и одном oxipng 10.2.0 дали три
разошедшихся кадра из десяти — 06-device-editor, 08-room-card, 09-device-info.

Взяты те же три флага, что у golden: --disable-lcd-text снимает субпиксельное
сглаживание, --font-render-hinting=none — зависимость от хинтинга,
--force-color-profile=srgb фиксирует профиль. Добавлен reducedMotion: 'reduce'
и два кадра ожидания перед съёмкой: animations: 'disabled' гасит анимации, но
не гарантирует, что запланированный ре-рендер успел лечь в композитор.

Байтовый контракт приёмки не ослаблен ни в одном месте — чинится источник
шума, а не проверка.

Правка меняет capture.mjs, поэтому captureScriptSha256 в манифесте протух и
check-docs красный до пересъёмки. Пересъёмка неизбежна и по существу: с
выключенным субпиксельным сглаживанием переписываются все десять кадров сразу,
то есть приёмка идёт через --no-witnesses --reason.

Issue: #410
User-Visible: no
2026-09-01 22:59:17 +03:00
Matysh 184e009806 ci: print frame hashes so two capture runs can be compared
Чтобы измерить недетерминированность съёмки, нужен текст, который видно с
экрана: артефакт для этого не годится — его надо скачать и распаковать. Шаг
печатает sha256 каждого кадра, и два прогона одного SHA сравниваются
построчно.

Сначала измерение, потом починка (#410).

Issue: #410
User-Visible: no
2026-09-01 22:52:00 +03:00
claude[bot] 36e1b7f9c2 docs: review document for #405
Issue: #405
User-Visible: no
2026-09-01 19:48:07 +00:00
Sergey Matyunin 24af34ccba docs: refresh #405 screenshot source fingerprint
Проверка (CI) / Классификация изменённых файлов (push) Successful in 27s
Проверка (CI) / HACS: валидация репозитория (push) Skipped
Проверка (CI) / Hassfest: манифест интеграции (push) Skipped
Проверка (CI) / Предполётные проверки: документация, провенанс, процесс (push) Failing after 1m10s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 40s
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Skipped
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Failing after 17m35s
Проверка (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
Canonical run 33549400366; the 76-pixel raster flake is tracked in #410.

Issue: #405
User-Visible: no
2026-09-01 22:36:15 +03:00
Sergey Matyunin b4809a12ff fix: await draft deletion through the card facade (#405)
Issue: #405
User-Visible: no
2026-09-01 22:23:57 +03:00
claude[bot] e926ea453e docs: review document for #405
Issue: #405
User-Visible: no
2026-09-01 19:20:46 +00:00
Sergey Matyunin d5c93d4e28 docs: revise #405 spec after review
Issue: #405
User-Visible: no
2026-09-01 22:14:26 +03:00
claude[bot]andSergey Matyunin bf40e26ed0 docs: review document for #405
Issue: #405
User-Visible: no
2026-09-01 22:12:14 +03:00
CodexandSergey Matyunin 2c6d937d46 docs: specify draft delete awaiting and witness floor (#405)
User-Visible: no
Issue: #405
2026-09-01 22:12:13 +03:00
claude[bot] 9c9a22354b docs: review document for #406
Проверка (CI) / Классификация изменённых файлов (push) Successful in 22s
Проверка (CI) / Предполётные проверки: документация, провенанс, процесс (push) Failing after 39s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 1m0s
Проверка (CI) / HACS: валидация репозитория (push) Failing after 24s
Проверка (CI) / Hassfest: манифест интеграции (push) Failing after 25s
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Failing after 16m42s
Проверка (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 6m24s
Issue: #406
User-Visible: no
2026-09-01 16:32:25 +00:00
claude[bot] 77a22efc78 docs: review document for #406
Issue: #406
User-Visible: no
2026-09-01 16:32:25 +00:00
Sergey Matyuninandclaude[bot] 269d828dd4 chore: refresh docs source fingerprint
Docs screenshots run 33530447151; all 10 canonical PNGs matched byte-for-byte and only the source fingerprint changed.

Issue: #406
User-Visible: no
2026-09-01 16:32:25 +00:00
Sergey Matyuninandclaude[bot] 816b1476f0 fix: preserve the ordinary dialog path
Issue: #406
User-Visible: no
2026-09-01 16:32:25 +00:00
Sergey Matyuninandclaude[bot] 372d838ec2 fix: close beta 2 polish gaps
Issue: #406
User-Visible: yes
2026-09-01 16:32:25 +00:00
claude[bot] 8273af59ca docs: review document for #406
Issue: #406
User-Visible: no
2026-09-01 16:32:25 +00:00
Sergey Matyuninandclaude[bot] 7806ab7182 docs: document confirm shell tradeoff
Issue: #406
User-Visible: no
2026-09-01 16:32:25 +00:00
claude[bot] da82ab9199 docs: review document for #406
Issue: #406
User-Visible: no
2026-09-01 16:32:25 +00:00
Sergey Matyuninandclaude[bot] c3bb62a3b6 docs: resolve beta2 polish review
Issue: #406
User-Visible: no
2026-09-01 16:32:25 +00:00
claude[bot] bd780c6013 docs: review document for #406
Issue: #406
User-Visible: no
2026-09-01 16:32:25 +00:00
claude[bot] b3f22b33e4 docs: review document for #406
Issue: #406
User-Visible: no
2026-09-01 16:32:25 +00:00
Sergey Matyuninandclaude[bot] aad1eeaa10 docs: revise beta2 polish spec
Issue: #406
User-Visible: no
2026-09-01 16:32:25 +00:00
Codexandclaude[bot] 15ff625964 docs: specify the beta.2 polish batch (#406)
User-Visible: no
Issue: #406
2026-09-01 16:32:25 +00:00
Matysh 8ac8f0105a fix: let the product build the marker-dialog fixture
Прогон показал, что дописать binding и bindingMode было мало: у объявленного
типа больше сорока обязательных полей, и рендер упал на следующем
недостающем — теперь на name внутри _markerDraft. Гоняться за типом руками
бессмысленно.

Смок открывает диалог штатным _openMarkerDialog() и переопределяет три поля.
Это заодно и доказательство, что дефекта поведения нет: продукт своим же
путём собирает объект, на котором рендер не падает.

Issue: #404
User-Visible: no
2026-09-01 19:19:05 +03:00
Matysh 2903374b72 fix: the exception guard reads its counter after delivery, not before
Гард «uncaught exception внутри карточки» жил в demo/serve.mjs с 2026-07-27 и
не срабатывал ни разу в самом частом случае. Счётчик читался синхронно, а
Playwright доставляет pageerror асинхронно по CDP: если исключение возникло
после последнего обращения смока к странице, счётчик к моменту проверки
нулевой, а browser.close() уносит недоставленное событие. В логе это видно
дословно — EXC печатается после результата и до OK.

finish() теперь делает round-trip по открытым страницам перед чтением
счётчика. Страницы регистрируются там, где создаются: ссылок на них у
finish(browser, out) нет, а менять сигнатуру нельзя — так её зовут 205
смоков.

Medium-1 жёлтого ревью ТЗ закрыт расширением, а не оговоркой. Страницы,
созданные смоком после launch(), регистрация в launchInternal не покрывает:
smoke_zoom_flash печатал своё EXC2 мимо счётчика, три страницы
smoke_svg_sandbox не имели слушателя вовсе. Документировать слепую зону в
задаче, которая существует ради устранения слепой зоны, значит закрыть issue,
оставив дефект. Наружу отдана одна функция watchPage(page): подписка и
регистрация неразделимы, иначе появится страница, чьи исключения считаются, а
доставки не ждёт никто.

Разрыв оказался шире, чем в ревью: проверка по всему набору нашла ещё два
файла со своей подпиской — smoke_cold_view_toggle и smoke_cold_view_vacuum.
Они не слепая зона, их страница приходит из launchColdView и уже
зарегистрирована, а свой счётчик они превращают в отдельное утверждение.
Поэтому инвариант сформулирован как «ни одна страница не создаётся мимо
гарда» и закреплён по всему набору, а не по двум названным файлам.

reportPageErrors() из #407 стал асинхронным: второй читатель счётчика обязан
ждать доставку так же, как finish(). Пять смоков получили await.

Фикстура smoke_danger_confirmation приведена к объявленному типу: без binding
и bindingMode _bindingHasHaPage падал на undefined.split(':') — два
исключения, которых гард не видел. Дефекта поведения нет, все 15 мест в src/,
создающих диалог, binding пишут; врала фикстура.

Два отступления от ТЗ, каждое по измеренной причине. Пробы лежат в
demo/guard/, а не demo/fixtures/: последний входит в корпус sourceFingerprint,
и каждый файл там объявил бы устаревшими бандл, скриншот-индекс и
golden-индекс — пробы же не касаются ни одного пикселя. Поведение
доказывается в job со браузером, а не в npm test: job «Фронтенд» браузеры не
ставит, и тест молча скипался бы — тот самый тихий успех, против которого вся
задача.

Issue: #404
User-Visible: no
2026-09-01 19:08:07 +03:00
claude[bot] b04387ce91 docs: review document for #403
Issue: #403
User-Visible: no
2026-09-01 15:08:22 +00:00
Sergey Matyuninandclaude[bot] 2274e6eb84 docs: refresh canonical screenshots
Docs screenshots run 33521193808; all 10 pairs were visually reviewed. The explicit no-witnesses reason is recorded in screenshots.json because the prior rasterization baseline is no longer reproducible.

Issue: #403
User-Visible: no
2026-09-01 15:08:22 +00:00
Sergey Matyuninandclaude[bot] 355b0516c7 fix: preserve area relocation state
Issue: #403
User-Visible: yes
2026-09-01 15:08:22 +00:00
claude[bot] 09613ce322 docs: review document for #403
Issue: #403
User-Visible: no
2026-09-01 15:08:22 +00:00
Sergey Matyuninandclaude[bot] 98d6edb7b2 docs: revise area relocation safety spec
Issue: #403
User-Visible: no
2026-09-01 15:08:22 +00:00
claude[bot] 64f48e7ffd docs: review document for #403
Issue: #403
User-Visible: no
2026-09-01 15:08:22 +00:00
Codexandclaude[bot] 8e7c927264 docs: specify area relocation safety (#403)
User-Visible: no
Issue: #403
2026-09-01 15:08:21 +00:00
Matysh 8119c523fa fix: the screenshot witness floor comes from the set, not from survivors
Тот же дефект, что #408 у golden, и в моём же коде из #401. Порог свидетелей
считался от числа кадров, уцелевших на диске: rm docs/images/*.png плюс
объявить все десять через --expect-change — уцелевших ноль, порог ноль,
причины никто не спрашивает, а в манифесте остаётся {"witnesses":0,"floor":0}
без единого слова о произошедшем. Щель была описана в комментарии над самой
функцией и оставлена открытой.

Порог теперь от набора сценариев, свидетели — из тех, с кем есть что
сравнить. Разделение принципиальное: удаление кадров лишает доказательств, но
не должно снижать планку. Первичная съёмка идёт через --no-witnesses
--reason, как теперь и в golden.

Отдельного параметра размера, как в golden, здесь не нужно, и это не
небрежность: `ids` и есть набор — docs-accept.mjs передаёт DOC_SCREENSHOTS, а
verifyDocsCandidate до того отказывает, если набор сцен в кандидате не совпал
с ожидаемым. Пустой ids — отказ, а не ноль.

Попутно Low из #405: повторная приёмка неизменённого набора затирала
acceptance.declared пустым списком. След приёмки отвечает на вопрос «когда
эти пиксели приняли и что тогда объявляли», а обновление отпечатка пикселей
не меняет — значит и стирать ответ не должно. Прежний след сохраняется и
помечается lastWriteWasFingerprintOnly.

Заодно отказ по свидетелям теперь возвращает сами числа: вызывающий печатает
свой вердикт, и сочинять их заново ему не из чего.

Issue: #409
User-Visible: no
2026-09-01 17:54:48 +03:00
Matysh cd0ecf4db2 fix: the witness floor comes from the matrix, not from surviving baselines
Порог свидетелей считался от числа сцен со статусом не missing-baseline, то
есть от эталонов, уцелевших на диске. Обход в одну команду: git rm
demo/golden/baselines/*.png — все сцены становятся missing-baseline, порог
обращается в ноль, свидетелей никто не требует, и чужая съёмка всей матрицы
принимается без единого следа причины в манифесте. Отказ
goldenAcceptanceRefusal этого не ловит: он требует объявить каждую новую сцену
в --expect-new, а объявить их все ничто не мешает.

Прежняя редакция объясняла ноль тем, что первичная съёмка свидетелей иметь не
может. Верно по факту и неверно по выводу: невозможность доказать среду не
отменяет требования, она требует сказать это вслух. Теперь и первичная съёмка
идёт через --no-witnesses --reason, а причина уезжает в манифест эталонов.

Размер матрицы стал обязательным параметром, а не выводится из отчёта: у
частичного прогона (run.mjs --only=…) results короче матрицы, и порог просел
бы молча — тот же дефект в другой одежде. Отсутствие параметра — отказ.

Формула не менялась: она общая с docsWitnessFloor и обязана такой остаться.
Менялся источник счётчика. На обычной приёмке ничего не меняется: при 143
эталонах порог был и остался 10.

Issue: #408
User-Visible: no
2026-09-01 17:25:54 +03:00
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