diff --git a/CLAUDE.md b/CLAUDE.md index d3710b3..3de7966 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -257,8 +257,28 @@ dort bereits nachvalidiert, ØR +0,305.) **Eine** Oberfläche: (WR/PF/Verhältnis/Worst je KW, Ausrichtungs-Split mit/gegen/ohne) gegen die Backtest-Erwartung (WR~68 % · PF~1,3 · Verh~0,55) und flaggt Leckagen (Gegen-Signal- Anteil, WR-Verfall, PF<1, Einzelverlust). **Wöchentlich** laufen lassen (B4/B5). -- **Vor „fertig":** immer `python -m py_compile `; JS grob via Klammern- - Balance prüfen (kein node im Env). +- **Vor „fertig":** immer `python -m py_compile `; JS via **`node --check`** + (Stufe B in `tools/check_nfalle.py`, läuft im pre-commit-Hook mit). + ⚠⚠ **KORREKTUR 2026-08-07: „kein node im Env" stimmte nicht mehr** — Node + **v24.18.0** ist installiert. Die Zeile hat die Frage „können wir Node nutzen?" + jahrelang falsch beantwortet. + **Gemessen, warum das zählt:** die alte Klammern-Balance findet **1 von 5** + realistischen Fehlern — `const x = ;`, doppeltes `let`/`const` und `return` + ausserhalb einer Funktion laufen glatt durch; `node --check` findet **5 von 5** + in **86 ms**. Ein Syntaxfehler in `app.js` bricht den **GESAMTEN** Render + (Dashboard friert auf Altwerten ein) — bei **95 direkt dereferenzierten** + `$("id")`-Zugriffen ist das kein theoretisches Risiko. + ⚠ **Geprüft wird als MODUL (`.mjs`), nicht als CommonJS:** als CJS hält Node ein + top-level `return` für legal, der Browser lädt `app.js` aber als klassisches + Script, wo es ein Syntaxfehler ist. Verifiziert, dass das echte `app.js` den + strengeren Modus **ohne Anpassung** besteht. + ⚠ **Kein npm, keine `package.json`, kein `node_modules`** — `node --check` ist + die Laufzeit selbst. Damit entsteht NICHT die Divergenz „Prüfumgebung ≠ + Laufumgebung" (die beim `.ps1`-BOM und beim `pre-commit`-Framework das Problem + war): Node und Chrome benutzen **denselben Parser (V8)**. + ✅ **Drei Richtungen verifiziert:** sauber → grün · mit eingebautem Fehler → + **Exit 1**, Commit gestoppt · **ohne Node im PATH** → Rückfall auf die alte + Prüfung, Exit 0 (eine frische Maschine darf am Hook nicht hängenbleiben). - **✅ BOOT-LÜCKE GESCHLOSSEN: Auto-Logon AKTIV (2026-08-07).** `OilTradingServer` und `HyperliquidDashboard` hängen an einem **Logon**-Trigger — nach einem Update-Reboot läuft nichts bis zur Anmeldung (real 20.07.: diff --git a/tools/check_nfalle.py b/tools/check_nfalle.py index 8c91fce..67b0941 100644 --- a/tools/check_nfalle.py +++ b/tools/check_nfalle.py @@ -190,18 +190,75 @@ def js_offene_strings(text: str): print() print("=" * 88) -print(" B) JAVASCRIPT — unabgeschlossene String-Literale") +print(" B) JAVASCRIPT — Syntax (node) + unabgeschlossene String-Literale") print("=" * 88) + + +def node_pruefen(p: pathlib.Path): + """Echte Syntaxpruefung mit `node --check`. Gibt die Fehlerzeile zurueck oder + None; `False` heisst „Node nicht verfuegbar". + + ⚠ WARUM DAS DAZUKAM (2026-08-07). Die Klammern-Balance findet gemessen nur + 1 von 5 realistischen Fehlern — `const x = ;`, ein doppeltes `let`/`const` + und ein `return` ausserhalb einer Funktion laufen glatt durch. Ein + Syntaxfehler in `app.js` bricht aber den GESAMTEN Render: das Dashboard + friert auf Altwerten ein. Bei 95 direkten Element-Zugriffen ist das kein + theoretisches Risiko. + + ⚠ GEPRUEFT WIRD ALS MODUL (.mjs), NICHT ALS CommonJS. Als CJS haelt Node ein + top-level `return` fuer legal — der Browser laedt `app.js` aber als + klassisches Script, wo es ein Syntaxfehler ist. Der Modul-Modus liegt naeher + am Browser; verifiziert, dass das echte `app.js` ihn ohne Anpassung besteht. + + ⚠ Kein npm, keine package.json, kein node_modules — `node --check` ist die + Laufzeit selbst. Damit entsteht NICHT die Divergenz „Pruefumgebung ist nicht + die Laufumgebung", an der dieses Projekt schon zweimal aufgelaufen ist: + Node und Chrome benutzen denselben Parser (V8). + + ⚠ Fehlt Node, faellt die Stufe still auf die alte Prueflogik zurueck — eine + frische Maschine soll den Hook nicht blockieren. + """ + try: + with tempfile.NamedTemporaryFile("w", suffix=".mjs", delete=False, + encoding="utf-8") as f: + f.write(p.read_text(encoding="utf-8", errors="replace")) + tmp = f.name + try: + r = subprocess.run(["node", "--check", tmp], + capture_output=True, text=True, timeout=60) + finally: + try: + pathlib.Path(tmp).unlink() + except OSError: + pass + except (FileNotFoundError, OSError, subprocess.TimeoutExpired): + return False + if r.returncode == 0: + return None + for z in (r.stderr or "").splitlines(): + if "Error" in z: + return z.strip() + return "node --check meldet einen Fehler" + + for p in dateien(".js"): if "lightweight-charts" in p.name: continue + rel = p.relative_to(WURZEL) + nd = node_pruefen(p) + if nd is False: + print(f" ⚠ node fehlt — nur Ersatzpruefung fuer {rel}") + elif nd: + befunde.append(f"JS {rel} (node)") + print(f" FEHLER {rel} {nd}") + continue # bei kaputter Syntax ist die Zeilenheuristik sinnlos tr = js_offene_strings(p.read_text(encoding="utf-8", errors="replace")) if tr: for nr, z in tr: - befunde.append(f"JS {p.relative_to(WURZEL)}:{nr}") - print(f" FEHLER {p.relative_to(WURZEL)}:{nr} {z}") + befunde.append(f"JS {rel}:{nr}") + print(f" FEHLER {rel}:{nr} {z}") else: - print(f" OK {p.relative_to(WURZEL)}") + print(f" OK {rel}" + (" (node)" if nd is None else "")) # ── C) literales \n als TEXT ─────────────────────────────────────────────