Jede Seite erklaert sich selbst -- drei Zeilen, und die dritte rechnet sich aus

Filipe: "ich will in jeder seite auch eine kleine detaillierte aber
schnelle erklaerung kurz und knapps noch zu jeder seite."

DREI ZEILEN AUF JEDER DER 25 SEITEN

  WOFUER    was auf dieser Seite steht
  DU TUST   was man hier konkret macht
  MERKE     nur dort, wo es etwas gibt, das man falsch versteht
  SIEHT     wer diese Seite ueberhaupt oeffnen kann

Offen sichtbar und nicht hinter einem Aufklapper: "schnell" war seine
Bedingung, und eine Erklaerung, die man erst aufklappen muss, ist
genau dann nicht da, wenn man sie braucht.

DIE ZEILE "SIEHT" IST GERECHNET, NICHT GESCHRIEBEN

Sie kommt aus der Rechtetafel -- aus derselben, aus der auch die
Schranke ihre Entscheidung holt. Haette ich sie danebengeschrieben,
waere sie beim ersten Umstellen in "Wer sieht was" still falsch
geworden, in einem Satz, der behauptet, wer etwas sieht. Die Pruefung
stellt die Tafel deshalb wirklich um und sieht nach, ob der Satz
mitwandert.

Die Erklaerung haengt hinter derselben Schranke wie die Seite: Wer sie
nicht oeffnen darf, bekommt 404 -- nicht 403, sonst waere dieser Weg
eine Landkarte des Hauses.

Eingebunden ist sie nicht ueber eine Liste von Dateinamen, sondern
ueber "wer kopf.js laedt": die 26. Seite ist damit automatisch dabei.
Fuenf Seiten haben keine Kopfzeile (Chat, Kalender, Start, Team,
Teamlage) -- dort haengt der Kasten an <main>, sonst waeren
ausgerechnet die haeufigsten Seiten lautlos leer geblieben.

ZWEI EIGENE MAENGEL, GEFUNDEN DURCH HINSEHEN, NICHT DURCH DIE PRUEFUNG

Die erste Fassung war gruen -- und stand mitten auf dem Buehnenbild,
mit einem Lichtfleck hinter "SIEHT". Und "Wofuer" sprach fast woertlich
die Unterzeile darueber nach. Beides misst die Pruefung jetzt: Kontrast
mit dem dritten Ausgang ("steht auf der Buehne" ist kein Ergebnis) und
die Wortueberschneidung mit der Unterzeile.

ZWEI BEFUNDE, DIE SCHON VORHER ROT WAREN

1. pruef-tempo-workspace verglich die UNKOMPRIMIERTE Groesse gegen eine
   Grenze, die fuer die Leitung gedacht war -- waehrend der Kommentar
   daneben "das ist, was wirklich ueber die Leitung ging" behauptete.
   Live steht Caddy davor. Nachgemessen an der echten Adresse:
   start.css 345 KB -> 111 KB zstd. Die Pruefung wog also 1,2 MB, wo
   Filipe 500 KB bekommt. Jetzt wird Komprimierbares im Pruefstand
   gzip-gepackt (115 KB gegen 111 KB live -- auf vier Prozent genau),
   geurteilt wird ueber die uebertragene Groesse, berichtet werden
   beide. Dabei prompt in die dokumentierte Falle getappt: `body()` auf
   einen Ereignisstrom endet nie, der Lauf blieb stehen. Jetzt
   ausgenommen, plus Notbremse je Koerper.

2. pruef-ueberlappung konnte seit Tagen nicht mehr zeigen, dass sie
   eine Ueberlappung ueberhaupt findet: Ihre Gegenprobe legt einen Knopf
   auf einen anderen, traf aber 6 px daneben. Zwei Ursachen in einer
   Zeile -- `position: fixed` bezieht sich auf einen Vorfahren mit
   `transform`, und die `transition` der Knoepfe liefert beim sofortigen
   Messen die Lage von vorher. Jetzt `transform` + `transition: none`:
   34x36 px erkannt, 20 Seiten-Breiten-Paare, 0 Befunde.

