Ausgeloest von pruef-modi-wortleck, die seit Tagen rot war: "24
Fundstellen -- der verborgene Zugang waere damit auffindbar." Die
erste Frage war, ob sie recht hat. Gemessen: ja, und schlimmer als
gedacht.
WER DIESE DATEIEN BEKOMMT: Nicht nur Kollegen. `curl` ohne jeden Keks
auf workspace.dogfather-universe.com liefert die Skripte und
Stilvorlagen des Arbeitsplatzes mit HTTP 200 -- fuer jeden im Netz
lesbar.
DARUNTER crew-haus.css, 27 806 Byte, das ganze Farbhaus von Team Dogi
samt seiner Kommentare. In deren Kopf stand seit dem 10.09. woertlich
"Diese Datei wird NUR auf crew.dogfather-universe.com ausgeliefert."
Das war eine Behauptung, keine Tatsache: Die Weiche biegt `haus.css`
auf diesen Namen um, wer den Namen direkt nannte, ging an ihr vorbei.
Ein Kommentar, der eine Absicht beschreibt, erfuellt sie nicht.
Zwei Stellen im Haus haben sich damit widersprochen -- die Datei sagte
"nur auf crew.", pruef-crew-adresse verlangte ausdruecklich das
Gegenteil ("sie ist kein Geheimnis"). Durchgesetzt war die offene
Fassung. Filipe hat am 21.09. entschieden: zusperren. Die alte
Begruendung dagegen war die Sorge, eine Sperre koenne die Pruefung
blind machen -- die ist jetzt beantwortet statt vermieden: Jeder
Eintrag der Tafel wird in BEIDE Richtungen gemessen, und dass die
Umbiegung von `haus.css` auf crew. weiterhin greift, ebenfalls.
DIE ADRESSE WAR DAS EIGENTLICHE GEHEIMNIS, nicht das Wort. Die
Rollennamen stehen auf der Zugangswand von Team Dogi ohnehin offen --
so gewollt. WO sie liegt, stand dagegen im Klartext in gate.css,
gate.js und crew-haus.css, alle drei oeffentlich abrufbar. Jetzt steht
sie in keiner ausgelieferten Datei mehr.
DIE PRUEFUNG SELBST HATTE DREI MAENGEL:
1. Sie kannte die Mehrzahl nicht. `\bmodi\b` fand "ein Modi", nicht
"die Modis" -- 23 weitere Stellen, darunter der Satz "Fuer die
rechte Hand und die Modis gibt es dort den stillen Zugang". Also
genau die Auskunft, die sie verhindern soll, in der Form, die sie
nicht sah.
2. Ihre Ausnahmeliste war abgeschrieben. Sie nannte eine Datei; die
zweite, die der Server auf crew. begrenzt, haette sie nie
erfahren. Ausgenommen ist jetzt genau das, was der Server auch
durchsetzt (GEHOERT_ZU_ADRESSE) -- kein Muster, sondern die
Durchsetzung selbst.
3. Sie mahnte 45 Kommentare an. Filipes Entscheidung: in Kommentaren
ja, in Code und sichtbaren Texten nein. Rot, das immer da ist,
wird ueberlesen -- und dann faengt sie auch den echten Fall nicht.
Dafuer neu: helfer-ohne-kommentar.mjs, ein Zerleger, der Kommentare
zeichengenau durch Leerzeichen ersetzt, ohne Zeichenketten,
Vorlagen oder Suchmuster zu beschaedigen. KEIN Suchausdruck -- genau
daran ist am 20.09. die Portumstellung gescheitert, mit gueltigem
JavaScript ohne das Feld `port`. Dreizehn Proben in beide Richtungen
beweisen, dass er weder zu viel noch zu wenig wegnimmt; ein Zerleger,
der zu viel nimmt, macht die ganze Pruefung STILL gruen.
Von 45 blieben damit drei echte, alle behoben:
- daten.modis -> daten.leute (Feldname in der Auskunft, also Code)
- zwei Saetze, die Menschen lesen, auf "die Moderation" umgestellt --
fuer jemanden, der neu im Treff ist, sogar klarer
Nebenbei, beim selben Durchgang gefunden und geschlossen:
- teamlage.js fiel auf einen Rollennamen zurueck. Nachgemessen: Die
Stilvorlage kennt zu dieser Karte gar keine solche Regel -- der
Rueckfall hat nie etwas bewirkt und nur das Wort ausgeliefert.
- werdegang.js fuehrte die Saetze ueber den Rollengruppen selbst,
mit den Rollennamen als Schluessel. Der Kommentar daneben
behauptete sogar, sie seien "abgeleitet, nicht abgeschrieben".
Sie kommen jetzt vom Server, und pruef-werdegang misst, dass
jede Gruppe ihren eigenen behaelt.
pruef-modi-wortleck 8/0 (war 5, davon 1 rot)
pruef-crew-adresse 144/0 (war 135)
pruef-werdegang 98 statt 95 Pruefungen, dieselben 3 alten Fehler
pruef-team-ampel 32/0, pruef-team-stufen 28/0, pruef-hilfe 84/0
Co-Authored-By: Claude Opus 5 <[email protected]>
263 lines
13 KiB
JavaScript
263 lines
13 KiB
JavaScript
/* =====================================================================
|
|
STEHT DAS WORT IN EINER DATEI, DIE JEDER BEKOMMT?
|
|
|
|
Der verborgene Zugang haelt genau so lange, wie niemand den
|
|
Rollennamen im Quelltext findet. Alles unter workspace/ wird an JEDEN
|
|
ausgeliefert, der die Seite oeffnet -- an jeden Manager, jeden Scout,
|
|
jeden Creator. Ein einziges `if (ich.rolle === '...')` dort, und der
|
|
ganze Aufwand darueber ist umsonst.
|
|
|
|
WARUM ES DIESE PRUEFUNG GIBT: Weil genau das passiert ist. Am
|
|
10.09.2026 habe ich beim Bau der Kategorien SECHS Vergleiche und VIER
|
|
Kommentare mit dem Rollennamen in zwei ausgelieferte Dateien
|
|
geschrieben -- waehrend ich an anderer Stelle penibel darauf achtete,
|
|
ihn herauszuhalten. Gefunden habe ich es durch Nachsehen, nicht durch
|
|
Nachdenken. Nachdenken hatte ich vorher schon getan.
|
|
|
|
Die Regel ist deshalb ab jetzt keine Absicht mehr, sondern ein
|
|
Werkzeug: Wer den Namen dort hineinschreibt, bekommt einen roten
|
|
Lauf, keinen erhobenen Zeigefinger im Kommentar.
|
|
|
|
NICHT BETROFFEN ist die oeffentliche Seite (team-modis.html und
|
|
Verwandte). Dort steht das Modi-Team seit jeher offen -- das ist
|
|
gewollt. Verborgen ist nicht das TEAM, sondern dass es einen eigenen
|
|
Zugang zum Workspace hat.
|
|
===================================================================== */
|
|
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
import { join, dirname, extname, relative } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { ohneKommentar } from "./helfer-ohne-kommentar.mjs";
|
|
|
|
const HIER = dirname(fileURLToPath(import.meta.url));
|
|
const ORDNER = join(HIER, "..", "workspace");
|
|
|
|
let fehler = 0;
|
|
let geprueft = 0;
|
|
const ok = (b, t) => { geprueft++; console.log((b ? " ok " : " FEHL ") + t); if (!b) fehler++; };
|
|
|
|
/* Alles, was der Server aus diesem Ordner herausgibt. Bewusst eine
|
|
Liste von Endungen und kein "alles ausser": Kaeme morgen eine neue
|
|
Art Datei dazu, faellt sie hier auf, statt stillschweigend
|
|
ungeprueft zu bleiben. */
|
|
const ENDUNGEN = new Set([".js", ".html", ".css", ".webmanifest", ".json", ".svg", ".txt"]);
|
|
|
|
/* `\bmodi\b` und nicht `modi`: "modifiziert", "Modul" und "Modus"
|
|
sollen nicht anschlagen -- eine Pruefung, die staendig Fehlalarm gibt,
|
|
wird abgeschaltet, und dann faengt sie auch den echten Fall nicht
|
|
mehr. Nachgemessen: Keines der drei Woerter passt auf dieses Muster,
|
|
weil nach "modi" dort ein Buchstabe folgt. */
|
|
/* DIE MEHRZAHL KAM AM 21.09.2026 DAZU -- und sie fehlte elf Tage.
|
|
|
|
`\bmodi\b` fand "ein Modi", aber nicht "die Modis". Nachgemessen:
|
|
23 weitere Fundstellen, darunter Saetze wie "Fuer die rechte Hand
|
|
und die Modis gibt es dort den stillen Zugang" -- also genau die
|
|
Auskunft, die diese Pruefung verhindern soll, in der Form, die sie
|
|
nicht sah. Eine Pruefung, die die Haelfte der Faelle nicht kennt,
|
|
beruhigt mehr, als sie schuetzt.
|
|
|
|
Die Gegenprobe unten bleibt gueltig: "modifiziert", "Modul",
|
|
"motion" und "Modus" passen auch auf das erweiterte Muster nicht. */
|
|
const MUSTER = /\bmodis?\b/i;
|
|
|
|
function dateien(pfad, aus = []) {
|
|
for (const name of readdirSync(pfad)) {
|
|
const voll = join(pfad, name);
|
|
if (statSync(voll).isDirectory()) { dateien(voll, aus); continue; }
|
|
if (ENDUNGEN.has(extname(name).toLowerCase())) aus.push(voll);
|
|
}
|
|
return aus;
|
|
}
|
|
|
|
console.log("\n=== Der Rollenname darf in keiner ausgelieferten Datei stehen ===\n");
|
|
|
|
/* =====================================================================
|
|
DIE EINE DATEI, DIE DEN NAMEN TRAGEN DARF (10.09.2026)
|
|
|
|
crew-index.html ist die Zugangswand von crew.dogfather-universe.com.
|
|
Filipe: "3 rollen. dogfather. rechte hand und modis." Auf dieser Wand
|
|
STEHEN die drei Namen -- als Kacheln, sichtbar, so gewollt.
|
|
|
|
WARUM DAS KEIN WIDERSPRUCH ZUR REGEL IST: Die Regel schuetzt nicht
|
|
den Namen, sondern die Tatsache, dass es einen eigenen Zugang zum
|
|
WORKSPACE gibt. Diese Datei wird ausserhalb von crew. ueberhaupt
|
|
nicht ausgeliefert -- der Server antwortet dort mit "gibt es nicht".
|
|
|
|
UND DAS IST DIE BEDINGUNG DER AUSNAHME, nicht ihre Begruendung: Sie
|
|
gilt nur, solange jene Sperre wirklich haelt. Gemessen wird das nicht
|
|
hier, sondern in pruef-crew-adresse.mjs ("die zweite Wand gibt es
|
|
dort nicht", drei Adressen plus doppelter Schraegstrich). Faellt jene
|
|
Pruefung, ist diese Ausnahme ungueltig -- deshalb steht der Verweis
|
|
hier und nicht nur in einem Kommentar irgendwo.
|
|
|
|
AUSDRUECKLICH EINE EINZELNE DATEI und kein Muster wie "crew-*":
|
|
Sonst waere die naechste crew-Datei stillschweigend mit ausgenommen,
|
|
und niemand haette entschieden, ob sie es sein darf. */
|
|
const { GEHOERT_ZU_ADRESSE } = await import("./crew-adresse.js");
|
|
|
|
/* KEIN MUSTER WIE "crew-*" -- ABER AUCH KEINE ZWEITE LISTE
|
|
(geaendert 21.09.2026).
|
|
|
|
Hier stand `new Set(["crew-index.html"])`, mit der Begruendung, ein
|
|
Muster wuerde die naechste crew-Datei stillschweigend mit
|
|
ausnehmen. Der Gedanke war richtig, die Umsetzung war eine
|
|
Abschrift: Am 21.09. kam crew-haus.css dazu (27 806 Byte, bis dahin
|
|
von der Agenturadresse OHNE Anmeldung abrufbar) -- und diese Liste
|
|
haette davon nichts gewusst.
|
|
|
|
Ausgenommen ist jetzt genau das, was der Server auch WIRKLICH auf
|
|
die zweite Adresse begrenzt: die Tafel GEHOERT_ZU_ADRESSE aus
|
|
crew-adresse.js. Das ist kein Muster, sondern die Durchsetzung
|
|
selbst. Wer eine Datei dort eintraegt, hat die Entscheidung
|
|
getroffen; wer es nicht tut, bekommt hier einen roten Lauf. Die
|
|
beiden koennen nicht mehr auseinanderlaufen.
|
|
|
|
DIE BEDINGUNG DER AUSNAHME BLEIBT DIESELBE: Sie gilt nur, solange
|
|
jene Sperre haelt. Gemessen wird das in pruef-crew-adresse.mjs, in
|
|
beide Richtungen und fuer jeden Eintrag der Tafel. */
|
|
const AUSGENOMMEN = new Set(
|
|
GEHOERT_ZU_ADRESSE.map((w) => relative(ORDNER, join(ORDNER, "..", w.datei))));
|
|
|
|
const alle = dateien(ORDNER);
|
|
/* DIE ZAHL GEHOERT IN DIE BEDINGUNG. Faende die Suche keine einzige
|
|
Datei -- verschobener Ordner, andere Endungen --, waere unten alles
|
|
gruen, ohne dass irgendetwas angesehen wurde. Genau diese Sorte
|
|
gruener Haken ist im Haus schon zweimal aufgefallen. */
|
|
ok(alle.length >= 30, `${alle.length} ausgelieferte Dateien durchsucht`);
|
|
|
|
const treffer = [];
|
|
let ausgenommen = 0;
|
|
for (const datei of alle) {
|
|
if (AUSGENOMMEN.has(relative(ORDNER, datei))) { ausgenommen++; continue; }
|
|
/* KOMMENTARE ZAEHLEN NICHT MIT (Entscheidung von Filipe,
|
|
21.09.2026).
|
|
|
|
Bis heute suchte diese Pruefung in der ganzen Datei und fand
|
|
45 Stellen -- fast alle in Kommentaren. Die Frage war also nicht,
|
|
ob sie recht hat, sondern was eigentlich geschuetzt werden soll.
|
|
|
|
GEMESSEN, WORUM ES WIRKLICH GEHT: Auf der Zugangswand von Team
|
|
Dogi stehen die drei Rollennamen ohnehin offen -- als Kacheln,
|
|
sichtbar, so gewollt. Wer die Adresse hat, liest sie dort.
|
|
Geschuetzt wird der Zugang durch den Code, nicht durch ein Wort.
|
|
Und die ADRESSE, um die es wirklich geht, steht seit dem
|
|
21.09.2026 in keiner ausgelieferten Datei mehr.
|
|
|
|
45 Kommentare anzumahnen waere damit eine Dauer-Rotmeldung --
|
|
und Rot, das immer da ist, wird ueberlesen. Dann faengt diese
|
|
Pruefung auch den Tag nicht mehr, an dem jemand einen Vergleich
|
|
auf den Rollennamen in eine ausgelieferte Datei schreibt. Genau
|
|
das ist am 10.09.2026 passiert und der Grund, warum es sie gibt.
|
|
|
|
GEPRUEFT WIRD DESHALB, WAS DAS PROGRAMM TUT UND WAS EIN MENSCH ZU
|
|
SEHEN BEKOMMT: Code, Zeichenketten, sichtbarer HTML-Text.
|
|
Kommentare werden vorher durch Leerzeichen ersetzt -- zeichengenau,
|
|
damit die Zeilennummer eines Fundes weiter stimmt.
|
|
|
|
Der Zerleger dafuer steht in helfer-ohne-kommentar.mjs. Er wird
|
|
unten mit dreizehn Proben gegengeprueft, und das ist nicht
|
|
Zierde: Ein Zerleger, der zu viel wegnimmt, macht diese ganze
|
|
Pruefung still gruen. */
|
|
const text = ohneKommentar(readFileSync(datei, "utf8"), extname(datei));
|
|
const zeilen = text.split("\n");
|
|
for (let i = 0; i < zeilen.length; i++) {
|
|
if (MUSTER.test(zeilen[i])) {
|
|
treffer.push(`${relative(ORDNER, datei)}:${i + 1} ${zeilen[i].trim().slice(0, 70)}`);
|
|
}
|
|
}
|
|
}
|
|
|
|
ok(treffer.length === 0, treffer.length
|
|
? `${treffer.length} Fundstelle(n) -- der verborgene Zugang waere damit auffindbar:\n `
|
|
+ treffer.slice(0, 12).join("\n ")
|
|
: "keine einzige Fundstelle");
|
|
|
|
/* DIE AUSNAHME MUSS AUCH WIRKLICH GEBRAUCHT WERDEN.
|
|
|
|
Waere crew-index.html eines Tages umbenannt oder geloescht, stuende
|
|
hier eine Ausnahme fuer eine Datei, die es nicht gibt -- und beim
|
|
naechsten Umbau wuerde jemand annehmen, sie decke etwas ab. Eine
|
|
Ausnahme, die ins Leere zeigt, ist schlimmer als keine: Sie sieht aus
|
|
wie ein Schutz. */
|
|
ok(ausgenommen === AUSGENOMMEN.size,
|
|
`${ausgenommen} von ${AUSGENOMMEN.size} ausgenommenen Dateien gibt es wirklich`);
|
|
|
|
/* ---------- Gegenprobe ------------------------------------------------
|
|
Findet dieselbe Suche den Namen ueberhaupt, wenn er dasteht? Ohne
|
|
diesen Schritt bewiese der Haken oben nichts: Er waere auch gruen,
|
|
wenn das Muster kaputt oder die Dateiliste leer waere.
|
|
|
|
Auf einem Text im Speicher, nicht auf einer echten Datei -- eine
|
|
Pruefung, die zum Beweisen etwas anlegt, hinterlaesst irgendwann
|
|
etwas. */
|
|
console.log("\n=== Gegenprobe: schlaegt die Suche ueberhaupt an? ===\n");
|
|
{
|
|
const probe = " if (ich.rolle === 'modi') { ziel.hidden = true; return; }";
|
|
ok(MUSTER.test(probe), "eine eingebaute Fundstelle wird erkannt");
|
|
/* Und die drei Woerter, die NICHT anschlagen duerfen -- sonst waere
|
|
die Pruefung nach dem ersten Fehlalarm abgeschaltet. */
|
|
const harmlos = ["const modifiziert = true;", "/* Modul */", "prefers-reduced-motion",
|
|
"let modus = 'hell';"];
|
|
ok(harmlos.every((z) => !MUSTER.test(z)),
|
|
`und "modifiziert", "Modul", "motion", "Modus" schlagen nicht an`);
|
|
}
|
|
|
|
|
|
/* ---------- DIE ZWEITE GEGENPROBE: TAUGT DER ZERLEGER? --------------
|
|
|
|
Seit dem 21.09.2026 werden Kommentare vor der Suche entfernt. Das
|
|
ist die gefaehrlichste Zeile dieser Datei: Ein Zerleger, der zu viel
|
|
wegnimmt, macht die ganze Pruefung STILL GRUEN -- sie laeuft, sie
|
|
meldet "keine Fundstelle", und sie sieht nichts mehr.
|
|
|
|
Deshalb dreizehn Proben, und zwar in beide Richtungen. Sechs
|
|
muessen gefunden werden, sieben nicht. Faende der Zerleger gar
|
|
nichts mehr, fielen die sechs durch; naehme er nichts weg, die
|
|
sieben.
|
|
|
|
Zwei davon sind die Fallen, an denen ein einfacher Suchausdruck
|
|
zerbricht: eine Adresse mit Sternchen-Schraegstrich in einer
|
|
Zeichenkette, und ein Teilen, dem ein Zeilenkommentar folgt. */
|
|
console.log("\n=== Gegenprobe: taugt der Zerleger? ===\n");
|
|
{
|
|
const PROBEN = [
|
|
{ text: "// Modi hier", endung: ".js", soll: false, satz: "ein Zeilenkommentar zaehlt nicht" },
|
|
{ text: "/* Modi im Block */", endung: ".js", soll: false, satz: "ein Blockkommentar auch nicht" },
|
|
{ text: "const r = { modi: 1 };", endung: ".js", soll: true, satz: "ein Feldname im Code SCHON" },
|
|
{ text: "const s = \"Nur du und der Modi\";", endung: ".js", soll: true, satz: "und eine Zeichenkette auch" },
|
|
{ text: "const p = \"https://x.de/*nicht*/mehr/modi\";", endung: ".js", soll: true, satz: "eine Adresse mit Sternchen-Schraegstrich bleibt heil" },
|
|
{ text: "a = b / c; // Modi", endung: ".js", soll: false, satz: "ein Teilen verwirrt den Zerleger nicht" },
|
|
{ text: "x = `Hallo ${name} Modi`;", endung: ".js", soll: true, satz: "eine Vorlage zaehlt als Text" },
|
|
{ text: "/* Modi */ .k[data-rolle=\"modi\"] {}", endung: ".css", soll: true, satz: "in CSS: Kommentar weg, Auswahlregel bleibt" },
|
|
{ text: "<!-- Modi --><p>x</p>", endung: ".html", soll: false, satz: "ein HTML-Kommentar zaehlt nicht" },
|
|
{ text: "<p>Der Modi sieht das</p>", endung: ".html", soll: true, satz: "sichtbarer Text auf der Seite SCHON" },
|
|
{ text: "<script>/* Modi */ var a=1;</script>", endung: ".html", soll: false, satz: "ein Kommentar IM eingebetteten Skript auch nicht" },
|
|
{ text: "<script>var t=\"Modi\";</script>", endung: ".html", soll: true, satz: "eine Zeichenkette im eingebetteten Skript schon" },
|
|
{ text: "<style>/* Modi */ p{}</style>", endung: ".html", soll: false, satz: "und im eingebetteten Stil ebenso wenig" },
|
|
];
|
|
let richtig = 0;
|
|
for (const pr of PROBEN) {
|
|
const rest = ohneKommentar(pr.text, pr.endung);
|
|
const gefunden = MUSTER.test(rest);
|
|
if (gefunden === pr.soll) richtig++;
|
|
else ok(false, `${pr.satz} -- ABER die Probe lief falsch: ${JSON.stringify(pr.text)}`);
|
|
}
|
|
/* DIE ZAHL GEHOERT IN DIE BEDINGUNG. "alle richtig" waere auch bei
|
|
einer leeren Liste wahr. */
|
|
ok(richtig === PROBEN.length && PROBEN.length === 13,
|
|
`alle ${richtig} von ${PROBEN.length} Proben treffen zu`);
|
|
|
|
/* Und die Laenge bleibt gleich -- daran haengen die Zeilennummern,
|
|
mit denen ein Fund oben gemeldet wird. Waere sie es nicht, zeigte
|
|
die Meldung auf die falsche Zeile, und wer nachsieht, findet
|
|
nichts und glaubt der Pruefung nicht mehr. */
|
|
const roh = "var a = 1; /* Modi */\nvar b = 2; // Modi\nvar c = 3;";
|
|
const ohne = ohneKommentar(roh, ".js");
|
|
ok(ohne.length === roh.length,
|
|
`der Text bleibt zeichengenau gleich lang (${ohne.length} von ${roh.length})`);
|
|
ok(ohne.split("\n").length === roh.split("\n").length,
|
|
`und behaelt seine ${roh.split("\n").length} Zeilen`);
|
|
}
|
|
|
|
console.log(`\n${fehler ? "FEHLGESCHLAGEN" : "BESTANDEN"} -- ${geprueft} geprueft, ${fehler} Fehler`);
|
|
process.exit(fehler ? 1 : 0);
|