Was dein Verlauf sagt -- die Analyse

Filipe: "mach mir auch eine analyse, mach eine perfektion draus. eine
professionelle auch mit infos und so aus aller welt was tiktok angeht.
ich will dass es perfekt ist!!!!"

SIE WIRD GERECHNET, NICHT GESPEICHERT. Kein Feld, keine Tabelle, keine
Note -- sie entsteht bei jedem Abruf neu aus dem Verlauf dieser einen
Person und verlaesst das Haus damit genauso wenig wie er.

DREI DINGE, DIE SIE TUT:

  1. Sie nennt das MUSTER, nicht den Einzelwert. "Da hakt es" in einer
     Runde ist ein schlechter Tag. Dasselbe in zwei Runden ist etwas
     anderes -- und genau das ist in der Forschung das Warnzeichen.
  2. Sie ordnet ein. Zu JEDER der sechs Fragen ein belegter Befund aus
     der Moderationsarbeit, damit niemand denkt, er sei der Einzige.
  3. Sie sagt, was hilft -- aber nur dort, wo es etwas zu tun gibt. Ein
     Rat an einer Stelle, die laeuft, ist Laerm und entwertet die
     anderen fuenf.

UND EINES, DAS SIE NICHT TUT: bewerten. Keine Punktzahl, kein Score,
kein Ampelgesicht. Eine Zahl ueber das eigene Befinden laedt dazu ein,
sie zu verbessern statt ehrlich zu antworten -- und ab da misst die
Abfrage nur noch sich selbst.

RECHERCHIERT, NICHT AUSGEDACHT. Die sechs Fragen standen schon auf der
richtigen Spur; die Quellen bestaetigen sie und liefern die Einordnung:

  "Zu wenig Zeit" und "Streit im Team" sind die zwei meistgenannten
  Gruende, warum freiwillige Moderatoren aufhoeren -- noch vor den
  Inhalten. Anschluss ans Team ist der staerkste einzelne Schutzfaktor.
  Bei bezahlten Moderatoren, auch bei TikTok, sagen ueber 80 % der
  Befragten, ihr Arbeitgeber muesse mehr fuer ihre psychische
  Gesundheit tun.

    https://news.umich.edu/online-content-moderators-likely-to-experience-burnout-u-m-study-suggests/
    https://discord.com/safety/understanding-and-avoiding-moderator-burnout
    https://restofworld.org/2025/tiktok-moderators-turkey/
    https://www.japantimes.co.jp/news/2025/07/04/world/science-health/content-moderators-mental-trauma/
    https://arxiv.org/pdf/2502.06985

Die drei wichtigsten stehen als Verweis unter der Analyse. Ein Satz
ueber "die Forschung" ohne Quelle ist eine Behauptung -- und bei diesem
Thema waere das der Moment, an dem man der ganzen Seite nicht mehr
glaubt.