PRUEFUNGEN: pruef-erklaerung neu mit 44, davon 8 im Browser (Seite mit
und ohne Kopfzeile, Handy, Kontrast, Echo). Mein Schild stand auf
10,88 px und lag unter der Hausgrenze von 11,5 -- gefunden von
pruef-css-klassen, nicht vom Auge.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-14 18:20:30 +02:00
co-authored by Claude Opus 5
parent 0cce22c08c
commit de19684883
36 changed files with 1307 additions and 353 deletions
+86 -5
View File
@@ -28,6 +28,7 @@
GEGENPROBE am Ende: eine kuenstlich erzeugte Doppelanfrage und ein
kuenstlicher Layout-Sprung muessen gefunden werden. */
import { gzipSync } from "node:zlib";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
@@ -153,9 +154,45 @@ await seite.waitForTimeout(600);
/* Grenzen. Grosszuegig -- sie sollen den Ausreisser finden, nicht das
Kilobyte. */
const GRENZE_ANFRAGEN = 40;
const GRENZE_BYTES = 1_200_000;
const GRENZE_MS = 4000;
/* ---- DAS GEWICHT: GEMESSEN WIRD, WAS UEBER DIE LEITUNG GEHT ----------
BIS ZUM 14.09.2026 WURDE HIER DAS FALSCHE GEMESSEN, und der Kommentar
daneben behauptete sogar das Richtige („das ist, was wirklich ueber
die Leitung ging"). Der Pruefstand spricht mit dem nackten
Express-Server auf 127.0.0.1, und der komprimiert nicht. Live steht
davor Caddy.
NACHGEMESSEN an der echten Adresse, nicht vermutet:
curl -H 'Accept-Encoding: zstd' workspace.dogfather-universe.com/…
start.css 345 KB -> 111 KB (Content-Encoding: zstd)
gate.css 120 KB -> 40 KB
kopf.js 65 KB -> 24 KB
Die Prueferei verglich also rund 1,2 MB gegen eine Grenze, die fuer
die Leitung gedacht war -- waehrend Filipe rund 500 KB bekommt. Die
Folge war eine Warnung, die nichts ueber sein Erlebnis sagt: genau
die Sorte, die man nach dreimal Lesen wegklickt.
JETZT WIRD BEIDES GEMESSEN. Komprimierbares wird im Pruefstand
gzip-gepackt (gemessen: start.css 356 KB -> 115 KB gzip gegen 111 KB
zstd live -- ein Stellvertreter, der auf vier Prozent genau ist),
alles andere zaehlt roh. Geurteilt wird ueber die uebertragene
Groesse, berichtet werden beide.
DIE GRENZE: 900 KB uebertragen. Die schwerste Seite liegt heute bei
rund 500 KB, davon 286 KB Buehnenbild -- das ist der Ausreisser, den
diese Zahl finden soll, mit Luft fuer eine zweite. Die rohe Groesse
bleibt in der Ausgabe stehen: Sie kostet zwar keine Leitung, aber
Rechenzeit beim Auswerten, und sie ist die Zahl, die man senken kann. */
const GRENZE_UEBERTRAGEN = 900_000;
/* Was Caddy komprimiert. Bilder, Schriften und Videos sind bereits
gepackt -- sie noch einmal durch gzip zu schicken kostet Zeit und
spart nichts. */
const KOMPRIMIERBAR = /^(text\/|application\/(javascript|json|xml|manifest)|image\/svg)/i;
/* ---- Layout-Sprung: eine GRUNDLINIE, kein Wunschwert ------------------
Gemessen am 04.09.2026 (Audit): Die Seiten springen beim Aufbau
zwischen 0 und 0,54. Nach Web Vitals gilt unter 0,1 als gut. Der
@@ -175,6 +212,7 @@ const ZIEL_SPRUNG = 0.1; // Web Vitals "gut" -- noch nicht erreicht
const zeilen = [];
let seitenGesamt = 0, anfragenGesamt = 0, bytesGesamt = 0;
const nichtGewogen = [];
const doppelte = [];
const langsame = [];
const springende = [];
@@ -184,9 +222,34 @@ const zuGross = [];
for (const datei of SEITEN) {
const gesehen = new Map();
let bytes = 0;
let roheBytes = 0, uebertragen = 0;
const warten = [];
const zaehler = (antwort) => {
const u = antwort.url();
gesehen.set(u, (gesehen.get(u) || 0) + 1);
/* Den Koerper JETZT holen -- nach dem Seitenwechsel ist er weg.
Ein Fehlschlag (Umleitung, 204, abgebrochen) ist kein Befund,
sondern schlicht nichts zu wiegen. */
const art = antwort.headers()["content-type"] || "";
/* EIN EREIGNISSTROM ENDET NIE -- und `body()` darauf auch nicht.
Genau daran ist am 06.09.2026 schon einmal ein ganzer Lauf
stehengeblieben, und hier ist es sofort wieder passiert: Der
Workspace haelt eine offene Verbindung fuer Benachrichtigungen.
Erst gar nicht anfassen -- und fuer alles andere trotzdem eine
Notbremse, weil die naechste Sorte Dauerverbindung noch nicht
erfunden ist. */
if (/event-stream/i.test(art)) return;
warten.push((async () => {
try {
const k = await Promise.race([
antwort.body(),
new Promise((r) => setTimeout(() => r(null), 3000)),
]);
if (!k?.length) return;
roheBytes += k.length;
uebertragen += KOMPRIMIERBAR.test(art) ? gzipSync(k).length : k.length;
} catch { /* nichts zu wiegen */ }
})());
};
seite.on("response", zaehler);
@@ -195,6 +258,7 @@ for (const datei of SEITEN) {
await seite.waitForTimeout(500);
const dauer = Date.now() - start;
seite.off("response", zaehler);
await Promise.all(warten);
/* Uebertragene Groesse aus der Zeitleiste des Browsers -- das ist,
was wirklich ueber die Leitung ging. */
@@ -309,12 +373,23 @@ for (const datei of SEITEN) {
schwankend.push(`${datei} ${sprung} → beim Nachmessen ${zweitens.wert}`);
}
}
if (anfragen > GRENZE_ANFRAGEN || bytes > GRENZE_BYTES) {
zuGross.push(`${datei} ${anfragen} Anfragen / ${Math.round(bytes / 1024)} KB`);
/* KONNTE ueberhaupt gewogen werden? Kommt aus den Koerpern nichts
zurueck (Browser aus dem Zwischenspeicher, alles abgebrochen),
waere „unter der Grenze" trivial wahr. Dann gilt die Zeitleiste
des Browsers als Rueckfall -- und der dritte Ausgang steht in der
Ausgabe. */
const gewogen = uebertragen > 0;
const zaehlwert = gewogen ? uebertragen : bytes;
if (!gewogen) nichtGewogen.push(datei);
if (anfragen > GRENZE_ANFRAGEN || zaehlwert > GRENZE_UEBERTRAGEN) {
zuGross.push(`${datei} ${anfragen} Anfragen / ${Math.round(zaehlwert / 1024)} KB übertragen`);
}
zeilen.push(` ${datei.padEnd(22)} ${String(anfragen).padStart(3)} Anfragen `
+ `${String(Math.round(bytes / 1024)).padStart(4)} KB ${String(dauer).padStart(4)} ms `
+ `${String(Math.round(zaehlwert / 1024)).padStart(4)} KB über die Leitung `
+ `(roh ${String(Math.round((roheBytes || bytes) / 1024)).padStart(4)}) `
+ `${String(dauer).padStart(4)} ms `
+ `Sprung ${String(sprung).padStart(5)} ${String(messung.knoten).padStart(4)} Knoten`);
}
@@ -388,7 +463,13 @@ console.log(` hinw ${ueberZiel} von ${seitenGesamt} Seiten liegen ueber dem Z
+ `${ZIEL_SPRUNG} fuer den Layout-Sprung (bauartbedingt: Geruest zuerst, Daten danach)`);
ok(zuGross.length === 0,
zuGross.length ? `zu schwer: ${zuGross.join(", ")}`
: `keine Seite ueber ${GRENZE_ANFRAGEN} Anfragen oder ${Math.round(GRENZE_BYTES / 1024)} KB`);
: `keine Seite ueber ${GRENZE_ANFRAGEN} Anfragen oder ${Math.round(GRENZE_UEBERTRAGEN / 1024)} KB ueber die Leitung`);
/* DER DRITTE AUSGANG: Konnte ueberhaupt gewogen werden? Eine Seite,
deren Koerper der Browser aus dem Zwischenspeicher genommen hat,
waere sonst lautlos „leicht“. */
ok(nichtGewogen.length === 0,
nichtGewogen.length ? `KONNTE NICHT WIEGEN: ${nichtGewogen.join(", ")} -- Ergebnis unbrauchbar`
: `alle ${seitenGesamt} Seiten wirklich gewogen`);
/* =======================================================================
GEGENPROBE