Files
DogFatherGit 1207b79a33 Hochladen sieht man jetzt, Leerzustaende sagen was hingehoert
DREI BLOECKE AUS DEM PERFEKTIONSLAUF.

1. HOCHLADEN MIT FORTSCHRITT UND ABBRUCH
   Alle fuenf Wege (Dateien, Chat-Anhang, Wissen-PDF, Aufgaben-Anhang,
   Profilbild) benutzten `fetch`. Das kann beim SENDEN nicht sagen, wie
   weit es ist -- sichtbar war "wird hochgeladen …", von der ersten bis
   zur letzten Sekunde gleich. Bei 40 MB im Mobilfunknetz zwei Minuten.
   Wer das sieht, drueckt noch einmal und laedt dieselbe Datei doppelt.
   Neu: workspace/assets/js/hochladen.js (XMLHttpRequest, das Einzige,
   was `upload.onprogress` kann) samt gemeinsamer Anzeige.
   Drei Ausgaenge: fertig / abgebrochen / schiefgegangen -- und ein
   Abbruch ist KEIN Fehler und bekommt keine rote Meldung.

   DABEI AUFGEFALLEN: KEINE EINZIGE PRUEFUNG im Haus laedt eine Datei
   ueber die Oberflaeche hoch. Der ganze Umbau waere gruen gewesen,
   ohne dass ein Byte je den Weg der Nutzer gegangen waere.
   Neu: server/pruef-hochladen.mjs -- 18/0, mit echter Datei.
   Zwei Irrtuemer beim Bauen, beide gemessen statt vermutet:
     Ohne Drosselung gibt es auf localhost EINEN Fortschritt-Stand.
       Das sah nach Befund aus und war keiner. Jetzt 2 MBit/s ueber
       CDP -- derselbe Verlauf wie bei den Modis im Mobilfunk, 57
       gemessene Zwischenstaende.
     Gewartet wurde auf den Dateinamen "irgendwo im Dokument" -- der
       stand auch im Fortschrittsbalken. Die Bedingung war erfuellt,
       bevor etwas angekommen war.

2. LEERZUSTAENDE
   Elf von 18 Brettern fielen auf "Noch kein Eintrag in diesem
   Bereich" zurueck. Am ersten Tag ist ALLES leer -- wer da achtzehn
   Bretter oeffnet und achtzehnmal denselben Satz liest, lernt nichts
   ueber die Bretter, sondern dass das System kaputt ist. Jeder Satz
   sagt jetzt, was hier hingehoert UND was der naechste Schritt ist.
   Neu: server/pruef-leerzustand.mjs -- 13/0, leitet die Bretter aus
   BEREICHE ab; ein neunzehntes ohne Satz macht sie rot.

3. ABMELDEN UND KONTRASTMODUS
   Abmelden war am Handy ein 44-Pixel-Zeichen neben Glocke und Suche,
   sofort wirksam. Teurer als es aussieht: Zum Wiederanmelden braucht
   man den Zugangscode, und den gibt es EINMAL. Jetzt mit Rueckfrage,
   die genau das sagt -- und dazu, dass Zumachen reicht (12 Stunden).

   Kontrastmodus: 68 Regeln zeigen einen Zustand NUR ueber Farbe
   (35x aria-pressed, 33x data-an). Der Modus ersetzt alle Farben und
   entfernt box-shadow -- gedrueckt sah aus wie nicht gedrueckt.
   14 CSS-Dateien hatten gar keinen Block. Statt 14 Bloecke zu pflegen
   eine Regel in gate.css, die den ZUSTAND trifft statt die Datei.
   Gemessen mit forcedColors: active -- vorher ununterscheidbar,
   jetzt `solid 2px Highlight`.
   Was seinen Zustand als WORT traegt (.marke-status, .t-stufe,
   .spalte), braucht nichts -- nachgesehen, nicht vermutet.

PRUEFUNGEN, DIE AUF confirm() WARTETEN: Fuenf Dateien benutzten
`seite.once("dialog", d => d.accept())`. Playwright faengt confirm()
selbst ab, einen <dialog> nicht -- pruef-chat-anhaenge meldete acht
Fehler, keiner davon im Code. Neu: server/helfer-nachfrage.mjs, der
beide Wege kennt (auch den Notnagel fuer Safari vor 15.4).
pruef-chat-anhaenge, -ausbau, -optik und pruef-code wieder gruen.

