Compare commits

..
3 Commits
Author SHA1 Message Date
DogFatherGitandClaude Opus 5 2c2c42d4aa Drei rote Zeilen im Werdegang -- alle drei verlangten Altes
Keine davon war ein Mangel an der Seite. Alle drei verlangten einen
Zustand, den Filipe am 19.09.2026 ausdruecklich geaendert hat.

1. "alphabetisch (Rieke, Diene)"

   Filipe am 19.09.: "die reihenfolge der listen soll immer angepasst
   sein hatten wir doch schon. die rechte hand rolle immer zuerst und
   dan die modis." Der Server sortiert seitdem nach ROLLEN_SORTIERUNG,
   dann nach Namen -- die Pruefung verlangte weiter rein alphabetisch.

   Sie prueft jetzt dieselbe Ordnung, abgeleitet aus derselben
   Konstante wie der Server. Wer dort eine Rolle verschiebt,
   verschiebt sie hier mit. Was bleibt, ist die eigentliche Aussage:
   sortiert wird nach etwas, das nichts ueber die Person sagt -- eine
   Liste nach Aktivitaet waere eine Rangliste mit anderem Namen, eine
   nach Rolle ist es nicht.

2. "jede Zelle traegt ihr Zeichen, nicht nur ihre Farbe"

   Im Quelltext der Seite steht seit dem 19.09. woertlich: "Leer ist
   jetzt WIRKLICH leer -- kein Zeichen, dafuer ein gestrichelter
   Rahmen. Man sieht das Fehlen, statt es zu lesen." Die Pruefung
   verlangte das Gegenteil.

   Gemessen werden jetzt beide Haelften, und die zweite ist die
   wichtigere: Stuende in einer leeren Zelle doch ein Zeichen, waere
   "noch nichts gesetzt" nicht mehr von "gesetzt" zu unterscheiden --
   und das faellt beim Hinsehen nicht auf, weil es nach Inhalt
   aussieht.

3. "unter dem Diagramm steht eine Legende (7 Eintraege)"

   Hier stand `=== 2`. Inzwischen sind es sieben: zwei fuer die
   Bewegungsrichtung, vier Stufen und der leere Zustand. Wieder eine
   Rechnung von gestern.

   Gefragt wird jetzt, was die Legende leisten muss: zu JEDER Stufe,
   die der Server kennt, ein Eintrag -- und einer fuer den leeren
   Zustand. Kommt eine Stufe dazu, waechst die Erwartung mit.

ZWEIMAL HAT MICH DABEI DIE ZAHL IN DER BEDINGUNG GERETTET. Erst
fragte ich die Stufen an der Liste ab -- die liefert sie gar nicht,
sie stehen an der einzelnen Karte. Ohne `stufenSoll.length > 0` waere
der Vergleich gegen eine leere Liste gelaufen und haette "die Legende
nennt jede davon" bestaetigt, ohne eine einzige zu kennen. Dieselbe
Zeile hatte zuvor schon in pruef-modi-checkliste einen stillen
Totalausfall verhindert.

pruef-werdegang: 103 Pruefungen, 0 Fehler (war 95, davon 3 rot)

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 13:15:35 +02:00
DogFatherGitandClaude Opus 5 9d4a40ff58 Zwei Pruefungen waren rot, weil etwas richtig gemacht wurde
pruef-auskunft und pruef-treff-werkzeuge -- beide bestraften eine
Verbesserung. Das ist die unangenehmste Sorte roter Pruefung: Wer sie
zweimal so erlebt, faengt an, rote Laeufe zu erklaeren statt sie zu
lesen.

1. "DIE COMMUNITY HAT KEINEN STECKBRIEF"

   So stand es woertlich in der Bedingung. Am 19.09. hat Filipe genau
   das Gegenteil entschieden -- "jeder soll ein steckbrief haben, jeder
   der ein account hat ... jeder soll genau wie ich foto und so
   hinzufuegen koennen" -- und die Community hat seitdem einen.

   Was die Zeile schuetzen wollte, steht in ihrem eigenen Kommentar:
   "Ohne die zweite Stelle haette die Gruppe mit den wenigsten Rechten
   auch dieses nicht -- und sie ist die groesste." Die Sorge ist
   richtig und hat mit der Anzahl der Seiten nichts zu tun. Die Frage
   lautet: KOMMT JEDE ROLLE AN IHRE AUSKUNFT?

   Genau das wird jetzt gemessen -- welche Seiten den Knopf tragen,
   aus den Dateien gelesen statt aufgezaehlt, und ob jede der acht
   Rollen mindestens eine davon erreichen darf, aus der Rechtetafel
   gelesen statt angenommen. Mit Gegenprobe (eine erfundene Rolle
   erreicht keine) und mit der Zahl in der Bedingung.

