Hauptuntersuchung: Ableitung aus Erstzulassung und Wartungsplan, drittes Feld entfernt
Gemeldet: Wartungsplan leer, Erstzulassung 01.03.2025, erwartet 01.03.2028 -
gezeigt wurden drei verschiedene Antworten (Uebersicht 01.08.2026, Mein Audi
"August 2026", Service "kein Eintrag im Wartungsplan").
Ursache war das Profilfeld hauptuntersuchung_faellig ("08/2026"), das die
Ableitung ueberstimmte, in keiner Oberflaeche ein Eingabefeld hatte und im
Backend kein Schema. Drei Bildschirme verarbeiteten denselben Wert
verschieden. Das Feld ist samt Lese- und Schreibweg entfernt; es gibt jetzt
zwei Quellen: Wartungsplan + 24 Monate, sonst Erstzulassung + 36 Monate.
Dabei mitbehoben:
* Die Service-Kachel verschluckte abgeleitete Termine, sobald kein
Wartungsplan-Eintrag dahinterstand.
* monatePlus() in der App verlor einen Tag ueber die Zeitumstellung (drei von
fuenf gemessenen Faellen) - betraf Oelwechsel- und Inspektionsprognose
genauso. Das Panel rechnete dort seit jeher richtig.
* Die App verlangte fuer jeden Wartungsplan-Eintrag eine Kilometerangabe. Eine
Hauptuntersuchung ist rein datumsbasiert; ohne km waere der erste HU-Eintrag
ignoriert worden. Ausserdem nahm das Panel den ersten Treffer der Liste, die
App den juengsten - beide nehmen jetzt den juengsten.
* Monatsgenauigkeit ("03/2025") bleibt auf beiden Seiten erhalten.
Neu: paritaet_hu.test.ts vergleicht die App gegen die aus der Panel-Quelle
herausgeschnittenen Originalfunktionen, 15 Faelle. Gesamt 292 App-Tests, 73
Python-Tests mit 231 Untertests, 0 Tracebacks. Live an der Testinstanz auf
allen drei gemeldeten Bildschirmen geprueft.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -11316,3 +11316,138 @@ Noch nicht gebaut. Offen bleiben damit:
|
||||
* "Jetzt lesen" als echtes Lesen (Cache loeschen, dann holen).
|
||||
* Der Waechter darf keinen Gleichstand melden, solange unbekannt ist, wann der
|
||||
Wert zuletzt vom Geraet bestaetigt wurde.
|
||||
|
||||
## CR. Ein Feld ohne Eingabefeld hat drei Bildschirme belogen (2026.9.5.3)
|
||||
|
||||
Meldung des Eigentuemers, 05.09.2026: Wartungsplan leer, Erstzulassung
|
||||
`01.03.2025`, erwartet also die Hauptuntersuchung am 01.03.2028. Gezeigt wurde
|
||||
stattdessen dreierlei:
|
||||
|
||||
| Bildschirm | Anzeige |
|
||||
|---|---|
|
||||
| Uebersicht | `01.08.2026` |
|
||||
| Mein Audi | `August 2026` |
|
||||
| Service | `kein Eintrag im Wartungsplan` |
|
||||
|
||||
Drei Antworten auf dieselbe Frage. Die Ursache war eine einzige Zeile in
|
||||
`/config/audi_dashboard/fahrzeugprofil.json`:
|
||||
|
||||
"hauptuntersuchung_faellig": "08/2026"
|
||||
|
||||
### Warum das niemand korrigieren konnte
|
||||
|
||||
Dieses Feld hatte **in keiner der beiden Oberflaechen ein Eingabefeld** und im
|
||||
Backend kein Schema - gemessen, nicht vermutet: kein `<input>` im Panel, keine
|
||||
Zeile in `Einstellungen.tsx`, kein Treffer in den `.py`-Dateien. Es wurde nur
|
||||
gelesen und beim Speichern unveraendert zurueckgeschrieben. Ein Wert, den man
|
||||
sieht, aber nicht anfassen kann.
|
||||
|
||||
Und er stand in der Ableitung **ganz vorn**: beide Codebasen fragten zuerst
|
||||
dieses Feld und erst dann Wartungsplan und Erstzulassung. Solange dort
|
||||
`08/2026` stand, war jede Ableitung wirkungslos.
|
||||
|
||||
Die drei verschiedenen Anzeigen erklaeren sich aus drei verschiedenen
|
||||
Verarbeitungen desselben Wertes:
|
||||
|
||||
* **Uebersicht** rief `new Date(fahrzeug.hu)` auf - an der Ableitung vorbei.
|
||||
`new Date("08/2026")` ergibt in V8 den 01.08.2026.
|
||||
* **Mein Audi** ging ueber die Ableitung, die `08/2026` als monatsgenau
|
||||
erkannte und korrekt "August 2026" schrieb.
|
||||
* **Service** prueft mit `new Date(huFaellig)`; fuer `"08/2026"` liefert das
|
||||
`Invalid Date`, also der Leertext.
|
||||
|
||||
### Die Regel, die jetzt gilt
|
||||
|
||||
Vorgabe des Eigentuemers: *"die eingabe reicht fuers erste mal in der
|
||||
Erstzulassung und danach ueber den Wartungsplan"*. Zwei Quellen, keine dritte:
|
||||
|
||||
1. juengster Wartungsplan-Eintrag + **24** Monate
|
||||
2. sonst Erstzulassung + **36** Monate
|
||||
|
||||
Die 36 gegen 24 sind kein Versehen - die erste Hauptuntersuchung eines
|
||||
Neuwagens ist nach drei Jahren faellig, jede weitere nach zwei.
|
||||
|
||||
Das Profilfeld ist samt Lese- und Schreibweg entfernt (Panel, `profilAdapter`,
|
||||
`Fahrzeug`-Typ, Beispieldaten) und der tote Schluessel aus der Profildatei der
|
||||
Testinstanz geloescht. **Die reale Instanz traegt ihn noch** - er wird jetzt
|
||||
nirgends mehr gelesen, aber er liegt dort.
|
||||
|
||||
### Drei weitere Fehler, die dabei ans Licht kamen
|
||||
|
||||
**Die Service-Kachel verschluckte abgeleitete Termine.** `intervalle(t)` gibt
|
||||
`null` zurueck, wenn kein Wartungsplan-Eintrag dahintersteht, und der fruehe
|
||||
Return schrieb dann "kein Eintrag im Wartungsplan" - auch wenn `t.datum` laengst
|
||||
einen Termin trug. Behoben: der Return greift nur noch, wenn wirklich kein
|
||||
Datum da ist.
|
||||
|
||||
**`monatePlus()` in der App verlor einen Tag ueber die Zeitumstellung.** Sie las
|
||||
mit `new Date(isoDatum)` (UTC-Mitternacht) und formatierte mit
|
||||
`toISOString()` zurueck. Fielen Start und Ziel in verschiedene
|
||||
Zeitzonen-Halbjahre, verschob das um eine Stunde - und die reicht ueber
|
||||
Mitternacht. Gemessen, drei von fuenf:
|
||||
|
||||
2025-01-15 + 6 Monate -> 2025-07-14 statt 2025-07-15
|
||||
2025-11-20 + 6 Monate -> 2026-05-19 statt 2026-05-20
|
||||
2025-02-10 + 4 Monate -> 2025-06-09 statt 2025-06-10
|
||||
|
||||
Das betraf **Oelwechsel- und Inspektionsprognose genauso**, nicht nur die
|
||||
Hauptuntersuchung. Das Panel rechnete an derselben Stelle von jeher in Ortszeit
|
||||
und war richtig - eine stille Paritaetsabweichung. Jetzt rechnen beide in
|
||||
Ortszeit.
|
||||
|
||||
**Der Wartungsplan-Eintrag brauchte in der App eine Kilometerangabe.**
|
||||
`letzterEintrag()` filtert auf `e.km != null`, weil Oelwechsel und Inspektion
|
||||
km-Prognosen rechnen. Die Hauptuntersuchung ist rein datumsbasiert; ohne
|
||||
km-Eintrag haette die App den Eintrag ignoriert und weiter aus der
|
||||
Erstzulassung gerechnet - drei Jahre statt zwei -, waehrend das Panel ihn
|
||||
benutzte. Das haette **genau beim ersten HU-Eintrag** zugeschlagen, also bei
|
||||
dem Weg, den der Eigentuemer beschrieben hat. `letzteHauptuntersuchung()` hat
|
||||
jetzt einen eigenen Filter ohne km. Dazu nahm das Panel mit `.find()` den
|
||||
ersten Treffer in Listenreihenfolge, die App den juengsten nach Datum - beide
|
||||
nehmen jetzt den juengsten.
|
||||
|
||||
### Monatsgenauigkeit bleibt erhalten
|
||||
|
||||
Das Eingabefeld der Erstzulassung schlaegt `MM/JJJJ` vor. Aus `03/2025` darf
|
||||
kein Termin mit Tag entstehen - `01.03.2028` waere eine Erfindung. Das Panel
|
||||
fuehrt die Genauigkeit als `genau` am Termin mit, die App als ISO-Monat im Text
|
||||
(`"2028-03"`, den `datum()` als "Maerz 2028" ausgibt). Verschiedene Form,
|
||||
gleiche Aussage.
|
||||
|
||||
### Geprueft
|
||||
|
||||
`companion-app/src/daten/paritaet_hu.test.ts` schneidet `datumAusText()`,
|
||||
`monatePlus()`, `dat()` und die Datumsmuster aus der **Panel-Quelle** heraus und
|
||||
laesst sie gegen die App laufen - 15 Faelle, darunter Schaltjahr-Ueberlauf
|
||||
(29.02.2024 + 24 Monate -> 01.03.2026 auf beiden Seiten), beide Schreibweisen
|
||||
derselben Erstzulassung und alle drei Zeitumstellungs-Faelle. Dazu sieben neue
|
||||
Faelle in `service.test.ts`. Gesamt 292 Tests gruen.
|
||||
|
||||
Live an der Testinstanz mit den echten Daten des Eigentuemers geprueft, alle
|
||||
drei gemeldeten Bildschirme:
|
||||
|
||||
| Bildschirm | vorher | jetzt |
|
||||
|---|---|---|
|
||||
| Uebersicht | `01.08.2026` (HU als naechster Termin) | `23.07.2027` (Oelwechsel; die HU liegt 2028 dahinter) |
|
||||
| Service | `kein Eintrag im Wartungsplan` | `01.03.2028` |
|
||||
| Mein Audi | `August 2026` | `01.03.2028` |
|
||||
|
||||
0 Tracebacks nach dem Neustart.
|
||||
|
||||
### Zwei Fallen der Umgebung, die eine Auslieferung verschleiert haben
|
||||
|
||||
Beim Ausliefern sah es dreimal so aus, als sei die neue Fassung im Container -
|
||||
sie war es nicht:
|
||||
|
||||
* **MSYS-Pfadumwandlung.** `docker exec ... rm -rf /config/www/dmapp` ohne
|
||||
Quoting macht Git Bash zu einem Windows-Pfad; das `rm` trifft ins Leere,
|
||||
und das folgende `docker cp` legt seinen Inhalt dann **in** den bestehenden
|
||||
Ordner (`dmapp/dist/`, `audi_dashboard/audi_dashboard/`). Pfade gehoeren in
|
||||
`sh -c '...'`, sonst greift die Umwandlung.
|
||||
* **Binaerpipe in `docker exec -i`.** `tar -cf - | docker exec -i ... tar -xf -`
|
||||
meldet Erfolg und uebertraegt nichts. Nicht benutzen; `docker cp` auf ein
|
||||
**nicht vorhandenes** Ziel ist der verlaessliche Weg.
|
||||
|
||||
Beides hat dazu gefuehrt, dass ich zwischenzeitlich alte Dateien gelesen und
|
||||
fuer neue gehalten habe. Gegenprobe, die das aufdeckt: `find <ziel> -name
|
||||
manifest.json | wc -l` muss `1` ergeben.
|
||||
|
||||
Reference in New Issue
Block a user