Erster Stand des öffentlichen Ausschnitts aus dem Vault. Die .gitignore arbeitet als Positivliste: ausgeschlossen ist alles, eingeschlossen nur, was ausdrücklich wieder aufgenommen wird. Notizen, Projekte, Finanzen, das Sitzungsgedächtnis und settings.local.json bleiben damit außen vor. Der Kundenname in AI/Regelwerk/seo.md ist durch eine neutrale Bezeichnung ersetzt; die Regeln selbst sind unverändert. Co-Authored-By: Claude Opus 5 <[email protected]>
117 lines
3.9 KiB
Python
117 lines
3.9 KiB
Python
"""Mutantenlauf Frontend auf der materialisierten Kopie (Windows-Python, vitest je Datei).
|
||
|
||
Je Mutant: Datei als Bytes sichern, genau eine Stelle ersetzen, die Testdatei fahren, zurueckspielen.
|
||
Erwartet ist ROT; ein gruener Mutant ist ein Befund. Zuerst die Grundlinie.
|
||
"""
|
||
|
||
import subprocess
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
DASH = Path(sys.argv[1]) / "dashboard" # Windows-Pfad der Kopie mit dem angewendeten Plan
|
||
|
||
MUTANTEN = [
|
||
(
|
||
"stufe() gibt den rohen Index zurueck",
|
||
"src/components/LaufKampagne.tsx",
|
||
" const wert = aktion - (verteilung.length - 1) / 2;",
|
||
" const wert = aktion;",
|
||
"src/components/LaufKampagne.test.tsx",
|
||
),
|
||
(
|
||
"stufe() ohne Pruefung der Verteilung",
|
||
"src/components/LaufKampagne.tsx",
|
||
" if (!Array.isArray(verteilung) || verteilung.length % 2 === 0) return STRICH;",
|
||
" if (!Array.isArray(verteilung)) return STRICH;",
|
||
"src/components/LaufKampagne.test.tsx",
|
||
),
|
||
(
|
||
"stufe() ohne Pruefung des Bereichs",
|
||
"src/components/LaufKampagne.tsx",
|
||
" if (aktion < 0 || aktion >= verteilung.length) return STRICH;\n",
|
||
"",
|
||
"src/components/LaufKampagne.test.tsx",
|
||
),
|
||
(
|
||
"Stille Fenster als Ertrag formatiert",
|
||
"src/components/LaufKampagne.tsx",
|
||
" wert={anteil(abschluss.anteil_fenster_ohne_trade)}",
|
||
" wert={prozent(abschluss.anteil_fenster_ohne_trade)}",
|
||
"src/components/LaufKampagne.test.tsx",
|
||
),
|
||
(
|
||
"close() merkt sich das Ende nicht",
|
||
"src/lib/api.ts",
|
||
" beendet = true;\n",
|
||
"",
|
||
"src/lib/api.test.ts",
|
||
),
|
||
(
|
||
"close() raeumt den Zeitgeber nicht",
|
||
"src/lib/api.ts",
|
||
" if (zeitgeber !== null) clearTimeout(zeitgeber);\n",
|
||
"",
|
||
"src/lib/api.test.ts",
|
||
),
|
||
(
|
||
# Der Backslash kommt aus chr(92): Eine Escape-Folge im eigenen Quelltext wertet sonst
|
||
# irgendeine Schicht aus -- genau das ist bei der Umsetzung passiert.
|
||
"Lizenztext mit doppeltem Backslash (Escape-Folge als Klartext auf der Seite)",
|
||
"src/components/Markt.tsx",
|
||
"Charts" + chr(92) + "u2122 Copyright (" + chr(92) + "u0441) 2025",
|
||
"Charts" + chr(92) * 2 + "u2122 Copyright (" + chr(92) * 2 + "u0441) 2025",
|
||
"src/components/Markt.test.tsx",
|
||
),
|
||
]
|
||
|
||
|
||
def fahre(testdatei: str) -> tuple[bool, str]:
|
||
ergebnis = subprocess.run(
|
||
f"npx vitest run {testdatei}",
|
||
cwd=DASH,
|
||
shell=True,
|
||
capture_output=True,
|
||
text=True,
|
||
encoding="utf-8",
|
||
errors="replace",
|
||
stdin=subprocess.DEVNULL,
|
||
)
|
||
ausgabe = ergebnis.stdout + ergebnis.stderr
|
||
rote = [z.strip() for z in ausgabe.splitlines() if z.strip().startswith(("×", "FAIL", "✗")) or " > " in z and "FAIL" in z]
|
||
return ergebnis.returncode == 0, "; ".join(rote[:4])
|
||
|
||
|
||
def main() -> int:
|
||
befunde = 0
|
||
for testdatei in sorted({m[4] for m in MUTANTEN}):
|
||
gruen, _ = fahre(testdatei)
|
||
if not gruen:
|
||
print(f"BEFUND Grundlinie: {testdatei} ist ohne Mutant nicht gruen")
|
||
return 2
|
||
print("Grundlinie gruen.")
|
||
for name, datei, alt, neu, testdatei in MUTANTEN:
|
||
pfad = DASH / datei
|
||
sicherung = pfad.read_bytes()
|
||
text = sicherung.decode("utf-8")
|
||
anzahl = text.count(alt)
|
||
if anzahl != 1:
|
||
print(f"BEFUND Mutant '{name}': Stelle steht {anzahl}-mal in {datei}")
|
||
befunde += 1
|
||
continue
|
||
try:
|
||
pfad.write_bytes(text.replace(alt, neu).encode("utf-8"))
|
||
gruen, rote = fahre(testdatei)
|
||
finally:
|
||
pfad.write_bytes(sicherung)
|
||
if gruen:
|
||
print(f"BEFUND Mutant '{name}' bleibt GRUEN ({testdatei})")
|
||
befunde += 1
|
||
else:
|
||
print(f"rot {name} [{rote}]")
|
||
print(f"{befunde} Befund(e).")
|
||
return 2 if befunde else 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|