2. "DIE COMMUNITY STEHT BEI 8 VON 33"

   Hier stand `community.seiten < 5`. Die Zahl stimmte an dem Tag, an
   dem sie geschrieben wurde. Seither hat der Treff eigene Seiten
   bekommen -- Regeln, Steckbrief, Hilfe, Draussen -- und die
   Community steht bei acht. Die Pruefung war rot, WEIL der Treff
   gewachsen ist. Dieselbe Fehlerklasse wie die Umbruchschwelle vom
   06.09.: Wer eine Zahl notiert, notiert einen Zustand, keine Regel.

   Gemeint war eine ORDNUNG: Ein Mitglied sieht weniger als die
   Moderation, die weniger als die rechte Hand, die weniger als
   DogFather. Nachgemessen 8 / 19 / 25 / 32 von 33. Geprueft wird
   jetzt das Verhaeltnis -- und zusaetzlich, dass die Community das
   Minimum ueber ALLE acht Rollen ist, nicht nur in dieser Kette. Das
   bleibt richtig, wenn der Treff weiterwaechst, und faellt sofort
   auf, wenn jemand die Reihenfolge versehentlich umdreht.

pruef-auskunft         46/0  (war 46, davon 1 rot)
pruef-treff-werkzeuge  73/0  (war 70, davon 1 rot)

Damit sind alle vier Pruefungen gruen, die heute frueh rot waren.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 13:12:36 +02:00
DogFatherGitandClaude Opus 5 95d753791d Die dritte Fassung derselben Pruefung -- diesmal ohne Liste
pruef-modi-checkliste war rot: "und alle stehen in einer Gruppe fuer
euch beide -- ausser: Der Treff, Treff-Chat, Anschlagbrett, ..."

DIE URSACHE WAR EINE GEPFLEGTE LISTE, zum zweiten Mal. Erst stand dort
`["Team Dogi"]`, dann `["Team Dogi", "Entwicklung & Nachwuchs"]`, und
daneben der Satz: "Kommt eine dritte Gruppe, wird diese Zeile rot. Das
ist Absicht." Am 21.09. kam sie -- der Treff -- und nichts daran war
falsch.

WARUM DIE FRAGE SELBST NICHT MEHR PASSTE: `bereiche_zusatz` hiess
einmal "die eine Kachel, die nur ihr zwei habt". Seit es den Treff
gibt, steht dort fuer DogFather auch der GANZE Treff -- zehn Kacheln
in der Gruppe "Community", die die rechte Hand, die Moderation und
jedes Mitglied ebenso sehen. Das ist der zweite Haushalt, kein Mangel:
Fuer ihn ist der Treff eine Zugabe, fuer sie das Zuhause.

MEIN ZWEITER VERSUCH WAR SCHLECHTER ALS DER ERSTE, und gefangen hat
das nur die Gegenprobe. Ich wollte die verbotenen Gruppen MESSEN statt
sie aufzuzaehlen: "welche Gruppen sieht ein Creator, welche Spicy
Media?" Nachgemessen sind das in dieser Pruefdatenbank NULL -- beide
haben dort gar keine Kacheln. Die Bedingung waere damit immer wahr
gewesen, und aus einer roten Pruefung waere eine gruene geworden, die
nichts mehr misst. Gefangen hat es allein die Zahl in der Bedingung
(`sehenAlle.size >= 2`). Ohne sie haette ich eine Pruefung stillgelegt
und es fuer eine Reparatur gehalten.

JETZT WIRD NACH DER KACHEL GEFRAGT, NICHT NACH IHRER GRUPPE: Gibt es
unter den Zugaben mindestens eine, die sonst NIEMAND hat? Gemessen am
Ziel, gegen Modi, Spicy Media und Creator zusammen. Das ist die
urspruengliche Aussage, und sie altert nicht -- die Gruppe war immer
nur ein Hilfsmerkmal.

Die alte Gruppen-Zeile steht nicht mehr daneben. Sie waere jetzt immer
wahr, und eine Zeile, die immer bestaetigt, bestaetigt nichts.

