install.ps1 warnt vor einem veralteten OTA-Bündel

Beim Prüfen, ob die GitHub-Entfernung eine Versionserhöhung brauchte, fiel
eine echte Lücke auf: nichts hielt frontend/app/bundle.json auf demselben
Stand wie manifest.json. Bei der nächsten echten Versionserhöhung ohne
"npm run ota" hätte das zu einem stillen Widerspruch geführt - die
Hinweisleiste hätte "veraltet" gemeldet (liest die Version live), die
Update-Seite "aktuell" (vergleicht gegen das eingefrorene, dann falsche
Bündel) -, ohne dass ein Update über OTA erreichbar gewesen wäre, bis
jemand den Widerspruch bemerkt.

install.ps1 liest jetzt direkt nach der Manifest-Version auch
frontend/app/bundle.json und vergleicht. Bei Abweichung: deutliche Warnung
plus erster Eintrag in der Restliste. Fehlt das Bündel ganz, passiert
nichts - OTA ist optional, das ist der normale Zustand.

Beide Pfade an einem Mock-Zielordner geprüft: passende Versionen melden
"OTA-Bündel passt zur Integration" ohne Restliste-Eintrag; eine testweise
erhöhte Manifest-Version (danach byte-genau zurückgesetzt, gegen HEAD
gegengeprüft) erzeugt die Warnung und landet als Restliste-Punkt 1.

