Regelwerk, Agenten, Skills und Werkzeuge veröffentlichen

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]>
This commit is contained in:
Pascal MichelandClaude Opus 5 committed 2026-09-17 22:38:15 +02:00
commit 2c9a4475fc
97 files changed
+14627

No files matched your search

@@ -0,0 +1,116 @@
"""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())