Der Treff sagt jetzt, ob gerade gestreamt wird

Filipe zu dieser Seite: "mach was anderes daraus oder mach es viel
krass und geiler ... erstell was was mich von den socken schmeisst. es
soll wirklich sogar ein wow effekt fuer die community ergeben." Dazu
die eine Auflage: die Kachel bleibt.

WAS SIE WAR: zwei Karten mit zwei Adressen. Sauber gebaut, richtig
beschriftet -- und niemand kam ein zweites Mal wieder. Wer im Treff
ist, kennt die Website. Den Rabattcode merkt man sich beim ersten Mal.

DIE FRAGE, DIE WIRKLICH JEMAND HAT, IST EINE ANDERE: Laeuft er
gerade? Und wenn nicht -- wie lange noch? Die Antwort kennt das Haus
seit dem 20.08.: postfach.dogfather-universe.com/live-status, derselbe
Dienst, von dem der oeffentliche Streamplan lebt. Im Treff gab es sie
bisher nicht.

Jetzt steht oben ein Puls: ein Ring, der sich ueber den Tag bis zur
naechsten Sendezeit fuellt, darin der Countdown auf die Sekunde. Sendet
er, wird die Karte rot, atmet im Ruhepuls und traegt den Titel des
Streams plus einen Weg hin. Darunter die drei Accounts und -- wenn die
Verwaltung eines eintraegt -- das besondere Event mit eigener Uhr.

DREI AUSGAENGE, NICHT ZWEI. Das ist der eigentliche Unterschied zur
oeffentlichen Seite: streamplan.js faengt dort jeden Fehler ab und
setzt `istLive = false`. Aus "wir konnten nicht fragen" wird "er sendet
nicht" -- und wer das liest, macht die Seite zu und verpasst den
Stream. Der Dienst liefert `autoHealthy` sogar mit; gelesen wird es
draussen nicht. Hier schon: Bei einer Stoerung steht "Konnten wir
gerade nicht nachsehen", dazu der Hinweis, dass das NICHT heisst, dass
kein Stream laeuft. Der Countdown laeuft dabei weiter -- er braucht
kein Netz.

NICHTS IST ABGESCHRIEBEN. Die drei Accounts kommen ueber
/workspace/api/draussen aus derselben KANAELE-Liste, an der die
Aufgabenverteilung haengt; die Adressen baut der Steckbrief. Die
Sendezeit steht im Server, und pruef-draussen haelt sie gegen
FIX_STUNDE in streamplan.js -- verschiebt jemand den Termin und aendert
nur einen Ort, wird die Pruefung rot.

Gemessen, bevor gebaut wurde: der Dienst antwortet und meldet sich
gesund, CORS steht auf *, und `connect-src` der Treff-Seiten fuehrt
postfach bereits. Ohne das Letzte waere der Abruf still blockiert
worden und haette ausgesehen wie ein toter Dienst.

Die Kachel heisst jetzt "Draussen" statt "Unsere Seiten" -- drei Dinge
statt zwei Adressen. Ziel und Datei bleiben gleich.
pruef-wege-nach-draussen schreibt den Namen nicht mehr ab, sondern
verlangt, dass Kachel und Seitenueberschrift uebereinstimmen. Zwei
Namen fuer denselben Ort waren schon einmal ein echter Fehler.

Nebenbefund, dort gleich behoben: Dieselbe Pruefung verlangte, dass
die Community-Kacheln restlos in Dreierreihen aufgehen -- obwohl ihr
eigener Kommentar sagt, eine freie Zelle am Ende sei erlaubt. Sie war
rot bei einwandfreiem Raster. Gemessen wird jetzt, was wirklich
schiefgeht: eine doppelt breite Kachel, die in der letzten Spalte
beginnt und die Zelle davor leer laesst. Mit Gegenprobe.

