Audit nach dem Dongle-Umbau: vier Befunde (2026.9.3.13)
1. profil_schreiben awaitete wunsch_uebernehmen und damit bis zu drei HTTP-Runden zu flespi - bei 39 Aufrufstellen von profilSpeichern() im Panel je Feldaenderung. Laeuft jetzt als eigene Aufgabe. 2. Ein gescheiterter Schreibversuch wurde bei jedem Speichern wiederholt, weil der Fehlerstand kein "werte" hat. Er merkt sich jetzt unter "versucht", was gescheitert ist. Dazu: kein zweites Schreiben, wenn der Wert schon als pending bereitliegt. 3. buendelPasst() versprach im Kommentar, ein aelteres Buendel abzulehnen, pruefte aber nur Ungleichheit - deshalb meldete die App "diese Fassung aendert auch Natives", obwohl nur das Buendel nach einem Versionssprung nicht neu gebaut war. Vergleicht jetzt gegen die Serverfassung, drei Regressionstests (der entscheidende gegen den alten Stand rot). Der Text behauptet keine Ursache mehr, die die App nicht kennen kann. 4. Das Regler-Minimum ging heute von 0 auf 1, ein bereits gespeicherter Wert darunter lief ungeprueft durch. Beide Oberflaechen klemmen jetzt auf 1-60. 182/182 Tests, 28 Backend-Dateien py_compile, beide Frontends als Modul geparst, Dienst- und Katalog-Konsistenz in beide Richtungen geprueft, Buendel auf derselben Fassung wie das Manifest. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,4 +40,26 @@ describe("buendelPasst", () => {
|
||||
expect(buendelPasst(buendel({ sha256: "" }), "2026.8.23.2")).toBe(false)
|
||||
expect(buendelPasst(buendel({ version: "" }), "2026.8.23.2")).toBe(false)
|
||||
})
|
||||
|
||||
/* Der eigentliche Zweck, und bis zum 03.09.2026 nur ein Kommentar: das
|
||||
Bündel muss zu der Fassung gehören, die der Server ausliefert. Ohne
|
||||
diese Prüfung meldete die App "diese Fassung ändert auch Natives",
|
||||
obwohl nur das Bündel nach einem Versionssprung nicht neu gebaut war. */
|
||||
it("akzeptiert, wenn das Bündel die Fassung des Servers ist", () => {
|
||||
expect(buendelPasst(buendel({ version: "2026.9.3.11" }), "2026.9.3.10", "2026.9.3.11")).toBe(
|
||||
true,
|
||||
)
|
||||
})
|
||||
|
||||
it("lehnt ab, wenn das Bündel hinter dem Server zurückliegt", () => {
|
||||
expect(buendelPasst(buendel({ version: "2026.9.3.10" }), "2026.9.3.9", "2026.9.3.11")).toBe(
|
||||
false,
|
||||
)
|
||||
})
|
||||
|
||||
it("prüft ohne bekannte Serverfassung nur gegen die eigene", () => {
|
||||
// Offline oder altes Backend: einen Vergleich, den man nicht anstellen
|
||||
// kann, darf der Knopf nicht ausbaden.
|
||||
expect(buendelPasst(buendel({ version: "2026.9.3.11" }), "2026.9.3.10", null)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -74,11 +74,23 @@ export async function startklarMelden(): Promise<void> {
|
||||
als "nicht vergleichbar", nicht als "abweichend". Alles andere böte einen
|
||||
Update-Knopf an, dessen Ziel man mit der laufenden Fassung gar nicht
|
||||
abgleichen konnte. */
|
||||
export function buendelPasst(buendel: Buendelangabe | null, eigene: string | null): boolean {
|
||||
export function buendelPasst(
|
||||
buendel: Buendelangabe | null,
|
||||
eigene: string | null,
|
||||
serverVersion?: string | null,
|
||||
): boolean {
|
||||
if (!buendel?.version || !buendel.url || !buendel.sha256 || !eigene) return false
|
||||
// Das Bündel muss zu der Fassung gehören, die diese Installation
|
||||
// ausliefert. Läge dort ein älteres, wäre ein "Update" ein Rückschritt.
|
||||
return buendel.version !== eigene
|
||||
// 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.
|
||||
if (serverVersion == null) return true
|
||||
return buendel.version === serverVersion
|
||||
}
|
||||
|
||||
export class OtaFehler extends Error {}
|
||||
|
||||
@@ -150,7 +150,10 @@ export function profilZuEinstellungen(profil: Profil): Einstellungen {
|
||||
// Der Wert hat die Zeit ueberlebt, in der die Einstellung nicht angeboten
|
||||
// wurde (31.08. bis 03.09.2026) - deshalb steht er in vielen Profilen
|
||||
// schon, und der Standard greift nur bei neuen.
|
||||
pausenzeitMin: zahl(einst, "fahrten_pausenzeit_min") ?? 15,
|
||||
// Auf den Bereich des Reglers geklemmt - siehe profilZuConfig() im Panel:
|
||||
// vor dem 03.09.2026 war 0 ("sofort") moeglich, das Geraet kennt aber kein
|
||||
// Schlaf-Timeout unter einer Minute.
|
||||
pausenzeitMin: Math.min(60, Math.max(1, zahl(einst, "fahrten_pausenzeit_min") ?? 15)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,8 @@ export function Einstellungen({
|
||||
const [backupImportFehler, setzeBackupImportFehler] = useState<string | null>(null)
|
||||
const backupDateiwahl = useRef<HTMLInputElement | null>(null)
|
||||
|
||||
const otaUpdateVerfuegbar = otaMoeglich() && buendelPasst(otaBuendel, eigeneVersion())
|
||||
const otaUpdateVerfuegbar =
|
||||
otaMoeglich() && buendelPasst(otaBuendel, eigeneVersion(), serverVersion)
|
||||
|
||||
const otaAusloesen = async () => {
|
||||
if (!otaBuendel) return
|
||||
|
||||
@@ -14,12 +14,17 @@
|
||||
* ZWEI FÄLLE, ZWEI TEXTE
|
||||
* ----------------------
|
||||
* Liegt ein passendes OTA-Bündel bereit, kann die App sich selbst erneuern —
|
||||
* dann steht hier der Knopf, der genau das tut. Fehlt eines, hat sich Natives
|
||||
* geändert (Plugins, Berechtigungen, die Hülle selbst), und dagegen hilft nur
|
||||
* neu aufspielen. Beides zu vermengen wäre die schlechtere Auskunft: ein
|
||||
* dann steht hier der Knopf, der genau das tut. Fehlt eines, hilft nur neu
|
||||
* aufspielen. Beides zu vermengen wäre die schlechtere Auskunft: ein
|
||||
* "Jetzt aktualisieren", das nichts ändern kann, oder ein "bitte manuell",
|
||||
* obwohl ein Knopf genügt hätte.
|
||||
*
|
||||
* Der Text sagt bewusst NICHT mehr "diese Fassung ändert auch Natives". Das
|
||||
* kann die App nicht wissen, und es war am 03.09.2026 schlicht falsch: die
|
||||
* Fassung war eine reine Backend-Korrektur, nur das Bündel war nach dem
|
||||
* Versionssprung nicht neu gebaut worden. Ein fehlendes Bündel heisst
|
||||
* "hier liegt nichts Passendes" — warum, weiss nur, wer es gebaut hat.
|
||||
*
|
||||
* EINMAL, NICHT BEI JEDEM START
|
||||
* -----------------------------
|
||||
* Weggetippt wird die gesehene Serverfassung gemerkt. Erst eine *andere*
|
||||
@@ -90,7 +95,7 @@ export function Versionshinweis({
|
||||
const offen =
|
||||
nativ && !weggetippt && hinweisFaellig(versionsstand, serverVersion, gesehenLesen())
|
||||
|
||||
const perOta = buendelPasst(otaBuendel, eigeneVersion())
|
||||
const perOta = buendelPasst(otaBuendel, eigeneVersion(), serverVersion)
|
||||
|
||||
const schliessen = () => {
|
||||
if (laeuft) return
|
||||
@@ -121,7 +126,7 @@ export function Versionshinweis({
|
||||
description={
|
||||
perOta
|
||||
? `Diese App läuft auf ${eigeneVersion() ?? "einer unbekannten Fassung"}, bereit liegt ${serverVersion}. Sie kann sich direkt hier erneuern.`
|
||||
: `Diese App läuft auf ${eigeneVersion() ?? "einer unbekannten Fassung"}, der Server liefert ${serverVersion}. Diese Fassung ändert auch Natives — dafür muss die App neu aufgespielt werden, ein Update in der App genügt nicht.`
|
||||
: `Diese App läuft auf ${eigeneVersion() ?? "einer unbekannten Fassung"}, der Server liefert ${serverVersion}. Dafür liegt hier kein passendes Bündel — sie muss über Xcode neu aufgespielt werden.`
|
||||
}
|
||||
actions={
|
||||
perOta
|
||||
|
||||
Reference in New Issue
Block a user