Die vorigen Durchgaenge waren Handarbeit und liefen nur, wenn jemand daran
dachte. Jetzt sind alle drei automatisiert.
JAVASCRIPT - DIE RENDER-PROBE DECKTE 2 VON 15 FUNKTIONEN AB.
render_check.mjs schnitt per Regex genau ZWEI Funktionen heraus (renderM15,
renderBrk). renderKontext und 13 weitere waren nie abgedeckt - und genau dort
ist mir heute der d-statt-snap-Beinahefehler unterlaufen. Die Probe haette ihn
DURCHGELASSEN.
Neu geschrieben: die komplette app.js laeuft in einem VM-Kontext gegen ein
Minimal-DOM, jede render*-Funktion wird aufgerufen - zweimal, mit dem Fixture
UND mit einem leeren Snapshot (der Kaltstart, in dem jedes Feld fehlt).
13 Funktionen laufen durch. Mutationsprobe mit genau dem heutigen Fehler:
4 Treffer, waehrend node --check NICHTS meldet - der blinde Fleck ist damit zu.
Kein npm, kein jsdom: das DOM ist eine Attrappe von 20 Zeilen, Pruef- und
Laufumgebung bleiben derselbe Parser.
ZWEI NEUE STUFEN, beide mutationsgeprueft:
F) ELEMENT-IDs - JS gegen HTML. Stand: 133 IDs, keine verwaist, keine doppelt.
Kommentare werden vorher entfernt, sonst waeren die Beispiele im
Kopfkommentar zwei Dauer-Fehlalarme (die Lehre vom Linter).
G) ABHAENGIGKEITEN - jeder Import aus server.py/core/ gegen requirements.txt.
Stand: 39 Dateien, alle 9 externen Importe aufgefuehrt, keine Versionsdrift.
UND DIE PIPELINE HAT SICH SELBST ERWISCHT: mein erster Entwurf von Stufe G
importierte `ast` nicht. Der stille except-continue liess JEDE Datei
durchfallen, und die Stufe meldete "alle 0 externen Laufzeit-Importe sind
aufgefuehrt" - ein gruener Haken, hinter dem nichts geprueft wurde. Fuenfte
Wiederholung dieser Fehlerklasse. Gefangen hat es ruff F821 in derselben
Pipeline. Behoben doppelt: Import ergaenzt UND Plausibilitaetspruefung (weniger
Dateien gelesen als vorhanden oder 0 Importe -> Befund).
SLOTS - keine neuen Defekte, drei Punkte praezisiert:
· Kein geteilter Modul-Zustand. Die modulweiten Container in trailing.py und
trader.py sind reine Nachschlagetabellen, kein global-Statement. Die beiden
Instanzen sind tatsaechlich unabhaengig - Voraussetzung des ganzen Umbaus.
· set_sltp bleibt Slot-1-only, verhaelt sich aber SICHER: liegt nur eine
BRK-Position, gibt modify_sltp einen Fehlertext zurueck. Es fasst NICHT die
falsche Position an. Bekannte Grenze, kein Fehler.
· trail_brk.enabled wird nicht persistiert; _rebind_brk schaltet es nach einem
Neustart bedingungslos ein. Sichere Richtung, bewusst so gelassen.
BIBLIOTHEKEN: nichts fehlt, nichts driftet. pandas/scikit-learn stehen in
requirements-dev und werden in 0 Dateien importiert (so dokumentiert); numba,
joblib, tqdm, pandas_ta, rich, httpx sind Beifang und ungenutzt - kein
Handlungsbedarf, sie stehen nicht im Laufzeit-Pfad.
Struktureller Rest benannt: engine.py importiert weekly_review und
measurement_reminder, zwei Skripte der obersten Ebene - dieselbe Klasse wie der
frueher direkte backtest-Import. Hier entschaerft, weil lazy und in try, mit
sichtbarer Fehlermeldung. In Stufe G als projekteigen ausgenommen, mit
Begruendung im Code.
Pipeline jetzt A A2 A3 B B2 C C2 D E F G - alle gruen, 97 Tests, deployt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
119 lines
5.0 KiB
JavaScript
119 lines
5.0 KiB
JavaScript
// Render-Probe: laesst ALLE render*-Funktionen gegen ein Minimal-DOM laufen.
|
|
//
|
|
// ⚠⚠ WOZU. Ein `ReferenceError` mitten im Render bricht den GESAMTEN Durchlauf
|
|
// ab: das Dashboard friert auf Altwerten ein, Server und Snapshot sind dabei
|
|
// korrekt. `node --check` sieht das NICHT — die Datei ist syntaktisch einwandfrei.
|
|
// Real passiert:
|
|
// · 01.08. — ein direkter Zugriff auf ein noch nicht ausgeliefertes Element
|
|
// · 20.08. — die RSI-Zeile griff in `renderM15(s)` auf `d.market` zu
|
|
// · 20.08. — der Trailing-Block landete in `renderKontext(snap)` und las `d.…`
|
|
// Der dritte Fall waere durch die ALTE Fassung dieser Probe geschluepft: sie
|
|
// schnitt per Regex genau ZWEI Funktionen heraus (`renderM15`, `renderBrk`).
|
|
// `renderKontext` und 13 weitere waren nie abgedeckt.
|
|
//
|
|
// ⚠ Jetzt wird die KOMPLETTE `app.js` in einem VM-Kontext geladen und jede
|
|
// gefundene `render*`-Funktion aufgerufen — mit dem Fixture-Snapshot UND mit
|
|
// einem leeren Objekt (der Kaltstart-Fall, in dem jedes Feld fehlt).
|
|
//
|
|
// ⚠ Kein npm, kein jsdom: das DOM ist eine Attrappe von 20 Zeilen. Damit bleibt
|
|
// die Pruefumgebung dieselbe Laufzeit wie die Zielumgebung (V8) — genau die
|
|
// Divergenz, die beim `.ps1`-BOM und beim pre-commit-Framework zugeschlagen hat.
|
|
//
|
|
// Aufruf: node tools/render_check.mjs <snapshot.json>
|
|
import fs from "node:fs";
|
|
import vm from "node:vm";
|
|
|
|
const pfad = process.argv[2] || "tests/fixtures/snapshot.json";
|
|
const snap = JSON.parse(fs.readFileSync(pfad, "utf-8"));
|
|
const src = fs.readFileSync("web/app.js", "utf-8");
|
|
|
|
function el() {
|
|
const o = {
|
|
textContent: "", innerHTML: "", className: "", title: "", value: "",
|
|
disabled: false, checked: false, style: {}, dataset: {},
|
|
classList: { add() {}, remove() {}, toggle() {}, contains() { return false; } },
|
|
appendChild() {}, removeChild() {}, setAttribute() {}, removeAttribute() {},
|
|
addEventListener() {}, focus() {}, blur() {}, remove() {},
|
|
getBoundingClientRect() { return { top: 0, left: 0, width: 0, height: 0 }; },
|
|
querySelector() { return el(); }, querySelectorAll() { return []; },
|
|
children: [], parentNode: null, firstChild: null,
|
|
};
|
|
return o;
|
|
}
|
|
|
|
const ctx = {
|
|
console,
|
|
document: {
|
|
getElementById: () => el(), querySelector: () => el(),
|
|
querySelectorAll: () => [], createElement: () => el(),
|
|
addEventListener() {}, body: el(), documentElement: el(),
|
|
activeElement: null, hidden: false, visibilityState: "visible",
|
|
},
|
|
window: {
|
|
addEventListener() {}, setTimeout() {}, clearTimeout() {},
|
|
location: { href: "", protocol: "http:", host: "x" },
|
|
localStorage: { getItem: () => null, setItem() {}, removeItem() {} },
|
|
matchMedia: () => ({ matches: false, addEventListener() {} }),
|
|
},
|
|
navigator: { userAgent: "node" },
|
|
location: { href: "", protocol: "http:", host: "x" },
|
|
localStorage: { getItem: () => null, setItem() {}, removeItem() {} },
|
|
setInterval: () => 0, clearInterval() {}, setTimeout: () => 0, clearTimeout() {},
|
|
requestAnimationFrame: () => 0,
|
|
fetch: () => new Promise(() => {}),
|
|
WebSocket: function () { return { close() {}, send() {} }; },
|
|
AudioContext: function () {
|
|
return { createOscillator: () => ({ connect() {}, start() {}, stop() {},
|
|
frequency: { setValueAtTime() {} }, type: "" }),
|
|
createGain: () => ({ connect() {}, gain: { setValueAtTime() {},
|
|
exponentialRampToValueAtTime() {} } }),
|
|
currentTime: 0, destination: {}, resume: () => Promise.resolve(),
|
|
state: "running" };
|
|
},
|
|
Notification: function () {},
|
|
alert() {}, confirm: () => true, prompt: () => null,
|
|
};
|
|
ctx.window.document = ctx.document;
|
|
ctx.globalThis = ctx;
|
|
ctx.self = ctx;
|
|
vm.createContext(ctx);
|
|
|
|
try {
|
|
vm.runInContext(src, ctx, { filename: "app.js" });
|
|
} catch (e) {
|
|
console.log(` ❌ app.js liess sich nicht laden: ${e.constructor.name}: ${e.message}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
// Jede render*-Funktion einsammeln (die im Kontext wirklich existiert).
|
|
const namen = Object.keys(ctx).filter(
|
|
(k) => /^render/.test(k) && typeof ctx[k] === "function");
|
|
if (namen.length < 5) {
|
|
console.log(` ❌ nur ${namen.length} render*-Funktionen gefunden — Probe greift nicht`);
|
|
process.exit(1);
|
|
}
|
|
|
|
// ⚠ Zwei Durchlaeufe. Der LEERE Snapshot ist der wichtigere: er stellt den
|
|
// Kaltstart nach, in dem noch kein Feld befuellt ist — dort schlagen fehlende
|
|
// Null-Pruefungen zu, nicht bei vollen Daten.
|
|
const faelle = [["Fixture", snap], ["leerer Snapshot", {}]];
|
|
let fehler = 0;
|
|
for (const [lbl, daten] of faelle) {
|
|
for (const n of namen) {
|
|
try {
|
|
// `renderM15` nimmt (setup, snapshot), alle uebrigen nur (snapshot).
|
|
if (n === "renderM15") ctx[n](daten.m15_setup || {}, daten);
|
|
else ctx[n](daten);
|
|
} catch (e) {
|
|
fehler++;
|
|
console.log(` ❌ ${n}(${lbl}): ${e.constructor.name}: ${e.message}`);
|
|
}
|
|
}
|
|
}
|
|
if (fehler) {
|
|
console.log(` ${fehler} Fehler in ${namen.length} render*-Funktionen`);
|
|
process.exit(1);
|
|
}
|
|
console.log(` ✅ ${namen.length} render*-Funktionen laufen durch `
|
|
+ `(Fixture UND leerer Snapshot)`);
|