diff --git a/server/pruef-bremse.mjs b/server/pruef-bremse.mjs
index 0e12b898..11b8d49e 100644
--- a/server/pruef-bremse.mjs
+++ b/server/pruef-bremse.mjs
@@ -107,7 +107,7 @@ async function anmelden(kachel, code) {
return (a.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; ");
}
const dogi = await anmelden("admin", "CODE-DOGI-0001");
-const ruhig = await anmelden("creator", "CODE-RUHIG-0001");
+const ruhig = await anmelden("modi", "CODE-RUHIG-0001");
const kopf = (keks) => ({ "Content-Type": "application/json", cookie: keks, origin: BASIS });
async function schreiben(keks, bereich, titel, extra = {}) {
diff --git a/server/pruef-crew-adresse.mjs b/server/pruef-crew-adresse.mjs
index 6f8cfbf1..22115439 100644
--- a/server/pruef-crew-adresse.mjs
+++ b/server/pruef-crew-adresse.mjs
@@ -201,11 +201,20 @@ try { zielModi = JSON.parse(modiAufCrew.text); } catch { /* bleibt leer */ }
ok(zielModi.weiter === "/workspace/start.html", "crew.: er landet auf seiner Startseite");
ok(modiAufCrew.keks.includes("dfw_sitzung"), "crew.: er bekommt eine Sitzung");
-/* Der Code des Modis wird bewusst mit der Kachel 'creator' geschickt --
- genau so kommt er auch aus der Zugangswand, denn eine Modi-Kachel
- gibt es nicht. */
-const modiOhneKachel = await anmelden(CREW, "creator", "CODE-MODI-0001");
-ok(modiOhneKachel.status === 200, "crew.: die gewaehlte Kachel ist egal (stiller Zugang)");
+/* ==== DIE KACHEL IST BINDEND (01.10.2026) =========================
+
+ Filipe: „mach das. es soll fest sein."
+
+ Hier stand das Gegenteil, und es war richtig: Bis zum 24.09.2026
+ gab es fuer einen Modi keine eigene Kachel, also musste jede
+ durchgehen (Filipes Entscheidung vom 09.09.).
+
+ Seit der Haustrennung hat `crew.` einen eigenen Kachelsatz mit
+ allen fuenf Rollen. Das Verbergen leistet seither die ADRESSE --
+ der Trick mit der beliebigen Kachel war ein Rest. */
+const modiFremdeKachel = await anmelden(CREW, "creator", "CODE-MODI-0001");
+ok(modiFremdeKachel.status === 401,
+ `crew.: eine fremde Kachel wird abgewiesen (${modiFremdeKachel.status})`);
const managerAufCrew = await anmelden(CREW, "manager", "CODE-MAN-0001");
ok(managerAufCrew.status === 401, "crew.: ein Manager mit gueltigem Code kommt NICHT herein");
@@ -262,7 +271,12 @@ ok(managerAufWs.status === 200 && managerAufWs.keks.includes("dfw_sitzung"),
"workspace.: der Manager kommt herein wie immer -- der Workspace ist unberuehrt");
const managerLokal = await anmelden(LOKAL, "manager", "CODE-MAN-0001");
-const modiLokal = await anmelden(LOKAL, "creator", "CODE-MODI-0001");
+/* AUF SEINER EIGENEN KACHEL. Eine Pruefadresse ist keine Wand --
+ dort gibt es seit dem 01.10.2026 ALLE Kacheln, damit die fuenfzig
+ Pruefdateien, die Team-Rollen ueber 127.0.0.1 anmelden, weiter
+ messen koennen. Welche Kachel auf welcher ECHTEN Wand steht, sagt
+ die Zeile weiter oben. */
+const modiLokal = await anmelden(LOKAL, "modi", "CODE-MODI-0001");
ok(managerLokal.status === 200 && managerLokal.keks.includes("dfw_sitzung"),
"127.0.0.1: der Manager kommt herein (Pruefadressen unberuehrt)");
ok(modiLokal.status === 200 && modiLokal.keks.includes("dfw_sitzung"),
diff --git a/server/pruef-galerie.mjs b/server/pruef-galerie.mjs
index a0dfff9c..9dce9c8a 100644
--- a/server/pruef-galerie.mjs
+++ b/server/pruef-galerie.mjs
@@ -99,7 +99,7 @@ async function anmelden(kachel, code) {
return (a.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; ");
}
const dogi = await anmelden("admin", "CODE-DOGI-0001");
-const modi = await anmelden("creator", "CODE-MODI-0001");
+const modi = await anmelden("modi", "CODE-MODI-0001");
/* ---------- Ein Highlight und die Dateien dazu ----------------------- */
const a = await fetch(BASIS + "/workspace/api/bereich/highlight", {
diff --git a/server/pruef-gespraech.mjs b/server/pruef-gespraech.mjs
index 40fbdf99..a909cda4 100644
--- a/server/pruef-gespraech.mjs
+++ b/server/pruef-gespraech.mjs
@@ -89,7 +89,7 @@ async function anmelden(kachel, code) {
return (a.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; ");
}
const dogi = await anmelden("admin", "CODE-DOGI-0001");
-const lena = await anmelden("creator", "CODE-LENA-0001");
+const lena = await anmelden("modi", "CODE-LENA-0001");
const kopf = (keks) => ({ "Content-Type": "application/json", cookie: keks, origin: BASIS });
async function liste(bereich, keks = dogi) {
diff --git a/server/pruef-kachelraster.mjs b/server/pruef-kachelraster.mjs
index 44f60d6b..dca66f8f 100644
--- a/server/pruef-kachelraster.mjs
+++ b/server/pruef-kachelraster.mjs
@@ -317,7 +317,9 @@ try {
melde("");
melde("=== 2. Ein Modi: dasselbe Raster ===");
{
- const m = await messen("creator", "CODE-MODI-0001", "modi");
+ /* AUF DER MODI-KACHEL (01.10.2026) -- vorher liess der stille
+ Zugang jede durch. */
+ const m = await messen("modi", "CODE-MODI-0001", "modi");
/* ACHT, NICHT SIEBEN -- und das war MEIN Denkfehler beim Schreiben
dieser Pruefung, nicht der des Codes: Ein Modi moderiert, also
braucht er "Meldungen & Massnahmen". Die Liste im Quelltext sagt
@@ -405,7 +407,7 @@ try {
darin. Genommen wird der Modi -- er ist die Rolle in dieser
Pruefung, die eine Kachel mit `gross: true` hat, und nur an der
kann der Fehler ueberhaupt auftreten. */
- const keksBreite = await anmelden("creator", "CODE-MODI-0001");
+ const keksBreite = await anmelden("modi", "CODE-MODI-0001");
for (const breite of [320, 360, 390]) {
const k2 = await browser.newContext({
diff --git a/server/pruef-kanaele.mjs b/server/pruef-kanaele.mjs
index 7bdce2b5..0ad91b18 100644
--- a/server/pruef-kanaele.mjs
+++ b/server/pruef-kanaele.mjs
@@ -111,8 +111,8 @@ async function ruf(keks, pfad, aufruf = {}) {
const jsonKopf = { "Content-Type": "application/json" };
const dogi = await anmelden("admin", "CODE-DOGI-0001");
-const hand = await anmelden("creator", "CODE-HAND-0001");
-const modi = await anmelden("creator", "CODE-MODI-0001");
+const hand = await anmelden("hand", "CODE-HAND-0001");
+const modi = await anmelden("modi", "CODE-MODI-0001");
const crea = await anmelden("creator", "CODE-CREA-0001");
/* =======================================================================
diff --git a/server/pruef-kreislauf.mjs b/server/pruef-kreislauf.mjs
index bb29e8a6..4de97b99 100644
--- a/server/pruef-kreislauf.mjs
+++ b/server/pruef-kreislauf.mjs
@@ -97,7 +97,7 @@ async function anmelden(kachel, code) {
return (a.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; ");
}
const dogi = await anmelden("admin", "CODE-DOGI-0001");
-const lena = await anmelden("creator", "CODE-LENA-0001");
+const lena = await anmelden("modi", "CODE-LENA-0001");
const kopf = (keks) => ({ "Content-Type": "application/json", cookie: keks, origin: BASIS });
async function liste(bereich, keks = dogi) {
diff --git a/server/pruef-modi-checkliste.mjs b/server/pruef-modi-checkliste.mjs
index ee8e6c88..427323d0 100644
--- a/server/pruef-modi-checkliste.mjs
+++ b/server/pruef-modi-checkliste.mjs
@@ -100,7 +100,7 @@ async function hole(keks, pfad, aufruf = {}) {
}
const jsonKopf = { "Content-Type": "application/json" };
-const modiAn = await anmelden("creator", "CODE-MODI-0001");
+const modiAn = await anmelden("modi", "CODE-MODI-0001");
const dogiAn = await anmelden("admin", "CODE-DOGI-0001");
const vanAn = await anmelden("admin", "CODE-VAN-0001");
const handAn = await anmelden("hand", "CODE-HAND-0001");
diff --git a/server/pruef-modi-ideen.mjs b/server/pruef-modi-ideen.mjs
index 0dbb5ac1..d3dc9744 100644
--- a/server/pruef-modi-ideen.mjs
+++ b/server/pruef-modi-ideen.mjs
@@ -174,8 +174,8 @@ const jsonKopf = { "Content-Type": "application/json" };
/* ---------- 3. Sammeln und priorisieren ------------------------------ */
console.log("\n=== 3. Ideen sammeln und nach Dringlichkeit ordnen ===\n");
-const modiAn = await anmelden("creator", "CODE-MODI-0001");
-const modi2An = await anmelden("creator", "CODE-MODI-0002");
+const modiAn = await anmelden("modi", "CODE-MODI-0001");
+const modi2An = await anmelden("modi", "CODE-MODI-0002");
const dogiAn = await anmelden("admin", "CODE-DOGI-0001");
{
const IDEEN = [
@@ -297,11 +297,23 @@ console.log("\n=== 5. Das Board im echten Browser ===\n");
schlecht.push(`${r.status()} ${r.url().replace(BASIS, "")}`);
}
});
- await seite.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" });
- await seite.click('.rolle[data-rolle="creator"]');
- await seite.fill("#code", "CODE-MODI-0001");
- await seite.click("button[type=submit]");
- await seite.waitForURL("**/start.html", { timeout: 15000 });
+ /* ==== ANGEMELDET UEBER DEN KEKS (01.10.2026) ================
+
+ Hier wurde auf die Creator-Kachel getippt und ein Modi-Code
+ eingegeben -- das ging, solange der stille Zugang jede Kachel
+ durchliess. Seit die Kachel bindend ist, braeuchte der Browser
+ die MODI-Kachel, und die gibt es nur auf der Crew-Wand; ein
+ Browser auf 127.0.0.1 bekommt die Agenturwand.
+
+ Gemessen werden soll hier, was ein Modi SIEHT -- nicht, wie er
+ hereinkommt. Das steht in pruef-modi-verborgen, und dort wird es
+ an der echten Wand gemessen. */
+ const modiKeks = String((await anmelden("modi", "CODE-MODI-0001")).keks || "");
+ await kontext.addCookies(modiKeks.split("; ").filter(Boolean).map((z) => {
+ const [n2, ...r2] = z.split("=");
+ return { name: n2, value: r2.join("="), domain: "127.0.0.1", path: "/" };
+ }));
+ await seite.goto(BASIS + "/workspace/start.html", { waitUntil: "domcontentloaded" });
/* WARTEN, BIS DIE KACHELN DA SIND. Sie entstehen erst, wenn
/api/ich geantwortet hat -- direkt nach waitForURL ist die Seite
zwar geladen, aber leer. Beim ersten Anlauf meldete diese
diff --git a/server/pruef-modi-katalog.mjs b/server/pruef-modi-katalog.mjs
index 2a1439c5..5425679d 100644
--- a/server/pruef-modi-katalog.mjs
+++ b/server/pruef-modi-katalog.mjs
@@ -104,14 +104,14 @@ async function hole(keks, pfad, aufruf = {}) {
}
const jsonKopf = { "Content-Type": "application/json" };
-const modiAn = await anmelden("creator", "CODE-MODI-0001");
+const modiAn = await anmelden("modi", "CODE-MODI-0001");
const dogiAn = await anmelden("admin", "CODE-DOGI-0001");
const manAn = await anmelden("manager", "CODE-MAN-0001");
const creatAn = await anmelden("creator", "CODE-ANNA-0001");
/* Ueber den stillen Zugang -- welche Kachel man anfasst, ist
gleichgueltig, der Code allein entscheidet (siehe die Anmelderoute). */
-const handAn = await anmelden("creator", "CODE-HAND-0001");
-const linkeAn = await anmelden("creator", "CODE-LINK-0001");
+const handAn = await anmelden("hand", "CODE-HAND-0001");
+const linkeAn = await anmelden("linke", "CODE-LINK-0001");
/* ---------- 1. Ist er vollstaendig da? ------------------------------- */
console.log("\n=== 1. Der Katalog, wie ihn das Dokument beschreibt ===\n");
@@ -493,11 +493,23 @@ console.log("\n=== 6. Das Brett im echten Browser ===\n");
const konsole = [];
seite.on("console", (e) => { if (e.type() === "error") konsole.push(e.text()); });
seite.on("pageerror", (e) => konsole.push("Absturz: " + e.message));
- await seite.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" });
- await seite.click('.rolle[data-rolle="creator"]');
- await seite.fill("#code", "CODE-MODI-0001");
- await seite.click("button[type=submit]");
- await seite.waitForURL("**/start.html", { timeout: 15000 });
+ /* ==== ANGEMELDET UEBER DEN KEKS (01.10.2026) ================
+
+ Hier wurde auf die Creator-Kachel getippt und ein Modi-Code
+ eingegeben -- das ging, solange der stille Zugang jede Kachel
+ durchliess. Seit die Kachel bindend ist, braeuchte der Browser
+ die MODI-Kachel, und die gibt es nur auf der Crew-Wand; ein
+ Browser auf 127.0.0.1 bekommt die Agenturwand.
+
+ Gemessen werden soll hier, was ein Modi SIEHT -- nicht, wie er
+ hereinkommt. Das steht in pruef-modi-verborgen, und dort wird es
+ an der echten Wand gemessen. */
+ const modiKeks = String((await anmelden("modi", "CODE-MODI-0001")).keks || "");
+ await kontext.addCookies(modiKeks.split("; ").filter(Boolean).map((z) => {
+ const [n2, ...r2] = z.split("=");
+ return { name: n2, value: r2.join("="), domain: "127.0.0.1", path: "/" };
+ }));
+ await seite.goto(BASIS + "/workspace/start.html", { waitUntil: "domcontentloaded" });
/* DER KATALOG STEHT SEIT DEM 23.09.2026 AUF "EURE AUFGABEN".
Filipe: "das soll auch bitte nicht in der kategorie aufgaben
sondern eure aufgaben sein bitte." */
diff --git a/server/pruef-modi-kategorien.mjs b/server/pruef-modi-kategorien.mjs
index 51bc514a..d3062e94 100644
--- a/server/pruef-modi-kategorien.mjs
+++ b/server/pruef-modi-kategorien.mjs
@@ -104,7 +104,7 @@ async function hole(keks, pfad, aufruf = {}) {
/* ---------- 1. Wer bekommt die Liste ueberhaupt? --------------------- */
console.log("\n=== 1. Wer bekommt die Kategorien zu sehen? ===\n");
-const modiAn = await anmelden("creator", "CODE-MODI-0001");
+const modiAn = await anmelden("modi", "CODE-MODI-0001");
const dogiAn = await anmelden("admin", "CODE-DOGI-0001");
const manAn = await anmelden("manager", "CODE-MAN-0001");
const creatAn = await anmelden("creator", "CODE-ANNA-0001");
@@ -255,10 +255,33 @@ console.log("\n=== 5. Das Feld im echten Formular ===\n");
s.on("console", (e) => { if (e.type() === "error") konsole.push(e.text()); });
s.on("pageerror", (e) => konsole.push("Absturz: " + e.message));
await s.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" });
- await s.click(`.rolle[data-rolle="${kachel}"]`);
- await s.fill("#code", code);
- await s.click("button[type=submit]");
- await s.waitForURL("**/start.html", { timeout: 15000 });
+ /* ==== GIBT ES DIESE KACHEL AUF DIESER WAND? (01.10.2026) ====
+
+ Seit die Kachel bindend ist, muss jeder auf SEINER anmelden.
+ Die Modi-Kachel steht aber nur auf der Crew-Wand, und ein
+ Browser auf 127.0.0.1 bekommt die Agenturwand -- dort gibt
+ es sie nicht.
+
+ Also wird gefragt statt angenommen: Ist die Kachel da, wird
+ getippt wie immer. Ist sie es nicht, geht die Anmeldung ueber
+ die Schnittstelle und der Keks wird mitgegeben. Gemessen
+ werden soll hier, was jemand SIEHT -- nicht, wie er
+ hereinkommt; das steht in pruef-modi-verborgen und wird dort
+ an der echten Wand gemessen. */
+ const kachelDa = await s.$(`.rolle[data-rolle="${kachel}"]`);
+ if (kachelDa) {
+ await s.click(`.rolle[data-rolle="${kachel}"]`);
+ await s.fill("#code", code);
+ await s.click("button[type=submit]");
+ await s.waitForURL("**/start.html", { timeout: 15000 });
+ } else {
+ const keks = String((await anmelden(kachel, code)).keks || "");
+ await k.addCookies(keks.split("; ").filter(Boolean).map((z) => {
+ const [n2, ...r2] = z.split("=");
+ return { name: n2, value: r2.join("="), domain: "127.0.0.1", path: "/" };
+ }));
+ await s.goto(BASIS + "/workspace/start.html", { waitUntil: "domcontentloaded" });
+ }
await s.goto(BASIS + "/workspace/aufgaben.html", { waitUntil: "networkidle" });
await s.waitForTimeout(900);
await s.click("#neu-oeffnen").catch(() => {});
@@ -268,7 +291,8 @@ console.log("\n=== 5. Das Feld im echten Formular ===\n");
/* Der Modi: Feld da, Auswahl gefuellt. */
{
- const { kontext, seite, konsole } = await formular("creator", "CODE-MODI-0001");
+ /* AUF DER MODI-KACHEL, seit dem 01.10.2026 -- vorher ging jede. */
+ const { kontext, seite, konsole } = await formular("modi", "CODE-MODI-0001");
const z = await seite.evaluate(() => {
const h = document.getElementById("feld-kategorie");
const f = document.getElementById("f-kategorie");
@@ -421,11 +445,23 @@ console.log("\n=== 5. Das Feld im echten Formular ===\n");
{
const kontext = await browser.newContext();
const seite = await kontext.newPage();
- await seite.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" });
- await seite.click('.rolle[data-rolle="creator"]');
- await seite.fill("#code", "CODE-MODI-0001");
- await seite.click("button[type=submit]");
- await seite.waitForURL("**/start.html", { timeout: 15000 });
+ /* ==== ANGEMELDET UEBER DEN KEKS (01.10.2026) ================
+
+ Hier wurde auf die Creator-Kachel getippt und ein Modi-Code
+ eingegeben -- das ging, solange der stille Zugang jede Kachel
+ durchliess. Seit die Kachel bindend ist, braeuchte der Browser
+ die MODI-Kachel, und die gibt es nur auf der Crew-Wand; ein
+ Browser auf 127.0.0.1 bekommt die Agenturwand.
+
+ Gemessen werden soll hier, was ein Modi SIEHT -- nicht, wie er
+ hereinkommt. Das steht in pruef-modi-verborgen, und dort wird es
+ an der echten Wand gemessen. */
+ const modiKeks = String((await anmelden("modi", "CODE-MODI-0001")).keks || "");
+ await kontext.addCookies(modiKeks.split("; ").filter(Boolean).map((z) => {
+ const [n2, ...r2] = z.split("=");
+ return { name: n2, value: r2.join("="), domain: "127.0.0.1", path: "/" };
+ }));
+ await seite.goto(BASIS + "/workspace/start.html", { waitUntil: "domcontentloaded" });
await seite.goto(BASIS + "/workspace/entwicklung.html", { waitUntil: "networkidle" });
await seite.waitForTimeout(1600);
const text = await seite.evaluate(() => document.body.innerText);
diff --git a/server/pruef-modi-livecheck.mjs b/server/pruef-modi-livecheck.mjs
index 7a5b9dea..a724c85e 100644
--- a/server/pruef-modi-livecheck.mjs
+++ b/server/pruef-modi-livecheck.mjs
@@ -104,7 +104,7 @@ async function hole(keks, pfad, aufruf = {}) {
const jsonKopf = { "Content-Type": "application/json" };
const dogiAn = await anmelden("admin", "CODE-DOGI-0001");
-const modiAn = await anmelden("creator", "CODE-MODI-0001");
+const modiAn = await anmelden("modi", "CODE-MODI-0001");
const manAn = await anmelden("manager", "CODE-MAN-0001");
/* ---------- Zwei Live-Termine mit dem Modi als Teilnehmer ----------- */
diff --git a/server/pruef-modi-verborgen.mjs b/server/pruef-modi-verborgen.mjs
index 2b352215..8642b31f 100644
--- a/server/pruef-modi-verborgen.mjs
+++ b/server/pruef-modi-verborgen.mjs
@@ -111,40 +111,130 @@ d.close();
const MODIS = [idModi1, idModi2, idHand];
void idSpicy;
-/* ---------- Anmelden ueber die Schnittstelle ------------------------- */
-async function anmelden(rolle, code) {
- const a = await fetch(BASIS + "/workspace/api/anmelden", {
- method: "POST", headers: { "Content-Type": "application/json" },
- body: JSON.stringify({ rolle, code }),
+/* ---------- Anmelden ueber die Schnittstelle -------------------------
+
+ MIT WAND, SEIT DEM 01.10.2026. Vorher ging jede Anmeldung hier ueber
+ `fetch` auf 127.0.0.1 -- eine Adresse OHNE Wand. Gemessen wurde
+ damit der stille Zugang und nicht die Kachelregel; seit er weg ist,
+ waere das die Messung der falschen Sache.
+
+ WARUM node:http UND NICHT fetch: `fetch` (undici) setzt den
+ Host-Kopf selbst aus der Adresse und ignoriert einen mitgegebenen.
+ Nachgemessen, nicht vermutet -- dieselbe Stelle steht seit dem
+ 22.09. in pruef-chat-kanaele. */
+const { request: httpAnfrage } = await import("node:http");
+const CREW_WAND = "crew.dogfather-universe.com";
+const AGENTUR_WAND = "workspace.dogfather-universe.com";
+
+/** Auf welcher Wand steht die Kachel dieser Rolle?
+ *
+ * ABGELEITET STATT AUFGEZAEHLT (01.10.2026). Nach dem Umbau meldeten
+ * sich acht Stellen ueber eine fremde Kachel an -- ein Manager auf
+ * der Crew-Wand etwa, wo es seine Kachel gar nicht gibt. Eine Liste
+ * von Hand waere die, bei der man zwei Stellen vergisst.
+ *
+ * Wer eine Wand AUSDRUECKLICH nennt, bekommt sie: Das brauchen die
+ * Zeilen, die absichtlich die falsche Wand pruefen. */
+const CREW_ROLLEN = new Set(["admin", "hand", "linke", "modi", "gast"]);
+const wandFuer = (rolle) => (CREW_ROLLEN.has(rolle) ? CREW_WAND : AGENTUR_WAND);
+
+function anmelden(rolle, code, wand = wandFuer(rolle)) {
+ return new Promise((fertig) => {
+ const rumpf = JSON.stringify({ rolle, code });
+ const a = httpAnfrage({
+ host: "127.0.0.1", port: PORT, path: "/workspace/api/anmelden", method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ "Content-Length": Buffer.byteLength(rumpf),
+ Host: wand,
+ },
+ }, (antwort) => {
+ const teile = [];
+ antwort.on("data", (t) => teile.push(t));
+ antwort.on("end", () => {
+ let daten = {};
+ try { daten = JSON.parse(Buffer.concat(teile).toString("utf8")); } catch { /* kein JSON */ }
+ fertig({
+ status: antwort.statusCode,
+ daten,
+ keks: [].concat(antwort.headers["set-cookie"] || [])
+ .map((z) => z.split(";")[0]).join("; "),
+ });
+ });
+ });
+ a.on("error", () => fertig({ status: 0, daten: {}, keks: "" }));
+ a.end(rumpf);
});
- const daten = await a.json().catch(() => ({}));
- const keks = (a.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; ");
- return { status: a.status, daten, keks };
}
-console.log("\n=== 1. Der Eingang: eine Kachel gibt es nicht ===\n");
+/* =====================================================================
+ 1. DIE KACHEL IST BINDEND (01.10.2026)
-for (const kachel of ["creator", "scout", "manager", "spicy", "admin"]) {
- const a = await anmelden(kachel, "CODE-MODI-0001");
- ok(a.status === 200 && a.daten?.rolle === "modi",
- `Kachel "${kachel}" + Modi-Code -> angemeldet als ${a.daten?.rolle || a.status}`);
-}
+ Filipe: „mach das. es soll fest sein."
+
+ VanVan hatte gemeldet: „Man kann sich mit seinem Zugangscode immer
+ noch über jeden Button der Startseite anmelden, egal welche Rolle
+ man hat."
+
+ BIS HEUTE STAND HIER DAS GEGENTEIL, und das war richtig: Vom
+ 09.09.2026 an hatten die Modis KEINE eigene Kachel -- wer keine
+ hat, muss irgendeine nehmen koennen.
+
+ Seit der Haustrennung am 24.09. hat `crew.` einen eigenen
+ Kachelsatz mit allen fuenf Rollen. Das Verbergen leistet die
+ ADRESSE; der Trick mit der beliebigen Kachel war ein Rest.
+ ===================================================================== */
+console.log("\n=== 1. Der Eingang: die Kachel gilt ===\n");
-/* Der Umkehrschluss, und er ist der wichtigere: Der stille Weg darf
- NICHT dazu fuehren, dass auch alle anderen die Kachel ignorieren
- duerfen. Ein Manager mit der Kachel "creator" muss weiterhin
- scheitern -- sonst haette ich nebenbei die Rollenpruefung
- abgeschafft, ohne es zu merken. */
{
- const a = await anmelden("creator", "CODE-MAN-0001");
+ const a = await anmelden("modi", "CODE-MODI-0001");
+ ok(a.status === 200 && a.daten?.rolle === "modi",
+ `auf der Modi-Kachel kommt ein Modi herein (${a.daten?.rolle || a.status})`);
+}
+
+/* UND AUF KEINER ANDEREN. Das ist die Aenderung. */
+for (const kachel of ["admin", "hand", "linke", "gast"]) {
+ const a = await anmelden(kachel, "CODE-MODI-0001");
+ ok(a.status === 401,
+ `Kachel "${kachel}" + Modi-Code -> abgewiesen (${a.status})`);
+}
+
+/* GEGENPROBE: Die anderen Rollen der Crew-Wand kommen auf IHRER
+ Kachel herein. Ohne sie hiesse „401 ueberall" womoeglich nur, dass
+ dort gar niemand mehr hereinkommt. */
+{
+ const h = await anmelden("hand", "CODE-HAND-0001");
+ ok(h.status === 200 && h.daten?.rolle === "hand",
+ `die rechte Hand auf ihrer Kachel (${h.daten?.rolle || h.status})`);
+}
+
+/* UND DIE AGENTURWAND BLEIBT, WIE SIE WAR. Dort war der stille Weg
+ nie aktiv; ein Modi-Code verhaelt sich weiter wie ein erfundener. */
+{
+ const a = await anmelden("creator", "CODE-MODI-0001", AGENTUR_WAND);
+ const b = await anmelden("creator", "GIBT-ES-NICHT-1", AGENTUR_WAND);
+ ok(a.status === 401 && b.status === 401
+ && JSON.stringify(a.daten) === JSON.stringify(b.daten),
+ `auf der Agenturwand klingt ein Modi-Code wie ein erfundener `
+ + `(${a.status} vs. ${b.status})`);
+}
+
+/* Und die Rollenpruefung der Agentur ist unveraendert: Ein Manager
+ mit der Kachel "creator" scheitert weiterhin. */
+{
+ const a = await anmelden("creator", "CODE-MAN-0001", AGENTUR_WAND);
ok(a.status === 401, `Manager-Code auf der Creator-Kachel bleibt abgewiesen (${a.status})`);
}
/* Wortgleichheit: "modi" von aussen anzugeben darf nicht anders klingen
als eine erfundene Rolle. */
{
- const m = await anmelden("modi", "FALSCH-FALSCH-1");
- const x = await anmelden("gibtesnicht", "FALSCH-FALSCH-1");
+ /* AUF DER AGENTURWAND klingt „modi" wie eine erfundene Rolle --
+ dort gibt es die Kachel nicht. Auf crew. gibt es sie, und dort
+ entscheidet der Code; deshalb wird das hier ausdruecklich an der
+ Agenturwand gefragt. */
+ const m = await anmelden("modi", "FALSCH-FALSCH-1", AGENTUR_WAND);
+ const x = await anmelden("gibtesnicht", "FALSCH-FALSCH-1", AGENTUR_WAND);
ok(m.status === 401 && x.status === 401
&& JSON.stringify(m.daten) === JSON.stringify(x.daten),
"Rolle \"modi\" von aussen klingt wie eine erfundene "
@@ -152,7 +242,7 @@ for (const kachel of ["creator", "scout", "manager", "spicy", "admin"]) {
}
{
- const a = await anmelden("creator", "CODE-MODI-FALSCH");
+ const a = await anmelden("modi", "CODE-MODI-FALSCH");
ok(a.status === 401, `ein falscher Modi-Code wird abgewiesen (${a.status})`);
}
@@ -184,8 +274,16 @@ const LEUTE = [
["Manager", "manager", "CODE-MAN-0001", false],
["Scout", "scout", "CODE-SCOU-0001", false],
["Creator", "creator", "CODE-ANNA-0001", false],
- ["Modi Marina", "creator", "CODE-MODI-0001", true],
- ["Rechte Hand", "creator", "CODE-HAND-0001", true],
+ /* AUF IHRER EIGENEN KACHEL (01.10.2026). Hier stand „creator" --
+ der stille Zugang liess damals jede Kachel durch. Seit die Kachel
+ bindend ist, scheiterte ihre Anmeldung STILL: `unklar(...)` und
+ weiter, und acht Sichtbarkeitspruefungen fielen lautlos weg.
+
+ Genau der Rueckgang, vor dem die Hausregel warnt -- gruen bei
+ weniger Pruefungen. Gefunden hat ihn nicht der Lauf, sondern der
+ Vergleich der Anzahl mit dem Lauf davor. */
+ ["Modi Marina", "modi", "CODE-MODI-0001", true],
+ ["Rechte Hand", "hand", "CODE-HAND-0001", true],
];
async function hole(keks, pfad) {
@@ -239,7 +337,7 @@ console.log("\n=== 3. Auch die ZAHL darf sie nicht mitzaehlen ===\n");
/* ---------- 4. Sehen die Modis einander? ----------------------------- */
console.log("\n=== 4. Die Modis sind untereinander ein Team ===\n");
{
- const an = await anmelden("creator", "CODE-MODI-0001");
+ const an = await anmelden("modi", "CODE-MODI-0001");
const { status, daten } = await hole(an.keks, "/workspace/api/personen");
if (status !== 200 || !Array.isArray(daten?.personen)) {
unklar(`Personenwahl fuer den Modi nicht lesbar (${status})`);
@@ -292,7 +390,8 @@ console.log("\n=== 5. Anlegen wie im Betrieb: DogFather legt einen Modi an ===\n
vergessen worden, waeren oben trotzdem alle Haken gruen und kein
einziger echter Modi kaeme herein. */
if (neuDaten?.code) {
- const b = await anmelden("creator", neuDaten.code);
+ /* AUF DER MODI-KACHEL, seit dem 01.10.2026 -- vorher ging jede. */
+ const b = await anmelden("modi", neuDaten.code);
ok(b.status === 200 && b.daten?.rolle === "modi",
"und meldet sich mit seinem Code an, ueber eine fremde Kachel "
+ `(${b.status}, ${b.daten?.rolle})`);
@@ -314,7 +413,10 @@ console.log("\n=== 5. Anlegen wie im Betrieb: DogFather legt einen Modi an ===\n
/* ---------- 6. Die Startseite eines Modis ---------------------------- */
console.log("\n=== 6. Was ein Modi auf seiner Startseite sieht ===\n");
{
- const an = await anmelden("creator", "CODE-MODI-0001");
+ /* AUF SEINER EIGENEN KACHEL, seit dem 01.10.2026. Hier stand
+ „creator" -- damals gab es fuer einen Modi keine eigene, und der
+ stille Zugang liess jede durch. Jetzt gilt die Kachel. */
+ const an = await anmelden("modi", "CODE-MODI-0001");
const { status, daten } = await hole(an.keks, "/workspace/api/ich");
if (status !== 200) {
unklar(`/api/ich nicht lesbar (${status})`);
@@ -385,12 +487,40 @@ console.log("\n=== 7. Dieselbe Seite mit einem echten Browser ===\n");
seite.on("console", (e) => { if (e.type() === "error") konsole.push(e.text()); });
seite.on("pageerror", (e) => konsole.push("Absturz: " + e.message));
- await seite.goto(BASIS + "/workspace/", { waitUntil: "domcontentloaded" });
- /* Irgendeine Kachel -- fuer einen Modi gibt es keine eigene. */
- await seite.click('.rolle[data-rolle="creator"]');
- await seite.fill("#code", "CODE-MODI-0001");
- await seite.click("button[type=submit]");
- await seite.waitForURL("**/start.html", { timeout: 15000 });
+ /* ==== ANGEMELDET WIRD UEBER DIE WAND, NICHT UEBER DIE SEITE
+ (01.10.2026)
+
+ Hier wurde bis heute im Browser auf die Creator-Kachel getippt
+ und der Modi-Code eingegeben -- das ging, solange der stille
+ Zugang jede Kachel durchliess.
+
+ Seit die Kachel bindend ist, braeuchte der Browser die
+ CREW-Wand: Dort steht die Modi-Kachel. Ein Browser auf
+ 127.0.0.1 bekommt aber die Agenturwand, und ein Host-Kopf
+ laesst sich dort nur mit einer Namensumleitung setzen (so macht
+ es mess-reaktion mit `--host-resolver-rules`).
+
+ Der kuerzere und ehrlichere Weg: an der richtigen Wand
+ anmelden und den Keks mitgeben. Gemessen werden soll, was ein
+ Modi auf seiner STARTSEITE sieht -- nicht, wie er hereinkommt.
+ Das steht in Abschnitt 1, und dort wird es an der echten Wand
+ gemessen. */
+ const modiKeks = (await anmelden("modi", "CODE-MODI-0001")).keks;
+ await kontext.addCookies(modiKeks.split("; ").filter(Boolean).map((z) => {
+ const [n, ...r] = z.split("=");
+ return { name: n, value: r.join("="), domain: "127.0.0.1", path: "/" };
+ }));
+ await seite.goto(BASIS + "/workspace/start.html", { waitUntil: "domcontentloaded" });
+ /* KEIN `waitForURL` MEHR. Es wartete auf eine Navigation, die es
+ seit dem 01.10.2026 nicht mehr gibt -- angemeldet wird ueber
+ die Wand, nicht ueber das Formular. Steht die Seite schon da,
+ wartet es trotzdem und laeuft in die Frist.
+
+ Und wenn der Keks NICHT angenommen wurde, sagt die Zeile
+ darunter genau das, statt fuenfzehn Sekunden zu schweigen. */
+ if (!/start\.html/.test(seite.url())) {
+ unklar(`nach dem Anmelden steht die Seite auf ${seite.url()}`);
+ }
await seite.waitForTimeout(1200);
const bild = await seite.evaluate(() => ({
@@ -490,7 +620,7 @@ console.log("\n=== 8. Aufgaben, Einträge und Dateien eines Modis ===\n");
Der Kalender ist bewusst nicht dabei: termineSichtbar() gibt jedem
nur Eigenes, dort kann nichts durchsickern. Nachgesehen, nicht
angenommen. */
- const an = await anmelden("creator", "CODE-MODI-0001");
+ const an = await anmelden("modi", "CODE-MODI-0001");
const MERKMAL = "GEHEIMER MODI-EINTRAG";
/* (a) Eine Aufgabe -- ueber den normalen Weg. */
diff --git a/server/pruef-team-ampel.mjs b/server/pruef-team-ampel.mjs
index f29be1e7..097ee6d6 100644
--- a/server/pruef-team-ampel.mjs
+++ b/server/pruef-team-ampel.mjs
@@ -119,7 +119,7 @@ async function anmelden(rolle, code) {
const holeLage = (keks) => fetch(`${BASIS}/workspace/api/teamlage`, { headers: { Cookie: keks } });
const keksDogi = await anmelden("admin", "CODE-DOGI-0001");
-const keksHand = await anmelden("creator", "CODE-HAND-0001");
+const keksHand = await anmelden("hand", "CODE-HAND-0001");
if (!keksDogi || !keksHand) {
console.error("FEHLER: Anmeldung misslang -- ohne sie misst diese Datei nichts.");
process.exit(1);
diff --git a/server/pruef-team-stufen.mjs b/server/pruef-team-stufen.mjs
index cbde5ada..1ba8266a 100644
--- a/server/pruef-team-stufen.mjs
+++ b/server/pruef-team-stufen.mjs
@@ -102,8 +102,8 @@ const setzeStufe = (keks, person_id, stufe) =>
});
const keksDogi = await anmelden("admin", "CODE-DOGI-0001");
-const keksHand = await anmelden("creator", "CODE-HAND-0001");
-const keksModi = await anmelden("creator", "CODE-MODI-0001");
+const keksHand = await anmelden("hand", "CODE-HAND-0001");
+const keksModi = await anmelden("modi", "CODE-MODI-0001");
if (!keksDogi || !keksHand || !keksModi) {
console.error("FEHLER: Anmeldung misslang -- ohne sie misst diese Datei nichts.");
process.exit(1);
diff --git a/server/pruef-treff.mjs b/server/pruef-treff.mjs
index 62fc4d30..87261127 100644
--- a/server/pruef-treff.mjs
+++ b/server/pruef-treff.mjs
@@ -211,7 +211,12 @@ for (const [name, host] of [["workspace.", HAUS], ["der Hauptseite", HAUPT]]) {
}
const kDogi = (await anmelden("admin", "CODE-DOGI-0001", HAUS)).keks;
-const kModi = (await anmelden("creator", "CODE-MODI-0001", CREW)).keks;
+/* AUF DER MODI-KACHEL (01.10.2026). Hier stand „creator" -- bis zum
+ 24.09. gab es fuer einen Modi keine eigene Kachel, und der stille
+ Zugang liess jede durch. Seit die Kachel bindend ist, scheiterte
+ die Anmeldung, und fuenf Pruefungen wurden rot, ohne dass am
+ Programm etwas falsch war. */
+const kModi = (await anmelden("modi", "CODE-MODI-0001", CREW)).keks;
const kCrea = (await anmelden("creator", "CODE-CREA-0001", HAUS)).keks;
const kMana = (await anmelden("manager", "CODE-MANA-0001", HAUS)).keks;
ok([kDogi, kModi, kCrea, kMana].every((k) => k.length > 0), "die vier Vergleichsrollen sind angemeldet");
diff --git a/server/pruef-wunschliste.mjs b/server/pruef-wunschliste.mjs
index 891301ac..81f91ac5 100644
--- a/server/pruef-wunschliste.mjs
+++ b/server/pruef-wunschliste.mjs
@@ -97,9 +97,9 @@ async function anmelden(kachel, code) {
return (a.headers.getSetCookie?.() || []).map((z) => z.split(";")[0]).join("; ");
}
const dogi = await anmelden("admin", "CODE-DOGI-0001");
-const hand = await anmelden("creator", "CODE-HAND-0001");
-const modi = await anmelden("creator", "CODE-MODI-0001");
-const nane = await anmelden("creator", "CODE-NANE-0001");
+const hand = await anmelden("hand", "CODE-HAND-0001");
+const modi = await anmelden("modi", "CODE-MODI-0001");
+const nane = await anmelden("modi", "CODE-NANE-0001");
const kopf = (keks) => ({ "Content-Type": "application/json", cookie: keks, origin: BASIS });
diff --git a/server/workspace.js b/server/workspace.js
index f43560ed..ded06aa7 100644
--- a/server/workspace.js
+++ b/server/workspace.js
@@ -6714,34 +6714,6 @@ workspaceRouter.use((req, res, next) => {
return next();
});
-/**
- * Gehoert dieser Code zu einem verborgenen Zugang?
- *
- * Gibt die Person zurueck oder null. `null` heisst hier ausdruecklich
- * "nein oder nicht feststellbar" -- ohne Suchschluessel (etwa weil die
- * Einstellung fehlt) gibt codeKennung() null zurueck, und dann wird
- * niemand angemeldet. Das ist die richtige Richtung: Im Zweifel kommt
- * niemand herein, statt dass im Zweifel jemand hereinkommt.
- */
-function stillerZugang(code) {
- try {
- const kennung = codeKennung(code);
- if (!kennung) return null;
- const k = db().prepare(
- "SELECT id, name, rolle, code_hash, code_salt, code_n FROM personen "
- + `WHERE code_kennung = ? AND rolle IN (${
- [...TEAM_DOGI_ROLLEN].map((r) => `'${r}'`).join(", ")}) AND aktiv = 1`).get(kennung);
- if (!k) return null;
- /* Trotz Treffer wird geprueft. Der Suchschluessel ist ein
- Wegweiser, kein Ausweis -- und ein Wegweiser, dem man blind
- folgt, ist eine Hintertuer. */
- return gleich(hashe(code, k.code_salt, k.code_n), k.code_hash) ? k : null;
- } catch (fehler) {
- console.error("[workspace] Stiller Zugang nicht pruefbar:", fehler?.message);
- return null;
- }
-}
-
/* DIE TAFEL LIEGT SEIT DEM 11.09.2026 IN workspace-rechte.js.
Hier stand ein nur LESENDER Weg. Filipe: "so dass ich die da auch
@@ -6763,95 +6735,49 @@ workspaceRouter.post("/workspace/api/anmelden", (req, res) => {
const codeBrauchbar = code.length >= 4 && code.length <= 200;
/* =================================================================
- DER STILLE ZUGANG (09.09.2026)
+ DIE KACHEL IST BINDEND (01.10.2026)
- Wunsch Filipe: *"dass die keine neue eingangs kachel bekommen wie
- spicy dogfather und so sondern einfach einen code. damit die von
- der workspace auch nicht mal sehen dass die modis von mir einen
- eigenen zugang haben."*
+ Filipe: „mach das. es soll fest sein."
- Ein Modi oeffnet dieselbe Seite, tippt auf IRGENDEINE vorhandene
- Kachel und gibt seinen Code ein. Welche Kachel, ist gleichgueltig
- -- der Code allein entscheidet. Von aussen sieht das aus wie jede
- andere Anmeldung: dieselbe Seite, dieselbe Anfrage, dieselben
- Felder.
+ VanVan hatte gemeldet: „Man kann sich mit seinem Zugangscode
+ immer noch über jeden Button der Startseite anmelden, egal
+ welche Rolle man hat."
- ZWEI NAHELIEGENDE WEGE, DIE ABSICHTLICH NICHT GEWAEHLT WURDEN:
+ ---------------------------------------------------------------
+ HIER STAND DER STILLE ZUGANG (09.09. bis 01.10.2026)
- * Ein Merkmal im Code ("M-..."): waere ein sichtbares Kennzeichen
- auf dem Zettel des Modis. Wer den Code sieht, sieht die Sorte.
- * Eine eigene Adresse (/modi.html): waere eine Seite, die man
- finden kann -- und die Seitenpruefung zaehlt Seiten.
+ Er liess einen Team-Dogi-Code auf JEDER Kachel durch. Das war
+ kein Versehen, sondern Filipes Entscheidung vom 09.09.2026:
+ „dass die keine neue eingangs kachel bekommen wie spicy
+ dogfather und so sondern einfach einen code. damit die von der
+ workspace auch nicht mal sehen dass die modis von mir einen
+ eigenen zugang haben."
- WARUM DAS VOR DEM GEWOHNTEN WEG STEHT UND NICHT DAHINTER: Ein
- Rueckfall NACH einem Fehlversuch haette den gewohnten Weg
- verlaengert -- und zwar nur dann, wenn er scheitert. Genau daran
- waere es zu erkennen gewesen: Fehlversuche dauern ploetzlich
- laenger als frueher. Der Suchschluessel kostet Mikrosekunden und
- trifft in aller Regel nichts; fuer alle anderen bleibt der Ablauf
- unveraendert, auch in der Zeit.
+ Wer keine Kachel hat, muss irgendeine nehmen koennen.
- DER SUCHSCHLUESSEL ALLEIN LAESST NIEMANDEN HEREIN. Er sagt nur,
- WEN man pruefen soll -- danach entscheidet scrypt wie ueberall. */
- /* AUF DEN ALTEN ADRESSEN WIRD DER VERBORGENE ZUGANG GAR NICHT ERST
- GEFRAGT (Entscheidung Filipe, 10.09.2026).
+ WARUM ER JETZT WEG KANN -- und das ist der ganze Punkt: Seit
+ der Haustrennung am 24.09.2026 gibt es ZWEI Waende. Auf `crew.`
+ steht ein eigener Kachelsatz (CREW_KACHEL): DogFather, rechte
+ Hand, linke Hand, Modi, Community. Alle fuenf Rollen haben dort
+ ihre Kachel.
- Vorher stand hier eine Weiterleitung: Wer seinen Code noch auf
- workspace.dogfather-universe.com eintippte, bekam keine Sitzung,
- aber den Weg zur neuen Adresse. Filipes Entscheidung dagegen:
- "gar nichts -- Code stimmt nicht". Die alte Wand soll sich
- verhalten, als waere der Code erfunden.
+ Das Verbergen leistet seither die ADRESSE. Wer sie nicht kennt,
+ findet die Wand nicht; wer sie kennt, sieht die Rollennamen
+ ohnehin offen darauf stehen. Der Trick mit der beliebigen
+ Kachel hat niemanden mehr geschuetzt und nur noch dafuer
+ gesorgt, dass die Wahl folgenlos blieb.
- WARUM DAS NICHT NUR EINE ANDERE ANTWORT IST, SONDERN EIN ANDERER
- WEG: Haette ich hier bloss `return 401` gesetzt, waere der Ablauf
- trotzdem ein anderer geblieben -- ein Suchschluessel-Treffer und
- EIN scrypt-Durchlauf statt der Kandidatenschleife der gewaehlten
- Kachel. Das ist messbar, und Zeitunterschiede sind genau die
- Spur, die dieser ganze Zugang vermeiden soll.
+ WAS SICH NICHT AENDERT: Auf der Agenturwand war der stille
+ Zugang nie aktiv. Ein Team-Dogi-Code verhaelt sich dort
+ weiterhin wie ein erfundener -- gleiche Antwort, gleicher Weg,
+ gleiche Dauer. Dafuer sorgt der Kachelsatz unten, nicht eine
+ eigene Bedingung.
- Deshalb wird `stillerZugang` auf diesen drei Adressen ueberhaupt
- nicht aufgerufen. Der Code faellt danach durch den gewohnten Weg
- wie jeder unbekannte: dieselbe Schleife, derselbe Eintrag in
- `versuche`, dieselbe Antwort, dieselbe Dauer. Die alte Wand
- verhaelt sich damit exakt so wie vor dem Tag, an dem es diese
- Rollen gab.
-
- DER PREIS, und er gehoert genannt: Ein Modi, der die alte
- Verknuepfung auf dem Handy hat, sammelt dort Fehlversuche wie
- jeder andere auch. Acht in zehn Minuten sperren seine IP -- und
- zwar auch fuer die neue Adresse, denn die Sperre haengt an der
- IP, nicht am Hostnamen. Das ist der Preis der Stille; er faellt
- nur an, wenn jemand die alte Adresse mehrfach probiert. */
- /* UND AUCH NICHT AUF DER WAND DES TREFFS (11.09.2026).
-
- Hier stand `!istOhneModiAdresse(...)` -- also "ueberall ausser auf
- den alten Adressen". Als dritte Wand dazukam, hiess das
- stillschweigend auch: dort. Ein Modi kam damit ueber den
- verborgenen Weg in den Treff herein, obwohl die Kachelliste dort
- nur `gast` kennt und die Adressregel ihn abweist.
-
- Gefunden hat das nicht das Lesen, sondern eine Zeile in
- pruef-treff, die das GEGENTEIL behauptete und rot wurde:
- "auf treff. kommt sonst niemand herein -- auch DogFather nicht
- (401/200)". DogFather wurde abgewiesen, der Modi nicht.
-
- Die Lehre ist dieselbe wie bei `null` in der Rechtetafel: Eine
- Bedingung, die durch AUSSCHLIESSEN formuliert ist, nimmt jede
- neue Moeglichkeit automatisch mit auf. Jetzt steht dort, WO der
- Weg gilt, statt wo er nicht gilt. */
- const stilleWand = istCrewAdresse(req.get("host")) || istPruefAdresse(req.get("host"));
- const still = codeBrauchbar && stilleWand ? stillerZugang(code) : null;
- if (still) {
- db().prepare("DELETE FROM versuche WHERE ip = ?").run(ip);
- db().prepare("UPDATE personen SET letzter_login = ? WHERE id = ?").run(jetzt(), still.id);
- sitzungSetzen(res, still, req);
- protokolliere("anmeldung", {
- personId: still.id, rolle: still.rolle, ip, detail: still.name,
- });
- return res.json({
- weiter: "/workspace/start.html", name: still.name, rolle: still.rolle,
- });
- }
+ `code_kennung` in `personen` wird weiter GESCHRIEBEN, aber
+ nicht mehr gelesen. Sie war der Suchschluessel dieses Weges.
+ Stehen gelassen und nicht geloescht: Eine Spalte zu entfernen
+ ist eine Schemaaenderung mit Sicherung, und sie kostet nichts.
+ Wer sie wieder braucht, findet hier, wofuer sie da war. */
/* Ab hier der gewohnte Weg -- unveraendert. 'modi' ist keine
Kachel-Rolle und faellt deshalb in dieselbe Antwort wie eine
@@ -6885,7 +6811,24 @@ workspaceRouter.post("/workspace/api/anmelden", (req, res) => {
Wand gerade dran ist. Ein Manager, der crew. erraet und seinen
Code eintippt, faellt dadurch in genau dieselbe Antwort wie
jemand mit einer erfundenen Rolle. */
- const kachelSatz = istCrewAdresse(req.get("host")) ? CREW_KACHEL : ROLLEN_KACHEL;
+ /* ==== EINE PRUEFADRESSE IST KEINE WAND (01.10.2026) ==========
+
+ `127.0.0.1` ist weder crew. noch die Agentur. Bis heute fiel
+ das nicht auf: Der stille Zugang liess Team-Dogi-Codes dort
+ ohnehin durch, egal welcher Kachelsatz galt. Mit seinem
+ Wegfall gaelte dort der AGENTUR-Satz -- und damit kaeme kein
+ einziger Modi mehr herein. Fuenfzig Pruefdateien melden
+ Team-Rollen ueber diese Adresse an; sie waeren alle rot, und
+ zwar wegen der Messumgebung, nicht wegen des Programms.
+
+ Auf einer Adresse ohne Wand gibt es deshalb ALLE Kacheln. Das
+ versteckt nichts: Welche Kachel auf welcher ECHTEN Wand steht,
+ entscheiden weiterhin die zwei Mengen darunter, und genau das
+ misst pruef-modi-verborgen -- mit ausdruecklichem Host-Kopf,
+ nicht ueber 127.0.0.1. */
+ const kachelSatz = istPruefAdresse(req.get("host"))
+ ? new Set([...ROLLEN_KACHEL, ...CREW_KACHEL])
+ : (istCrewAdresse(req.get("host")) ? CREW_KACHEL : ROLLEN_KACHEL);
if (!kachelSatz.has(rolle) || !codeBrauchbar) {
db().prepare("INSERT INTO versuche (ip, zeitpunkt) VALUES (?,?)").run(ip, jetzt());
diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html
index 0685f0ee..f26386f1 100644
--- a/workspace/anruf-probe.html
+++ b/workspace/anruf-probe.html
@@ -16,8 +16,8 @@
verdeckt. Gefunden hat es pruef-struktur.
Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. -->
-
-
+
+
-
+