Im Bildschirmfoto gesehen und behoben: Der Satz oben und die
Quellenzeile standen direkt auf der Buehne, also auf einem Foto. Die
Quellenzeile ist die kleinste Schrift der Seite. Dieselbe Antwort wie
heute Mittag bei der Entwicklungskarte -- keine hellere Schrift,
sondern etwas Deckendes darunter.

  server/pruef-befinden.mjs   75 Pruefungen (vorher 48), 0 Fehler
  Darunter: aus "neu" wird nach der dritten Runde "dauerhaft", jeder
  der sechs Befunde ist ein ANDERER (kein Satz, der zu allen passt),
  DogFather bekommt seine eigene leere Analyse, und im Protokoll steht
  weiterhin nichts davon -- weder die Analyse noch ein Anlass.

  pruef-css-klassen, pruef-entwicklung 43 -- 0 Fehler

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-15 17:38:57 +02:00
co-authored by Claude Opus 5
parent a919bc8720
commit 04f87603f6
34 changed files with 922 additions and 362 deletions
+139
View File
@@ -366,6 +366,145 @@ melde("=== 6. Im Browser ===");
await browser.close();
}
/* =======================================================================
7. WAS DEIN VERLAUF SAGT
Filipe: „mach mir auch eine analyse, mach eine perfektion draus. eine
professionelle auch mit infos und so aus aller welt was tiktok
angeht."
Eine Auswertung über das eigene Befinden ist das Empfindlichste, was
dieses Haus rechnet. Also dieselben drei Fragen wie beim Verlauf:
Sagt sie das Richtige? Sagt sie es nur IHR? Und sagt sie gar nichts,
wenn sie noch nichts sagen kann?
======================================================================= */
melde("");
melde("=== 7. Die Analyse ===");
{
const holen = async (keks, host) =>
json(await ruf("/workspace/api/befinden", host, "GET", { cookie: keks }));
/* Stand nach Abschnitt 3: zwei Runden. In der zweiten hakt der erste
Punkt, vorher lief er -- das ist „neu", noch kein Muster. */
const d = await holen(kFrida, CREW);
const erste = d.punkte[0].schluessel;
ok(d.analyse?.moeglich === true, `mit ${d.analyse?.runden} Runden gibt es eine Analyse`);
ok(d.analyse.zeilen.length === d.punkte.length,
`sie geht alle ${d.analyse.zeilen.length} Fragen durch, nicht nur die schlechten`);
const z1 = d.analyse.zeilen.find((z) => z.schluessel === erste);
ok(z1.art === "neu", `der frisch hakende Punkt gilt als neu, nicht als Muster (${z1.art})`);
ok(/noch kein Muster/i.test(d.analyse.satz),
`und der Satz oben sagt genau das: „${d.analyse.satz.slice(0, 60)}…“`);
/* DIE EINORDNUNG IST DER TEIL, DER „AUS ALLER WELT" HEISST. Sie steht
bei JEDER Zeile -- auch bei denen, die laufen. */
ok(d.analyse.zeilen.every((z) => z.welt && z.welt.length > 40),
"zu jeder der sechs Fragen steht ein belegter Befund");
ok(new Set(d.analyse.zeilen.map((z) => z.welt)).size === d.punkte.length,
"und jeder ist ein anderer — kein Satz, der zu allen passen würde");
/* „Was hilft" NUR dort, wo es etwas zu tun gibt. */
ok(d.analyse.zeilen.filter((z) => z.hilft).length === 1,
`ein Rat steht nur an der Stelle, an der es hakt (${d.analyse.zeilen.filter((z) => z.hilft).length})`);
/* ---- Und jetzt dasselbe ein zweites Mal: daraus wird ein Muster ---- */
for (const p of d.punkte) {
await ruf(`/workspace/api/entwicklung/mich/${p.schluessel}`, CREW, "PUT",
{ cookie: kFrida }, p.schluessel === erste
? { stufe: "hakt", anlass: "Immer noch dasselbe." } : { stufe: "laeuft" });
}
const dritte = await ruf("/workspace/api/befinden/runde", CREW, "POST", { cookie: kFrida }, {});
ok(dritte.code === 201, `eine dritte Runde (${dritte.code})`);
const n = await holen(kFrida, CREW);
const z2 = n.analyse.zeilen.find((z) => z.schluessel === erste);
ok(z2.art === "dauerhaft", `jetzt ist es ein Muster (${z2.art})`);
ok(z2.runden === modul.MUSTER_AB, `über ${z2.runden} Runden`);
ok(/kein schlechter Tag/i.test(n.analyse.satz),
`und der Satz sagt, worauf es ankommt: „${n.analyse.satz.slice(0, 64)}…“`);
/* DIE REIHENFOLGE MACHT DIE AUSSAGE -- das Muster gehört nach oben.
Sortiert wird im Browser; hier wird geprüft, dass die Angabe dafür
überhaupt mitkommt. */
ok(n.analyse.zahlen.dauerhaft === 1 && n.analyse.zahlen.neu === 0,
`die Zahlen daneben stimmen (${JSON.stringify(n.analyse.zahlen)})`);
/* ---- Sie gehört ihr allein ---- */
const seine = await holen(kDogi, CREW);
ok(seine.analyse?.moeglich === false,
"DogFather bekommt seine eigene — und die ist leer");
ok(!JSON.stringify(seine).includes("Immer noch dasselbe"),
"nichts von ihr steht darin");
/* ---- Und ohne zweite Runde gibt es sie gar nicht ---- */
ok(seine.analyse.ab === modul.MUSTER_AB,
`sie sagt, ab wann es sie gibt (ab ${seine.analyse.ab} Runden)`);
ok(Array.isArray(seine.analyse.zeilen) && seine.analyse.zeilen.length === 0,
"und liefert bis dahin keine einzige Zeile");
/* ---- Im Protokoll steht weiterhin nichts davon ---- */
const db = oeffne();
const spuren = db.prepare("SELECT aktion, detail FROM protokoll").all();
db.close();
ok(!spuren.some((x) => /analyse/i.test(x.aktion || "")),
"eine Analyse ist kein Vorgang — sie steht in keinem Protokoll");
ok(!spuren.some((x) => /Immer noch dasselbe/.test(x.detail || "")),
"und ihr Anlass erst recht nicht");
}
/* =======================================================================
8. DIE ANALYSE AUF DEM BILDSCHIRM
======================================================================= */
melde("");
melde("=== 8. Die Analyse im Browser ===");
{
const { chromium } = await import(
"file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs");
const browser = await chromium.launch();
const kontext = await browser.newContext({ viewport: { width: 1280, height: 1000 } });
await kontext.addCookies(kFrida.split("; ").filter(Boolean).map((teil) => {
const i = teil.indexOf("=");
return { name: teil.slice(0, i), value: teil.slice(i + 1), domain: "127.0.0.1", path: "/" };
}));
const seite = await kontext.newPage();
const konsole = [];
seite.on("console", (m) => { if (m.type() === "error" && !/favicon|ERR_/i.test(m.text())) konsole.push(m.text()); });
seite.on("pageerror", (e) => konsole.push("Absturz: " + e.message));
await seite.goto(`http://127.0.0.1:${PORT}/workspace/befinden.html`, { waitUntil: "networkidle" });
await seite.waitForTimeout(1000);
const a = await seite.evaluate(() => ({
da: document.getElementById("analyse-block")?.hidden === false,
satz: document.getElementById("analyse-satz")?.textContent.trim() || "",
zeilen: document.querySelectorAll(".b-analyse__zeile").length,
ersteMarke: document.querySelector(".b-analyse__zeile")?.dataset.ton || "",
welt: document.querySelectorAll(".b-analyse__welt").length,
hilft: document.querySelectorAll(".b-analyse__hilft").length,
quellen: [...document.querySelectorAll(".b-analyse__quelle-hin")].map((x) => x.href),
blank: [...document.querySelectorAll(".b-analyse__quelle-hin")]
.every((x) => x.rel.includes("noopener")),
}));
ok(a.da, "die Analyse steht auf der Seite");
ok(a.zeilen === 6, `mit allen sechs Fragen (${a.zeilen})`);
/* DAS MUSTER STEHT OBEN. Alphabetisch oder in Katalogreihenfolge
müsste man es suchen -- und wer sucht, liest es beim zweiten Mal
nicht mehr. */
ok(a.ersteMarke === "hakt",
`und das, was seit mehreren Runden hakt, steht zuoberst (${a.ersteMarke})`);
ok(a.welt === 6, `zu jeder Zeile die Einordnung (${a.welt})`);
ok(a.hilft === 1, `ein Rat, genau dort, wo es hakt (${a.hilft})`);
ok(a.quellen.length === 3, `${a.quellen.length} Quellen stehen darunter`);
ok(a.quellen.some((x) => /tiktok/i.test(x)),
"darunter eine zu TikTok — danach hatte Filipe ausdrücklich gefragt");
ok(a.blank, "die Verweise öffnen ohne Zugriff aufs eigene Fenster (noopener)");
if (process.env.SCHIRM) {
await seite.locator("#analyse-block").screenshot(
{ path: "C:/Users/qciga/Documents/Obelix/DogiHompage/blick.png" });
}
ok(konsole.length === 0,
konsole.length ? "Fehler im Browser: " + konsole[0].slice(0, 90) : "keine Fehler im Browser");
await browser.close();
}
/* ------------------------------------------------------------------- */
melde("");
melde(`${geprueft} Pruefungen, ${fehler} Fehler`);