Drei weitere Prüfungen, die das Falsche prüften

Der Durchgang, zweiter Teil. Gesucht nach dem schaerfsten Filter, den
es dafuer gibt: dem VERSPRECHEN GEGEN DIE WIRKLICHKEIT -- Pruefsaetze,
die „jede Rolle" oder „jede Seite" sagen. Genau so ist pruef-glocke
heute frueh aufgefallen.

1. pruef-workspace-seiten meldete aufgaben.html als „Breite 1560px".
   KEIN FEHLER: Die Seite traegt zusaetzlich `.inhalt--brett`, und die
   setzt ausdruecklich 1560 px -- mit Begruendung in aufgaben.css („ein
   Brett darf breiter sein als Text, der Kopfbereich bleibt lesbar
   schmal"). Die Pruefung verglich starr mit 1240 und kannte die
   Klasse nicht; sie meldete damit eine Absicht als Fehler, seit dem
   Tag, an dem die Klasse entstand. Mit Gegenprobe belegt: schon vor
   allen Aenderungen von heute rot.
   Jetzt kommt die erwartete Breite aus den KLASSEN des Elements.
   Beide Zahlen bleiben stehen, weil sie etwas aussagen -- kommt
   weder 1240 noch 1560 an, ist die Regel verloren.

2. pruef-meldungen meldete „ohne Satz: ungueltiger_stand". Zuerst ein
   ECHTER Fehler, und zwar meiner vom selben Tag: In
   workspace-support.js stand eine nackte Kennung statt eines Satzes.
   Behoben -- und danach meldete die Pruefung sie WEITER, weil sie das
   Zitat im Kommentar las, der die Behebung begruendet.
   Dieselbe Falle wie ein Grep ueber eine Datei, die ihre eigene
   Geschichte enthaelt; mir ist sie heute schon einmal passiert. Eine
   Pruefung, die verbietet, ueber einen behobenen Fehler zu SCHREIBEN,
   erzieht dazu, die Begruendung wegzulassen. Kommentare zaehlen jetzt
   nicht mehr; Adressen mit // in Zeichenketten bleiben unberuehrt.

3. pruef-auskunft meldete „NICHT EINGEORDNET:
   vorlagen_bewerbungen.aufgabe_id". ECHT: Die Spalte zeigt auf eine
   Aufgabe, nicht auf einen Menschen, und stand in keiner der beiden
   Listen. Das ist mehr als Ordnungsliebe -- bei einer
   Auskunftsanfrage muss das Haus sagen koennen, welche Spalten auf
   eine Person zeigen. Eine unbekannte Spalte ist eine, bei der
   niemand weiss, ob sie mitgehoert.

ZWISCHENSTAND: ACHT Pruefungen an einem Tag, die rot waren oder das
Falsche prueften. Das Muster ist immer dasselbe -- eine Liste oder
Zahl, die zum Zeitpunkt des Schreibens stimmte. Sie wird nicht falsch,
sie wird unzustaendig.

Gruen: pruef-meldungen (8), pruef-auskunft (46),
pruef-workspace-seiten, pruef-support (45), pruef-vorlagen.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-24 13:01:25 +02:00
co-authored by Claude Opus 5
parent 24523cdd4b
commit 1d41e29bf7
44 changed files with 698 additions and 619 deletions
+22 -1
View File
@@ -98,7 +98,28 @@ function kennungenAusServer() {
for (const datei of readdirSync(HIER)) {
if (!datei.endsWith(".js")) continue;
if (datei.startsWith("pruef-") || datei.startsWith("test-")) continue;
const text = readFileSync(join(HIER, datei), "utf8");
/* KOMMENTARE ZAEHLEN NICHT ALS KENNUNG (24.09.2026).
Gefunden an einer Stelle, die genau das dokumentierte, was
diese Pruefung verlangt: In workspace-support.js stand
fehler: "ungueltiger_stand" -- behoben, und der Kommentar
daneben zitierte die alte Zeile als Begruendung. Die Pruefung
las das Zitat und meldete den Fehler weiter, obwohl er behoben
war.
Dieselbe Falle wie ein Grep ueber eine Datei, die ihre eigene
Geschichte enthaelt -- mir ist sie heute schon einmal
passiert. Eine Pruefung, die verbietet, ueber einen behobenen
Fehler zu SCHREIBEN, erzieht dazu, die Begruendung
wegzulassen.
Zeichenketten mit // darin (Adressen) bleiben unberuehrt:
geschnitten wird nur, wo kein Doppelpunkt und kein
Anfuehrungszeichen davorsteht. */
const ohneKommentare = (roh) => roh
.replace(/\/\*[\s\S]*?\*\//g, " ")
.replace(/(^|[^:"'\\])\/\/[^\n]*/gm, "$1");
const text = ohneKommentare(readFileSync(join(HIER, datei), "utf8"));
for (const m of text.matchAll(/fehler:\s*"([a-z0-9_]+)"/g)) {
if (!gefunden.has(m[1])) gefunden.set(m[1], datei);
}
+27 -2
View File
@@ -121,9 +121,17 @@ for (const [breite, hoehe, wie] of [[1440, 1000, "Computer"], [390, 844, "Handy"
.filter((e) => e.getBoundingClientRect().right > window.innerWidth + 1)
.map((e) => (e.tagName + "." + e.className).slice(0, 40)).slice(0, 4),
/* Die verschobenen Klassen muessen weiterhin greifen. .inhalt--breit
setzt 1240px -- kommt nur 880px an, ist die Regel verloren. */
setzt 1240px -- kommt nur 880px an, ist die Regel verloren.
WELCHE KLASSEN TRAEGT DAS ELEMENT? (24.09.2026) Eine Seite
kann zusaetzlich `.inhalt--brett` tragen, und die setzt
ausdruecklich 1560px: Ein Brett darf breiter sein als Text,
der Kopfbereich bleibt bei 1240. Die Pruefung verglich starr
mit 1240 und meldete aufgaben.html deshalb als fehlerhaft --
seit dem Tag, an dem die Klasse entstand. */
breit: document.querySelector(".inhalt--breit")
? getComputedStyle(document.querySelector(".inhalt--breit")).maxWidth : null,
brett: !!document.querySelector(".inhalt--breit.inhalt--brett"),
kopfzeile: document.querySelector(".kopf-zeile")
? getComputedStyle(document.querySelector(".kopf-zeile")).display : null,
abmelden: (() => {
@@ -255,7 +263,24 @@ for (const [breite, hoehe, wie] of [[1440, 1000, "Computer"], [390, 844, "Handy"
? `Bühne: ${r.buehneBild} statt ${r.buehne}`
: `Bühne: die Seite trägt gar kein data-buehne (geladen: ${r.buehneBild || "nichts"})`);
}
if (!(r.breit === null || r.breit === "1240px")) gruende.push(`Breite ${r.breit}`);
/* DIE ERWARTETE BREITE HAENGT AN DER KLASSE, nicht an einer Zahl
im Kopf (24.09.2026).
`.inhalt--brett` setzt 1560px, und zwar mit Begruendung in
aufgaben.css: „Ein Brett darf breiter sein; der Kopfbereich
bleibt lesbar schmal." Wer hier starr 1240 erwartet, meldet
genau diese Absicht als Fehler -- und tat es seit dem Tag, an
dem die Klasse entstand. Gegenprobe gemacht: aufgaben.html war
schon vor jeder Aenderung von heute rot.
BEIDE ZAHLEN BLEIBEN STEHEN, weil sie etwas aussagen: Kommt
weder 1240 noch 1560 an, ist die Regel verloren -- genau der
Fall, fuer den diese Messung gebaut wurde. */
const sollBreit = r.brett ? "1560px" : "1240px";
if (!(r.breit === null || r.breit === sollBreit)) {
gruende.push(`Breite ${r.breit} (erwartet ${sollBreit}`
+ `${r.brett ? ", die Seite traegt .inhalt--brett" : ""})`);
}
if (!(r.kopfzeile === null || r.kopfzeile === "flex")) gruende.push(`Kopfzeile ${r.kopfzeile}`);
const gut = gruende.length === 0;
if (!gut) fehler++;
+16 -1
View File
@@ -72,7 +72,22 @@ export const ZUSATZ = [
/** Spalten auf `_id`, die KEINE Person meinen. Stehen hier, damit die
* Pruefung sagen kann: jede undeklarierte Spalte ist eingeordnet. */
export const KEINE_PERSON = ["eintraege.saeule_id", "treff_entfernt.eintrag_id"];
export const KEINE_PERSON = [
"eintraege.saeule_id",
"treff_entfernt.eintrag_id",
/* Welche Aufgabe aus einer angenommenen Bewerbung entstanden ist
(workspace-vorlagen.js). Sie zeigt auf `aufgaben`, nicht auf einen
Menschen -- die Person steht eine Spalte weiter in `person_id`,
und die hat einen Fremdschluessel.
EINGETRAGEN AM 24.09.2026, gefunden von pruef-auskunft. Ohne
diesen Eintrag ist die Spalte „nicht eingeordnet", und das ist
mehr als Ordnungsliebe: Bei einer Auskunftsanfrage muss das Haus
sagen koennen, welche Spalten auf einen Menschen zeigen. Eine
unbekannte Spalte ist eine, bei der niemand weiss, ob sie
mitgehoert. */
"vorlagen_bewerbungen.aufgabe_id",
];
const GEHEIM = /hash|salt|kennung|token|secret|geheim/i;
+19 -1
View File
@@ -356,7 +356,25 @@ supportRouter.patch("/workspace/api/support/:id(\\d+)", express.json(), (req, re
const wunsch = String(req.body?.stand || "");
if (!Object.values(SUPPORT_STAND).includes(wunsch)) {
return res.status(400).json({ fehler: "ungueltiger_stand" });
/* EIN SATZ, KEINE KENNUNG (24.09.2026, gefunden von
pruef-meldungen am selben Tag, an dem diese Datei entstand).
Hier stand `fehler: "ungueltiger_stand"`. Das Haus verlangt
zu jeder Kennung einen Satz in meldung.js -- sonst steht auf
dem Bildschirm ein Wort mit Unterstrichen. Diesen Fall
trifft ein Mensch zwar nie (die Oberflaeche schickt nur
gueltige Staende), aber "trifft nie ein" ist genau die
Begruendung, mit der solche Stellen stehen bleiben, bis sie
doch jemand sieht.
Ein Satz direkt hier statt eines Eintrags in der Tabelle:
Die anderen Absagen dieser Route machen es ebenso, und ein
Wort, das nur an einer Stelle vorkommt, braucht keine
Uebersetzung an einer zweiten. */
return res.status(400).json({
fehler: "Diesen Stand gibt es nicht. Moeglich sind: neu, "
+ "in Arbeit, erledigt.",
});
}
const antwort = textSauber(req.body?.antwort, ANTWORT_MAX);
/* WER ZUMACHT, SAGT WARUM. Nicht als Schikane: Der Melder sieht