/* ===================================================================== helfer-standwache.mjs — hat sich der Stand WÄHREND des Laufs geändert? --------------------------------------------------------------------- DER FEHLER, DEN DAS SICHTBAR MACHT Am 06./07.09.2026 wurden fünf Gesamtläufe gestartet und dreimal davon WÄHREND des Laufs weitergebaut. Jeder dieser Läufe hat damit einen Stand gemessen, den es schon nicht mehr gab, und war wertlos — rund zwei Stunden Wartezeit ohne einen einzigen zusätzlichen Befund. Am 01.10.2026 ist dieselbe Lage zum zweiten Mal entstanden, nur anders: Zwei Claude-Sitzungen arbeiteten gleichzeitig im Verzeichnis. Während die eine Prüfläufe fuhr, hat die andere Dateien gespeichert. Aufgefallen ist es nur, weil die zweite Sitzung es von sich aus gesagt hat. --------------------------------------------------------------------- WARUM NICHT DAS ARBEITSSCHLOSS FRAGEN Das Schloss beantwortet „arbeitet hier jemand". Das ist die falsche Frage, und zwar in beide Richtungen: * Es blockiert zu viel: Wer zwei Stunden lang am Schloss sitzt, hätte in dieser Zeit keinen einzigen Prüflauf mehr. Eine Sicherung, die das eigene Arbeiten anhält, wird abgeschafft. * Es blockiert zu wenig: Filipe, der in VS Code speichert, hat kein Schloss. Mein eigenes Werkzeug, das nebenbei stempelt, auch nicht. Die Frage, auf die es ankommt, ist eine MESSUNG und keine Zuständigkeit: Ist der Stand am Ende noch derselbe wie am Anfang? Das trifft jede Quelle — die andere Sitzung, den Menschen am Editor, ein Werkzeug von mir. --------------------------------------------------------------------- WAS GEZÄHLT WIRD, UND WAS NICHT Gezählt wird, was eine Messung verfälschen kann: der Quelltext der Seiten und des Servers. Nicht gezählt werden Bilder — die Messdateien legen selbst welche ab (`server/mess-*.png`), und eine Wache, die bei jedem Bildschirmfoto anschlägt, ist eine Warnung, die immer kommt. --------------------------------------------------------------------- SIE HÄLT NICHTS AN Sie meldet. Ein Lauf, dessen Grundlage sich verschoben hat, ist nicht „nicht in Ordnung" — er ist NICHT NACHSEHBAR, der dritte Ausgang. Deshalb setzt sie den Rückgabewert auf 3 und sagt ausdrücklich, dass das kein Befund am Code ist. Ein grüner Haken über einen Stand, den es nicht mehr gibt, wäre das Schlimmere. ===================================================================== */ import { readdirSync, statSync } from "node:fs"; import { join, dirname, extname } from "node:path"; import { fileURLToPath } from "node:url"; const WURZEL = join(dirname(fileURLToPath(import.meta.url)), ".."); /* Wo Quelltext liegt, der eine Messung verändern kann. */ const ORTE = ["workspace", "assets", "server", "webdesign"]; const ZAEHLT = new Set([".js", ".mjs", ".css", ".html", ".webmanifest"]); /** Ein Fingerabdruck des Standes: Anzahl, Gesamtgröße, jüngste Änderung. * * KEIN HASH ÜBER DEN INHALT. Der wäre genauer und kostet bei rund * tausend Dateien ein Mehrfaches — und genauer muss es nicht sein: * Gesucht ist „hat jemand gespeichert", und das ändert immer * mindestens die Änderungszeit. */ export function standNehmen() { let anzahl = 0, bytes = 0, jüngste = 0; const gehen = (ordner, tiefe) => { let eintraege; try { eintraege = readdirSync(ordner, { withFileTypes: true }); } catch { return; } for (const e of eintraege) { if (e.name.startsWith(".") || e.name === "node_modules") continue; const voll = join(ordner, e.name); if (e.isDirectory()) { if (tiefe < 5) gehen(voll, tiefe + 1); continue; } if (!ZAEHLT.has(extname(e.name))) continue; try { const s = statSync(voll); anzahl += 1; bytes += s.size; if (s.mtimeMs > jüngste) jüngste = s.mtimeMs; } catch { /* im Flug verschwunden -- der Vergleich merkt es */ } } }; for (const ort of ORTE) gehen(join(WURZEL, ort), 0); /* Die Seiten im Wurzelverzeichnis gehören dazu, aber nicht alles darunter -- deshalb hier flach. */ try { for (const name of readdirSync(WURZEL)) { if (!ZAEHLT.has(extname(name))) continue; const s = statSync(join(WURZEL, name)); anzahl += 1; bytes += s.size; if (s.mtimeMs > jüngste) jüngste = s.mtimeMs; } } catch { /* egal */ } return { anzahl, bytes, jüngste, genommen: Date.now() }; } /** Vergleicht und meldet. Gibt `true` zurück, wenn der Stand hielt. */ export function standPruefen(vorher, wer = "dieser Lauf") { if (!vorher) return true; const jetzt = standNehmen(); const gleich = jetzt.anzahl === vorher.anzahl && jetzt.bytes === vorher.bytes && jetzt.jüngste === vorher.jüngste; if (gleich) return true; const sek = Math.round((jetzt.genommen - vorher.genommen) / 1000); console.error(""); console.error("\x1b[33m -- NICHT NACHSEHBAR: Der Stand hat sich WÄHREND des Laufs" + " geändert.\x1b[0m"); console.error(` ${wer} lief ${sek} Sekunden. In dieser Zeit:`); if (jetzt.anzahl !== vorher.anzahl) { console.error(` Dateien: ${vorher.anzahl} -> ${jetzt.anzahl}`); } if (jetzt.bytes !== vorher.bytes) { console.error(` Groesse: ${vorher.bytes} -> ${jetzt.bytes} Bytes`); } if (jetzt.jüngste !== vorher.jüngste) { console.error(" jüngste Änderung: " + `${new Date(vorher.jüngste).toLocaleTimeString("de-DE")}` + ` -> ${new Date(jetzt.jüngste).toLocaleTimeString("de-DE")}`); } console.error(""); console.error(" DAS IST KEIN BEFUND AM CODE. Es heisst, dass dieser Lauf"); console.error(" einen Stand gemessen hat, den es am Ende nicht mehr gab —"); console.error(" genau das hat am 06./07.09.2026 zwei Stunden Wartezeit"); console.error(" ohne einen einzigen Befund gekostet."); console.error(""); console.error(" Wer hat gespeichert? Eine zweite Sitzung, ein Editor, ein"); console.error(" Werkzeug? Nachsehen: node tools/arbeitsschloss.mjs ansehen"); console.error(" Dann noch einmal laufen lassen."); console.error(""); return false; } /** Nimmt den Stand und vergleicht ihn beim Programmende von selbst. * * SETZT DEN RÜCKGABEWERT AUF 3 — den dritten Ausgang. Nicht auf 1: * „nicht in Ordnung" wäre eine Aussage über den Code, und die hat * dieser Lauf nicht gemacht. Und nicht auf 0: Ein grüner Haken über * einen Stand, den es nicht mehr gibt, ist das Schlimmere. * * Nur wenn der Lauf sonst erfolgreich war: Ein echter Befund * (Rückgabe 1) ist die wichtigere Nachricht und bleibt stehen. */ export function standWache(wer) { const vorher = standNehmen(); process.on("exit", () => { const hielt = standPruefen(vorher, wer); if (!hielt && (process.exitCode === 0 || process.exitCode === undefined)) { process.exitCode = 3; } }); return vorher; }