diff --git a/server/pruef-kachelraster.mjs b/server/pruef-kachelraster.mjs index 7310b884..598aff98 100644 --- a/server/pruef-kachelraster.mjs +++ b/server/pruef-kachelraster.mjs @@ -26,9 +26,23 @@ ist dagegen in Ordnung und faellt aus dieser Rechnung heraus. GEPRUEFT IN ZWEI LAGEN, denn die Kachelzahl haengt an der Rolle: - ein Modi moderiert und sieht dieselben acht wie DogFather, ein reiner - Zuschauer sieben. Eine Reihenfolge, die nur fuer eine Zahl aufgeht, - geht nicht auf. + DogFather und ein Modi sehen verschieden viele. Eine Anordnung, die + nur fuer eine Zahl aufgeht, geht nicht auf. + + OHNE FESTE ZAHLEN (23.09.2026). Hier stand „acht" -- in der + Ueberschrift, im Text und in der Bedingung. Am 22.09. sind Kacheln + dazugekommen, und die Pruefung wurde rot, ohne dass am Raster etwas + kaputt war: Sie hat die Zahl von gestern verteidigt. + + Und sie mass fuer DogFather und einen Modi VERSCHIEDENE Gruppen -- + gesucht wurde „die Community-Gruppe" ueber ihre Ueberschrift, mit + der letzten Gruppe als Rueckfall. Fuer den einen griff der Treffer, + fuer den anderen der Rueckfall; beides hiess in der Meldung gleich. + Eine Pruefung, die je nach Rolle etwas anderes misst, kann ihr + Ergebnis nicht erklaeren. + + Jetzt werden ALLE Gruppen gemessen, und die Frage ist ueberall + dieselbe: Hat das Raster ein Loch? MIT GEGENPROBE: Dieselbe Rechnung wird auf eine absichtlich falsche Reihenfolge angewandt (breite Kachel an dritter Stelle). Sie MUSS @@ -144,14 +158,26 @@ async function messen(kachel, code, wer) { await seite.waitForTimeout(500); const daten = await seite.evaluate(() => { - /* DIE COMMUNITY-GRUPPE finden -- ueber ihre Ueberschrift, nicht - ueber eine Position. Eine Position aendert sich, sobald jemand - eine Gruppe dazwischenschiebt. */ - const gruppen = [...document.querySelectorAll(".kacheln")]; - const treffer = gruppen.find((g) => { - const kopf = g.previousElementSibling; - return kopf && /COMMUNITY/i.test(kopf.textContent || ""); - }) || gruppen[gruppen.length - 1]; + /* ================================================================= + ALLE GRUPPEN, NICHT EINE (23.09.2026) + ================================================================= + + Hier wurde „die Community-Gruppe" gesucht -- ueber ihre + Ueberschrift, mit der letzten Gruppe als Rueckfall. Gemessen am + 23.09. ergab das fuer DogFather EINE Kachel und fuer einen Modi + ZEHN, und beides hiess in der Meldung „Community-Kacheln". Zwei + verschiedene Dinge unter einem Namen: Der eine Treffer war eine + echte Gruppe mit einer Kachel, der andere der Rueckfall. + + Eine Pruefung, die je nach Rolle etwas anderes misst, kann ihr + Ergebnis nicht erklaeren. Und die Frage, um die es geht -- hat + das Raster ein Loch? --, stellt sich fuer JEDE Gruppe. + + Also alle. Der Name der Gruppe kommt mit, damit eine Meldung + sagt, wo etwas klemmt. + ================================================================= */ + const messeGruppe = (behaelter) => { + const treffer = behaelter; const stil = getComputedStyle(treffer); const spalten = stil.gridTemplateColumns.split(" ").filter(Boolean).length; const kacheln = [...treffer.querySelectorAll(".kachel")].map((k) => ({ @@ -170,6 +196,23 @@ async function messen(kachel, code, wer) { })); const reihen = new Set(kacheln.map((k) => k.oben)).size; return { spalten, kacheln, reihen }; + }; + + const gruppen = [...document.querySelectorAll(".kacheln")].map((g) => { + const kopf = g.previousElementSibling; + return { + name: (kopf?.textContent || "").replace(/\s+/g, " ").trim().slice(0, 40) + || "(ohne Ueberschrift)", + ...messeGruppe(g), + }; + }).filter((g) => g.kacheln.length > 0); + + /* Die groesste Gruppe bleibt fuer die Zeilen, die eine einzelne + brauchen (Zeichen, Toene) -- dort geht es um Unterscheidbarkeit + nebeneinander, und die entscheidet sich innerhalb einer Gruppe. */ + const groesste = gruppen.reduce((a, b) => + (b.kacheln.length > (a?.kacheln.length || 0) ? b : a), null) || { kacheln: [], spalten: 0, reihen: 0 }; + return { gruppen, ...groesste }; }); if (process.env.SCHIRM) { @@ -196,27 +239,49 @@ async function messen(kachel, code, wer) { try { /* ===================================================================== - 1. DOGFATHER -- ACHT KACHELN + 1. DOGFATHER -- SEINE GRUPPEN GEHEN AUF ===================================================================== */ melde(""); - melde("=== 1. DogFather sieht acht ==="); + melde("=== 1. DogFather: kein Loch in einer Gruppe ==="); { const m = await messen("admin", "CODE-DOGI-0001", "dogfather"); - ok(m.kacheln.length === 8, `${m.kacheln.length} Community-Kacheln`); - ok(m.spalten === 3, `drei Spalten (${m.spalten})`); - /* DIE BREITE KACHEL STEHT VORNE -- das ist die eigentliche - Reparatur. Ohne diese Zeile waere nicht geprueft, WARUM kein - Loch da ist; bei acht Kacheln ginge die Rechnung zufaellig auch - mit ihr an anderer Stelle auf. */ - const breitAn = m.kacheln.findIndex((k) => k.breit); - ok(breitAn === 0, - `die doppelt breite Kachel steht an erster Stelle (${breitAn === 0 - ? m.kacheln[0].name : "Platz " + (breitAn + 1)})`); + /* KEINE FESTE ZAHL MEHR (23.09.2026). + Hier stand `=== 8`. Am 22.09. sind Kacheln dazugekommen, und die + Zeile wurde rot, ohne dass am Raster etwas kaputt war -- sie hat + die Zahl von gestern verteidigt. Dasselbe Muster wie bei den + Stufen und der abgeschriebenen Spaltenliste. + + Geprueft wird jetzt, was wirklich gelten muss: Es gibt Gruppen, + sie sind nicht leer, und KEINE von ihnen hat ein Loch. Die Zahl + steht in der Meldung, nicht in der Bedingung. */ + ok(m.gruppen.length >= 2, + `DogFather sieht ${m.gruppen.length} Kachelgruppen ` + + `(${m.gruppen.map((g) => `${g.name}: ${g.kacheln.length}`).join(", ")})`); + ok(m.spalten === 3, `die groesste Gruppe hat drei Spalten (${m.spalten})`); + + /* WENN eine Gruppe eine doppelt breite Kachel hat, muss sie vorn + stehen -- sonst entsteht das Loch, um das es hier geht. Es gibt + heute keine mehr; die Regel bleibt trotzdem stehen, denn sie + gilt fuer die naechste. Eine Bedingung, die nur greift, wenn es + etwas zu pruefen gibt, ist kein uebersprungener Test: Die ZAHL + der geprueften Gruppen steht daneben. */ + const mitBreit = m.gruppen.filter((g) => g.kacheln.some((k) => k.breit)); + const falschPlatziert = mitBreit.filter((g) => !g.kacheln[0].breit); + ok(falschPlatziert.length === 0, + mitBreit.length + ? `${mitBreit.length} Gruppe(n) mit breiter Kachel, alle vorn` + : "keine Gruppe hat eine doppelt breite Kachel -- die Regel greift, sobald es eine gibt"); + + /* JEDE GRUPPE, nicht eine. Die Frage "hat das Raster ein Loch" + stellt sich ueberall gleich. */ + const mitLoch = m.gruppen.filter((g) => loecher(g).loch); + ok(m.gruppen.length > 0 && mitLoch.length === 0, + mitLoch.length + ? `Loch in: ${mitLoch.map((g) => `${g.name} (${loecher(g).reihen} statt ` + + `${loecher(g).minimum})`).join(", ")}` + : `kein Loch in einer der ${m.gruppen.length} Gruppen`); const r = loecher(m); - ok(!r.loch, - `kein Loch: ${r.zellen} Zellen auf ${m.spalten} Spalten = ${r.minimum} Reihen, ` - + `gemessen ${r.reihen}`); /* JEDES ZEICHEN GENAU EINMAL. Vorher trugen "Regeln & Hilfe" und "Meldungen & Massnahmen" beide denselben Schild -- nebeneinander @@ -250,7 +315,7 @@ try { 2. EIN MODI -- SIEBEN KACHELN ===================================================================== */ melde(""); - melde("=== 2. Ein Modi sieht dieselben acht ==="); + melde("=== 2. Ein Modi: dasselbe Raster ==="); { const m = await messen("creator", "CODE-MODI-0001", "modi"); /* ACHT, NICHT SIEBEN -- und das war MEIN Denkfehler beim Schreiben @@ -260,7 +325,9 @@ try { Der reine Zuschauer sieht sieben; an den kommt eine Pruefung ohne Gastzugang nicht heran, deshalb steht der Fall unten in der Rechnung. */ - ok(m.kacheln.length === 8, `${m.kacheln.length} Community-Kacheln`); + ok(m.gruppen.length >= 1 && m.kacheln.length > 0, + `ein Modi sieht ${m.gruppen.length} Gruppe(n), groesste mit ` + + `${m.kacheln.length} Kacheln`); const r = loecher(m); /* SIEBEN KACHELN, EINE DAVON BREIT = ACHT ZELLEN auf drei Spalten = drei Reihen. Die letzte Reihe hat eine freie Zelle -- die ist diff --git a/server/pruef-rollen.mjs b/server/pruef-rollen.mjs index b2cfee04..3cedf226 100644 --- a/server/pruef-rollen.mjs +++ b/server/pruef-rollen.mjs @@ -30,6 +30,10 @@ import { mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { heuteLokal, tagLokal } from "./helfer-zeit.mjs"; +/* Die Adresse des anderen Hauses kommt aus der EINEN Stelle, an der + sie steht -- eine zweite hier waere die, die beim Umzug stehen + bleibt und dann eine falsche Adresse als "bekannt" durchwinkt. */ +import { CREW_ADRESSE } from "./crew-adresse.js"; const ordner = mkdtempSync(join(tmpdir(), "ws-rollen-")); process.env.WORKSPACE_DB = join(ordner, "workspace.db"); @@ -81,7 +85,14 @@ setTimeout(() => { console.log("ABBRUCH"); process.exit(1); }, 540_000).unref?.( let fehler = 0; let geprueft = 0; +/* DER DRITTE AUSGANG (23.09.2026). Diese Pruefung kannte nur zwei: in + Ordnung und nicht in Ordnung. Eine Kachel, die aus dem Haus + hinausfuehrt, ist weder das eine noch das andere -- sie ist von hier + aus nicht messbar. Ohne diesen Ausgang muesste man sie entweder + gruen luegen oder rot melden; beides sagt etwas, das nicht stimmt. */ +let offen = 0; const ok = (b, t) => { geprueft++; console.log((b ? " ok " : " FEHL ") + t); if (!b) fehler++; }; +const unklar = (t) => { offen++; console.log(" -- " + t); }; /* ---------- Ein Team mit echten Daten ---------------------------------- Ohne Daten prüft ein Rundgang nur leere Seiten -- und leere Seiten @@ -353,6 +364,45 @@ for (const r of ROLLEN) { ohne dass ein einziger Knopf gedrueckt wurde. */ ok(kacheln.length > 0, `${r.name.padEnd(18)} bekommt ${kacheln.length} Kacheln angeboten`); for (const href of kacheln) { + /* ================================================================= + EINE KACHEL KANN AUS DEM HAUS HINAUSFUEHREN (23.09.2026) + ================================================================= + + DogFather bekommt auf der Agenturadresse die Kachel „Zu Team + Dogi". Ihr Ziel ist eine VOLLSTAENDIGE Adresse -- es muss eine + sein, das andere Haus liegt auf einem anderen Rechnernamen. + + Diese Pruefung klebte jedes Ziel an `BASIS + "/workspace/"`. + Bei einer vollstaendigen Adresse kommt dabei Unsinn heraus; der + Browser landete auf start.html, und die Zeile meldete + „LANDET AUF start.html". Ein echter Befund war das nie -- die + Kachel ist richtig, die Messung war es nicht. + + Dass es solche Kacheln GIBT, steht im Server ausdruecklich + (`aussen: true` an der Kachel, samt Begruendung). Das Merkmal + kommt aber nicht in die Seite; hier ist nur die Adresse zu + sehen. Also wird abgeleitet: Wer eine vollstaendige Adresse + traegt, fuehrt hinaus. + + WAS DANN GEPRUEFT WIRD -- und was nicht. Ob die andere Tuer + aufgeht, laesst sich von hier nicht sagen: Das andere Haus + antwortet unter einem anderen Namen, und dieser Browser kennt + nur BASIS. Das ist der dritte Ausgang, und er wird als solcher + gemeldet. Geprueft wird stattdessen, was hier zu pruefen IST: + dass die Adresse zu einem Haus fuehrt, das dieses Haus kennt -- + und nicht irgendwohin. + ================================================================= */ + if (/^https?:\/\//i.test(href)) { + let ziel2 = null; + try { ziel2 = new URL(href); } catch { ziel2 = null; } + const heim = (() => { try { return new URL(CREW_ADRESSE).host; } catch { return null; } })(); + ok(!!ziel2 && !!heim && ziel2.host === heim && /\.html$/.test(ziel2.pathname), + `${r.name.padEnd(18)} Kachel fuehrt aus dem Haus: ${href}` + + (ziel2 && ziel2.host === heim ? " (bekanntes Haus)" : " -- FREMDE ADRESSE")); + unklar(`${r.name.padEnd(18)} ob dort die Tuer aufgeht, laesst sich von hier` + + " nicht messen -- das andere Haus hat eine andere Adresse"); + continue; + } const ziel = href.split("#")[0]; const seitenname = ziel.split("?")[0]; await seite.goto(BASIS + "/workspace/" + ziel, { waitUntil: "networkidle" }); @@ -381,5 +431,6 @@ if (berichte.length) { } try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ } -console.log(`\n${fehler ? "FEHLER: " + fehler : "Alles in Ordnung"} — ${geprueft} Prüfungen`); +console.log(`\n${fehler ? "FEHLER: " + fehler : "Alles in Ordnung"} — ${geprueft} Prüfungen` + + (offen ? `, ${offen} nicht nachsehbar` : "")); process.exit(fehler ? 1 : 0); diff --git a/server/workspace-steckbrief.js b/server/workspace-steckbrief.js index 76e0ba35..373b9622 100644 --- a/server/workspace-steckbrief.js +++ b/server/workspace-steckbrief.js @@ -155,6 +155,23 @@ const ABSCHNITTE = { admin: { name: "Leitung", text: "Wer freigibt und entscheidet." }, manager: { name: "Leitung", text: "Wer freigibt und entscheidet." }, hand: { name: "Team Dogi", text: "Wer den Laden mit am Laufen hält." }, + /* DIE LINKE HAND FEHLTE (23.09.2026). + + Gefunden von pruef-jeder-hat-eine-seite: „alle 9 Rollen sind + zugeordnet -- fehlt: linke". Sie landete damit im Sammelplatz + „Weitere" -- auf der Übersicht über die Menschen des Hauses stand + sie unter einer Überschrift ohne Bedeutung, neben niemandem. + + Sie gehört dorthin, wo die rechte Hand steht: Beide führen Team + Dogi mit. Eine eigene Überschrift mit einem Namen darunter wäre + mehr Gliederung als Inhalt -- derselbe Gedanke steht schon bei + ROLLEN_GRUPPE. + + WARUM DIE PRÜFUNG DAS FINDEN KONNTE und ein Mensch nicht: Sie + geht ALLE Rollen des Hauses durch, nicht die vier, die zufällig + angelegt sind. Eine Zuordnung, die man an den vorhandenen Leuten + prüft, ist eine Aussage über die Testdaten. */ + linke: { name: "Team Dogi", text: "Wer den Laden mit am Laufen hält." }, modi: { name: "Moderation", text: "Wer im Rudel und im Stream nach dem Rechten sieht." }, scout: { name: "Scouting", text: "Sie finden neue Creator und begleiten den Anfang." }, creator: { name: "Creator", text: "Die Leute, um die es geht." }, diff --git a/server/workspace.js b/server/workspace.js index 7fa9bb3f..8e060dbc 100644 --- a/server/workspace.js +++ b/server/workspace.js @@ -822,6 +822,13 @@ export const ROLLEN_GRUPPE = { Menschen, keine Rangordnung -- und zwei Ueberschriften mit je einem Namen darunter waeren mehr Gliederung als Inhalt. */ hand: "Team Dogi", + /* DIE LINKE HAND GEHOERT DAZU (23.09.2026). Ohne diesen Eintrag + faellt sie auf ROLLEN_NAME zurueck und bekommt in der Auswahl eine + eigene Ueberschrift „Linke Hand" mit genau einem Namen darunter -- + also dieselbe Rangordnung, die zwei Zeilen hoeher ausdruecklich + vermieden werden sollte. Aufgefallen beim Nachgehen des Befundes + zum Steckbrief; dort fehlte sie ebenfalls. */ + linke: "Team Dogi", modi: "Team Dogi", };