From 26aec420f43fe55aa69555084b6ac5d0b4361cdc Mon Sep 17 00:00:00 2001 From: Dogfather Date: Tue, 6 Oct 2026 10:30:26 +0200 Subject: [PATCH] Drei Fehlalarme abgestellt -- und zwei Schriften, die wirklich zu klein waren ERSTENS: die drei Ladehinweise, die der Rollen-Rundgang meldete. #liste auf werdegang.html, #personen und #meine-karte auf entwicklung.html sollten Vorleseprogrammen dauerhaft "wird geladen" melden. Nachgemessen stimmt das nicht: Alle drei stehen in einem Abschnitt mit `hidden`, und gate.css setzt hausweit `[hidden] { display: none !important; }`. Sie werden nicht dargestellt und sind damit aus dem Baum draussen, den Vorleseprogramme lesen. Dort hoert nie jemand etwas. Meine eigene Notiz behauptete das Gegenteil -- ausfuehrlich begruendet und trotzdem falsch, weil ich sie hergeleitet statt gemessen hatte. Genau der Fall, vor dem die Projektnotiz warnt. Die Messung zaehlt jetzt nur noch, was auch dasteht. Mit `checkVisibility()` und nicht mit der Kasten-Rechnung daneben: Ein sichtbarer, aber noch leerer Ladebehaelter hat Hoehe 0 -- die Kasten-Rechnung haette ausgerechnet den durchgewunken, fuer den die Zeile da ist. Dazu zwei Gegenproben je Rolle, mit DERSELBEN Funktion, die der Rundgang benutzt: Ein sichtbarer Ladehinweis MUSS gefunden werden, ein verborgener darf es nicht. 16 von 16 gruen -- die Pruefung kann also weiterhin rot werden, sie sieht nur nicht mehr dorthin, wo niemand hinsieht. Und der Befund nennt jetzt das Element, statt nur zu zaehlen. ZWEITENS: zwei Schriften unter 11,5 px. pruef-css-klassen zaehlte 44 statt 42. Welche zwei neu waren, sagte die Meldung nicht -- sie zeigte `zuKlein.slice(-6)`, und das ist nach DATEINAMEN sortiert, nicht nach Alter. Sie zeigte damit auf uebersicht.css und wissen.css, die seit Wochen unveraendert dastehen. Gefunden wurden die echten durch Nachzaehlen ueber die letzten vierzig Commits: bereich.css .ev-mitmacher__schild .7rem = 11,20 px (03.10.) chat.css .chat-nachricht__bearbeitet .68rem = 10,88 px (04.10.) Beide bekommen .72rem -- nicht geraten, sondern der Wert ihrer direkten Nachbarn: Die beiden anderen __schild in bereich.css stehen schon auf .72rem, und der Chat-Vermerk soll laut seinem eigenen Kommentar "so leise wie die Zeit daneben" sein, und die hat .72rem. Ueberlaufen kann dadurch nichts, beide Elternelemente haben `flex-wrap: wrap`. Die irrefuehrende Meldung ist mit korrigiert: Sie sagt jetzt, was sie weiss (Verteilung je Datei), und nennt den Weg zu dem, was sie nicht wissen kann -- statt mit "vermutlich" auf Unschuldige zu zeigen. DRITTENS: `erklaert` wurde seit dem ersten Tag gemessen und nie benutzt. Im Kopf von pruef-rollen steht "Ein leerer Bereich OHNE ERKLAERUNG sieht aus wie ein Fehler". Die Erklaerung wurde auch ermittelt -- und dann verworfen; gemeldet wurde jede kurze Seite. Eine Seite, die zu Recht leer ist und das ordentlich sagt, waere als Fehler dagestanden, und der naheliegende "Fix" waere gewesen, die Grenze fuer alle zu senken. Jetzt wirkt das Feld. Heute aendert es nichts: keiner der 384 Durchgaenge liegt unter 120 Zeichen. Gemessen pruef-rollen 384 Pruefungen, 0 Fehler, 1 nicht nachsehbar (vorher 368 -- die 16 neuen sind die Gegenproben) pruef-css-klassen alles in Ordnung, 42 Stellen unter 11,5 px, Grundlinie wieder erreicht Der erste Lauf endete mit Rueckgabewert 3, weil ich waehrenddessen eine Datei gespeichert habe -- die Pruefung hat ihren eigenen Schutz gegen "misst einen Stand, den es nicht mehr gibt" an mir vorgefuehrt. Die Zahlen oben stammen aus dem sauberen Lauf danach. Co-Authored-By: Claude Opus 5 --- server/pruef-css-klassen.mjs | 37 +++++- server/pruef-rollen.mjs | 196 ++++++++++++++++++++++++++----- workspace/anruf-probe.html | 10 +- workspace/app.webmanifest | 8 +- workspace/assets/css/bereich.css | 2 +- workspace/assets/css/chat.css | 2 +- workspace/aufgaben.html | 38 +++--- workspace/automation.html | 32 ++--- workspace/befinden.html | 34 +++--- workspace/bereich.html | 44 +++---- workspace/bewerben.html | 38 +++--- workspace/bewerbungen.html | 36 +++--- workspace/buehne.html | 6 +- workspace/calls.html | 34 +++--- workspace/chat.html | 40 +++---- workspace/content.html | 34 +++--- workspace/crew-index.html | 12 +- workspace/crew.webmanifest | 8 +- workspace/dateien.html | 34 +++--- workspace/entwicklung.html | 36 +++--- workspace/hilfe.html | 30 ++--- workspace/index.html | 10 +- workspace/kalender.html | 34 +++--- workspace/leistung.html | 32 ++--- workspace/manager-ziele.html | 28 ++--- workspace/material.html | 32 ++--- workspace/notizen.html | 28 ++--- workspace/personen.html | 32 ++--- workspace/profil.html | 36 +++--- workspace/reaktion.html | 38 +++--- workspace/rechte.html | 34 +++--- workspace/report.html | 36 +++--- workspace/scouting.html | 32 ++--- workspace/start.html | 32 ++--- workspace/startcheck.html | 34 +++--- workspace/steckbrief.html | 36 +++--- workspace/support.html | 28 ++--- workspace/tafel.html | 6 +- workspace/talente.html | 36 +++--- workspace/team.html | 32 ++--- workspace/teamlage.html | 34 +++--- workspace/teilen.html | 30 ++--- workspace/treff-moderation.html | 32 ++--- workspace/treff-regeln.html | 32 ++--- workspace/uebersicht.html | 32 ++--- workspace/unsere-seiten.html | 30 ++--- workspace/unterstuetzen.html | 32 ++--- workspace/werdegang.html | 32 ++--- workspace/willkommen.html | 30 ++--- workspace/wissen.html | 34 +++--- 50 files changed, 886 insertions(+), 719 deletions(-) diff --git a/server/pruef-css-klassen.mjs b/server/pruef-css-klassen.mjs index 45a65aa7..95c75faa 100644 --- a/server/pruef-css-klassen.mjs +++ b/server/pruef-css-klassen.mjs @@ -355,13 +355,44 @@ console.log("\n=== Ist irgendeine Schrift zu klein? ==="); jetzt .72rem. Die Grundlinie wird MITGEZOGEN -- sonst duerfte der Fortschritt lautlos wieder verlorengehen, und eine Grundlinie, die nur nach oben nachgibt, ist keine. */ + /* DIE MELDUNG HAT AUF DIE FALSCHEN DATEIEN GEZEIGT (06.10.2026). + + Hier stand frueher „Neu hinzugekommen ist vermutlich eine davon" + und dann `zuKlein.slice(-6)`. Diese Liste ist aber nach + DATEINAMEN sortiert, nicht nach Alter -- die letzten sechs sind + schlicht die am Ende des Alphabets. Bei zwei neuen Stellen in + `bereich.css` und `chat.css` zeigte die Meldung auf + `uebersicht.css` und `wissen.css`, die seit Wochen unveraendert + dastanden. Ich habe daraufhin eine Stunde an der falschen Stelle + gesucht. + + Ein Hinweis, der mit „vermutlich" auf Unschuldige zeigt, ist + schlechter als gar keiner: Ohne ihn haette ich gleich gesucht. + Sie sagt jetzt, was sie WEISS (wie viele, in welcher Datei), und + nennt den Weg zu dem, was sie nicht wissen kann. Der Weg ist + nachgemessen und hat die beiden Stellen in zwei Minuten + gefunden. */ const GRUNDLINIE = 42; + const jeDatei = {}; + for (const z of zuKlein) { + const n = z.split(":")[0]; + jeDatei[n] = (jeDatei[n] || 0) + 1; + } + const verteilung = Object.entries(jeDatei) + .sort((a, b) => b[1] - a[1]) + .map(([n, z]) => `${n} ${z}`) + .join(" · "); ok(zuKlein.length <= GRUNDLINIE && gemessen > 150, zuKlein.length > GRUNDLINIE ? `${zuKlein.length} Stellen unter ${GRENZE_PX} px — das sind ` - + `${zuKlein.length - GRUNDLINIE} MEHR als die Grundlinie ${GRUNDLINIE}. ` - + `Neu hinzugekommen ist vermutlich eine davon:\n ` - + zuKlein.slice(-6).join("\n ") + + `${zuKlein.length - GRUNDLINIE} MEHR als die Grundlinie ${GRUNDLINIE}.` + + `\n Verteilung: ${verteilung}` + + "\n WELCHE neu ist, steht hier nicht -- die Liste ist nach" + + " Dateinamen sortiert, nicht nach Alter." + + "\n So findet man sie (nachgemessen, dauert zwei Minuten):" + + " dasselbe Zaehlen ueber `git archive workspace/assets/css`" + + "\n fuer die letzten Commits laufen lassen und den Sprung" + + " von 42 auf 43 suchen." : `${zuKlein.length} Stellen unter ${GRENZE_PX} px ` + `(Grundlinie ${GRUNDLINIE}, nicht mehr geworden)`); diff --git a/server/pruef-rollen.mjs b/server/pruef-rollen.mjs index 3e91c624..cfe0743f 100644 --- a/server/pruef-rollen.mjs +++ b/server/pruef-rollen.mjs @@ -322,6 +322,81 @@ const istEgal = (t) => EGAL.some((r) => r.test(t)); const berichte = []; +/* ===================================================================== + DIE MESSUNG EINER SEITE -- an EINER Stelle, weil sie zweimal + gebraucht wird: einmal fuer die Seite selbst, einmal fuer die + Gegenprobe weiter unten. Eine zweite, danebengeschriebene Fassung + waere die, die beim naechsten Umbau auseinanderlaeuft -- und dann + prueft die Gegenprobe etwas anderes als der Rundgang. + + Sie laeuft IM BROWSER (Playwright schickt den Quelltext hinueber), + darf also nichts aus diesem Modul benutzen. + ===================================================================== */ +function zustandMessen() { + const sichtbar = (e) => { + const k = e.getBoundingClientRect(); + return k.width > 0 && k.height > 0 && getComputedStyle(e).visibility !== "hidden"; + }; + /* Verweise, die ins Leere zeigen. Ein Knopf, der nichts tut, ist + schlimmer als kein Knopf: Man klickt ihn immer wieder. */ + const tote = [...document.querySelectorAll("a[href]")] + .filter(sichtbar) + .filter((a) => { + const h = a.getAttribute("href"); + return !h || h === "#" || h === "javascript:void(0)"; + }) + .map((a) => a.textContent.trim().slice(0, 40)); + + /* ================================================================== + EIN LADEHINWEIS ZAEHLT NUR, WENN ER AUCH DASTEHT (06.10.2026) + + Diese Prüfung meldete drei Befunde, und alle drei waren falsch: + `#liste` auf werdegang.html, `#personen` und `#meine-karte` auf + entwicklung.html. Alle drei stehen in einem Abschnitt, der + `hidden` traegt, und `gate.css` setzt hausweit + `[hidden] { display: none !important; }`. Sie werden also gar + nicht dargestellt und sind damit auch aus dem Baum draussen, den + Vorleseprogramme lesen -- niemand bekommt dort je ein "wird + geladen" zu hoeren. + + Ich hatte das Gegenteil notiert und sauber begruendet ("meldet + Vorleseprogrammen dauerhaft, die Seite laedt"). Die Begruendung + klang schluessig und war trotzdem falsch, weil ich sie nicht + nachgemessen hatte. Und eine Warnung, die bei jedem Lauf kommt, + ohne dass jemand etwas davon hat, ist keine Warnung mehr -- sie + bringt einem bei, die naechste zu ueberlesen, und die koennte + echt sein. + + `checkVisibility()` statt der Kasten-Rechnung oben: Ein + Ladebehaelter, der sichtbar, aber noch LEER ist, hat Hoehe 0 -- + die Kasten-Rechnung wuerde ihn durchwinken, und das waere genau + der Fall, den diese Zeile fangen soll. `checkVisibility` fragt + dagegen, ob das Element ueberhaupt dargestellt wird. + + Kann der Browser die Frage nicht beantworten (sehr alt), wird + NICHT stillschweigend gefiltert, sondern alles gemeldet und das + Nichtwissen weitergereicht -- siehe `kannSichtbarkeit`. + ================================================================== */ + const kannSichtbarkeit = typeof Element.prototype.checkVisibility === "function"; + const ladend = [...document.querySelectorAll('[aria-busy="true"]')]; + const haengt = (kannSichtbarkeit ? ladend.filter((e) => e.checkVisibility()) : ladend) + .map((e) => e.id || e.getAttribute("class") || e.tagName.toLowerCase()); + + /* Sichtbarer Text insgesamt -- eine Seite, auf der praktisch + nichts steht, ist entweder leer oder kaputt. */ + const text = (document.querySelector("main")?.innerText || "").trim(); + return { + tote, + laenge: text.length, + /* Ein sichtbarer Hinweis, der die Leere erklärt. */ + erklaert: [...document.querySelectorAll(".leer-hinweis, .leer, .k-leer, .block__frage")] + .some((e) => e.getBoundingClientRect().height > 0 && e.textContent.trim().length > 25), + haengt, + kannSichtbarkeit, + ueber: document.documentElement.scrollWidth - document.documentElement.clientWidth, + }; +} + for (const r of ROLLEN) { /* `--ignore-certificate-errors` als ARGUMENT und nicht nur `ignoreHTTPSErrors` am Kontext: Die Domain steht in der @@ -408,47 +483,108 @@ for (const r of ROLLEN) { await seite.goto(wurzel + "/workspace/" + pfad, { waitUntil: "networkidle" }); await seite.waitForTimeout(700); - const zustand = await seite.evaluate(() => { - const sichtbar = (e) => { - const k = e.getBoundingClientRect(); - return k.width > 0 && k.height > 0 && getComputedStyle(e).visibility !== "hidden"; - }; - /* Verweise, die ins Leere zeigen. Ein Knopf, der nichts tut, ist - schlimmer als kein Knopf: Man klickt ihn immer wieder. */ - const tote = [...document.querySelectorAll("a[href]")] - .filter(sichtbar) - .filter((a) => { - const h = a.getAttribute("href"); - return !h || h === "#" || h === "javascript:void(0)"; - }) - .map((a) => a.textContent.trim().slice(0, 40)); - /* Sichtbarer Text insgesamt -- eine Seite, auf der praktisch - nichts steht, ist entweder leer oder kaputt. */ - const text = (document.querySelector("main")?.innerText || "").trim(); - return { - tote, - laenge: text.length, - /* Ein sichtbarer Hinweis, der die Leere erklärt. */ - erklaert: [...document.querySelectorAll('.leer-hinweis, .leer, .k-leer, .block__frage')] - .some((e) => e.getBoundingClientRect().height > 0 && e.textContent.trim().length > 25), - /* Steht ein Ladehinweis noch da, ist etwas haengengeblieben. */ - haengt: [...document.querySelectorAll('[aria-busy="true"]')].length, - ueber: document.documentElement.scrollWidth - document.documentElement.clientWidth, - }; - }); + const zustand = await seite.evaluate(zustandMessen); + /* DER DRITTE AUSGANG: Kann der Browser die Sichtbarkeit nicht + beantworten, meldet die Messung ALLE Ladehinweise -- auch die + verborgenen. Dann ist ein Befund hier kein Befund am Code, + sondern ein Hinweis auf die Messung. Darf nicht schweigen. */ + if (!zustand.kannSichtbarkeit) { + unklar(`${r.name.padEnd(18)} ${pfad.padEnd(22)} dieser Browser kennt` + + " checkVisibility() nicht -- Ladehinweise ungefiltert gezaehlt"); + } const probleme = []; if (konsole.length) probleme.push("Konsole: " + konsole.slice(0, 2).join(" | ").slice(0, 160)); if (schlechteAntworten.length) probleme.push("Server: " + [...new Set(schlechteAntworten)].slice(0, 3).join(", ")); if (zustand.tote.length) probleme.push("tote Verweise: " + zustand.tote.slice(0, 3).join(", ")); - if (zustand.haengt) probleme.push(`${zustand.haengt}× haengt beim Laden`); - if (zustand.laenge < 120) probleme.push(`fast kein Inhalt (${zustand.laenge} Zeichen)`); + /* Mit NAMEN und nicht nur als Zahl: "3x haengt beim Laden" schickt + einen auf die Suche, "haengt beim Laden: liste" nicht. */ + if (zustand.haengt.length) probleme.push("haengt beim Laden: " + zustand.haengt.join(", ")); + /* ================================================================= + „WORTLOS leer" -- das Wort stand im Kopf dieser Datei und war + nie umgesetzt (gefunden 06.10.2026). + + Oben heisst es seit dem ersten Tag: „Ein leerer Bereich OHNE + ERKLAERUNG sieht aus wie ein Fehler." Gemessen wurde die + Erklaerung auch -- `erklaert` stand im Rueckgabewert. Benutzt + hat sie nie jemand. Eine Seite, die zu Recht leer ist und das + ordentlich sagt („Noch nichts hier"), waere also als Fehler + gemeldet worden. + + Das ist keine Kleinigkeit, sondern eine gestellte Falle: Wer + eines Tages so eine Seite baut, bekommt Rot ohne Fehler und + senkt am wahrscheinlichsten die Grenze von 120 -- fuer alle + Seiten, auch die wirklich kaputten. Eine Messung, die + danebenliegt und nicht benutzt wird, liest sich im Quelltext + wie eine Zusage, die es nicht gibt. + + HEUTE AENDERT DAS NICHTS: Keine der 368 Durchgaenge liegt unter + 120 Zeichen, der Lauf davor war mit der strengen Fassung + ebenso gruen. Die Zeile wirkt erst in dem Fall, fuer den sie + von Anfang an gedacht war -- und sie schweigt ihn nicht weg, + sondern schreibt ihn in den Bericht. */ + if (zustand.laenge < 120) { + if (zustand.erklaert) { + /* NICHT `unklar()`: Das ist der dritte Ausgang fuer „konnte + nicht nachsehen". Hier wurde nachgesehen, und das Ergebnis + ist in Ordnung -- nur erwaehnenswert. Die Seite bekommt + ihren normalen Haken wie jede andere. */ + console.log(` INFO ${r.name.padEnd(18)} ${pfad.padEnd(22)} ist leer` + + ` (${zustand.laenge} Zeichen), sagt aber warum -- kein Fehler`); + } else { + probleme.push(`wortlos leer (${zustand.laenge} Zeichen, kein Hinweis, der es erklaert)`); + } + } if (zustand.ueber > 0) probleme.push(`ragt ${zustand.ueber}px heraus`); ok(!probleme.length, `${r.name.padEnd(18)} ${pfad.padEnd(22)} ${probleme.join(" · ")}`); if (probleme.length) berichte.push({ rolle: r.name, pfad, probleme }); } + /* ===================================================================== + DIE GEGENPROBE ZUM LADEHINWEIS (06.10.2026) + + Seit die Messung oben verborgene Ladehinweise nicht mehr zaehlt, + kann sie auf zwei Arten falsch sein: Sie koennte gar nichts mehr + finden. Eine Pruefung, die immer bestaetigt, bestaetigt nichts -- + also wird hier beides bewiesen, und zwar MIT DERSELBEN Funktion, + die der Rundgang benutzt: + + 1. Ein SICHTBARER Ladehinweis wird gefunden -> sie kann rot. + 2. Ein VERBORGENER wird nicht gefunden -> sie filtert + wirklich nach Sichtbarkeit und nicht nach irgendetwas. + + Beides auf der Seite, auf der die Rolle gerade steht. Die beiden + Knoten verschwinden sofort wieder; der naechste Aufruf laedt die + Seite ohnehin neu. + ===================================================================== */ + await seite.evaluate(() => { + const wo = document.querySelector("main") || document.body; + const sicht = document.createElement("p"); + sicht.id = "gegenprobe-sichtbar"; + sicht.setAttribute("aria-busy", "true"); + sicht.textContent = "wird geladen …"; + wo.append(sicht); + + const huelle = document.createElement("section"); + huelle.hidden = true; + const still = document.createElement("p"); + still.id = "gegenprobe-verborgen"; + still.setAttribute("aria-busy", "true"); + still.textContent = "wird geladen …"; + huelle.append(still); + wo.append(huelle); + }); + const probe = await seite.evaluate(zustandMessen); + ok(probe.haengt.includes("gegenprobe-sichtbar"), + `${r.name.padEnd(18)} Gegenprobe: ein SICHTBARER Ladehinweis wird gefunden`); + ok(!probe.haengt.includes("gegenprobe-verborgen"), + `${r.name.padEnd(18)} Gegenprobe: ein VERBORGENER wird nicht mitgezaehlt`); + await seite.evaluate(() => { + document.getElementById("gegenprobe-sichtbar")?.remove(); + document.getElementById("gegenprobe-verborgen")?.closest("section")?.remove(); + }); + /* ===================================================================== JEDE KACHEL, DIE EINE ROLLE BEKOMMT, MUSS AUCH AUFGEHEN diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html index 48e7c690..ab291add 100644 --- a/workspace/anruf-probe.html +++ b/workspace/anruf-probe.html @@ -16,8 +16,8 @@ verdeckt. Gefunden hat es pruef-struktur. Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. --> - - + + - +