Versionsvergleich: nur eine neuere Fassung zaehlt

Nach dem Xcode-Lauf lief die App auf 2026.9.4.17, die Instanz auf
2026.9.4.5 - und die App bot an, sich auf .5 zu erneuern. Die
Gleichheitspruefung konnte den Rueckschritt nicht sehen.

versionOrdnung() sortiert jetzt Stelle fuer Stelle als Zahl, aber nur was
dem Format JJJJ.M.T.N entspricht; sonst gibt es eine Abweichung ohne
Richtung. Streifen, Startblatt und OTA-Knopf schlagen nur noch an, wenn
die App nachweislich aelter ist. Damit ist die frueher dokumentierte
Entscheidung "nur auf Gleichheit" umgedreht - Begruendung in
VERSIONIERUNG.md und AGENTS.md Abschnitt CL.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-04 16:10:47 +02:00
parent 6365136275
commit cefb235f6d
12 changed files with 328 additions and 33 deletions
+97
View File
@@ -10477,3 +10477,100 @@ einer anderen Adresse steht, muss prozentkodiert werden - oder er gehoert dort n
hin. Die frueheren, erfolgreichen Installationen liefen alle ueber die blanke
Manifest-Adresse; der Zusatz kam am 04.09. dazu und ist seither nie durch eine
gelungene Installation gegangen.
## CL. Der Versionsvergleich kennt jetzt eine Richtung (2026.9.4.19)
Gemeldet nach dem ersten Start der frisch installierten `.17`: „App laeuft auf
4.17, bereit liegt 4.5. Sie kann sich direkt hier erneuern." Die reale Instanz
stand noch auf `2026.9.4.5` - angeboten wurde also ein **Rueckschritt um zwoelf
Fassungen**, der die Oberflaeche still auf den Stand vom Vormittag zurueckgedreht
haette (ohne QR-Scanner, ohne Bestaetigungsblatt, ohne Debug-Bereich), waehrend
die native Huelle auf `.17` geblieben waere. Danach haetten App und Server
uebereingestimmt und die Meldung waere verschwunden - der Verlust also still.
**Die alte Pruefung konnte das nicht sehen**, und zwar folgerichtig: sie
verglich nur auf Gleichheit. Das Buendel (`.5`) passte zur Serverfassung (`.5`)
und war ungleich der laufenden (`.17`) - beide Bedingungen erfuellt, Knopf da.
Dass `.5` **aelter** ist als `.17`, war ihr per Konstruktion unzugaenglich.
**Vorgabe des Eigentuemers:** erkannt wird eine neuere Fassung und keine andere.
### Eine dokumentierte Entscheidung wurde damit umgedreht
`appVersion.ts` und `VERSIONIERUNG.md` sagten bis hierher ausdruecklich das
Gegenteil - „bewusst kein groesser/kleiner-Vergleich: die Version ist eine
Kennung, keine Zahl. Ein Sortierversuch waere scheingenau und wuerde bei einem
Formatwechsel still falsche Antworten geben." Beide Stellen sind umgeschrieben,
nicht ergaenzt (Regel dieses Dokuments: ueberholte Regeln entfernen, nicht
stapeln).
**Der Einwand von damals ist eingebaut, nicht verworfen:** `versionOrdnung()`
sortiert ausschliesslich, was dem Format `JJJJ.M.T.N` entspricht - jede Stelle
muss eine reine Ziffernfolge sein, geprueft mit einem Muster und **nicht** mit
`parseInt`, das `4b` klaglos als 4 gelesen und damit genau die scheingenaue
Antwort erzeugt haette. Passt eine Seite nicht ins Schema, kommt `null` zurueck:
dann meldet die App eine Abweichung **ohne Richtung** und bietet nichts an.
Verglichen wird Stelle fuer Stelle als Zahl - zeichenweise stuende `.17` vor
`.5`, also genau der gemeldete Fall.
### Was sich wo aendert
| Lage | Streifen | Startblatt | OTA-Knopf |
|---|---|---|---|
| App aelter | „bitte aktualisieren" | ja | ja |
| **App neuer** | **still** | **nein** | **nein** |
| verschieden, nicht sortierbar | neutraler Hinweis | nein | nur bei Serveruebereinstimmung |
| gleich / nicht vergleichbar | still | nein | nein |
`Versionsstand` heisst jetzt `gleich | aelter | neuer | abweichend | unbekannt`;
`abweichend` bedeutet nur noch „verschieden, aber nicht sortierbar". Der Streifen
meldet diesen Fall **neutral** statt zu schweigen - der Grundsatz „nie eine
stille Veraltung" gilt auch dort, nur ohne eine Richtung zu behaupten, die nicht
belegt ist.
`buendelPasst()` behaelt seine bisherigen Bedingungen und bekommt eine dritte:
das Buendel muss **vorwaerts** gehen. Ist die Reihenfolge nicht bestimmbar, gilt
weiter die alte Regel (nur Serveruebereinstimmung) - eine erfundene Reihenfolge
waere schlechter als die Regel von vorher.
### Kein Panel-Gegenstueck, und das ist geprueft
Das Panel liest `APP_VERSION` an genau drei Stellen und **zeigt** sie nur an
(`vEinst()`, Zeile 3417). Es vergleicht nichts und kennt kein OTA-Buendel - es
laedt seine Dateien bei jedem Aufruf frisch und kann gar nicht veralten. Echte
Ausnahme von der Paritaetsregel, kein stillschweigend ausgelassener Port.
### Verifiziert
`tsc --noEmit` sauber, **244 Tests** (von 225; 6 neue fuer `versionOrdnung()`,
5 fuer den Rueckschritt in `buendelPasst()`, 2 fuer das Startblatt, dazu zwei
geaenderte Erwartungen in `appVersion.test.ts` - die Richtungsangabe ist eine
gewollte Verhaltensaenderung, kein Bruch). `vite build` sauber, Panel als Modul
geparst, `audi_ha_test` auf `2026.9.4.19` sauber gestartet, kein Traceback.
**Gegen den alten Stand als fehlschlagend nachgewiesen:** mit ausgehaengter
Reihenfolgepruefung fallen drei der neuen Tests um, darunter der gemeldete Fall
wortwoertlich (`buendelPasst(.5, laeuft .17, Server .5)` liefert dann `true`).
**Live in allen drei Lagen**, ohne den Container anzufassen - dafuer bekam nur
der Entwicklungsserver voruebergehend eine andere einkompilierte Nummer,
waehrend die Instanz durchgehend auf `.19` stand:
| einkompiliert | Instanz | Streifen | Startblatt | OTA-Knopf |
|---|---|---|---|---|
| `.99` (App voraus) | `.19` | still | nein | **nicht vorhanden** |
| `.18` (App zurueck) | `.19` | „aelter als der Server" | - | - |
| `.19` (gleich) | `.19` | still | nein | nein |
Das Startblatt erscheint im Browser grundsaetzlich nicht (`otaMoeglich()`, nur
nativ) - seine Entscheidung ist deshalb ueber `hinweisFaellig()` geprueft, nicht
optisch. Das Manifest steht danach wieder auf `2026.9.4.19`, gleichauf mit dem
Buendel (sha256 `58969a38…`).
### Was der Eigentuemer davon merkt
Die Meldung auf dem Telefon verschwindet nicht durch dieses Update - die App
laeuft ja auf `.17` und bekommt `.19` erst, wenn die Instanz sie ausliefert. Der
Weg bleibt: **erst die Integration auf der realen Instanz aktualisieren**
(Einstellungen -> Version -> pruefen, installieren, neu starten), danach bietet
die App den Schritt `.17` -> `.19` an, und der geht vorwaerts.
+24 -5
View File
@@ -74,11 +74,30 @@ Der Vergleich läuft in eine Richtung: **die Integration sagt, welcher Stand
installiert ist; die App sagt, welchen sie hat.** Stimmen sie nicht überein,
ist die App zu alt (oder, seltener, die Integration).
Bewusst **nur auf Gleichheit**, nie größer/kleiner: die Version ist eine
Kennung, keine Zahl. Ein Sortierversuch wäre scheingenau und würde bei einem
Formatwechsel still falsche Antworten geben. Fehlt eine der beiden Seiten, wird
gar nicht verglichen und nichts gemeldet — ein älteres Backend oder ein Start
ohne Netz darf keinen Fehlalarm auslösen.
**Verglichen wird der Reihe nach, nicht nur auf Gleichheit — geändert am
04.09.2026.** Bis dahin galt hier ausdrücklich das Gegenteil (die Version sei
eine Kennung und keine Zahl). Der Anlass war ein echter Fall: nach einem
Xcode-Lauf lief die App auf `2026.9.4.17`, die Instanz stand noch auf
`2026.9.4.5` — und die App bot an, sich auf `.5` zu erneuern. Ein Rückschritt um
zwölf Fassungen, den eine Gleichheitsprüfung gar nicht sehen kann. Vorgabe des
Eigentümers: **erkannt wird eine neuere Fassung und keine andere.**
Der damalige Einwand ist nicht verworfen, sondern eingebaut: sortiert wird nur,
was dem Format `JJJJ.M.T.N` entspricht, und zwar Stelle für Stelle als Zahl —
zeichenweise stünde `.17` vor `.5`. Passt eine Seite nicht ins Schema, gilt sie
als **nicht sortierbar**; dann meldet die App eine Abweichung ohne Richtung und
bietet nichts an, statt eine Reihenfolge zu erfinden. Fehlt eine der beiden
Seiten ganz, wird gar nicht verglichen und nichts gemeldet — ein älteres Backend
oder ein Start ohne Netz darf keinen Fehlalarm auslösen.
Daraus folgen vier Verhaltensweisen, entschieden in `src/daten/appVersion.ts`:
| Lage | Streifen | Startblatt | Update-Knopf |
|---|---|---|---|
| App älter als der Server | bitte aktualisieren | ja | ja |
| App neuer (frisch signiert) | still | nein | **nein** |
| verschieden, nicht sortierbar | neutraler Hinweis | nein | nur bei Serverübereinstimmung |
| gleich / nicht vergleichbar | still | nein | nein |
## Was du tun musst
+54 -4
View File
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest"
import { versionVergleichen } from "./appVersion"
import { versionOrdnung, versionVergleichen } from "./appVersion"
/* Der Vergleich entscheidet, ob die App dem Nutzer sagt „ich bin älter als der
Server". Beide Fehlrichtungen sind teuer: ein Fehlalarm schickt ihn grundlos
@@ -12,9 +12,15 @@ describe("versionVergleichen", () => {
expect(v.stand).toBe("gleich")
})
it("meldet eine Abweichung, sobald die Zeichenketten sich unterscheiden", () => {
expect(versionVergleichen("2026.08.23.1", "2026.08.24.1").stand).toBe("abweichend")
expect(versionVergleichen("2026.08.23.2", "2026.08.23.1").stand).toBe("abweichend")
it("nennt die Richtung, statt nur eine Abweichung zu melden", () => {
expect(versionVergleichen("2026.08.23.1", "2026.08.24.1").stand).toBe("aelter")
expect(versionVergleichen("2026.08.23.2", "2026.08.23.1").stand).toBe("neuer")
})
it("meldet ohne erkennbares Format eine Abweichung ohne Richtung", () => {
// Der Einwand, der bis zum 04.09.2026 GEGEN jede Sortierung sprach: bei
// einem Formatwechsel darf nichts erfunden werden.
expect(versionVergleichen("2026.8.23.1", "fruehling-2").stand).toBe("abweichend")
})
it("vergleicht nicht, wenn das Backend nichts meldet", () => {
@@ -38,3 +44,47 @@ describe("versionVergleichen", () => {
expect(v.server).toBe("2026.08.24.1")
})
})
/* versionOrdnung() ist die Stelle, an der aus zwei Kennungen ein Vorher und
ein Nachher wird. Sie entscheidet, ob der Update-Knopf erscheint - und ein
Vorzeichenfehler hier böte einen Rückschritt an, wie am 04.09.2026 real
geschehen (App .17, Instanz .5). */
describe("versionOrdnung", () => {
it("erkennt die letzte Stelle, auch zweistellig", () => {
// Genau der gemeldete Fall: 5 gegen 17. Zeichenweise verglichen stuende
// "17" vor "5" - deshalb wird je Stelle als Zahl verglichen.
expect(versionOrdnung("2026.9.4.5", "2026.9.4.17")).toBe(-1)
expect(versionOrdnung("2026.9.4.17", "2026.9.4.5")).toBe(1)
})
it("vergleicht Stelle für Stelle von links", () => {
expect(versionOrdnung("2026.8.31.9", "2026.9.1.1")).toBe(-1)
expect(versionOrdnung("2026.9.1.1", "2025.12.31.9")).toBe(1)
})
it("behandelt fehlende Stellen als Null", () => {
expect(versionOrdnung("2026.9.4", "2026.9.4.0")).toBe(0)
expect(versionOrdnung("2026.9.4", "2026.9.4.1")).toBe(-1)
})
it("stoert sich nicht an fuehrenden Nullen", () => {
expect(versionOrdnung("2026.08.23.1", "2026.8.23.1")).toBe(0)
})
it("sortiert nicht, was nicht ins Format passt", () => {
// parseInt haette "4b" klaglos als 4 gelesen - genau die scheingenaue
// Antwort, die hier nicht entstehen darf.
expect(versionOrdnung("2026.9.4b", "2026.9.5")).toBeNull()
expect(versionOrdnung("v2026.9.4", "2026.9.5")).toBeNull()
expect(versionOrdnung("2026..4", "2026.9.4")).toBeNull()
})
it("nennt zeichengleiche Kennungen gleich, auch ohne lesbares Format", () => {
expect(versionOrdnung("fruehling-2", "fruehling-2")).toBe(0)
})
it("entscheidet nichts, wenn eine Seite fehlt", () => {
expect(versionOrdnung(null, "2026.9.4.1")).toBeNull()
expect(versionOrdnung("2026.9.4.1", "")).toBeNull()
})
})
+61 -7
View File
@@ -7,17 +7,30 @@
* gebündelt und bleibt auf dem Stand vom Signieren — unbegrenzt und bisher
* unbemerkt. Diese Datei macht daraus ein sichtbares Signal.
*
* Bewusst kein „größer/kleiner"-Vergleich: die Version ist eine Kennung
* (`2026.8.23.2`), keine Zahl. Ein Sortierversuch wäre nur scheingenau und
* würde bei einem Formatwechsel still falsche Antworten geben. Verglichen wird
* auf Gleichheit — alles andere heißt „stimmt nicht überein", und was davon
* älter ist, entscheidet der Mensch.
* ENTSCHEIDUNG GEÄNDERT AM 04.09.2026 — vorher stand hier ausdrücklich
* „bewusst kein größer/kleiner-Vergleich: die Version ist eine Kennung, keine
* Zahl". Der Anlass war ein echter Fall: nach einem Xcode-Lauf lief die App
* auf `2026.9.4.17`, die Instanz stand noch auf `2026.9.4.5` — und die App bot
* an, sich auf `.5` zu „erneuern". Ein Rückschritt, den die Gleichheitsprüfung
* gar nicht sehen konnte. Vorgabe des Eigentümers: erkannt werden soll eine
* NEUERE Fassung und keine andere.
*
* Der damalige Einwand bleibt gültig und ist deshalb eingebaut, statt
* verworfen: sortiert wird nur, was dem Format `JJJJ.M.T.N` entspricht. Passt
* eine der beiden Zeichenketten nicht ins Schema (Formatwechsel), liefert der
* Vergleich „abweichend" statt einer erfundenen Reihenfolge — dann sagt die
* App, dass etwas nicht übereinstimmt, aber nicht, in welche Richtung.
*/
export type Versionsstand =
/** App und Backend melden denselben Stand. */
| "gleich"
/** Sie weichen ab — die App ist mit hoher Wahrscheinlichkeit älter. */
/** Die App ist nachweislich älter — nur hier gibt es etwas zu holen. */
| "aelter"
/** Die App ist nachweislich neuer, etwa direkt nach einem Xcode-Lauf,
solange die Instanz noch nicht nachgezogen hat. Kein Handlungsbedarf. */
| "neuer"
/** Verschieden, aber nicht in eine Reihenfolge zu bringen (Formatwechsel). */
| "abweichend"
/** Kein Vergleich möglich (Backend meldet nichts, offline, altes Backend). */
| "unbekannt"
@@ -36,10 +49,51 @@ export function eigeneVersion(): string | null {
return typeof __APP_VERSION__ === "string" && __APP_VERSION__ ? __APP_VERSION__ : null
}
/** Zerlegt `2026.9.4.17` in [2026, 9, 4, 17]. `null`, sobald ein Teil keine
reine Ziffernfolge ist — dann wird nicht sortiert (siehe Modulkopf). */
function teile(version: string): number[] | null {
const stuecke = version.split(".")
if (stuecke.length === 0) return null
const zahlen: number[] = []
for (const stueck of stuecke) {
// Bewusst kein parseInt: das würde "4b" klaglos als 4 lesen und damit
// genau die scheingenaue Sortierung erzeugen, vor der der Modulkopf warnt.
if (!/^[0-9]+$/.test(stueck)) return null
zahlen.push(Number(stueck))
}
return zahlen
}
/**
* `-1` wenn `a` älter ist als `b`, `0` bei Gleichstand, `+1` wenn `a` neuer
* ist — und `null`, wenn sich das nicht entscheiden lässt.
*
* Fehlende Stellen zählen als 0, damit `2026.9.4` und `2026.9.4.0` denselben
* Stand bezeichnen.
*/
export function versionOrdnung(a: string | null, b: string | null): number | null {
if (!a || !b) return null
// Zeichengleich ist gleich, auch wenn das Format unbekannt ist.
if (a === b) return 0
const links = teile(a)
const rechts = teile(b)
if (!links || !rechts) return null
const laenge = Math.max(links.length, rechts.length)
for (let i = 0; i < laenge; i++) {
const l = links[i] ?? 0
const r = rechts[i] ?? 0
if (l !== r) return l < r ? -1 : 1
}
return 0
}
export function versionVergleichen(
app: string | null,
server: string | null,
): Versionsvergleich {
if (!app || !server) return { stand: "unbekannt", app, server }
return { stand: app === server ? "gleich" : "abweichend", app, server }
const ordnung = versionOrdnung(app, server)
if (ordnung === null) return { stand: "abweichend", app, server }
if (ordnung === 0) return { stand: "gleich", app, server }
return { stand: ordnung < 0 ? "aelter" : "neuer", app, server }
}
+39
View File
@@ -63,3 +63,42 @@ describe("buendelPasst", () => {
expect(buendelPasst(buendel({ version: "2026.9.3.11" }), "2026.9.3.10", null)).toBe(true)
})
})
/* Der gemeldete Fall vom 04.09.2026: nach einem Xcode-Lauf lief die App auf
2026.9.4.17, die Instanz stand noch auf 2026.9.4.5 - und bot an, sich auf
.5 zu "erneuern". Das Bündel passte zur Serverfassung, war also nach der
damaligen Prüfung in Ordnung; dass es ein Rückschritt ist, konnte sie nicht
sehen. Vorgabe des Eigentümers: erkannt wird eine NEUERE Fassung, sonst
keine. */
describe("buendelPasst geht nur vorwaerts", () => {
it("lehnt den gemeldeten Rueckschritt ab, obwohl das Buendel zum Server passt", () => {
expect(
buendelPasst(buendel({ version: "2026.9.4.5" }), "2026.9.4.17", "2026.9.4.5"),
).toBe(false)
})
it("nimmt dieselbe Lage nach dem Nachziehen der Instanz an", () => {
// Sobald die Integration auf .18 steht, geht es wieder vorwaerts.
expect(
buendelPasst(buendel({ version: "2026.9.4.18" }), "2026.9.4.17", "2026.9.4.18"),
).toBe(true)
})
it("lehnt einen Rueckschritt auch ohne bekannte Serverfassung ab", () => {
expect(buendelPasst(buendel({ version: "2026.9.4.5" }), "2026.9.4.17", null)).toBe(false)
})
it("vergleicht die letzte Stelle als Zahl, nicht zeichenweise", () => {
// "9" gegen "10": zeichenweise stuende "10" davor.
expect(buendelPasst(buendel({ version: "2026.9.4.10" }), "2026.9.4.9", null)).toBe(true)
expect(buendelPasst(buendel({ version: "2026.9.4.9" }), "2026.9.4.10", null)).toBe(false)
})
it("bleibt beim alten Verhalten, wenn sich die Reihenfolge nicht bestimmen laesst", () => {
// Formatwechsel: dann entscheidet weiterhin allein die Serverfassung -
// eine Reihenfolge zu erfinden waere schlechter als die alte Regel.
expect(buendelPasst(buendel({ version: "fruehling-3" }), "2026.9.4.17", "fruehling-3")).toBe(
true,
)
})
})
+11 -6
View File
@@ -39,6 +39,7 @@ import { Capacitor } from "@capacitor/core"
import { CapacitorUpdater } from "@capgo/capacitor-updater"
import type { Buendelangabe } from "../api"
import { versionOrdnung } from "./appVersion"
/** Läuft die App in der nativen Hülle? Nur dort gibt es etwas auszutauschen —
im Browser und im HA-Panel lädt ohnehin jeder Seitenaufruf den aktuellen
@@ -83,12 +84,16 @@ export function buendelPasst(
// Es muss etwas ANDERES sein als das, was gerade läuft - sonst gibt es
// nichts zu holen.
if (buendel.version === eigene) return false
// Und es muss die Fassung sein, die diese Installation ausliefert. Der
// Kommentar hier versprach das schon ("läge dort ein älteres, wäre ein
// Update ein Rückschritt"), geprüft wurde es nie: ein blosses !== laesst
// ein aelteres Buendel genauso durch wie ein neueres. Ohne bekannte
// Serverfassung bleibt es beim alten Verhalten - ein Vergleich, den man
// nicht anstellen kann, darf den Knopf nicht wegnehmen.
// Und es muss VORWAERTS gehen. Am 04.09.2026 lief die App nach einem
// Xcode-Lauf auf 2026.9.4.17, während die Instanz noch 2026.9.4.5
// auslieferte - angeboten wurde ein Rückschritt auf .5, der die
// Oberfläche still um zwölf Fassungen zurückgedreht hätte. Die
// Gleichheitsprüfung konnte das nicht sehen; siehe appVersion.ts.
const ordnung = versionOrdnung(buendel.version, eigene)
if (ordnung !== null && ordnung <= 0) return false
// Und es muss die Fassung sein, die diese Installation ausliefert. Ohne
// bekannte Serverfassung bleibt es beim alten Verhalten - ein Vergleich,
// den man nicht anstellen kann, darf den Knopf nicht wegnehmen.
if (serverVersion == null) return true
return buendel.version === serverVersion
}
+14 -4
View File
@@ -26,12 +26,21 @@ export function Hinweisleiste({
// Derselbe Grundsatz wie beim Offline-Hinweis oben: keine stille Veraltung.
// Nur hier veraltet nicht die Anzeige, sondern die App selbst — sie trägt
// ihre Dateien fest gebündelt und merkt eine neuere Fassung sonst nie.
const veraltet = versionsstand === "abweichend"
//
// "neuer" schlägt bewusst NICHT an: direkt nach einem Xcode-Lauf ist die
// App der Instanz voraus, und daraus einen Handlungsbedarf zu machen
// hiesse, den Nutzer zu einem Rückschritt zu drängen (siehe
// daten/appVersion.ts). Nur bei einer nicht sortierbaren Abweichung wird
// neutral gemeldet, statt eine Richtung zu behaupten - der Grundsatz
// 'keine stille Veraltung' gilt auch dann.
const veraltet = versionsstand === "aelter"
const unklar = versionsstand === "abweichend"
const versionshinweis = veraltet || unklar
// "verbindet" gleich beim Start nicht als Offline melden — das würde bei
// jedem App-Start kurz aufblitzen.
if (!offline && wartend === 0 && !veraltet) return null
if (verbindung === "verbindet" && wartend === 0 && !veraltet) return null
if (!offline && wartend === 0 && !versionshinweis) return null
if (verbindung === "verbindet" && wartend === 0 && !versionshinweis) return null
const gescheitert = warteschlange.filter((a) => a.fehlversuche > 0).length
@@ -51,8 +60,9 @@ export function Hinweisleiste({
: `${wartend} Änderungen warten auf Übertragung.`
: null}
{gescheitert > 0 ? ` ${gescheitert} davon mit Fehlversuchen.` : null}
{veraltet && (offline || wartend > 0) ? " " : null}
{versionshinweis && (offline || wartend > 0) ? " " : null}
{veraltet ? "Diese App ist älter als der Server — bitte aktualisieren." : null}
{unklar ? "App und Server melden verschiedene Fassungen." : null}
</span>
</div>
)
@@ -8,7 +8,7 @@ import { hinweisFaellig } from "./Versionshinweis"
nie jemand erfährt. */
describe("hinweisFaellig", () => {
it("meldet, wenn App und Server auseinanderlaufen", () => {
expect(hinweisFaellig("abweichend", "2026.9.3.3", null)).toBe(true)
expect(hinweisFaellig("aelter", "2026.9.3.3", null)).toBe(true)
})
it("schweigt bei gleichem Stand", () => {
@@ -23,16 +23,31 @@ describe("hinweisFaellig", () => {
})
it("schweigt ohne Serverfassung, auch wenn abweichend gemeldet wird", () => {
expect(hinweisFaellig("abweichend", null, null)).toBe(false)
expect(hinweisFaellig("aelter", null, null)).toBe(false)
})
it("schweigt zur bereits weggetippten Fassung", () => {
expect(hinweisFaellig("abweichend", "2026.9.3.3", "2026.9.3.3")).toBe(false)
expect(hinweisFaellig("aelter", "2026.9.3.3", "2026.9.3.3")).toBe(false)
})
it("meldet erneut, sobald eine andere Fassung bereitliegt", () => {
// Der Kern der Merkfunktion: weggetippt gilt für genau eine Fassung,
// nicht für "Updates" im Allgemeinen.
expect(hinweisFaellig("abweichend", "2026.9.4.1", "2026.9.3.3")).toBe(true)
expect(hinweisFaellig("aelter", "2026.9.4.1", "2026.9.3.3")).toBe(true)
})
})
/* Nachgetragen am 04.09.2026: die App lief nach einem Xcode-Lauf auf
2026.9.4.17, die Instanz stand auf 2026.9.4.5 - und das Blatt bot an, sich
auf .5 zu "erneuern". Seither meldet nur noch "aelter". */
describe("hinweisFaellig, wenn die App der Instanz voraus ist", () => {
it("schweigt, wenn die App neuer ist als der Server", () => {
expect(hinweisFaellig("neuer", "2026.9.4.5", null)).toBe(false)
})
it("schweigt bei einer Abweichung ohne erkennbare Richtung", () => {
// Formatwechsel: der Streifen meldet das neutral, ein eigenes Blatt waere
// dafuer zu viel - und "bitte aktualisieren" waere nicht belegbar.
expect(hinweisFaellig("abweichend", "gestern-3", null)).toBe(false)
})
})
@@ -56,7 +56,13 @@ export function hinweisFaellig(
): boolean {
// "unbekannt" heißt: kein Vergleich möglich (offline, altes Backend). Das
// ist kein Grund für eine Meldung — genauso wenig wie "gleich".
if (versionsstand !== "abweichend") return false
//
// Seit dem 04.09.2026 zählt nur noch "aelter". "neuer" tritt nach jedem
// Xcode-Lauf auf, solange die Instanz noch nicht nachgezogen hat - dort
// gibt es nichts zu holen, und die Meldung hätte zu einem Rückschritt
// eingeladen. "abweichend" (nicht sortierbar) meldet der Streifen neutral,
// ein eigenes Blatt wäre dafür zu viel.
if (versionsstand !== "aelter") return false
if (!serverVersion) return false
return serverVersion !== gesehen
}
@@ -1 +1 @@
{"version":"2026.9.4.18","sha256":"d8b50e70f23ee796ac1618a94ee49893c202bed6139863e840fa76456b2694ca","bytes":322373,"gebaut":"2026-09-04T12:14:55Z"}
{"version":"2026.9.4.19","sha256":"58969a387bfa72c3d452c04b689e8ec01440c9a2a89b7a097d43fe0418092ae6","bytes":322568,"gebaut":"2026-09-04T14:06:53Z"}
@@ -1,7 +1,7 @@
{
"domain": "audi_dashboard",
"name": "Audi Dashboard",
"version": "2026.9.4.18",
"version": "2026.9.4.19",
"documentation": "https://gitea.nothaft.cloud/paul/audi-app/src/branch/main/README.md",
"issue_tracker": "https://gitea.nothaft.cloud/paul/audi-app/issues",
"codeowners": [