Добавлены безопасные 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
The sidebar page could serve a previous card for hours. It imported the
card through the stable facade, `./houseplan-card.js` — a relative
specifier, and relative resolution does not inherit a query. A dashboard
reaches the same file as `houseplan-card.js?v=1.74.0`, so an upgrade
changes its URL and the browser must refetch. The panel always asked for
the same address, and entries are served with no Cache-Control at all —
only ETag and Last-Modified — so the browser applies heuristic freshness
and may answer from cache without asking. A stale 1164-byte loader names
a stale chunk, chunks are immutable for a year, and the panel then ran a
previous card against the current backend without a single error. The
version banner was telling the truth; reloading could not help, because
the address never changed.
Rollup already emits the right edge: the panel's side-effect import
points straight at the shared implementation. The rewrite in
entryFallbackPlugin replaced it with the facade for a fallback that the
hashed name gives anyway — and better: a chunk the manifest no longer
serves now raises the panel's own "House Plan was updated" notice
instead of silently working on old code.
Two #486 assertions change meaning and are rewritten, not adjusted: the
panel no longer routes through the facade, and its initial graph no
longer contains it. The invariant they defended — the panel reuses the
exact card graph, never a second copy — is now stated over the
implementation, and a new test pins that no built entry reaches the card
by an address without a version.
Issue: #535
User-Visible: yes
Обе задачи вошли в стабильный тег кодом, но их строки чейнджлога остались под
«Не выпущено»: #532 и #534 закрывались в тот же день, что и сам выпуск, и
секция версии к тому моменту уже была закрыта. Тело релиза при этом не называло
ни ту, ни другую — обе молча попали под «мелкие исправления и улучшения», хотя
#532 это как раз та правка, ради которой владелец и присылал три профиля
Firefox.
Строки перенесены в секцию v1.74.0, тело релиза переписано: первый пункт теперь
называет все четыре правки скорости (#532, #531, #524, #534). Проверка правил
#328 зелёная на диапазоне v1.73.0..v1.74.0.
Тег не двигается: он указывает на протестированное дерево, а тело релиза на
GitHub обновляется отдельно — именно его читает человек.
Issue: #534
User-Visible: no
К2 задачи #532 назвала это заранее: промоушен поверхности контура в свой
композиционный слой делит SVG надвое, оставшееся содержимое ложится на другую
субпиксельную сетку, и диагональная штриховка стен сглаживается иначе. Кадры
полагалось пересмотреть на кандидате — они дожили до кандидата стабильного,
потому что golden-джоба гоняется только на дереве с трейлером `Release:`, а
мерж #532 такого трейлера не нёс.
Проверено по критериям AC3 самой #532: разошлись **ровно четыре** кадра
`day-cycle-{dawn,day,dusk,night}-dark`, средний цвет кадра сдвинулся на
0,001–0,080 из 255 при пороге 0,1, средний знаковый сдвиг на разошедшихся
пикселях от −0,19 до +0,87. Кадры просмотрены глазами: отличается только
сглаживание штриховки стен, палитра, геометрия, подписи и ореол те же.
Приняты из артефакта полного прогона Linux CI на этом же дереве, остальные
165 сцен сохранены без изменений, свидетелей среды 129.
Issue: #532
User-Visible: no
Release: v1.74.0
Baseline-Reviewed: https://github.com/Matysh/houseplan-card/actions/runs/34641155082