Files
DogFatherGitandClaude Opus 5 775aabef38 Standwache: hat sich der Stand WAEHREND des Laufs geaendert?
Die zweite Sitzung hat die Luecke benannt: Das Arbeitsschloss
schuetzt den Commit und die Stempellaeufe, nicht die Pruefläufe. Wer
misst, waehrend ein anderer speichert, misst einen Stand, den es
nicht mehr gibt.

Am 06./07.09.2026 sind so fuenf Gesamtlaeufe wertlos geworden — rund
zwei Stunden Wartezeit ohne einen einzigen Befund. Am 01.10. dieselbe
Lage, nur anders: zwei Sitzungen im Verzeichnis, eine misst, die
andere speichert. Aufgefallen ist es nur, weil die andere es von
sich aus gesagt hat.

DIE FRAGE IST EINE MESSUNG, KEINE ZUSTAENDIGKEIT

„Haelt jemand das Schloss" waere die falsche Frage, und zwar in
beide Richtungen:

  * Sie blockiert zu viel: Wer zwei Stunden am Schloss sitzt, haette
    in der Zeit keinen Prueflauf mehr. Eine Sicherung, die das eigene
    Arbeiten anhaelt, wird abgeschafft.
  * Sie blockiert zu wenig: Filipe am Editor hat kein Schloss, mein
    eigenes Werkzeug auch nicht.

Gefragt wird deshalb: Ist der Stand am Ende noch derselbe wie am
Anfang? Das trifft jede Quelle.

AN DER NOTBREMSE, NICHT IN 179 DATEIEN

Gemessen: 179 von 231 Pruef- und Messdateien rufen `notbremse`. Das
ist die eine Stelle, an der alle etwas bekommen — dieselbe
Ueberlegung wie bei der Notbremse selbst. Einzelne Dateien
nachzuruesten hilft nur bis zur naechsten ohne.

Fingerabdruck: Anzahl, Gesamtgroesse und juengste Aenderung von
workspace, assets, server, webdesign und den Seiten im
Wurzelverzeichnis — 670 Dateien in 27 ms. Kein Hash ueber den
Inhalt: Gesucht ist „hat jemand gespeichert", und das aendert immer
mindestens die Zeit.

BILDER ZAEHLEN NICHT. Die Messdateien legen selbst welche ab; eine
Wache, die bei jedem Bildschirmfoto anschlaegt, wird weggeklickt und
nimmt die echte Meldung mit.

SIE HAELT NICHTS AN. Ein Lauf, dessen Grundlage sich verschoben hat,
ist nicht „nicht in Ordnung" — er ist NICHT NACHSEHBAR. Deshalb
Rueckgabewert 3 (nicht 1, das waere eine Aussage ueber den Code; und
nicht 0, ein gruener Haken ueber einen Stand, den es nicht mehr
gibt, waere das Schlimmere) und ein ausdruecklicher Satz, dass das
kein Befund ist.

GEPRUEFT — pruef-arbeitsschloss 35 -> 48 Pruefungen, 0 Fehler:

  zwei Aufnahmen hintereinander gleich   (sonst waere jede Meldung
                                          wertlos)
  geaenderte Datei            -> faellt auf
  neue Datei                  -> faellt auf
  neues Bild                  -> faellt NICHT auf
  Lauf mit Aenderung          -> Rueckgabe 3, sagt NICHT NACHSEHBAR
  Lauf ohne Aenderung         -> Rueckgabe 0  (Gegenprobe; sonst
                                 waere „endet mit 3" auch wahr, wenn
                                 sie IMMER 3 meldet)

Alles in einem Wegwerf-Verzeichnis mit gefaelschtem Baum — moeglich,
weil die Wache ihre Wurzel aus ihrem EIGENEN Pfad ableitet. Waere
sie festgeschrieben, liesse sich die Wache nicht pruefen, ohne am
echten Haus zu wackeln.

UND AM ECHTEN LAUF NACHGEWIESEN: Mitten in pruef-arten eine Datei
gespeichert -> Rueckgabe 3, mit Groesse und Uhrzeit. Ohne Eingriff
bei neun Laeufen (treff 85, kalender 141, material 159,
erwaehnung 129, arten, dabei-optik, tagesblick, aufgabenbrett,
kopfleiste, seiteninhalt) kein einziger Fehlalarm.

EINE ERWARTUNG VON MIR WAR FALSCH, und die Wache hatte recht: Ich
hatte im gefaelschten Baum eine zaehlende Datei erwartet, es sind
zwei — die Seite UND die Kopie der Wache selbst im server-Ordner.
Der zaehlt mit, und das ist richtig: Eine geaenderte Pruefdatei
verschiebt den Stand genauso wie eine geaenderte Seite.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-10-01 23:18:13 +02:00

101 lines
4.4 KiB
JavaScript

