Automatischer Push: 19 Datei(en) geändert
- .vault-tools/plan-kopie/LIESMICH.md - .vault-tools/plan-kopie/rot_nachweis.py - .vault-tools/plan-kopie/welle_vergleich.py - .vault-tools/plan-kopie/welle_vergleich_treiber.py - .vault-tools/trading-plattform-pruefung/LIESMICH.md - .vault-tools/trading-plattform-pruefung/angriffe.py - .vault-tools/trading-plattform-pruefung/browserlauf.py - .vault-tools/trading-plattform-pruefung/browserlauf_zugang.py - .vault-tools/trading-plattform-pruefung/c_eigenlauf.py - .vault-tools/trading-plattform-pruefung/d_eigenlauf.py - .vault-tools/trading-plattform-pruefung/handelstag_auswertung.py - .vault-tools/trading-plattform-pruefung/ntfy_probe_server.py - … und 7 weitere Erzeugt vom PostToolUse-Hook .vault-tools/auto-push/auto_push.py. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
371a1f5d2a
commit
395642c480
19 files changed
+1636
-32
No files matched your search
@@ -0,0 +1,122 @@
|
||||
"""Vergleicht zwei JSONL-Protokolle der Messwerkzeuge Wert fuer Wert (Bitgleichheit nach einem Umbau).
|
||||
|
||||
Koordinator-Werkzeug, nicht fuers Repo. Frage (Herkunft: Projektvorgabe, Anforderung Paket B vom
|
||||
2026-09-18, "Die eine Regel ueber allem"): Liefert der umgebaute Code auf denselben echten Daten dieselben
|
||||
Zahlen wie das Referenzprotokoll -- jede Gleitkommazahl exakt gleich, nan gleich nan?
|
||||
Es unterscheidet drei Dinge und vermischt sie nicht:
|
||||
ABWEICHUNG ein Blattwert unter demselben Pfad ist anders -> Befund (Exit 2)
|
||||
NUR NEU ein Pfad steht nur im neuen Protokoll (neuer Schluessel) -> gemeldet, kein Befund, ausser mit --streng
|
||||
NUR ALT ein Pfad steht nur im alten Protokoll -> Befund (Exit 2)
|
||||
Zeilen werden in ihrer Reihenfolge gepaart; verschiedene Zeilenzahlen oder Zeilenarten sind ein Befund.
|
||||
Uebergangen werden die Schluessel aus --ohne (Vorgabe: zeit, dauer_s, protokoll, name), weil sie vom Lauf
|
||||
abhaengen und nicht von der Rechnung.
|
||||
Was es nicht sieht: ob das Referenzprotokoll selbst stimmt, und Zeilen, die in beiden Protokollen fehlen.
|
||||
Regressionsnachweis: --sabotage veraendert im neuen Protokoll eine Zahl in der letzten Stelle und muss rot enden.
|
||||
|
||||
Aufruf: python protokoll_vergleich.py <alt.jsonl> <neu.jsonl> [--ohne k1 k2 ...] [--streng] [--sabotage]
|
||||
Exit 0 ohne Befund, 2 mit Befund, 3 wenn eine Datei fehlt oder leer ist.
|
||||
"""
|
||||
|
||||
import json
|
||||
import math
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def lies(pfad: Path) -> list[dict]:
|
||||
zeilen = []
|
||||
with open(pfad, encoding="utf-8") as datei:
|
||||
for zeile in datei:
|
||||
if zeile.strip():
|
||||
zeilen.append(json.loads(zeile, parse_constant=float))
|
||||
return zeilen
|
||||
|
||||
|
||||
def flach(knoten, ohne: set[str], praefix: str = "") -> dict:
|
||||
werte: dict = {}
|
||||
if isinstance(knoten, dict):
|
||||
for name, inhalt in knoten.items():
|
||||
if name in ohne:
|
||||
continue
|
||||
werte.update(flach(inhalt, ohne, f"{praefix}.{name}"))
|
||||
elif isinstance(knoten, list):
|
||||
for nummer, inhalt in enumerate(knoten):
|
||||
werte.update(flach(inhalt, ohne, f"{praefix}[{nummer}]"))
|
||||
else:
|
||||
werte[praefix] = knoten
|
||||
return werte
|
||||
|
||||
|
||||
def gleich(a, b) -> bool:
|
||||
if isinstance(a, float) and isinstance(b, float):
|
||||
return a == b or (math.isnan(a) and math.isnan(b))
|
||||
return type(a) is type(b) and a == b
|
||||
|
||||
|
||||
def main() -> int:
|
||||
argumente = sys.argv[1:]
|
||||
streng = "--streng" in argumente
|
||||
sabotage = "--sabotage" in argumente
|
||||
ohne = {"zeit", "dauer_s", "protokoll", "name"}
|
||||
if "--ohne" in argumente:
|
||||
stelle = argumente.index("--ohne")
|
||||
ohne = set()
|
||||
for wort in argumente[stelle + 1 :]:
|
||||
if wort.startswith("--"):
|
||||
break
|
||||
ohne.add(wort)
|
||||
pfade = [Path(a) for a in argumente if not a.startswith("--") and a not in ohne]
|
||||
if len(pfade) != 2 or not all(p.is_file() for p in pfade):
|
||||
print(__doc__)
|
||||
return 3
|
||||
alt, neu = lies(pfade[0]), lies(pfade[1])
|
||||
if not alt or not neu:
|
||||
print("VORAUSSETZUNG FEHLT: ein Protokoll ist leer")
|
||||
return 3
|
||||
if sabotage:
|
||||
for zeile in reversed(neu):
|
||||
zahlen = [k for k, v in zeile.items() if isinstance(v, float) and math.isfinite(v) and v != 0.0]
|
||||
if zahlen:
|
||||
zeile[zahlen[0]] = math.nextafter(zeile[zahlen[0]], math.inf)
|
||||
print(f"sabotage: {zahlen[0]} in einer Zeile der Art {zeile.get('art')} um ein ULP verschoben")
|
||||
break
|
||||
|
||||
befunde: list[str] = []
|
||||
if len(alt) != len(neu):
|
||||
befunde.append(f"Zeilenzahl: alt {len(alt)}, neu {len(neu)}")
|
||||
verglichen = 0
|
||||
nur_neu: dict[str, int] = {}
|
||||
for nummer, (a, n) in enumerate(zip(alt, neu), start=1):
|
||||
if a.get("art") != n.get("art"):
|
||||
befunde.append(f"Zeile {nummer}: Art alt {a.get('art')!r}, neu {n.get('art')!r}")
|
||||
continue
|
||||
fa, fn = flach(a, ohne), flach(n, ohne)
|
||||
for pfad in fa.keys() - fn.keys():
|
||||
befunde.append(f"Zeile {nummer} ({a.get('art')}): NUR ALT {pfad}")
|
||||
for pfad in fn.keys() - fa.keys():
|
||||
kurz = pfad.split("[")[0]
|
||||
nur_neu[kurz] = nur_neu.get(kurz, 0) + 1
|
||||
if streng:
|
||||
befunde.append(f"Zeile {nummer} ({a.get('art')}): NUR NEU {pfad}")
|
||||
for pfad in fa.keys() & fn.keys():
|
||||
verglichen += 1
|
||||
if not gleich(fa[pfad], fn[pfad]):
|
||||
befunde.append(f"Zeile {nummer} ({a.get('art')}): ABWEICHUNG {pfad}: alt {fa[pfad]!r}, neu {fn[pfad]!r}")
|
||||
|
||||
print(f"{min(len(alt), len(neu))} Zeilen gepaart, {verglichen} Werte verglichen, uebergangene Schluessel: {sorted(ohne)}")
|
||||
for pfad, zahl in sorted(nur_neu.items()):
|
||||
print(f"NUR NEU: {pfad} in {zahl} Zeile(n)")
|
||||
for befund in befunde[:25]:
|
||||
print("BEFUND:", befund)
|
||||
if len(befunde) > 25:
|
||||
print(f"... und {len(befunde) - 25} weitere")
|
||||
print(f"{len(befunde)} Befund(e).")
|
||||
return 2 if befunde else 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
sys.exit(main())
|
||||
except Exception as ausnahme: # noqa: BLE001 - ein Absturz des Werkzeugs ist selbst ein Befund
|
||||
print(f"BEFUND: das Werkzeug ist abgebrochen: {ausnahme!r}")
|
||||
sys.exit(2)
|
||||
Reference in new issue
Block a user