Die Meldung sagt seitdem auch etwas:
  DogFather    davon 3, die sonst niemand hat (Dein Team, Wer sieht
               was, Talente), erwartet mindestens eine
  Creator      davon 0, die sonst niemand hat, erwartet keine

75 Pruefungen, 0 Fehler (war 70, davon 2 rot)

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-09-21 13:10:41 +02:00
4 changed files with 296 additions and 42 deletions
+69 -12
View File
@@ -315,21 +315,78 @@ melde("=== 5. Nachvollziehbar ===");
melde("");
melde("=== 6. Der Knopf ===");
{
const { readFileSync } = await import("node:fs");
for (const seite of ["steckbrief.html", "treff-regeln.html"]) {
const s = readFileSync(new URL("../workspace/" + seite, import.meta.url), "utf8");
ok(/id="auskunft-knopf"/.test(s), `${seite} hat den Knopf`);
ok(/assets\/js\/auskunft\.js/.test(s), `${seite} lädt das Skript dazu`);
/* NICHT "AUF DIESEN ZWEI SEITEN", SONDERN "FUER JEDE ROLLE
ERREICHBAR" (umgestellt 21.09.2026).
Hier stand woertlich: `ok(!tafel["…/steckbrief.html"]
.includes("gast"), "die Community hat keinen Steckbrief")`.
Am 19.09. hat Filipe genau das Gegenteil entschieden -- "jeder
soll ein steckbrief haben, jeder der ein account hat ... jeder
soll genau wie ich foto und so hinzufuegen koennen" -- und die
Community hat seitdem einen. Die Zeile war also rot, WEIL etwas
richtig gemacht wurde.
Das ist die unangenehmste Sorte roter Pruefung: Sie bestraft die
Verbesserung. Wer sie zweimal so erlebt, faengt an, rote Laeufe
zu erklaeren statt sie zu lesen.
WAS SIE EIGENTLICH SCHUETZEN WOLLTE, steht in ihrem eigenen
Kommentar: "Ohne die zweite Stelle haette die Gruppe mit den
wenigsten Rechten auch dieses nicht -- und sie ist die groesste."
Die Sorge ist richtig und hat mit der Anzahl der Seiten nichts zu
tun. Die Frage lautet: KOMMT JEDE ROLLE AN IHRE AUSKUNFT?
Gemessen wird sie jetzt so: Welche Seiten tragen den Knopf (aus
den Dateien gelesen, nicht aufgezaehlt), und erreicht jede Rolle
mindestens eine davon (aus der Rechtetafel gelesen, nicht
angenommen)? Kommt morgen eine dritte Seite dazu oder faellt eine
weg, bleibt die Aussage dieselbe. */
const { readFileSync, readdirSync } = await import("node:fs");
const ordnerSeiten = new URL("../workspace/", import.meta.url);
const mitKnopf = [];
for (const datei of readdirSync(ordnerSeiten)) {
if (!datei.endsWith(".html")) continue;
const inhalt = readFileSync(new URL(datei, ordnerSeiten), "utf8");
if (!/id="auskunft-knopf"/.test(inhalt)) continue;
mitKnopf.push(datei);
/* Ein Knopf ohne sein Skript ist eine Sackgasse, die aussieht wie
ein Weg -- man tippt darauf und es passiert nichts. */
ok(/assets\/js\/auskunft\.js/.test(inhalt), `${datei} lädt das Skript dazu`);
}
/* WARUM AUSGERECHNET DIESE ZWEI: Die Community hat keinen Steckbrief.
Ohne die zweite Stelle haette die Gruppe mit den wenigsten Rechten
auch dieses nicht -- und sie ist die groesste. */
/* DIE ZAHL GEHOERT IN DIE BEDINGUNG. Faende die Suche keine einzige
Seite -- umbenannt, verschoben, anderer Bezeichner --, waere
"jede Rolle kommt hin" unten fuer alle falsch ODER fuer alle
wahr, je nach Schleife. Beides waere ohne diese Zeile nicht zu
unterscheiden. */
ok(mitKnopf.length >= 1,
`${mitKnopf.length} Seite(n) tragen den Knopf (${mitKnopf.join(", ")})`);
const rechte = await import("./rechte.js");
const tafel = rechte.tafelJetzt();
ok(!(tafel["/workspace/steckbrief.html"] || []).includes("gast"),
"die Community hat keinen Steckbrief");
ok((tafel["/workspace/treff-regeln.html"] || []).includes("gast"),
"aber die Treff-Regeln – deshalb steht er auch dort");
const wege = (rolle) => mitKnopf.filter(
(d) => (tafel["/workspace/" + d] || []).includes(rolle));
/* JEDE ROLLE, NICHT EINE AUSGEWAEHLTE. Die Liste kommt aus dem
Haus, damit eine neue Rolle nicht stillschweigend ungeprueft
bleibt -- genau so entstehen Gruppen, die etwas nicht koennen und
es niemandem sagen. */
const ohneWeg = rechte.ALLE_ROLLEN.filter((r) => wege(r).length === 0);
ok(ohneWeg.length === 0,
ohneWeg.length
? `DIESE ROLLEN KOMMEN NICHT AN IHRE AUSKUNFT: ${ohneWeg.join(", ")}`
: `alle ${rechte.ALLE_ROLLEN.length} Rollen erreichen mindestens eine `
+ `Seite mit dem Knopf`);
/* Und die groesste Gruppe ausdruecklich benannt: Sie hat die
wenigsten Rechte, also faellt bei ihr zuerst etwas weg. */
ok(wege("gast").length >= 1,
`die Community kommt ueber ${wege("gast").join(", ") || "KEINE Seite"} hin`);
/* GEGENPROBE: Kann diese Rechnung ueberhaupt "nein" sagen? Eine
Rolle, die es nicht gibt, darf keine einzige Seite erreichen --
sonst waere `wege()` kaputt und alles darueber wertlos. */
ok(wege("diese-rolle-gibt-es-nicht").length === 0,
"Gegenprobe: eine erfundene Rolle erreicht keine");
}
/* ------------------------------------------------------------------- */
+56 -17
View File
@@ -377,29 +377,68 @@ for (const [name, an, wenigstens] of [
]) {
const a = await hole(an.keks, "/workspace/api/ich");
const zusatz = a.daten?.bereiche_zusatz || [];
/* ZWEI GRUPPEN SIND ERLAUBT, und die Liste steht ausgeschrieben da
(11.09.2026).
/* GEFRAGT WIRD NACH DER KACHEL, NICHT NACH IHRER GRUPPE
(21.09.2026, dritte Fassung).
Hier stand nur "Team Dogi". Seit es "Entwicklung & Nachwuchs" gibt,
waere die Pruefung rot geworden -- und die naheliegende Reparatur
("prueft eben gar nicht mehr, in welcher Gruppe") haette die
Aussage weggeworfen statt sie nachzuziehen.
DIE BEIDEN VORHERIGEN WAREN LISTEN, UND BEIDE SIND GEALTERT:
zuerst `["Team Dogi"]`, dann `["Team Dogi", "Entwicklung &
Nachwuchs"]`. Daneben stand: "Kommt eine dritte Gruppe, wird diese
Zeile rot. Das ist Absicht." Am 21.09. kam sie -- der Treff -- und
die Pruefung war rot, ohne dass etwas falsch war.
Die Aussage ist: Eine Zusatzkachel darf NICHT in einer Gruppe
landen, die alle sehen. Steht sie in "Taeglich" oder "Rund um den
Creator", sitzt sie zwischen Kacheln, die jeder hat -- und dort
faellt niemandem auf, dass sie nur bei zweien steht.
DER ZWEITE VERSUCH WAR NOCH SCHLECHTER, und das hat nur die
Gegenprobe gezeigt: Ich wollte die verbotenen Gruppen MESSEN statt
sie aufzuzaehlen -- "welche Gruppen sieht ein Creator, welche
Spicy Media?". Nachgemessen sind das in dieser Pruefdatenbank
NULL: Beide haben dort gar keine Kacheln. Die Bedingung waere
damit immer wahr gewesen, und die Pruefung haette ab sofort
geschwiegen. Gefangen hat das allein die Zahl in der Bedingung
(`sehenAlle.size >= 2`) -- ohne sie waere aus einer roten Pruefung
eine gruene geworden, die nichts mehr misst. Das ist der
gefaehrlichere Ausgang von beiden.
Kommt eine dritte Gruppe, wird diese Zeile rot. Das ist Absicht:
Wo Kacheln ueber Menschen stehen, ist etwas Reibung richtig. */
const ERLAUBTE_GRUPPEN = new Set(["Team Dogi", "Entwicklung & Nachwuchs"]);
const falsch = zusatz.filter((k) => !ERLAUBTE_GRUPPEN.has(k.gruppe)).map((k) => k.name);
WARUM DIE ALTE FRAGE NICHT MEHR PASST: `bereiche_zusatz` hiess
einmal "die eine Kachel, die nur ihr zwei habt". Seit es den Treff
gibt, steht dort fuer DogFather auch der GANZE Treff -- zehn
Kacheln in der Gruppe "Community", die die rechte Hand, die
Moderation und jedes Mitglied ebenfalls sehen. Das ist kein
Mangel, sondern der zweite Haushalt: Fuer ihn ist der Treff eine
Zugabe, fuer sie ist er das Zuhause.
DIE AUSSAGE, DIE BLEIBT, IST DIE URSPRUENGLICHE: Es muss eine
Kachel geben, die WIRKLICH nur die beiden haben. Genau danach
wird jetzt gefragt -- am ZIEL, nicht an der Gruppe. Das Ziel ist
die Kachel selbst; die Gruppe war immer nur ein Hilfsmerkmal, und
Hilfsmerkmale altern.
DIE ALTE GRUPPEN-ZEILE STEHT NICHT MEHR DANEBEN. Sie waere jetzt
immer wahr, und eine Zeile, die immer bestaetigt, bestaetigt
nichts -- sie erhoeht nur die Zahl der Pruefungen und den
Eindruck von Sorgfalt. */
const zieleVon = async (keks) => {
const b = await hole(keks, "/workspace/api/ich");
return new Set([...(b.daten?.bereiche || []), ...(b.daten?.bereiche_zusatz || [])]
.map((k) => String(k.ziel || "")).filter(Boolean));
};
const andere = new Set([
...(await zieleVon(modiAn.keks)),
...(await zieleVon(spicyAn.keks)),
...(await zieleVon(creatAn.keks)),
]);
/* DIE ZAHL GEHOERT IN DIE BEDINGUNG. Kaeme hier nichts heraus --
weil die Auskunft sich aendert oder eine Anmeldung scheitert --,
waere jede Kachel "nur ihre", und die Zeile unten waere fuer alle
gruen. Genau in diese Falle bin ich eine Fassung vorher gelaufen. */
ok(andere.size >= 3,
`die drei anderen kommen zusammen auf ${andere.size} Kacheln`);
const nurIhr = zusatz.filter((k) => !andere.has(String(k.ziel || ""))).map((k) => k.name);
ok(wenigstens ? zusatz.length >= 1 : zusatz.length === 0,
`${name.padEnd(12)} bekommt ${zusatz.length} Zusatzkachel(n)`
+ `, erwartet ${wenigstens ? "mindestens eine" : "keine"}`);
ok(falsch.length === 0,
`${name.padEnd(12)} und alle stehen in einer Gruppe fuer euch beide`
+ (falsch.length ? ` -- ausser: ${falsch.join(", ")}` : ""));
ok(wenigstens ? nurIhr.length >= 1 : nurIhr.length === 0,
`${name.padEnd(12)} davon ${nurIhr.length}, die sonst niemand hat`
+ (nurIhr.length ? ` (${nurIhr.join(", ")})` : "")
+ `, erwartet ${wenigstens ? "mindestens eine" : "keine"}`);
}
+55 -3
View File
@@ -562,9 +562,61 @@ melde("=== 8. Der Regeltext ===");
const t = json(meine);
ok(meine.code === 200 && t.seiten?.length === rechte.alleSeiten().length,
`DogFather bekommt alle ${t.seiten?.length} Seiten`);
const community = (t.rollen || []).find((x) => x.schluessel === "gast");
ok(community && community.seiten < 5,
`und die Community steht bei ${community?.seiten} von ${t.seiten?.length}`);
/* EINE FESTE ZAHL IST EINE RECHNUNG VON GESTERN (berichtigt
21.09.2026).
Hier stand `community.seiten < 5`. Die Zahl stimmte an dem Tag,
an dem sie geschrieben wurde. Seither hat der Treff eigene Seiten
bekommen -- Regeln, Steckbrief, Hilfe, Draussen -- und die
Community steht bei acht. Die Pruefung war damit rot, WEIL der
Treff gewachsen ist. Dieselbe Fehlerklasse wie die Umbruchschwelle
vom 06.09.: Wer eine Zahl notiert, notiert einen Zustand, keine
Regel.
DIE AUSSAGE, DIE GEMEINT WAR, IST EINE ORDNUNG, KEINE GRENZE:
Ein Mitglied sieht weniger als die Moderation, die weniger als die
rechte Hand, die weniger als DogFather. Wer Rechte vergibt, darf
diese Reihenfolge nicht versehentlich umdrehen -- und genau das
faellt an einer Zahl nicht auf, an der Ordnung sofort.
Nachgemessen am 21.09.: 8 / 19 / 25 / 32 von 33 Seiten. Die Zahlen
stehen hier nur als Beleg; gemessen wird ihr Verhaeltnis, und das
bleibt richtig, wenn der Treff weiterwaechst. */
const zahl = (schluessel) =>
(t.rollen || []).find((x) => x.schluessel === schluessel)?.seiten;
const kette = ["gast", "modi", "hand", "admin"].map((r) => [r, zahl(r)]);
/* DIE ZAHL GEHOERT IN DIE BEDINGUNG. Fehlte eine Rolle in der
Auskunft, waere `undefined < undefined` schlicht false -- aber
`[...].every(...)` ueber eine leere Liste waere wahr. Deshalb
zuerst: Sind ueberhaupt alle vier da? */
ok(kette.every(([, n]) => Number.isFinite(n)),
`die Auskunft nennt alle vier: ${kette.map(([r, n]) => `${r} ${n}`).join(", ")}`);
const steigt = kette.every(([, n], i) => i === 0 || n > kette[i - 1][1]);
ok(steigt,
steigt
? `und sie stehen in der richtigen Ordnung `
+ `(${kette.map(([r, n]) => `${r} ${n}`).join(" < ")} von ${t.seiten?.length})`
: `DIE ORDNUNG STIMMT NICHT: `
+ `${kette.map(([r, n]) => `${r} ${n}`).join(", ")} -- jemand `
+ `weiter unten sieht mehr als jemand weiter oben`);
/* UND DIE COMMUNITY IST DAS MINIMUM UEBER ALLE ROLLEN, nicht nur in
dieser Kette: Die Agentur steht daneben, nicht darueber, und auch
ihr gegenueber darf ein Mitglied nicht mehr Seiten haben. */
const alleZahlen = (t.rollen || []).filter((x) => Number.isFinite(x.seiten));
ok(alleZahlen.length >= 4 && alleZahlen.every((x) => x.schluessel === "gast"
|| x.seiten > zahl("gast")),
`die Community hat die wenigsten von allen ${alleZahlen.length} Rollen `
+ `(${zahl("gast")} von ${t.seiten?.length})`);
/* GEGENPROBE: Kann diese Ordnung ueberhaupt "nein" sagen? Umgekehrt
gelesen muss dieselbe Rechnung falsch herauskommen -- sonst waere
sie eine Bestaetigungsmaschine. */
const rueckwaerts = [...kette].reverse();
ok(!rueckwaerts.every(([, n], i) => i === 0 || n > rueckwaerts[i - 1][1]),
"Gegenprobe: umgekehrt gelesen faellt dieselbe Rechnung durch");
}
/* ------------------------------------------------------------------- */
+116 -10
View File
@@ -501,12 +501,52 @@ melde("=== 10. Die Liste ===");
ok(!l.liste.some((p) => p.name === "Tili"), "ein Creator steht nicht darin");
ok(!l.liste.some((p) => p.name === "Filipe"), "DogFather auch nicht");
/* NACH NAMEN SORTIERT, NICHT NACH AKTIVITÄT. Eine Liste, die die mit
der meisten Bewegung nach oben stellt, ist eine Rangliste mit einem
anderen Namen. */
const namen = l.liste.map((p) => p.name);
ok(namen.join(",") === [...namen].sort((a, b) => a.localeCompare(b, "de")).join(","),
`alphabetisch (${namen.join(", ")})`);
/* NACH ROLLE, DANN NACH NAMEN -- UND NICHT NACH AKTIVITAET
(nachgezogen 21.09.2026).
Hier stand "alphabetisch", und die Zeile war rot: Die Liste kam
als "Rieke, Diene" zurueck, also nicht alphabetisch. Nachgesehen
war das kein Mangel, sondern eine Entscheidung vom 19.09.2026.
Filipe damals: "die reihenfolge der listen soll immer angepasst
sein hatten wir doch schon. die rechte hand rolle immer zuerst
und dan die modis."
Der Server sortiert seitdem nach `ROLLEN_SORTIERUNG`, dann nach
Namen. Die Pruefung ist zwei Tage lang rot gewesen, weil sie die
alte Regel weiter verlangt hat -- und eine rote Zeile, die rot
bleibt, bringt Menschen dazu, Rot zu ueberlesen.
WAS BLEIBT, IST DIE EIGENTLICHE AUSSAGE: Sortiert wird nach etwas,
das nichts ueber die Person sagt. Eine Liste, die die mit der
meisten Bewegung nach oben stellt, waere eine Rangliste mit einem
anderen Namen. Eine Sortierung nach ROLLE ist das nicht -- sie
sagt nur, welche Aufgabe jemand hat.
ABGELEITET, NICHT ABGESCHRIEBEN: Die Reihenfolge kommt aus
derselben Konstante, die der Server benutzt. Wer dort eine Rolle
verschiebt, verschiebt sie hier mit -- und diese Zeile wird nicht
wieder rot, ohne dass etwas kaputt ist. */
const { ROLLEN_REIHE } = await import("./workspace.js");
const platz = (r) => {
const i = ROLLEN_REIHE.indexOf(r);
return i === -1 ? ROLLEN_REIHE.length : i;
};
const soll = [...l.liste].sort((a, b) =>
platz(a.rolle) - platz(b.rolle) || a.name.localeCompare(b.name, "de"));
const ist = l.liste.map((p) => `${p.rolle}:${p.name}`).join(", ");
ok(ist === soll.map((p) => `${p.rolle}:${p.name}`).join(", "),
`nach Rolle, dann nach Namen (${ist})`);
/* GEGENPROBE: Dass die Liste ueberhaupt MEHRERE Rollen enthaelt --
sonst waere "nach Rolle sortiert" bei einer einzigen Rolle
trivial wahr, und die Zeile darueber pruefte nur noch die
Namenssortierung. */
ok(new Set(l.liste.map((p) => p.rolle)).size >= 2,
`und es sind wirklich mehrere Rollen darin `
+ `(${[...new Set(l.liste.map((p) => p.rolle))].join(", ")})`);
ok(/kein vergleich/i.test(l.hinweis || ""),
"und die Seite sagt selbst, dass sie niemanden vergleicht");
@@ -596,18 +636,84 @@ melde("=== 11. Im Browser ===");
name: document.getElementById('karte-name')?.textContent || '',
balken: document.querySelectorAll('.w-bewegung__balken').length,
zellen: document.querySelectorAll('.w-streifen__zelle').length,
/* GETRENNT NACH GESETZT UND LEER (21.09.2026). Vorher wurde
verlangt, dass JEDE Zelle Text traegt -- auch die leeren. Seit
dem 19.09. sind die aber absichtlich leer. */
zellenMitStufe: [...document.querySelectorAll('.w-streifen__zelle')]
.filter((z) => z.dataset.stufe && z.dataset.stufe !== 'leer').length,
zeichenInZellen: [...document.querySelectorAll('.w-streifen__zelle')]
.filter((z) => z.dataset.stufe && z.dataset.stufe !== 'leer')
.every((z) => (z.textContent || '').trim().length > 0),
leereMitZeichen: [...document.querySelectorAll('.w-streifen__zelle')]
.filter((z) => z.dataset.stufe === 'leer'
&& (z.textContent || '').trim().length > 0).length,
legende: document.querySelectorAll('.w-legende__punkt').length,
legendeStreifen: [...document.querySelectorAll(
'.w-legende--streifen .w-legende__zeichen')].map((z) => z.dataset.stufe),
texte: document.querySelectorAll('.w-text').length,
breiter: document.documentElement.scrollWidth > document.documentElement.clientWidth,
}));
ok(/Diene|Rieke/.test(karte.name), `eine Karte öffnet sich (${karte.name})`);
ok(karte.zellen > 0, `der Streifen ist gezeichnet (${karte.zellen} Zellen)`);
/* DIE FARBE IST NIE DIE AUSKUNFT. Jede Zelle trägt ihr Zeichen als
Text -- wer Farben schlecht unterscheidet, liest dasselbe. */
ok(karte.zeichenInZellen, "jede Zelle trägt ihr Zeichen, nicht nur ihre Farbe");
ok(karte.legende === 2, `unter dem Diagramm steht eine Legende (${karte.legende} Einträge)`);
/* DIE FARBE IST NIE DIE AUSKUNFT. Jede Zelle MIT EINER STUFE traegt
ihr Zeichen als Text -- wer Farben schlecht unterscheidet, liest
dasselbe.
BIS ZUM 21.09.2026 STAND HIER "jede Zelle", ohne Unterschied.
Seit dem 19.09. sind leere Zellen aber absichtlich leer; im
Quelltext steht woertlich: "Leer ist jetzt WIRKLICH leer -- kein
Zeichen, dafuer ein gestrichelter Rahmen. Man sieht das Fehlen,
statt es zu lesen." Die Pruefung verlangte also das Gegenteil
einer Entscheidung und war deshalb rot.
Beide Haelften werden jetzt gemessen, und die zweite ist die
wichtigere: Stuende in einer leeren Zelle doch ein Zeichen, waere
"noch nichts gesetzt" nicht mehr von "gesetzt" zu unterscheiden --
und das faellt beim Hinsehen nicht auf, weil es nach Inhalt
aussieht. */
ok(karte.zellenMitStufe > 0,
`${karte.zellenMitStufe} Zellen tragen eine Stufe`);
ok(karte.zeichenInZellen,
"und jede davon ihr Zeichen, nicht nur ihre Farbe");
ok(karte.leereMitZeichen === 0,
`die leeren bleiben leer (${karte.leereMitZeichen} mit Zeichen)`);
/* DIE LEGENDE WIRD ABGELEITET, NICHT GEZAEHLT (21.09.2026).
Hier stand `karte.legende === 2`. Die Zahl stimmte, solange es
zwei Eintraege gab; inzwischen sind es sieben -- zwei fuer die
Bewegungsrichtung und fuenf fuer den Streifen (vier Stufen plus
"noch nichts gesetzt"). Wieder eine Rechnung von gestern.
Gefragt wird jetzt, was die Legende leisten muss: Zu JEDER Stufe,
die der Server kennt, gehoert ein Eintrag -- und einer fuer den
leeren Zustand. Kommt eine Stufe dazu, waechst die Erwartung von
selbst mit. Die Stufen kommen aus derselben Auskunft, aus der die
Seite sie baut; abgeschrieben waere sie die naechste Zahl von
gestern. */
/* DIE STUFEN WERDEN HIER NEU GEHOLT und nicht aus Abschnitt 10
mitgenommen: Jener Block hat seinen eigenen Geltungsbereich, und
eine Variable von dort waere hier schlicht nicht da. Beim ersten
Versuch war genau das der Fall -- die Pruefung brach mitten im
Browserteil ab, ohne Ergebnis. */
/* DIE STUFEN STEHEN AN DER EINZELNEN KARTE, nicht an der Liste --
nachgesehen in workspace-werdegang.js, nicht angenommen. Der
erste Versuch fragte die Liste und bekam null Stufen; gefangen
hat das die Zeile darunter, die die Zahl in der Bedingung hat. */
const wenListe = json(await ruf("/workspace/api/werdegang/liste", CREW, "GET", { cookie: kDogi }));
const wessen = wenListe.liste?.[0]?.id;
const fuerLegende = json(await ruf(
`/workspace/api/werdegang/person/${wessen}`, CREW, "GET", { cookie: kDogi }));
const stufenSoll = (fuerLegende.stufen || []).map((x) => x.schluessel);
ok(stufenSoll.length > 0,
`der Server kennt ${stufenSoll.length} Stufen (${stufenSoll.join(", ")})`);
const legendeSoll = [...stufenSoll, "leer"].join(",");
ok((karte.legendeStreifen || []).join(",") === legendeSoll,
`die Legende nennt jede davon und den leeren Zustand `
+ `(${(karte.legendeStreifen || []).join(", ") || "KEINE"})`);
ok(karte.legende === stufenSoll.length + 1 + 2,
`insgesamt ${karte.legende} Eintraege -- ${stufenSoll.length} Stufen, `
+ "der leere Zustand und zwei fuer die Bewegungsrichtung");
ok(karte.texte > 0, `und die Texte dazu (${karte.texte})`);
ok(!karte.breiter, "nichts steht über den rechten Rand hinaus");