Добавлены безопасные pinned entrypoints, вывод фактических путей, идемпотентный Windows setup и WSL verification с настоящим HA subset и Linux capture.
Issue: #557
User-Visible: no
`release-zip.yml` выкладывал `houseplan.zip` в ту же секунду, когда релиз
становился публичным — до Validate, Full Performance и E2E; `release.yml`
параллельно пересобирал `houseplan-card.js`, а E2E требовал публичного ZIP,
чтобы вообще начаться. Публикаторов было четыре, порядок — ни одного.
Теперь публикатор стабильных один — `release.yml`: закрепить SHA → релиз в
черновике (опубликованный руками немедленно возвращается в черновик) → гейты
на SHA (трейлер `Release: <tag>`, контракт `--stable`, Validate, Full
Performance, E2E на коммите-кандидате через tarball codeload) → одна сборка,
`git archive` ZIP из того же дерева, `SHA256SUMS` → загрузка в черновик →
публикация → скачать публичное и сверить с паспортом → анонс. Dispatch на
публичный тег — ремонт: догружается только недостающее, расходящийся хеш —
отказ. Беты кладут тот же паспорт; локальный публикатор больше не ждёт
републикаторов — их нет.
- `.github/workflows/release-zip.yml` удалён
- `scripts/release-assets.mjs` — паспорт ассетов (`sums`/`check`), чистые
функции под юнитами
- `scripts/e2e-gate.mjs --ref=<sha>` — под тестом кандидат, `--tag` только
для выбора `upgrade_from`
- `scripts/release-contract.mjs --stable`
- мутанты: независимый публикатор, снятая зависимость от гейта, релиз без
возврата в черновик, `--clobber` в ремонте, E2E на теге, слепой паспорт
Issue: #540
User-Visible: no
Сводная панель теперь использует канонический порядок карточек Home Assistant и не переносит локальные настройки между визуальными колонками после remount.
Issue: #561
User-Visible: yes
`release-contract.test.mjs` требовал в анонсе условие про
`github.event_name == 'release'` — оно и было единственным местом, где путь
события закреплялся. Раз анонс вызывается только после выкладки, требование
перевёрнуто: ветки события в файле быть не должно.
Issue: #538
User-Visible: no
Мутант, снимающий `needs: build` с анонса, выживал: проверка искала подстроку
`needs: build` в блоке задания, а ровно эта строка процитирована двумя
строками выше — в комментарии, объясняющем, зачем зависимость нужна. Проверка
зеленела на собственном объяснении.
Issue: #538
User-Visible: no
Три воркфлоу висели на одном событии `release: published` и бежали
параллельно. Анонс выигрывал эту гонку всегда: проверять ему нечего. 12.09
стабильную v1.75.0 объявили в канале в ту же минуту, когда гейт отказал —
Full Performance был красный (#537), E2E после него не выполнялся вовсе,
ассеты не выкладывались. Подписчики получили сообщение о релизе, страница
которого осталась без `houseplan-card.js`.
Триггер события снят: у анонса остаются кнопка проверки связи и вызов из
воркфлоу. `release.yml` зовёт его после джобы выкладки (`needs: build`), то
есть красный гейт или несостоявшаяся выкладка сообщения не рождают. Путь беты
не тронут — `publish-prerelease.yml` звал анонс сам и раньше.
Мёртвая ветка чтения события из шага убрана вместе с триггером: тело берётся
из заметок ветки тега, как в вызове из беты.
Issue: #538
User-Visible: no
Мутант, выкидывающий сравнение ответа REST с новой вершиной, выживал: проверка
смотрела на вызов `gh api`, токен, порядок шагов и текст отказа — всё это
мутант оставляет на месте, а цикл после него выходит на первой же итерации, и
ожидание становится декорацией.
Issue: #539
User-Visible: no
`workflow_dispatch` в API принимает только ref: SHA туда передать нельзя, имя
ветки резолвится на стороне GitHub в момент запуска. Конвейер перед этим сам
переписывает ветку ребейзом — и 12.09 на #536 диспатч, отправленный через три
секунды после force-push, встал на ДОпушевый SHA. Гейт искал прогон строго на
SHA материала, не нашёл и вернул задачу автору со словами «материал сменился».
Чинить было нечего: дерево задачи не менялось ни на байт, материал сдвинул сам
конвейер.
Две меры, у каждой своя роль.
Шаг ребейза не заканчивается, пока REST не отдаст новую вершину — именно REST,
потому что через него же идёт диспатч. Минута ожидания, после чего отказ, а не
молчание: диспатч на устаревший SHA стоит трёх минут гейта и потерянного
захода.
Гейт, не дождавшись прогона на материале и увидев на ветке диспатч на другом
SHA, сначала пробует запустить ещё раз. Своя гонка этим закрывается, чужой
коммит переживает и вторую попытку, а формулировка отказа больше не называет
сменой материала то, что ею не является.
Issue: #539
User-Visible: no
The performance harness runs the candidate's benchmark against a
baseline checkout, so the candidate's validator reads a manifest built
by an older commit. #535 put a rule about the CURRENT build into that
shared validator — the panel graph must not contain the card facade —
and it is false of every build before #535 by construction. The
candidate then refused to load any older baseline: all nine performance
profiles went red at once on the same step, the stable release gate
withheld `houseplan-card.js` from the published v1.75.0, and none of it
was about speed.
assertBundleManifest now answers only the loader's question: paths
exist, nothing is duplicated, graphs reference listed assets, sizes add
up. The topology of the current build moves to assertOwnBundleTopology,
called from bundle-sync.mjs, which materializes our own dist, and from
the unit test that reads dist/houseplan-assets.json. Neither ever looks
at a foreign tree.
Reproduced end to end, not only in a unit: a v1.74.0 worktree built with
its own code, then `node demo/benchmark_large_house.mjs
--target-root=<baseline>` from this tree. Before the change it stops
with «initial panel graph must contain its own stable entry only»; after
it, the profile is captured.
Issue: #537
User-Visible: no
Promotion-only on top of v1.75.0-beta.1: seven version sources, the
generated bundle snapshots and the release metadata. No product source
code moves in this commit.
The line aggregates from the stable v1.74.0 and carries one user-visible
fix. The House Plan sidebar page could serve a previous version of the
card for hours: the panel entry fetched it through `./houseplan-card.js`,
a relative specifier, and relative resolution does not inherit the `?v=`
a dashboard gets from its Lovelace resource, while the entry files carry
no Cache-Control at all. The panel now imports the implementation by its
content-hashed name, so either the matching card arrives or the panel
says out loud that the page is stale (#535). Internal in the line: #536.
Known contradiction, recorded rather than silenced: the release contract
in scripts/release-contract.mjs requires the grouped "small fixes"
bullet unconditionally, while `npm run release:notes -- v1.75.0
--verify` rejects it because every user-visible issue of the range is
already itemised. The two rules deadlock any stable with a single
user-visible issue. The bullet stays, because the contract is the
automated gate that Validate enforces; the verifier's objection is
written down in STATUS and will get its own issue.
npm test 2532/2531/0 fail, release contract green on all seven sources,
docs strict green.
Issue: #535
User-Visible: yes
Release: v1.75.0
Seven version sources move together to 1.75.0-beta.1, both changelogs
close their section over what has landed since the stable v1.74.0, the
release notes carry the one shipped bullet on each side with the grouped
small-fixes bullet last, and STATUS says what this beta is.
What the user gets: the House Plan sidebar page can no longer serve a
previous version of the card. The panel entry fetched it through
`./houseplan-card.js` — a relative specifier, and relative resolution
does not inherit the `?v=` a dashboard gets from its Lovelace resource,
while the entry files carry no Cache-Control at all. A browser was free
to answer from its own heuristic cache for hours, and a stale loader
named a stale immutable chunk, so the panel ran an old card against the
current backend with nothing but the version banner to show for it —
and reloading could not help, because the address never changed (#535).
Internal in the line: #536 — the version banner now asks the host to
repaint when it drops the notice on disconnect, instead of leaving its
removal to whatever unrelated update happened to run next.
npm test 2532/2530/0 fail (the #349 manifest-tracking check goes green
with this commit), release contract green on all seven sources, bundle
287 323 B gzip inside the ceiling, docs strict green.
The `Release:` trailer is what asks CI for the heavy gates — smokes,
golden and the full performance comparison — on this exact SHA (#479).
Issue: #535
User-Visible: yes
Release: v1.75.0-beta.1
The controller dropped its banner on disconnect without asking the host
to repaint. Lit renders neither on disconnect nor on reconnect, so the
markup produced before the detach outlived it: the notice stayed on
screen while the controller no longer owned one, and it left only when
some unrelated update happened to run. Correctness rested on a
coincidence.
Measured on the built module with a counter: the sequence mismatch ->
disconnect -> versions agree -> connect asked for exactly one repaint,
the one that showed the notice. It now asks for two, and the second is
the one that takes the notice away.
Nothing else about the teardown changes. The field is still cleared
because a detached element cannot deliver animationend, reconnect still
rebuilds the notice from the retained input, and a disconnect with no
notice still asks for nothing.
Issue: #536
User-Visible: no