Files
DogFatherGitandClaude Opus 5 39ca642a52 Acht Pruefungen standen Nacht fuer Nacht als rot da -- sie waren gruen
Der naechtliche Lauf meldete heute frueh "37 Pruefungen sind rot".
Acht davon waren gar nicht rot: fehlerfrei durchgelaufen, Exitcode 0,
keine einzige FEHL-Zeile. Der Laeufer zaehlte bei ihnen aber NULL
Einzelpruefungen, und "null Pruefungen ist ein Fehler" -- eine Regel,
die richtig ist und hier das Falsche traf.

DER GRUND WAR EIN GROSSBUCHSTABE. Der Zaehler suchte `(ok|FEHL)`;
pruef-kachelfarben, -livepunkt, -tippziele, -turn-wege, -leerzustand,
-nachfrage, -tagesruf und -anruf-klingelt schreiben `  OK `.

Zwei Schaeden auf einmal:
  1. Ihre Punkte fehlten in der Gesamtzahl -- allein in fuenf der acht
     sind das 114 Stueck. Ausgerechnet die Zahl, die vor stillen
     Aussetzern schuetzen soll, war selbst eine Luecke.
  2. Acht dauerhaft rote Eintraege in einer Notiz, die morgens gelesen
     wird. Eine Warnung, die immer kommt, ist keine mehr.

Der Zaehler liest jetzt beide Schreibweisen. Die Dateien werden NICHT
vereinheitlicht: Acht umzuschreiben waeren acht Gelegenheiten, etwas
kaputtzumachen -- und die neunte, die morgen jemand anlegt, schreibt
ohnehin wieder, was sie will.

DAZU EINE PRUEFUNG, DIE DAS FESTHAELT (server/pruef-pruefzaehler.mjs).
Ein Kommentar haette den naechsten Fall nicht verhindert. Sie holt
sich den Ausdruck AUS alles-pruefen.mjs (zwei Fassungen desselben
Musters laufen auseinander), startet vier der schnellsten Pruefungen
wirklich -- je zwei in beiden Schreibweisen -- und hat drei
Gegenproben: Sie darf nicht wahllos zaehlen, sie muss zwei als zwei
zaehlen, und sie muss null als null sehen koennen, sonst waere "null
ist ein Fehler" blind.

UND DIE NOTIZ SAGT JETZT, WAS SIE MEINT. Statt "(keine Fehlerzeile
gefunden)" steht bei diesen Faellen: "Kein Befund -- es wurde keine
einzige Pruefung GEZAEHLT", mit der Erklaerung dazu. Fuer alles andere
ohne Fehlerzeile gibt es den dritten Ausgang ("Konnte nicht sagen,
woran es lag") samt den letzten Ausgabezeilen.

NEBENBEFUND, GEFUNDEN VON pruef-rueckmeldung: Die Tuer ins andere Haus
trug Ton 40 -- dieselbe Nummer wie "Entwicklung". Auf DogFathers Wand
standen zwei Kacheln in derselben Farbe, und er ist der Einzige, der
beide sieht; deshalb ist es nie jemandem aufgefallen.

  Die naheliegende Antwort waere eine 46. Farbe gewesen. Gerechnet kam
  ein Abstand von 0,0862 heraus -- unter der Hausgrenze von 0,09. Der
  Farbraum ist bei 45 Toenen voll, und eine zweite benannte Ausnahme
  am selben Tag waere der Anfang vom Ende der Regel.

  Richtig ist die andere Antwort: Die Tuer ist gar keine
  Bereichskachel. Sie fuehrt hinaus und gehoert keinem Bereich an --
  also bekommt sie keine Bereichsfarbe, sondern faellt auf --akzent
  zurueck. Damit unterscheidet sie sich von allen 45 anderen.

  Gefunden hat das die Pruefung erst, nachdem sie SAGEN konnte, welche
  Nummer doppelt ist. Vorher stand dort nur "kein Farbton doppelt (34
  Kacheln vom Server)" -- damit sucht man in vier Listen ueber zwei
  Dateien.

  Dazu: start.js schreibt kein data-ton="undefined" mehr (String()
  macht aus einem fehlenden Wert sonst ein Wort, und jede Pruefung,
  die Toene zaehlt, liest dann Text statt Zahl).

WAS MICH VOR DER FALSCHEN REPARATUR BEWAHRT HAT: Meine erste Vermutung
war, die FEHL-Zeilen staenden zu weit hinten im Ausgabefenster. Die
Gegenprobe dazu wurde rot -- null Dateien. Genau dafuer ist sie da.