/* DIE NOTBREMSE FÜR PRÜFUNGEN
---------------------------------------------------------------------
DER FEHLER, DEN DAS VERHINDERT (06.09.2026, drei Stunden gekostet)
index.js setzt am Ende bewusst zwei Auffangnetze:
process.on("uncaughtException", (f) => console.error(…));
process.on("unhandledRejection", (g) => console.error(…));
Für den echten Betrieb ist das genau richtig: Ein Fehler in einer
Nebensache darf die Website nicht offline nehmen.
Für eine PRÜFUNG ist es das Gegenteil. Eine Prüfung importiert
index.js in denselben Prozess -- und erbt damit die Netze. Wenn dann
ihr eigener Ablauf abstürzt (ein Playwright-Klick auf ein Element,
das es nicht gibt), wird der Absturz nur PROTOKOLLIERT. Danach
passiert nichts mehr: Das Skript ist zu Ende, aber der Express-Server
hält den Prozess am Leben. Kein Fehler, kein Ergebnis, kein Ende.
Genau so blieb pruef-call-kategorien.mjs drei Stunden stehen -- und
mit ihr der gesamte Regressionslauf, der auf sie wartete. Von aussen
sieht "läuft noch" genauso aus wie "hängt für immer".
---------------------------------------------------------------------
WAS DIESE DATEI TUT
Sie hängt ZWEI eigene Zuhörer daneben (process.on ergänzt, es
ersetzt nicht -- die Meldung von index.js bleibt also erhalten) und
beendet den Lauf mit einem Fehler. Und sie stellt einen Wecker: Wer
nach der Frist noch läuft, wartet nicht mehr, er hängt.
Beides greift NUR in Prüfungen. Der Betrieb importiert diese Datei
nicht und behält seine Netze unverändert.
---------------------------------------------------------------------
BENUTZUNG — nach dem Import von index.js, vor dem ersten Browser:
import { notbremse } from "./helfer-notbremse.mjs";
await import("./index.js");
notbremse(300_000, "die Kategorienpruefung");
*/
/** @param {number} fristMs Nach dieser Zeit gilt der Lauf als haengend.
* @param {string} wer Name für die Meldung. */
import { standWache } from "./helfer-standwache.mjs";
export function notbremse(fristMs = 300_000, wer = "diese Pruefung") {
/* ==== UND HAT SICH DER STAND WAEHREND DES LAUFS GEAENDERT? =======
(01.10.2026, angestossen von der zweiten Claude-Sitzung.)
Am 06./07.09.2026 wurden fuenf Gesamtlaeufe gestartet und
dreimal davon WAEHREND des Laufs weitergebaut. Jeder dieser
Laeufe hat einen Stand gemessen, den es schon nicht mehr gab --
rund zwei Stunden Wartezeit ohne einen einzigen Befund.
Am 01.10. dieselbe Lage, nur anders: Zwei Sitzungen im
Verzeichnis, eine misst, die andere speichert. Aufgefallen ist
es nur, weil die andere es von sich aus gesagt hat.
HIER UND NICHT IN 179 DATEIEN: Wer eine Notbremse hat, bekommt
die Standwache mit. Das ist dieselbe Ueberlegung wie bei der
Notbremse selbst -- einzelne Dateien nachzuruesten hilft nur bis
zur naechsten ohne.
SIE HAELT NICHTS AN. Ein Lauf, dessen Grundlage sich verschoben
hat, ist nicht „nicht in Ordnung" -- er ist NICHT NACHSEHBAR.
Deshalb Rueckgabewert 3 und ein ausdruecklicher Satz, dass das
kein Befund am Code ist. */
standWache(wer);
let schonAus = false;
const raus = (art, was) => {
if (schonAus) return;
schonAus = true;
console.error(`\n FEHL ${wer}: ${art}`);
console.error(` ${String(was?.stack || was).split("\n").slice(0, 6).join("\n ")}`);
console.error(`\n Abgebrochen. Ohne diese Notbremse wuerde der Prozess`);
console.error(` weiterlaufen, weil der Server ihn am Leben haelt --`);
console.error(` ohne Fehler, ohne Ergebnis, ohne Ende.\n`);
process.exit(1);
};
process.on("uncaughtException", (f) => raus("unbehandelter Fehler", f));
process.on("unhandledRejection", (g) => raus("unbehandeltes Versprechen", g));
/* unref(): Der Wecker allein soll den Prozess NICHT am Leben halten.
Sonst haette ausgerechnet die Notbremse dafuer gesorgt, dass eine
fertige Pruefung noch fuenf Minuten herumsteht. */
const wecker = setTimeout(() => {
console.error(`\n FEHL ${wer} HING: nach ${Math.round(fristMs / 1000)} s war sie `
+ `noch nicht fertig.`);
console.error(` Haeufigste Ursachen: ein Warten auf ein Element, das nie kommt,`);
console.error(` oder eine Verbindung, die nie endet (Ereignisstrom).\n`);
process.exit(1);
}, fristMs);
wecker.unref?.();
return () => clearTimeout(wecker);
}