Trading-Plattform-Pruefung: Abendkontrolle prueft die Sicherung des vorigen Handelstags (Paket E9, Task 726)
abendkontrolle_wsl.py nimmt --sicherung (Stand der Ablage vom Host) und meldet per ntfy, wenn die Sicherung des vorigen Handelstags fehlt, kein Archiv hat, nicht bestaetigt ist oder die Bestaetigung nicht passt; vor erster-tag still, ohne erster-tag ein Befund. abendkontrolle_angriffe.py mit --nur-sicherung (60 Faelle), abendkontrolle_mutanten.py mit --nur und 30 Sicherungs-Mutanten. Gegengeprueft: byte-gleich mit der Plankopie, Lauf gegen echte Archive ohne Abweichung. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_0126RDfXiECscXipzf67uypJ
This commit is contained in:
1 parent
c5db92c6de
commit
3e55bb915d
3 files changed
+514
-3
No files matched your search
@@ -4,8 +4,11 @@ Koordinator-Werkzeug, nicht fuers Repo. Jeder Mutant laeuft auf einer Wegwerfkop
|
||||
In WSL (Venv) die Mutanten von abendkontrolle_wsl.py, unter Windows die von abendkontrolle.py und
|
||||
rueckweg_aapl.py. Aufruf: python abendkontrolle_mutanten.py Exit 0, wenn keiner ueberlebt.
|
||||
Ein Mutant, der das Verhalten nicht aendert, ist keine Luecke (AI/Regelwerk/pruefwerkzeuge.md, Abschnitt 8).
|
||||
Seit Paket E9: --nur TEXT faehrt nur die Mutanten mit TEXT im Namen (etwa --nur Sicherung in WSL); ein
|
||||
fuenftes Element im Tupel geht als Argument an den Treiber.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -64,6 +67,78 @@ WSL_MUTANTEN = [
|
||||
("IBKR Muster aus", "abendkontrolle_wsl.py", " if muster in text:", " if False:"),
|
||||
("IBKR Titel ohne Praefix", "abendkontrolle_wsl.py", 'IBKR_TITEL = "IBKR "', 'IBKR_TITEL = ""'),
|
||||
("IBKR Meldeweiche aus", "abendkontrolle_wsl.py", "melde(IBKR_TITEL + titel if ibkr else titel,", "melde(titel,"),
|
||||
# Seit Paket E9 (Task 726): --sicherung. Der Treiber faehrt dafuer nur seine Faelle zur Sicherung.
|
||||
("Sicherung letzter Listeneintrag statt juengster Tag", "abendkontrolle_wsl.py",
|
||||
" return max(tage) if tage else None", " return tage[-1] if tage else None", "--nur-sicherung"),
|
||||
("Sicherung Vortag statt Kalender", "abendkontrolle_wsl.py",
|
||||
" vorher = juengster_handelstag(lies_kalender_spanne(start, ende, argumente.kalender, Path(argumente.projekt)))",
|
||||
" vorher = ende", "--nur-sicherung"),
|
||||
("Sicherung Kalenderform egal", "abendkontrolle_wsl.py",
|
||||
' raise ValueError("Kalender mit einem Eintrag ohne date JJJJ-MM-TT")', " continue",
|
||||
"--nur-sicherung"),
|
||||
("Sicherung Fehler des Hosts ueberlesen", "abendkontrolle_wsl.py", ' if "fehler" in stand:', " if False:",
|
||||
"--nur-sicherung"),
|
||||
("Sicherung Stand ohne Typpruefung", "abendkontrolle_wsl.py", " if not isinstance(stand, dict):", " if False:",
|
||||
"--nur-sicherung"),
|
||||
("Sicherung eintraege ohne Typpruefung", "abendkontrolle_wsl.py",
|
||||
' if "erster_tag" not in stand or not isinstance(stand.get("eintraege"), dict):',
|
||||
' if "erster_tag" not in stand:', "--nur-sicherung"),
|
||||
("Sicherung erster_tag ohne Formpruefung", "abendkontrolle_wsl.py",
|
||||
" if not isinstance(erster, str) or not DATUM.fullmatch(erster):", " if False:", "--nur-sicherung"),
|
||||
("Sicherung ohne erster_tag nur Hinweis", "abendkontrolle_wsl.py",
|
||||
' k.befund("Sicherung nicht geprueft: auf dem Docker-Host fehlt erster-tag der Sicherung")',
|
||||
' k.hinweis("Sicherung nicht geprueft: auf dem Docker-Host fehlt erster-tag der Sicherung")', "--nur-sicherung"),
|
||||
("Sicherung vor erster_tag geprueft", "abendkontrolle_wsl.py", " if vorher < erster:", " if False:",
|
||||
"--nur-sicherung"),
|
||||
("Sicherung erster_tag selbst ausgenommen", "abendkontrolle_wsl.py", " if vorher < erster:",
|
||||
" if vorher <= erster:", "--nur-sicherung"),
|
||||
("Sicherung kein Handelstag still", "abendkontrolle_wsl.py",
|
||||
' k.befund(f"Sicherung: kein Handelstag in den {SICHERUNG_FENSTER_TAGE} Tagen vor {tag} im Kalender")',
|
||||
" pass", "--nur-sicherung"),
|
||||
("Sicherung immer alpaca", "abendkontrolle_wsl.py",
|
||||
' instanz = "ibkr" if argumente.teil == "ibkr" else "alpaca"', ' instanz = "alpaca"', "--nur-sicherung"),
|
||||
("Sicherung fehlender Eintrag still", "abendkontrolle_wsl.py",
|
||||
' k.befund(f"Sicherung {name} fehlt auf dem Docker-Host")', " pass", "--nur-sicherung"),
|
||||
("Sicherung Summe ungeprueft", "abendkontrolle_wsl.py",
|
||||
" if not isinstance(summe, str) or not SUMME.fullmatch(summe):", " if summe is None:", "--nur-sicherung"),
|
||||
("Sicherung Bestaetigung ungeprueft", "abendkontrolle_wsl.py",
|
||||
" elif not isinstance(bestaetigt, str) or not SUMME.fullmatch(bestaetigt):", " elif False:",
|
||||
"--nur-sicherung"),
|
||||
("Sicherung Vergleich aus", "abendkontrolle_wsl.py", " elif bestaetigt != summe:", " elif False:",
|
||||
"--nur-sicherung"),
|
||||
("Sicherung Schalter nicht verdrahtet", "abendkontrolle_wsl.py", " if argumente.sicherung:", " if False:",
|
||||
"--nur-sicherung"),
|
||||
# Seit der Plankritik Runde 1 (Task 726): Fenster, erster_tag, Archiv und die zwei Faelle ohne Mutanten.
|
||||
("Sicherung Fenster 1 Tag", "abendkontrolle_wsl.py", "SICHERUNG_FENSTER_TAGE = 10", "SICHERUNG_FENSTER_TAGE = 1",
|
||||
"--nur-sicherung"),
|
||||
("Sicherung Fenster einen Tag kuerzer", "abendkontrolle_wsl.py",
|
||||
" start = (geprueft - timedelta(days=SICHERUNG_FENSTER_TAGE)).isoformat()",
|
||||
" start = (geprueft - timedelta(days=SICHERUNG_FENSTER_TAGE - 1)).isoformat()", "--nur-sicherung"),
|
||||
("Sicherung Ende am Tag selbst", "abendkontrolle_wsl.py",
|
||||
" ende = (geprueft - timedelta(days=1)).isoformat()", " ende = geprueft.isoformat()", "--nur-sicherung"),
|
||||
("Sicherung Spanne der Datei aus", "abendkontrolle_wsl.py",
|
||||
' return in_spanne(json.loads(Path(kalender_datei).read_text(encoding="utf-8")), start, ende)',
|
||||
' return json.loads(Path(kalender_datei).read_text(encoding="utf-8"))', "--nur-sicherung"),
|
||||
("Sicherung Spanne ohne Anfang", "abendkontrolle_wsl.py", ' or start <= eintrag["date"] <= ende',
|
||||
' or eintrag["date"] <= ende', "--nur-sicherung"),
|
||||
("Sicherung Spanne ohne Typpruefung", "abendkontrolle_wsl.py",
|
||||
" if not isinstance(liste, list):\n return liste", " if False:\n return liste",
|
||||
"--nur-sicherung"),
|
||||
("Sicherung Kalender ohne Typpruefung", "abendkontrolle_wsl.py",
|
||||
' if not isinstance(liste, list):\n raise ValueError("Kalender ist keine Liste")',
|
||||
' if False:\n raise ValueError("Kalender ist keine Liste")', "--nur-sicherung"),
|
||||
("Sicherung erster_tag nach dem Tag still", "abendkontrolle_wsl.py", " if erster > tag:", " if False:",
|
||||
"--nur-sicherung"),
|
||||
("Sicherung erster_tag am Tag selbst als Befund", "abendkontrolle_wsl.py", " if erster > tag:",
|
||||
" if erster >= tag:", "--nur-sicherung"),
|
||||
("Sicherung Archiv ungeprueft", "abendkontrolle_wsl.py", ' elif eintrag.get("archiv") is not True:',
|
||||
" elif False:", "--nur-sicherung"),
|
||||
("Sicherung Archiv nur false zaehlt", "abendkontrolle_wsl.py", ' elif eintrag.get("archiv") is not True:',
|
||||
' elif eintrag.get("archiv") is False:', "--nur-sicherung"),
|
||||
("Sicherung ohne Schalter geprueft", "abendkontrolle_wsl.py", " if argumente.sicherung:", " if True:",
|
||||
"--nur-sicherung"),
|
||||
("Sicherung unbekannter Schluessel als Fehler", "abendkontrolle_wsl.py", ' if "fehler" in stand:',
|
||||
' if "fehler" in stand or set(stand) - {"erster_tag", "eintraege"}:', "--nur-sicherung"),
|
||||
]
|
||||
WIN_MUTANTEN = [
|
||||
("keine Ergebnisdatei", "abendkontrolle.py", '(ablage / f"{tag}{endung}.json").write_text(',
|
||||
@@ -109,9 +184,19 @@ TREIBER = {
|
||||
"rueckweg_aapl.py": "rueckweg_aapl_angriffe.py",
|
||||
}
|
||||
|
||||
zerleger = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
||||
# Seit Paket E9: nur die Mutanten, deren Name den Text enthaelt.
|
||||
zerleger.add_argument("--nur", help="nur Mutanten, deren Name diesen Text enthaelt")
|
||||
argumente = zerleger.parse_args()
|
||||
mutanten = WIN_MUTANTEN if sys.platform == "win32" else WSL_MUTANTEN
|
||||
if argumente.nur is not None:
|
||||
mutanten = [mutant for mutant in mutanten if argumente.nur in mutant[0]]
|
||||
if not mutanten:
|
||||
print(f"KEIN MUTANT mit {argumente.nur!r} im Namen")
|
||||
sys.exit(2)
|
||||
ueberlebt = []
|
||||
for name, datei, alt, neu in mutanten:
|
||||
# Ein fuenftes Element im Tupel geht als Argument an den Treiber (seit Paket E9).
|
||||
for name, datei, alt, neu, *treiber_argumente in mutanten:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
ziel = Path(tmp) / "pruefung"
|
||||
shutil.copytree(HIER, ziel, ignore=shutil.ignore_patterns("__pycache__"))
|
||||
@@ -122,7 +207,7 @@ for name, datei, alt, neu in mutanten:
|
||||
ueberlebt.append(name)
|
||||
continue
|
||||
pfad.write_text(text.replace(alt, neu), encoding="utf-8", newline="\n")
|
||||
lauf = subprocess.run([sys.executable, str(ziel / TREIBER[datei])], capture_output=True, text=True,
|
||||
lauf = subprocess.run([sys.executable, str(ziel / TREIBER[datei]), *treiber_argumente], capture_output=True, text=True,
|
||||
timeout=1800, encoding="utf-8", errors="replace", cwd=tmp)
|
||||
faelle = [z for z in lauf.stdout.splitlines() if z.startswith("FEHL")]
|
||||
rot = lauf.returncode != 0
|
||||
|
||||
Reference in new issue
Block a user