hilfeAufraeumen bleibt ausgeschaltet -- das loescht echte Daten und
ist Filipes Entscheidung.
2026-09-19 20:16:23 +02:00

158 lines
6.7 KiB
JavaScript

/* =====================================================================
pruef-leerzustand.mjs — Eine leere Seite ist keine Auskunft.
Filipe, 19.09.2026: „Wenn irgendwo noch nichts vorhanden ist, soll
der Benutzer nicht einfach auf eine leere Seite schauen, sondern
verständlich erklärt bekommen, was dort passiert und was er als
Nächstes machen kann."
---------------------------------------------------------------------
WARUM DAS MEHR IST ALS EIN SCHÖNHEITSFEHLER
Der erste Tag im Workspace ist der Tag, an dem ALLES leer ist. Wer
dann auf achtzehn Bretter klickt und achtzehn Mal denselben Satz
liest — „Noch kein Eintrag in diesem Bereich" —, lernt daraus nichts
über die Bretter, sondern etwas über das System: dass es kaputt ist.
Das war am 17.09.2026 schon einmal aufgefallen und für sieben
Bretter behoben. Elf blieben. Genau so altert ein Handgriff, den
niemand erzwingt: Er wird beim ersten Mal gemacht und danach nie
wieder.
---------------------------------------------------------------------
WAS GEPRÜFT WIRD
1. VOLLSTÄNDIG — jedes Brett in BEREICHE hat einen eigenen Satz.
Abgeleitet aus der Tabelle, nicht aus einer Liste: Ein
neunzehntes Brett ohne Satz macht die Prüfung rot.
2. VERSCHIEDEN — keine zwei Bretter sagen dasselbe. Zwei gleiche
Sätze sind fast so schlecht wie achtzehn gleiche.
3. EIN ECHTER SATZ — nicht „leer", nicht „—", keine
Maschinenkennung, und lang genug, dass er etwas sagt.
4. SAGT, WAS HIER HINGEHÖRT — der Satz nennt den Gegenstand des
Bretts, nicht nur seinen Zustand. „Noch nichts da" beantwortet
die Frage nicht, die man in dem Moment hat.
Dazu GEGENPROBEN, damit die Prüfung auch „nicht in Ordnung" sagen
kann.
AUFRUF: node server/pruef-leerzustand.mjs
Läuft in unter zwei Sekunden, ohne Server.
===================================================================== */
import { readFileSync } from "node:fs";
import { join, dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { BEREICHE } from "./workspace-bereiche.js";
const HIER = dirname(fileURLToPath(import.meta.url));
const JS = join(HIER, "..", "workspace", "assets", "js");
let ok = 0, fehl = 0;
const pruef = (name, bedingung, zusatz = "") => {
if (bedingung) { ok++; console.log(` OK ${name}`); }
else { fehl++; console.log(` FEHL ${name}${zusatz ? "\n " + zusatz : ""}`); }
};
console.log("\n=== Leerzustände: sagt jedes Brett, was hier hingehört? ===\n");
const namen = Object.keys(BEREICHE);
/* ---- 1. Vollständig ------------------------------------------------ */
const ohne = namen.filter((b) => !BEREICHE[b].leer);
/* DIE ZAHL GEHOERT IN DIE BEDINGUNG: Bei einer leeren Tabelle waere
"keiner ohne Satz" trivialerweise wahr. */
pruef("jedes Brett hat einen eigenen Satz für den leeren Fall",
namen.length > 0 && ohne.length === 0,
`${namen.length} Bretter, ohne Satz: ${ohne.join(", ") || "keins"}`);
/* ---- 2. Verschieden ------------------------------------------------ */
const gesehen = new Map();
const doppelt = [];
for (const b of namen) {
const t = BEREICHE[b].leer;
if (!t) continue;
if (gesehen.has(t)) doppelt.push(`${gesehen.get(t)} = ${b}`);
else gesehen.set(t, b);
}
pruef("keine zwei Bretter sagen dasselbe", doppelt.length === 0,
doppelt.join("; "));
/* ---- 3. Ein echter Satz -------------------------------------------- */
const MINDEST = 40;
const zuKurz = [], ohnePunkt = [], mitKennung = [];
for (const b of namen) {
const t = BEREICHE[b].leer;
if (!t) continue;
if (t.length < MINDEST) zuKurz.push(`${b} (${t.length})`);
if (!/[.!?]$/.test(t.trim())) ohnePunkt.push(b);
/* Eine Maschinenkennung ist alles, was aussieht wie ein
Bezeichner -- kleingeschrieben mit Unterstrich. */
if (/\b[a-z]+_[a-z_]+\b/.test(t)) mitKennung.push(b);
}
pruef(`jeder Satz ist länger als ${MINDEST} Zeichen`, zuKurz.length === 0,
zuKurz.join(", "));
pruef("jeder Satz endet wie ein Satz", ohnePunkt.length === 0, ohnePunkt.join(", "));
pruef("kein Satz enthält eine Maschinenkennung", mitKennung.length === 0,
mitKennung.join(", "));
/* ---- 4. Sagt, was hier hingehört ------------------------------------
Gemessen wird das GEGENTEIL: Ein Satz, der NUR aus Verneinung
besteht ("Noch nichts da."), sagt nichts ueber das Brett. Ein
brauchbarer Satz hat neben der Verneinung noch einen zweiten Teil --
entweder einen zweiten Satz oder einen Gedankenstrich. */
const nurVerneinung = [];
for (const b of namen) {
const t = (BEREICHE[b].leer || "").trim();
if (!t) continue;
const teile = t.split(/[.!?—–]\s*/).filter((x) => x.trim().length > 3);
if (teile.length < 2) nurVerneinung.push(b);
}
pruef('jeder Satz sagt mehr als: hier ist nichts',
nurVerneinung.length === 0,
`nur Verneinung: ${nurVerneinung.join(", ")}`);
/* ---- 5. Der Notnagel ist noch da, wird aber nicht gebraucht --------
Er bleibt absichtlich stehen: Wer morgen ein Brett anlegt und den
Satz vergisst, soll keine leere Zeile sehen, sondern wenigstens
etwas. Die Pruefung oben sorgt dafuer, dass es nie so weit kommt. */
const bereichJs = readFileSync(join(JS, "bereich.js"), "utf8");
pruef("der Notnagel für ein vergessenes Brett existiert noch",
/einstellung\?\.leer \|\|/.test(bereichJs));
pruef('und der gefilterte Fall wird davon unterschieden',
/Zu dieser Auswahl gibt es nichts/.test(bereichJs),
'sonst liest man: noch kein Eintrag — obwohl es welche gibt, nur nicht in dieser Auswahl');
/* ---- DIE GEGENPROBEN ----------------------------------------------- */
console.log("\n --- Gegenproben (jede MUSS anschlagen) ---");
pruef("Gegenprobe: ein fehlender Satz würde gefunden",
["a", "b"].filter((b) => !({ a: { leer: "x" }, b: {} })[b].leer).length === 1);
pruef("Gegenprobe: zwei gleiche Sätze würden gefunden",
(() => {
const m = new Map(); let d = 0;
for (const [k, v] of [["a", "gleich"], ["b", "gleich"]]) {
if (m.has(v)) d++; else m.set(v, k);
}
return d === 1;
})());
pruef('Gegenprobe: eine reine Verneinung faellt auf',
"Noch nichts da.".split(/[.!?—–]\s*/).filter((x) => x.trim().length > 3).length < 2);
pruef("Gegenprobe: ein echter Satz fällt NICHT auf",
"Noch keine Idee gesammelt. Fang klein an — ein Stichwort reicht."
.split(/[.!?—–]\s*/).filter((x) => x.trim().length > 3).length >= 2);
pruef("Gegenprobe: eine Maschinenkennung im Satz würde gefunden",
/\b[a-z]+_[a-z_]+\b/.test("Fehler: kein_zugriff auf dieses Brett."));
console.log(`\n ${ok} bestanden, ${fehl} fehlgeschlagen`);
console.log(` (${namen.length} Bretter geprüft, `
+ `${gesehen.size} verschiedene Sätze)\n`);
process.exit(fehl ? 1 : 0);