VERSIONIERUNG.md: "Was du tun musst" nennt den OTA-Neubau jetzt als
eigenen nummerierten Schritt, statt ihn ganz auszulassen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-24 09:32:36 +02:00
parent ba182cb180
commit 2ea01ce2ce
3 changed files with 65 additions and 5 deletions
+20
View File
@@ -1982,6 +1982,26 @@ published the new manifest version and a complete `buendel` block; the zip serve
identically to `bundle.json`'s `sha256`; `unzip -l`/`-t` confirmed 13 entries, `index.html` at the identically to `bundle.json`'s `sha256`; `unzip -l`/`-t` confirmed 13 entries, `index.html` at the
root, no backslashes, no corruption. root, no backslashes, no corruption.
**A second, quieter bug surfaced 2026-08-24 when a manifest-only metadata change (the GitHub-removal
commit) prompted the question of whether it needed a version bump.** It didn't — but the question
exposed that nothing enforced `frontend/app/bundle.json`'s version staying in sync with
`manifest.json`'s on a *real* bump. Trace the failure: bump manifest to V2, ship via `install.ps1`,
forget `npm run ota` → backend publishes `app: "V2"` live, but `bundle.json` (frozen at build time)
still says V1, and the already-installed app is still V1. `Hinweisleiste` compares app-vs-server and
correctly says "you're outdated, update" (V1 ≠ V2) — but the Update screen's `buendelPasst()`
compares app-vs-*bundle* and says "you're current" (V1 = V1, the bundle's stale number). Two
contradictory messages, and no way to actually reach V2 via OTA until someone notices and reruns
`npm run ota` — the exact kind of silent-until-discovered coordination bug this project has fixed
repeatedly elsewhere (trip status, tire counter, `edited_fields`). Fixed at the one chokepoint every
delivery already passes through: `install.ps1` now reads `frontend/app/bundle.json`'s version right
after reading the manifest's, warns loudly and adds the mismatch as the **first** Restliste item if
they differ (a missing bundle file is not a mismatch — OTA is optional, silence is correct then).
Verified both ways on a mock config dir: matching versions print "OTA-Bündel passt zur Integration"
and add nothing to the Restliste; a deliberately bumped manifest (tested via a temporary edit,
reverted byte-for-byte after, diffed against `HEAD` to confirm) produces the warning and lands it as
Restliste item 1. `VERSIONIERUNG.md`'s "Was du tun musst" now lists the OTA rebuild as its own
numbered step (2, before shipping) instead of omitting it entirely.
Capacitor's `server.url` pointed at HA was considered and **rejected**: it would make the app as Capacitor's `server.url` pointed at HA was considered and **rejected**: it would make the app as
current as the panel, but the shell then cannot boot without reaching HA, gutting the deliberately current as the panel, but the shell then cannot boot without reaching HA, gutting the deliberately
built offline queue (`api/warteschlange.ts`). built offline queue (`api/warteschlange.ts`).
+18 -5
View File
@@ -88,13 +88,26 @@ ohne Netz darf keinen Fehlalarm auslösen.
1. `version` in `manifest.json` erhöhen — bei mehreren Änderungen am selben Tag 1. `version` in `manifest.json` erhöhen — bei mehreren Änderungen am selben Tag
die laufende Nummer: `2026.8.23.2``2026.8.23.3`, am nächsten Tag die laufende Nummer: `2026.8.23.2``2026.8.23.3`, am nächsten Tag
`2026.8.24.1`. `2026.8.24.1`.
2. Integration ausliefern: `homeassistant\installationspaket\Installieren.cmd` 2. **OTA-Bündel neu bauen: `npm run ota`** (in `companion-app/`). Baut die
Oberfläche und packt sie mit der neuen Versionsnummer — siehe
[OTA-Updates](#ota-updates-seit-2026-08-24) unten. Ohne diesen Schritt
trägt `frontend/app/bundle.json` noch die alte Nummer: die Hinweisleiste
sagt dann „du bist veraltet" (liest die Version live), die Update-Seite
sagt „du bist aktuell" (vergleicht gegen das eingefrorene, jetzt falsche
Bündel) — ein Widerspruch, aus dem es ohne diesen Schritt keinen Ausweg
gibt. `install.ps1` prüft das seit 2026-08-24 selbst und warnt, falls
vergessen — aber besser, es passiert gar nicht erst.
3. Integration ausliefern: `homeassistant\installationspaket\Installieren.cmd`
(HACS scheidet aus — siehe Kasten oben, das Repository ist privat). (HACS scheidet aus — siehe Kasten oben, das Repository ist privat).
3. iOS-App neu bauen (`npm run build`), damit sie dieselbe Zahl einkompiliert 4. iOS-App für Xcode neu bauen (`npm run build`), damit eine über App Store
bekommt. Connect / Sideload signierte Fassung dieselbe Zahl einkompiliert bekommt.
Für alle, die die App schon installiert haben, erledigt Schritt 2 das
automatisch über OTA — dieser Schritt ist nur für die nächste
Neuinstallation oder Signatur-Erneuerung nötig.
Vergisst du Schritt 3, ist das kein stiller Fehler mehr: die App meldet selbst, Vergisst du Schritt 4, ist das kein stiller Fehler mehr: die App meldet selbst,
dass sie älter ist als der Server. dass sie älter ist als der Server. Vergisst du Schritt 2, bleibt es leider
still — deshalb die Prüfung in `install.ps1`.
**Bei einer reinen Neuinstallation** ohne Codeänderung: nichts tun. **Bei einer reinen Neuinstallation** ohne Codeänderung: nichts tun.
@@ -106,6 +106,33 @@ if (-not $quelle) {
$version = (Get-Content (Join-Path $quelle "manifest.json") -Raw | ConvertFrom-Json).version $version = (Get-Content (Join-Path $quelle "manifest.json") -Raw | ConvertFrom-Json).version
Gut "Quelle: $quelle (Version $version)" Gut "Quelle: $quelle (Version $version)"
# ------------------------------------------------ OTA-Bündel auf Stand prüfen
# Das Bündel für die iOS-App (frontend\app\bundle.json, gebaut von
# companion-app\scripts\ota-paket.ps1) trägt seine eigene, zum Bauzeitpunkt
# eingefrorene Versionsnummer. Ändert sich manifest.json's Version, ohne dass
# jemand "npm run ota" erneut laufen lässt, bekommt die App zwei
# widersprüchliche Signale gleichzeitig: die Hinweisleiste sagt "du bist
# veraltet" (vergleicht gegen die live gelesene manifest-Version), die
# Update-Seite sagt "du bist aktuell" (vergleicht gegen das eingefrorene, nun
# falsche Bündel) - und es gibt keinen Weg, das Update zu bekommen, bis jemand
# den Widerspruch bemerkt. Das ist kein Zustand, den ein Installer schweigend
# durchwinken sollte - hier ist der eine Ort, an dem jede Auslieferung
# durchläuft, also der einzige verlässliche Punkt für diese Prüfung.
#
# Ein fehlendes Bündel ist dagegen kein Fehler: OTA ist eine optionale
# Zusatzfunktion, nicht jede Installation liefert eins mit.
$buendelInfo = Join-Path $quelle "frontend\app\bundle.json"
if (Test-Path $buendelInfo) {
$buendelVersion = (Get-Content $buendelInfo -Raw | ConvertFrom-Json).version
if ($buendelVersion -ne $version) {
Warnung "OTA-Bündel (frontend\app\bundle.json) steht auf Version $buendelVersion, die Integration auf $version."
Write-Host " Die App-Update-Funktion würde bis zur Behebung falsche Ergebnisse zeigen." -ForegroundColor Yellow
[void]$restliste.Add("OTA-Bündel ist veraltet (Version $buendelVersion statt $version): in companion-app\ 'npm run ota' ausführen, dann dieses Skript erneut laufen lassen.")
} else {
Info "OTA-Bündel passt zur Integration (Version $buendelVersion)"
}
}
# ---------------------------------------------------------------- Ziel finden # ---------------------------------------------------------------- Ziel finden
if (-not $Ziel) { if (-not $Ziel) {
Schritt "Suche Home Assistant ..." Schritt "Suche Home Assistant ..."