GEMESSEN:
- pruef-pruefzaehler (neu): 7 Pruefungen, 0 Fehler.
- pruef-rueckmeldung: 30 geprueft, 0 Fehler (war rot).
- pruef-kachelfarben 26/0, pruef-haus-trennung 100/0,
  pruef-crew-adresse 153/0.
- tools/.nachtlauf-* ist jetzt ignoriert: Laufzeitzustand, der sich
  jede Nacht aendert. Das Ergebnis steht in der Vault-Notiz.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-25 06:46:49 +02:00

161 lines
7.0 KiB
JavaScript

/* Laesst JEDE Pruefung laufen und zaehlt mit.
WARUM EIN EIGENER LAeUFER und nicht eine Zeile in der Shell:
1. DIE ANZAHL MUSS STIMMEN. Ein gruener Lauf ist kein Beweis, solange
nicht auch die Zahl der Pruefungen stimmt -- eine Datei, die still
nicht startet, faellt sonst niemandem auf. Hier wird jede Datei
einzeln gezaehlt, und die Gesamtzahl der Einzelpruefungen steht am
Ende.
2. EIN FEHLSCHLAG DARF DEN LAUF NICHT ABBRECHEN. Sonst sieht man den
ersten Fehler und weiss nichts ueber die restlichen zwanzig.
3. DIE DAUER GEHOeRT DAZU. Eine Pruefung, die ploetzlich dreimal so
lange braucht, ist meist eine, die auf etwas wartet, das es nicht
mehr gibt.
*/
import { readdirSync } from "node:fs";
import { spawn } from "node:child_process";
import { join } from "node:path";
const ORDNER = "server";
const dateien = readdirSync(ORDNER)
.filter((n) => n.startsWith("pruef-") && n.endsWith(".mjs"))
.sort();
console.log(`${dateien.length} Pruefdateien gefunden\n`);
/* ---------- JEDE PRUEFUNG BEKOMMT EINE FRIST (06.09.2026) ---------------
VIERTER GRUND fuer diesen eigenen Laeufer, und er hat mich an einem
Tag ZWEIMAL erwischt:
Eine Pruefung, die haengt, bringt den GANZEN Lauf zum Stillstand --
ohne Fehlermeldung, ohne FEHL, ohne Absturz. Es steht einfach nichts
mehr da. Von aussen sieht "noch nicht fertig" genauso aus wie "haengt
fuer immer", und deshalb faellt es erst Stunden spaeter auf.
* pruef-alle-wege lief in den Ereignisstrom des Chats und wartete
auf ein Ende, das es nie gibt (behoben in der Datei selbst).
* pruef-call-kategorien blieb DREI STUNDEN stehen. Sie hatte, anders
als pruef-handy, keine eigene Notbremse.
Einzelne Dateien nachzuruesten hilft genau so lange, bis jemand die
naechste ohne Notbremse schreibt. Deshalb sitzt sie jetzt HIER, wo
sie fuer alle gilt -- auch fuer die, die es noch nicht gibt.
Und eine ueberschrittene Frist ist ein FEHLER, kein Ueberspringen: Sie
wird gezaehlt, gemeldet und mit der letzten Ausgabe der Datei belegt,
damit man sieht, wo sie stehengeblieben ist. Ein stiller Stillstand
waere das Gegenteil.
600 Sekunden sind grosszuegig bemessen: Die langsamste ehrliche
Pruefung im Haus (pruef-barrierefrei-workspace) braucht 190 s. Wer
das Dreifache davon ueberschreitet, wartet nicht -- er haengt. */
const FRIST_MS = 600_000;
const laufen = (datei) => new Promise((fertig) => {
const start = Date.now();
const kind = spawn(process.execPath, [join(ORDNER, datei)], {
stdio: ["ignore", "pipe", "pipe"],
});
let aus = "";
let abgewuergt = false;
kind.stdout.on("data", (d) => { aus += d; });
kind.stderr.on("data", (d) => { aus += d; });
const wecker = setTimeout(() => {
abgewuergt = true;
/* Erst freundlich, dann bestimmt. Ein Playwright-Browser haengt
sonst als Waise weiter und belegt Speicher bis zum Neustart. */
try { kind.kill("SIGTERM"); } catch { /* schon weg */ }
setTimeout(() => { try { kind.kill("SIGKILL"); } catch { /* schon weg */ } }, 3000);
}, FRIST_MS);
kind.on("close", (code) => {
clearTimeout(wecker);
const sek = Math.round((Date.now() - start) / 100) / 10;
/* ==== GROSS ODER KLEIN -- BEIDES ZAEHLT (25.09.2026) ==========
Hier stand `(ok|FEHL)`. Acht Pruefdateien schreiben aber „OK"
in Grossbuchstaben (pruef-kachelfarben, -livepunkt, -tippziele,
-turn-wege, -leerzustand, -nachfrage, -tagesruf,
-anruf-klingelt). Fuer sie zaehlte dieser Ausdruck NULL --
und weil „null Pruefungen ist ein Fehler" (die Regel direkt
darunter, und sie ist richtig), standen sie Nacht fuer Nacht
als ROT in der Notiz, obwohl sie fehlerfrei durchliefen.
Exitcode 0, keine FEHL-Zeile, trotzdem rot.
Zwei Schaeden auf einmal: Ihre Pruefungen fehlten in der
Gesamtzahl (also genau der Zahl, die vor stillen Aussetzern
schuetzen soll), und acht dauerhaft rote Eintraege gewoehnen
einem das Hinsehen ab.
DIE SCHREIBWEISE WIRD NICHT VEREINHEITLICHT, SONDERN GELESEN.
Acht Dateien umzuschreiben waere acht Gelegenheiten, etwas
kaputtzumachen -- und die neunte Datei, die jemand morgen
anlegt, schreibt ohnehin wieder, was sie will. Ein Zaehler, der
beide Schreibweisen kennt, braucht niemanden zu erziehen. */
const einzeln = (aus.match(/^\s{2}(ok|OK|FEHL)\s/gm) || []).length;
const schlecht = (aus.match(/^\s{2}FEHL\s/gm) || []).length;
if (abgewuergt) {
aus += `\n\n FEHL DIE PRUEFUNG HING. Nach ${Math.round(FRIST_MS / 1000)} s kam nichts mehr`
+ " -- abgebrochen.\n Letzte Ausgabe davor steht oben; dort ist sie stehengeblieben."
+ "\n Haeufigste Ursache: eine Verbindung, die nie endet (Ereignisstrom),"
+ "\n oder ein warten auf etwas, das nicht kommt.\n";
}
fertig({
datei, code: abgewuergt ? 124 : code, sek,
/* Die abgewuergte Pruefung zaehlt als fehlgeschlagen, nicht als
"keine Pruefung gelaufen" -- das sind zwei verschiedene Sachen,
und beide muessen unterscheidbar bleiben. */
einzeln: einzeln + (abgewuergt ? 1 : 0),
schlecht: schlecht + (abgewuergt ? 1 : 0),
aus, hing: abgewuergt,
});
});
});
let gesamt = 0, kaputt = 0, einzelnGesamt = 0, einzelnSchlecht = 0;
const fehlerhafte = [];
for (const datei of dateien) {
const r = await laufen(datei);
gesamt++;
einzelnGesamt += r.einzeln;
einzelnSchlecht += r.schlecht;
/* NULL PRUEFUNGEN IST EIN FEHLER, KEIN ERFOLG.
Beim ersten Lauf stand hier nur `code === 0 && schlecht === 0` --
und pruef-kopf-messen.mjs kam damit als "ok" durch, obwohl sie
ueberhaupt nichts geprueft hat (sie war ein reines Messwerkzeug und
endete immer mit 0). Genau so sieht eine Pruefung aus, die immer
bestaetigt: gruen, und wertlos. */
const gut = r.code === 0 && r.schlecht === 0 && r.einzeln > 0;
if (!gut) { kaputt++; fehlerhafte.push(r); }
console.log(
`${gut ? " ok " : " FEHL "} ${r.datei.padEnd(30)}`
+ `${String(r.einzeln).padStart(4)} Pruefungen`
+ `${r.schlecht ? `, ${r.schlecht} FEHLGESCHLAGEN` : ""}`
+ ` ${String(r.sek).padStart(6)} s`
+ (r.einzeln === 0 ? " KEINE PRUEFUNG GELAUFEN" : ""));
}
console.log("\n" + "=".repeat(64));
console.log(`Dateien: ${gesamt - kaputt} von ${gesamt} in Ordnung`);
console.log(`Einzelpunkte: ${einzelnGesamt - einzelnSchlecht} von ${einzelnGesamt} bestanden`);
/* Eine Datei ohne eine einzige Pruefung ist ein Fehler, kein Erfolg. */
const leer = dateien.length && einzelnGesamt === 0;
if (leer) console.log("ACHTUNG: keine einzige Pruefung ist gelaufen.");
for (const r of fehlerhafte) {
console.log("\n" + "-".repeat(64));
console.log(`### ${r.datei} (Exitcode ${r.code})`);
const zeilen = r.aus.split("\n").filter((z) => /FEHL|Error|error:/.test(z));
console.log(zeilen.slice(0, 12).join("\n") || r.aus.slice(-800));
}
console.log("\n" + (kaputt || leer ? "NICHT in Ordnung." : "Alles in Ordnung."));
process.exit(kaputt || leer ? 1 : 0);