pruef-draussen: 39 Pruefungen, alle vier Lagen im echten Browser --
die Stoerung wird dafuer absichtlich hergestellt.
pruef-wege-nach-draussen: 67 statt 66, keine Fehler mehr.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-21 12:06:23 +02:00
co-authored by Claude Opus 5
parent 9a71f3a242
commit eca9aed279
44 changed files with 2141 additions and 729 deletions
+75 -5
View File
@@ -128,7 +128,28 @@ const { bereicheFuer, TREFF_BRETTER } = await import("./workspace.js");
`ein Mitglied bekommt ${TREFF_BEREICHE?.length} Kacheln`);
const kachel = TREFF_BEREICHE.find((k) => k.ziel === "unsere-seiten.html");
ok(!!kachel, "sie steht in der Liste der Treff-Kacheln");
ok(kachel?.name === "Unsere Seiten", `sie heisst „${kachel?.name}“`);
/* DER NAME WIRD ABGELEITET, NICHT ABGESCHRIEBEN (21.09.2026).
Hier stand "Unsere Seiten" als Text. Als die Seite umgebaut wurde
und "Draußen" hiess, war diese Zeile rot -- ohne dass irgendetwas
kaputt war. Genau so entstehen Pruefungen, die man irgendwann
stumpf nachzieht, und ab da pruefen sie nur noch sich selbst.
Gefragt wird deshalb die Sache, auf die es ankommt: Steht auf der
Kachel dasselbe wie über der Seite, auf der man landet? Zwei Namen
für denselben Ort waren im Haus schon einmal ein echter Fehler --
am 19.09. gab es zwei Kacheln "Chat" mit demselben Ziel, und man
klickte die falsche und suchte den Unterschied. */
const seiteRoh = readFileSync(
new URL("../workspace/unsere-seiten.html", import.meta.url), "utf8");
const h1 = (seiteRoh.match(/<h1 class="titel">([\s\S]*?)<\/h1>/) || [])[1]?.trim();
ok(!!h1 && h1.length > 2, `die Seite trägt eine Überschrift („${h1 || "KEINE"}“)`);
ok(!!h1 && kachel?.name === h1,
`Kachel und Seite heißen gleich („${kachel?.name}“ / „${h1}“)`);
/* Gegenprobe: dass der Vergleich überhaupt "nicht in Ordnung" sagen
kann -- sonst bestätigt er nur sich selbst. */
ok(h1 !== "Ein Name, der dort nicht steht",
"Gegenprobe: ein falscher Name würde auffallen");
ok(!!kachel?.unter && kachel.unter.length > 5,
`und sagt, was dahinter steckt („${kachel?.unter}“)`);
@@ -159,10 +180,59 @@ const { bereicheFuer, TREFF_BRETTER } = await import("./workspace.js");
jeGruppe.get(x.gruppe).push(x);
}
const treffGruppe = jeGruppe.get("Community") || [];
const plaetze = treffGruppe.reduce((n, k) => n + (k.gross ? 2 : 1), 0);
ok(treffGruppe.length > 0 && plaetze % 3 === 0,
`die Community-Gruppe geht auf: ${treffGruppe.length} Kacheln = ${plaetze} Plaetze,`
+ ` ${plaetze / 3} volle Reihen`);
/* HIER STAND `plaetze % 3 === 0` -- UND DAS WAR DER FALSCHE MASSSTAB
(berichtigt 21.09.2026).
Der Kommentar darueber sagt seit dem ersten Tag: "Eine freie Zelle
am ENDE einer Gruppe ist erlaubt -- ein Loch in der MITTE nicht."
Die Bedingung darunter verlangte aber, dass die Gruppe restlos
aufgeht, also genau das Gegenteil. Ein Kommentar, der eine Absicht
beschreibt, erfuellt sie nicht.
Aufgefallen ist es, als die Community neun Kacheln hatte (10
Plaetze, weil "Der Treff" doppelt breit ist): Reihe 1 bis 3 voll,
in Reihe 4 steht "Regeln & Hilfe" allein. Das ist voellig in
Ordnung und sah trotzdem rot aus. Eine rote Zeile, die rot bleibt,
bringt Menschen dazu, Rot zu ueberlesen -- und dann uebersieht man
auch die echte.
WAS WIRKLICH SCHIEFGEHEN KANN: Eine doppelt breite Kachel, die in
der LETZTEN Spalte beginnt. Sie passt dort nicht mehr hin, rutscht
in die naechste Reihe -- und laesst die Zelle davor leer. DAS ist
das Loch in der Mitte. Gemessen wird deshalb der Umbruch, nicht
die Teilbarkeit. */
const SPALTEN = 3;
function loecherFinden(kacheln) {
let platz = 0;
const loecher = [];
for (const k of kacheln) {
const breite = k.gross ? 2 : 1;
if (breite === 2 && platz % SPALTEN === SPALTEN - 1) {
loecher.push(k.name);
platz += 1; /* die Zelle, die leer bleibt */
}
platz += breite;
}
return { loecher, platz };
}
const raster = loecherFinden(treffGruppe);
ok(treffGruppe.length > 0 && raster.loecher.length === 0,
raster.loecher.length
? `LUECKE IN DER MITTE vor: ${raster.loecher.join(", ")}`
: `die Community-Gruppe hat kein Loch: ${treffGruppe.length} Kacheln, `
+ `${raster.platz} Plaetze, letzte Reihe mit ${raster.platz % SPALTEN || SPALTEN} `
+ "belegt");
/* GEGENPROBE -- kann diese Rechnung ueberhaupt ein Loch melden?
Ohne sie waere die Zeile darueber auch dann gruen, wenn
`loecherFinden` immer ein leeres Feld zurueckgaebe. Genau so ist
die alte Fassung jahrelang falsch geblieben. */
const erfunden = loecherFinden([
{ name: "eins" }, { name: "zwei" }, { name: "breit", gross: true }]);
ok(erfunden.loecher.length === 1 && erfunden.loecher[0] === "breit",
`Gegenprobe: eine breite Kachel in der letzten Spalte faellt auf `
+ `(${erfunden.loecher.join(", ") || "NICHTS GEFUNDEN"})`);
ok(treffGruppe.findIndex((k) => k.gross) === 0,
"und die doppelt breite Kachel steht an erster Stelle");