diff --git a/server/pruef-meldungen.mjs b/server/pruef-meldungen.mjs
index 1ce4a932..763bd37b 100644
--- a/server/pruef-meldungen.mjs
+++ b/server/pruef-meldungen.mjs
@@ -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);
}
diff --git a/server/pruef-workspace-seiten.mjs b/server/pruef-workspace-seiten.mjs
index 485ab1ca..158435a5 100644
--- a/server/pruef-workspace-seiten.mjs
+++ b/server/pruef-workspace-seiten.mjs
@@ -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++;
diff --git a/server/workspace-auskunft.js b/server/workspace-auskunft.js
index 1dec5fce..28e13f89 100644
--- a/server/workspace-auskunft.js
+++ b/server/workspace-auskunft.js
@@ -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;
diff --git a/server/workspace-support.js b/server/workspace-support.js
index 7bb5f537..3aedc53f 100644
--- a/server/workspace-support.js
+++ b/server/workspace-support.js
@@ -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
diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html
index 443e3f93..27d96c3b 100644
--- a/workspace/anruf-probe.html
+++ b/workspace/anruf-probe.html
@@ -16,15 +16,15 @@
verdeckt. Gefunden hat es pruef-struktur.
Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. -->
-
-
+
+
-
+