diff --git a/server/pruef-befinden.mjs b/server/pruef-befinden.mjs
index 69e117bb..edf942b5 100644
--- a/server/pruef-befinden.mjs
+++ b/server/pruef-befinden.mjs
@@ -61,6 +61,9 @@ const melde = (t) => console.log(t);
kaputt war. Eine feste Zahl ist eine Rechnung von gestern. */
const anzahlFragen = (await import("./workspace-entwicklungs-punkte.js"))
.ENTWICKLUNG_PUNKTE.befinden.length;
+/* Und wie viele davon der Kern sind -- aus demselben Grund abgeleitet. */
+const kernAnzahl = (await import("./workspace-entwicklungs-punkte.js"))
+ .ENTWICKLUNG_PUNKTE.befinden.filter((p) => p.kern).length;
const ok = (b, t) => { geprueft++; console.log((b ? " ok " : " FEHL ") + t); if (!b) fehler++; };
@@ -170,10 +173,63 @@ melde("");
melde("=== 2. Sechs Fragen, ein Rhythmus ===");
{
const d = json(await ruf("/workspace/api/befinden", CREW, "GET", { cookie: kFrida }));
- ok(d.punkte?.length === kat.ENTWICKLUNG_SELBST.length,
- `${d.punkte?.length} Fragen — so viele wie im Katalog`);
- /* Die Recherche: fuenf bis fuenfzehn, unter zwei Minuten. Sechs sind
- richtig; zwanzig waeren es nicht. */
+
+ /* ==== KERN UND ROTATION (19.09.2026) ==============================
+
+ Filipe wollte "viel mehr Fragen" UND "kurz und knapp". Geloest
+ ueber fuenf feste Fragen plus drei wechselnde: Jede Runde bleibt
+ kurz, ueber die Monate wird alles abgedeckt -- und der Katalog
+ kann wachsen, ohne dass eine Runde laenger wird.
+ ============================================================== */
+ const kern = kat.ENTWICKLUNG_PUNKTE.befinden.filter((p) => p.kern);
+ const rest = kat.ENTWICKLUNG_PUNKTE.befinden.filter((p) => !p.kern);
+ ok(kern.length > 0, `${kern.length} Fragen sind als Kern markiert`);
+ ok(rest.length > modul.ZUSATZ_PRO_RUNDE,
+ `${rest.length} wechseln sich ab — mehr als die ${modul.ZUSATZ_PRO_RUNDE} Plätze je Runde`);
+ ok(d.punkte?.length === kern.length + modul.ZUSATZ_PRO_RUNDE,
+ `${d.punkte?.length} Fragen in dieser Runde (${kern.length} feste + ${modul.ZUSATZ_PRO_RUNDE})`);
+ ok(d.punkte.length < kat.ENTWICKLUNG_SELBST.length,
+ `weniger als die ${kat.ENTWICKLUNG_SELBST.length} des Katalogs — genau darum geht es`);
+ ok(d.fragen_gesamt === kat.ENTWICKLUNG_SELBST.length,
+ "und die Seite sagt, wie viele es insgesamt gibt");
+ /* JEDE KERNFRAGE IST DABEI. Der Riegel: Waere eine davon in der
+ Rotation, erfuehre man die wichtigste Auskunft im Schnitt sechs
+ Wochen zu spaet. */
+ ok(kern.every((k) => d.punkte.some((p) => p.schluessel === k.schluessel)),
+ "jede Kernfrage ist in dieser Runde dabei");
+ /* GEGENPROBE: Es sind NICHT alle -- sonst waere die Rotation nur
+ behauptet. */
+ ok(rest.some((x) => !d.punkte.some((p) => p.schluessel === x.schluessel)),
+ "und mindestens eine wechselnde Frage ist diesmal NICHT dran");
+ /* IN KATALOGREIHENFOLGE. Wer sie jede Runde anders sortiert sieht,
+ liest sie jedes Mal neu statt sie wiederzuerkennen. */
+ const ordnung = kat.ENTWICKLUNG_PUNKTE.befinden.map((p) => p.schluessel);
+ const gezeigt = d.punkte.map((p) => p.schluessel);
+ ok(gezeigt.join() === [...gezeigt].sort((a, b) => ordnung.indexOf(a) - ordnung.indexOf(b)).join(),
+ "die Fragen stehen in der Reihenfolge des Katalogs");
+
+ /* ÜBER VIER RUNDEN KOMMT JEDE FRAGE DRAN. Eine Frage, die nie
+ drankommt, koennte man ebenso gut loeschen -- und genau das
+ passiert, wenn der Versatz und die Zahl der Fragen einen
+ gemeinsamen Teiler haben. */
+ {
+ const gesehen = new Set();
+ for (let r = 0; r < 6; r++) {
+ for (const p of modul.fragenFuer(idFrida, r).alle) gesehen.add(p.schluessel);
+ }
+ ok(gesehen.size === kat.ENTWICKLUNG_SELBST.length,
+ `über sechs Runden kommt jede der ${kat.ENTWICKLUNG_SELBST.length} Fragen dran (${gesehen.size})`);
+ /* Und die Auswahl ist STABIL: derselbe Stand, dieselbe Liste.
+ Zufall hiesse, dass bei jedem Neuladen etwas anderes dasteht. */
+ ok(modul.fragenFuer(idFrida, 2).alle.map((p) => p.schluessel).join()
+ === modul.fragenFuer(idFrida, 2).alle.map((p) => p.schluessel).join(),
+ "zweimal dieselbe Runde ergibt zweimal dieselben Fragen");
+ ok(modul.fragenFuer(idFrida, 2).alle.map((p) => p.schluessel).join()
+ !== modul.fragenFuer(idFrida, 3).alle.map((p) => p.schluessel).join(),
+ "die nächste Runde ergibt andere — sonst wäre es keine Rotation");
+ }
+
+ /* Die Recherche: fuenf bis fuenfzehn, unter zwei Minuten. */
ok(d.punkte.length >= 5 && d.punkte.length <= 15,
"zwischen fünf und fünfzehn — kurz genug, dass man sie wirklich beantwortet");
ok(d.rhythmus_tage === modul.RHYTHMUS_TAGE,
@@ -212,12 +268,55 @@ melde("=== 3. Der Verlauf entsteht ===");
"und es ist erst einmal nichts mehr fällig — die Seite fragt nicht jeden Tag");
ok(nach.rhythmus.vollstaendig === true, "die Runde gilt als vollständig");
- /* Eine zweite Runde mit anderen Antworten -- erst dann gibt es ein
- Muster, und erst dann ist der Verlauf ueberhaupt etwas wert. */
- await ruf(`/workspace/api/entwicklung/mich/${d.punkte[0].schluessel}`, CREW, "PUT",
- { cookie: kFrida }, { stufe: "hakt", anlass: "Diese Woche war viel los." });
+ /* ==== DER FEHLER, DEN DIESE PRUEFUNG SELBST FESTGESCHRIEBEN HAT ===
+
+ Hier stand bis zum 19.09.2026:
+
+ eine Antwort aendern
+ POST /runde
+ ok(zweite.code === 201, "eine zweite Runde geht auch sofort")
+
+ Gruen -- und ein Beleg fuer genau das Gegenteil dessen, was sie
+ pruefen sollte. Eine Runde galt naemlich als vollstaendig, sobald
+ zu jeder Frage IRGENDEIN Stand vorlag. Nach der ersten Runde ist
+ das immer der Fall: Die Antworten bleiben stehen. Ab da liess sich
+ jede weitere Runde abschliessen, OHNE eine einzige Frage
+ anzufassen -- die alten Antworten wanderten mit neuem Datum ein
+ zweites Mal in den Verlauf.
+
+ Der Verlauf zeigte dann eine gerade Linie, und die bedeutete nicht
+ "es ist gleich geblieben", sondern "niemand hat gefragt". Genau
+ die Sorte Zahl, die dieses Haus verbietet: eine, die etwas
+ Falsches behauptet, und der man glaubt.
+
+ Ab jetzt zaehlt nur, was NACH der letzten Runde gesetzt wurde.
+ ============================================================== */
+ const leer = await ruf("/workspace/api/befinden/runde", CREW, "POST", { cookie: kFrida }, {});
+ ok(leer.code === 400,
+ `eine zweite Runde ohne neue Antwort geht NICHT (${leer.code})`);
+ ok(json(leer).offen === d.punkte.length,
+ `und zwar sind alle ${json(leer).offen} Fragen wieder offen — `
+ + "die alten Antworten zaehlen nicht als neue");
+
+ const zwischen = json(await ruf("/workspace/api/befinden", CREW, "GET", { cookie: kFrida }));
+ /* KEINE EINZIGE gilt als frisch. Bei den Fragen, die schon beim
+ letzten Mal dran waren, steht die alte Antwort sichtbar da; bei den
+ neu hereinrotierten gibt es noch gar keine. Beides ist "offen". */
+ ok(zwischen.punkte.every((p) => !p.frisch),
+ "keine Antwort gilt als frisch — auch die vom letzten Mal nicht");
+ ok(zwischen.punkte.some((p) => p.meins && !p.frisch),
+ "die alten stehen trotzdem sichtbar da („vom letzten Mal“)");
+
+ /* GEGENPROBE: Mit frischen Antworten geht es sehr wohl. Ohne sie
+ waere die Zeile oben auch dann gruen, wenn ueberhaupt keine Runde
+ mehr moeglich waere. */
+ const zweiteFragen = zwischen.punkte;
+ for (const p of zweiteFragen) {
+ await ruf(`/workspace/api/entwicklung/mich/${p.schluessel}`, CREW, "PUT",
+ { cookie: kFrida }, { stufe: p.schluessel === d.punkte[0].schluessel ? "hakt" : "laeuft" });
+ }
const zweite = await ruf("/workspace/api/befinden/runde", CREW, "POST", { cookie: kFrida }, {});
- ok(zweite.code === 201, `eine zweite Runde geht auch sofort (${zweite.code})`);
+ ok(zweite.code === 201, `mit frischen Antworten geht die zweite Runde (${zweite.code})`);
const nach2 = json(await ruf("/workspace/api/befinden", CREW, "GET", { cookie: kFrida }));
ok(nach2.verlauf.length === 2, `jetzt ${nach2.verlauf.length} Runden`);
@@ -229,6 +328,11 @@ melde("=== 3. Der Verlauf entsteht ===");
der sich rueckwirkend aendert, ist kein Verlauf. */
ok(Object.keys(nach2.verlauf[1].antworten).length === d.punkte.length,
"die alte Runde steht unverändert da");
+ /* UND DIE ANALYSE SIEHT ALLE FRAGEN, nicht nur die dieser Runde --
+ der Verlauf hoert nicht auf, wenn eine Frage gerade nicht dran ist. */
+ ok(nach2.analyse?.zeilen?.length === kat.ENTWICKLUNG_SELBST.length,
+ `die Auswertung deckt alle ${kat.ENTWICKLUNG_SELBST.length} Fragen ab `
+ + `(${nach2.analyse?.zeilen?.length}), nicht nur die ${nach2.punkte.length} dieser Runde`);
}
/* =======================================================================
@@ -255,6 +359,9 @@ melde("=== 4. Privat ===");
const spur = d.prepare(
"SELECT detail FROM protokoll WHERE aktion = 'befinden_runde' ORDER BY id DESC").all();
const verlaufZeilen = d.prepare("SELECT COUNT(*) AS n FROM befinden_verlauf").get().n;
+ const runProRunde = d.prepare(
+ "SELECT COUNT(*) AS n FROM befinden_verlauf GROUP BY runde ORDER BY runde")
+ .all().map((z) => z.n);
d.close();
ok(spur.length === 2, `${spur.length} Runden stehen im Protokoll`);
ok(spur.every((z) => !/laeuft|hakt|waechst|unklar/.test(z.detail || "")),
@@ -265,8 +372,18 @@ melde("=== 4. Privat ===");
17.09.2026 wurden aus sechs Fragen zwoelf, und drei Zeilen in
dieser Datei waren ab da rot, ohne dass irgendetwas kaputt war.
Eine feste Zahl ist eine Rechnung von gestern. */
- ok(verlaufZeilen === 2 * anzahlFragen,
- `im Verlauf liegen ${verlaufZeilen} Antworten (2 Runden x ${anzahlFragen})`);
+ /* ABGELEITET, NICHT GERECHNET (19.09.2026, mit der Rotation).
+
+ Hier stand `2 * anzahlFragen` -- zwei Runden mal ALLE Fragen. Seit
+ eine Runde nur Kern plus drei Zusatzfragen enthaelt, stimmt das
+ nicht mehr. Und die naechste feste Zahl waere derselbe Fehler noch
+ einmal: Wer ZUSATZ_PRO_RUNDE aendert, haette sie wieder rot.
+
+ Gezaehlt wird deshalb, was WIRKLICH in den Runden steht. */
+ ok(verlaufZeilen === runProRunde.reduce((x, y) => x + y, 0),
+ `im Verlauf liegen ${verlaufZeilen} Antworten (${runProRunde.join(" + ")})`);
+ ok(runProRunde.length === 2 && runProRunde.every((n) => n === runProRunde[0]),
+ `zwei gleich grosse Runden zu je ${runProRunde[0]} Fragen`);
/* UND DIE AMPEL ZAEHLT WEITER NUR DEN AKTUELLEN STAND, ohne Namen. */
const a = await ruf("/workspace/api/entwicklung/ampel", CREW, "GET", { cookie: kDogi });
@@ -345,22 +462,147 @@ melde("=== 6. Im Browser ===");
verlauf: document.getElementById('verlauf-block')?.hidden === false,
spalten: document.querySelectorAll('.b-verlauf__zeile--kopf .b-verlauf__datum').length,
punkte: document.querySelectorAll('.b-verlauf__punkt').length,
+ /* Die Zeilen OHNE die Kopfzeile -- sie traegt die Datumsangaben,
+ keine Antworten. */
+ zeilen: document.querySelectorAll('.b-verlauf__zeile:not(.b-verlauf__zeile--kopf)').length,
text: document.querySelector('main')?.innerText || '',
}));
+ if (process.env.SCHIRM) {
+ await seite.screenshot({
+ path: "C:/Users/qciga/Documents/Obelix/DogiHompage/blick-befinden.png",
+ fullPage: true });
+ }
ok(stand.fragen >= 5, `${stand.fragen} Fragen stehen auf der Seite`);
ok(stand.knoepfe === stand.fragen * 4, `mit je vier Knöpfen (${stand.knoepfe})`);
ok(stand.takt === true, `der Rhythmus steht oben: „${stand.taktText.slice(0, 70)}“`);
/* FRIDA HAT ZWEI RUNDEN -- bei ihr MUSS er dastehen. */
ok(stand.verlauf === true, "ihr Verlauf steht auf der Seite");
ok(stand.spalten === 2, `mit zwei Ständen nebeneinander (${stand.spalten})`);
- ok(stand.punkte === 2 * anzahlFragen,
- `und ${2 * anzahlFragen} Antworten darin (${stand.punkte})`);
+ /* Zeilen x Spalten des Gitters. Die Zeilen sind die Fragen MIT
+ GESCHICHTE -- nach zwei Runden mit Rotation sind das mehr als die
+ acht dieser Runde und weniger als alle zwoelf. Gerechnet, nicht
+ angenommen: Eine feste Zahl waere hier beim naechsten Umbau still
+ falsch. */
+ ok(stand.punkte === stand.zeilen * stand.spalten && stand.punkte > 0,
+ `${stand.punkte} Felder im Gitter (${stand.zeilen} Fragen x ${stand.spalten} Stände)`);
+ ok(stand.zeilen > kernAnzahl && stand.zeilen <= anzahlFragen,
+ `${stand.zeilen} Fragen haben schon eine Geschichte — mehr als der Kern (${kernAnzahl}), `
+ + `weniger als der ganze Katalog (${anzahlFragen})`);
/* KEIN FREMDER NAME AUF DEM BILDSCHIRM. Ihr eigener darf oben in der
Kopfleiste stehen -- gemessen wird deshalb nur der Inhalt, und
gesucht wird nach DogFather, also nach dem, der hier nichts zu
suchen hat. */
ok(!/Filipe/.test(stand.text), "und kein anderer Mensch steht darauf");
+ /* ==== ZWEI DINGE, DIE KEIN ZAHLENVERGLEICH FINDET ================
+
+ Beide sind beim Ansehen des Bildschirmfotos aufgefallen, nicht
+ beim Lesen der Ausgabe -- und beide waren wahr und trotzdem
+ irrefuehrend.
+
+ 1. Der Satz "diese Runde sind 8 von 12 dran" stand nur, solange
+ etwas offen oder faellig war. Im RUHEZUSTAND -- dem, den man am
+ haeufigsten sieht -- fehlte er. Wer dann acht Fragen zaehlt, wo
+ zwoelf im Katalog stehen, haelt vier fuer verschwunden.
+
+ 2. "Das war deine Antwort beim letzten Mal" stand an JEDER Frage,
+ unmittelbar nachdem man sie beantwortet und die Runde
+ abgeschlossen hatte. Technisch richtig (die Antwort ist vor dem
+ Rundenabschluss gesetzt), als Auskunft Unsinn.
+ ============================================================== */
+ ok(/von \d+ Fragen dran/.test(stand.taktText),
+ `der Satz erklaert die kurze Runde auch im Ruhezustand: `
+ + `„…${(stand.taktText.match(/Diese Runde[^.]*\./) || [""])[0].slice(0, 60)}…“`);
+ const ruhig = await seite.evaluate(() => ({
+ alt: document.querySelectorAll('.e-punkt[data-alt="ja"]').length,
+ hinweise: document.querySelectorAll('.e-punkt__alt').length,
+ kernmarken: document.querySelectorAll('.e-punkt__marke').length,
+ }));
+ ok(ruhig.alt === 0 && ruhig.hinweise === 0,
+ `direkt nach einer Runde steht nirgends „vom letzten Mal“ (${ruhig.hinweise})`);
+ ok(ruhig.kernmarken === kernAnzahl,
+ `die ${kernAnzahl} festen Fragen sind als solche gekennzeichnet (${ruhig.kernmarken})`);
+
+ /* GEGENPROBE: Ist eine Runde wirklich faellig, MUSS der Hinweis da
+ sein -- sonst hiesse die Zeile oben nur, dass er nie erscheint.
+ Die Runde wird dafuer um mehr als den Rhythmus zurueckdatiert;
+ die Uhr laesst sich nicht vorstellen. */
+ {
+ /* ALLE Runden verschieben, nicht nur die letzte.
+
+ Erster Anlauf datierte nur die juengste zurueck -- danach war
+ die ZWEITGROESSTE die juengste, und die lag weiterhin auf heute.
+ Die Seite meldete folgerichtig "ruhig", und die Gegenprobe war
+ rot, ohne dass an der Sache etwas falsch war.
+
+ In JavaScript gerechnet und nicht in SQL: `datetime(runde, '-15
+ days')` gibt ein anderes Format zurueck (Leerzeichen statt T,
+ ohne Z) -- Date.parse liest das als ORTSZEIT, und die Rechnung
+ waere danach um zwei Stunden daneben. */
+ const versatz = (modul.RHYTHMUS_TAGE + 1) * 86400000;
+ const dd = oeffne();
+ const runden = dd.prepare(
+ "SELECT DISTINCT runde FROM befinden_verlauf WHERE person_id = ?").all(idFrida)
+ .map((z) => z.runde);
+ const setzen = dd.prepare(
+ "UPDATE befinden_verlauf SET runde = ?, am = ? WHERE person_id = ? AND runde = ?");
+ const alteStaende = runden.map((r) => [r, new Date(Date.parse(r) - versatz).toISOString()]);
+ for (const [vorher, nachher] of alteStaende) setzen.run(nachher, nachher, idFrida, vorher);
+
+ /* UND DIE ANTWORTEN GLEICH MIT. Im Betrieb werden sie gesetzt und
+ kurz darauf die Runde abgeschlossen -- sie sind also IMMER etwas
+ aelter als die Runde. Nur die Runden zurueckzudatieren erzeugte
+ einen Zustand, den es nie gibt: Antworten von heute unter einer
+ Runde von vor zwei Wochen. Die Seite hielt sie folgerichtig fuer
+ frisch, und die Gegenprobe war rot an der falschen Stelle. */
+ const antworten = dd.prepare(
+ `SELECT schluessel, am FROM entwicklung_stand
+ WHERE person_id = ? AND von_id = ?`).all(idFrida, idFrida);
+ const setzenA = dd.prepare(
+ `UPDATE entwicklung_stand SET am = ?
+ WHERE person_id = ? AND von_id = ? AND schluessel = ?`);
+ const alteAntworten = antworten.map((z) =>
+ [z.schluessel, z.am, new Date(Date.parse(z.am) - versatz).toISOString()]);
+ for (const [k, , nachher] of alteAntworten) setzenA.run(nachher, idFrida, idFrida, k);
+ dd.close();
+
+ await seite.reload({ waitUntil: "networkidle" });
+ await seite.waitForTimeout(900);
+ const faellig = await seite.evaluate(() => ({
+ lage: document.getElementById('takt')?.dataset.lage || '',
+ alt: document.querySelectorAll('.e-punkt[data-alt="ja"]').length,
+ hinweise: document.querySelectorAll('.e-punkt__alt').length,
+ fragen: document.querySelectorAll('.e-punkt--meins').length,
+ knopf: !document.getElementById('takt-knopf')?.hidden,
+ }));
+ ok(faellig.lage === "faellig", `jetzt ist eine Runde fällig (${faellig.lage})`);
+ ok(faellig.hinweise > 0 && faellig.alt > 0,
+ `und die alten Antworten sind als solche gekennzeichnet (${faellig.hinweise} von ${faellig.fragen})`);
+ /* UND DER KNOPF IST WEG, solange nichts bestaetigt ist. Genau das
+ war der Fehler: Er stand da und schloss eine leere Runde ab. */
+ ok(faellig.knopf === false,
+ "der Knopf zum Abschließen ist weg, solange nichts bestätigt ist");
+
+ /* ZURUECKDREHEN. Ohne das liefe der Rest dieser Datei auf einem
+ Stand, den die Pruefung selbst verbogen hat -- Abschnitt 7 fand
+ danach ein "besser" statt eines Musters und meldete fuenf
+ Fehler, die keine waren. Genau die Sorte Befund, die man
+ stundenlang im falschen Code sucht. */
+ const dz = oeffne();
+ const zurueckSetzen = dz.prepare(
+ "UPDATE befinden_verlauf SET runde = ?, am = ? WHERE person_id = ? AND runde = ?");
+ for (const [vorher, nachher] of alteStaende) zurueckSetzen.run(vorher, vorher, idFrida, nachher);
+ const zurueckA = dz.prepare(
+ `UPDATE entwicklung_stand SET am = ?
+ WHERE person_id = ? AND von_id = ? AND schluessel = ?`);
+ for (const [k, vorher] of alteAntworten) zurueckA.run(vorher, idFrida, idFrida, k);
+ dz.close();
+ const zurueck = json(await ruf("/workspace/api/befinden", CREW, "GET", { cookie: kFrida }));
+ ok(zurueck.rhythmus?.letzte === runden.sort().at(-1)
+ && zurueck.rhythmus?.faellig === false,
+ "der Stand ist danach wieder so, wie er war");
+ }
+
/* GEGENPROBE mit einem zweiten Menschen: DogFather hat keine einzige
Runde. Bei ihm muss derselbe Block WEG sein -- sonst hiesse „er
erscheint ab der zweiten Runde" nur, dass er immer erscheint. */
@@ -410,8 +652,9 @@ melde("=== 7. Die Analyse ===");
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`);
+ ok(d.analyse.zeilen.length === anzahlFragen,
+ `sie geht alle ${d.analyse.zeilen.length} Fragen des Katalogs durch, `
+ + `nicht nur die ${d.punkte.length} dieser Runde und 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),
@@ -420,8 +663,8 @@ melde("=== 7. Die Analyse ===");
/* 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,
+ `zu jeder der ${anzahlFragen} Fragen steht ein belegter Befund`);
+ ok(new Set(d.analyse.zeilen.map((z) => z.welt)).size === anzahlFragen,
"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,
@@ -439,7 +682,11 @@ melde("=== 7. Die Analyse ===");
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`);
+ /* "MALE", NICHT "RUNDEN": Mit der Rotation ist eine Frage nicht in
+ jeder Runde dran -- gezaehlt wird, wie oft sie gestellt wurde. */
+ ok(z2.male === modul.MUSTER_AB, `über ${z2.male} Male hintereinander gleich`);
+ ok(z2.gefragt >= z2.male,
+ `und sie war insgesamt ${z2.gefragt}x dran — die Zahl gibt es wirklich`);
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.
diff --git a/server/workspace-befinden.js b/server/workspace-befinden.js
index c157d2db..26cb6e09 100644
--- a/server/workspace-befinden.js
+++ b/server/workspace-befinden.js
@@ -76,6 +76,18 @@ export const befindenRouter = express.Router();
* die Abfrage nur noch sich selbst. */
export const RHYTHMUS_TAGE = 14;
+/** Wie viele Zusatzfragen je Runde zum Kern dazukommen.
+ *
+ * DREI. Mit fünf Kernfragen macht das acht je Runde — die Quellen zu
+ * Puls-Abfragen sagen übereinstimmend fünf bis fünfzehn, unter zwei
+ * Minuten. Acht liegt mittig und lässt Platz: Der Katalog kann auf
+ * zwanzig Fragen wachsen, ohne dass eine einzelne Runde länger wird.
+ *
+ * Das ist der ganze Trick an Filipes zwei Wünschen, die sich zu
+ * widersprechen schienen — „viel mehr Fragen" und „kurz und knapp".
+ * Beides geht, nur nicht gleichzeitig in DERSELBEN Runde. */
+export const ZUSATZ_PRO_RUNDE = 3;
+
/** So viele frühere Antworten bekommt die Person zu sehen.
*
* Sechs Stände sind drei Monate — lang genug, um ein Muster zu sehen,
@@ -150,8 +162,7 @@ function block() {
* und läuft danach auseinander -- und zwar still, weil beide Seiten
* plausible Zahlen liefern. */
export function rhythmus(personId) {
- const b = block();
- const gesamt = (ENTWICKLUNG_PUNKTE[b.schluessel] || []).length;
+ const kern = alleFragen().filter((p) => p.kern).length;
const letzte = db().prepare(
`SELECT runde, COUNT(*) AS n FROM befinden_verlauf
WHERE person_id = ? GROUP BY runde ORDER BY runde DESC LIMIT 1`).get(personId);
@@ -160,10 +171,109 @@ export function rhythmus(personId) {
return {
letzte: letzte.runde,
tage,
- vollstaendig: letzte.n >= gesamt,
- /* FAELLIG heisst: die letzte Runde ist alt genug -- ODER sie war nie
- fertig. Eine halb beantwortete Runde ist keine Runde. */
- faellig: tage >= RHYTHMUS_TAGE || letzte.n < gesamt,
+ /* GEGEN DEN KERN GEZAEHLT, NICHT GEGEN DEN GANZEN KATALOG
+ (geaendert 19.09.2026, mit der Rotation).
+
+ Vorher stand hier `letzte.n >= gesamt` -- die Zahl ALLER Fragen.
+ Seit eine Runde nur Kern plus drei Zusatzfragen enthaelt, waere
+ das nie wieder erfuellt: Jede abgeschlossene Runde haette sich
+ selbst fuer unvollstaendig erklaert und waere sofort wieder
+ faellig gewesen. Die Seite haette jeden Tag gefragt, und genau
+ davor warnt die eigene Begruendung oben ("dann misst die Abfrage
+ nur noch sich selbst").
+
+ Der Kern ist in JEDER Runde enthalten -- daran laesst sich eine
+ Runde erkennen, ohne dass irgendwo stehen muss, wie viele Fragen
+ sie hatte. */
+ vollstaendig: letzte.n >= kern,
+ faellig: tage >= RHYTHMUS_TAGE || letzte.n < kern,
+ };
+}
+
+/** Alle Fragen des Blocks. */
+function alleFragen() {
+ const b = block();
+ return b ? (ENTWICKLUNG_PUNKTE[b.schluessel] || []) : [];
+}
+
+/** Wie viele Runden diese Person schon abgeschlossen hat. */
+function rundenBisher(personId) {
+ return db().prepare(
+ "SELECT COUNT(DISTINCT runde) AS n FROM befinden_verlauf WHERE person_id = ?")
+ .get(personId).n;
+}
+
+/* =====================================================================
+ WELCHE FRAGEN DIESE RUNDE — Kern plus Rotation (19.09.2026)
+
+ Filipe wollte "viel mehr Fragen" UND "kurz und knapp". Das geht, nur
+ nicht gleichzeitig in derselben Runde.
+
+ ---------------------------------------------------------------------
+ DIE ROTATION WIRD GERECHNET, NICHT GEWUERFELT
+
+ Aus der Zahl der bisherigen Runden. Zwei Gruende, und beide sind
+ Hausregeln:
+
+ * Zufall hiesse, dass bei jedem Neuladen eine andere Liste
+ dasteht. Eine Seite, die sich unter den Fingern aendert,
+ beantwortet niemand zu Ende -- und die halbe Runde waere dann
+ auch noch eine andere als die angefangene.
+ * Gerechnet braucht es kein zusaetzliches Feld. Ein gespeicherter
+ Zeiger waere eine zweite Stelle, an der der Stand stimmen muss,
+ und die zweite ist immer die, die irgendwann danebenliegt.
+
+ ---------------------------------------------------------------------
+ DER RAND, DEN MAN LEICHT UEBERSIEHT
+
+ Sieben Zusatzfragen, drei je Runde -- das geht nicht glatt auf.
+ Gerechnet wird deshalb mit Umlauf (`% laenge`), und die Auswahl
+ nimmt drei AUFEINANDERFOLGENDE aus dem Kreis. Ueber vier Runden
+ kommt damit jede Frage mindestens einmal dran; keine faellt dauerhaft
+ heraus, weil der Versatz um drei und die Laenge sieben teilerfremd
+ sind.
+
+ Waeren es einmal sechs Fragen bei drei je Runde, kaemen nur noch
+ zwei feste Haelften dran -- dieselben drei, immer abwechselnd. Der
+ Fall ist unten abgefangen: Bei einem gemeinsamen Teiler wird der
+ Versatz um eins erhoeht, damit der Kreis trotzdem vollstaendig
+ durchlaufen wird. Das ist kein Schoenheitsfehler -- eine Frage, die
+ nie drankommt, ist eine Frage, die man ebenso gut loeschen koennte.
+ ===================================================================== */
+
+/** Der groesste gemeinsame Teiler -- fuer den Rand oben. */
+function ggt(a, b) { return b ? ggt(b, a % b) : a; }
+
+/** Die Fragen dieser Runde: alle Kernfragen plus die Zusatzfragen, die
+ * turnusgemaess dran sind. */
+export function fragenFuer(personId, runden = null) {
+ const alle = alleFragen();
+ const kern = alle.filter((p) => p.kern);
+ const rest = alle.filter((p) => !p.kern);
+ const n = runden == null ? rundenBisher(personId) : runden;
+
+ if (rest.length <= ZUSATZ_PRO_RUNDE) {
+ /* Weniger Zusatzfragen als Plaetze -- dann gibt es nichts zu
+ drehen, und alle kommen jede Runde dran. */
+ return { kern, zusatz: rest, alle: [...kern, ...rest], runden: n };
+ }
+
+ let schritt = ZUSATZ_PRO_RUNDE;
+ while (ggt(schritt, rest.length) !== 1) schritt++;
+
+ const start = (n * schritt) % rest.length;
+ const zusatz = [];
+ for (let i = 0; i < ZUSATZ_PRO_RUNDE; i++) zusatz.push(rest[(start + i) % rest.length]);
+
+ /* IN KATALOGREIHENFOLGE AUSGELIEFERT, nicht in Rotationsreihenfolge.
+ Der Katalog ist nach Thema sortiert; wer ihn jede Runde in einer
+ anderen Reihenfolge sieht, liest ihn jedes Mal neu statt ihn
+ wiederzuerkennen. */
+ const gewaehlt = new Set([...kern, ...zusatz].map((p) => p.schluessel));
+ return {
+ kern, zusatz,
+ alle: alle.filter((p) => gewaehlt.has(p.schluessel)),
+ runden: n,
};
}
@@ -198,16 +308,68 @@ befindenRouter.get("/workspace/api/befinden", angemeldet, (req, res) => {
zeilen.filter((z) => z.runde === r).map((z) => [z.schluessel, z.stufe])),
}));
- const punkte = (ENTWICKLUNG_PUNKTE[b.schluessel] || []).map((pt) => ({
- ...pt, meins: meine.get(pt.schluessel) || null,
- }));
+ const takt = rhythmus(req.person.id);
+ const diese = fragenFuer(req.person.id);
+
+ /* ==== WAS IST "FRISCH"? ==========================================
+
+ DER FEHLER, DEN DAS BEHEBT (gefunden 19.09.2026):
+
+ Eine Runde galt als vollstaendig, sobald zu jeder Frage IRGENDEIN
+ Stand in `entwicklung_stand` lag. Nach der ersten Runde ist das
+ immer der Fall -- die Antworten bleiben ja stehen. Ab da liess
+ sich jede weitere Runde abschliessen, OHNE eine einzige Frage
+ anzufassen: Die alten Antworten wanderten ein zweites Mal in den
+ Verlauf, mit neuem Datum.
+
+ Das ist schlimmer als eine fehlende Runde. Der Verlauf zeigte
+ dann eine gerade Linie, und die bedeutete nicht "es ist alles
+ gleich geblieben", sondern "niemand hat gefragt". Genau diese
+ Sorte Zahl ist im Haus verboten: eine, die etwas Falsches
+ behauptet, und der man glaubt.
+
+ Die vorhandene Pruefung hat den Fehler nicht gefunden, sondern
+ FESTGESCHRIEBEN -- sie aenderte eine Antwort und stellte
+ zufrieden fest, dass die zweite Runde durchgeht.
+
+ Frisch heisst ab jetzt: nach der letzten Runde gesetzt. Vor der
+ ersten Runde ist alles frisch. */
+ const grenze = takt.letzte ? Date.parse(takt.letzte) : null;
+ const istFrisch = (stand) => !stand ? false
+ : grenze === null ? true
+ : Date.parse(stand.am) > grenze;
+
+ const punkte = diese.alle.map((pt) => {
+ const m = meine.get(pt.schluessel) || null;
+ return {
+ ...pt,
+ meins: m,
+ /* Die Antwort bleibt sichtbar -- sie ist ja nicht falsch, nur
+ alt. Sie zaehlt nur nicht mehr mit, und die Seite sagt das. */
+ frisch: istFrisch(m),
+ };
+ });
res.json({
block: b,
stufen: ENTWICKLUNG_STUFEN,
rhythmus_tage: RHYTHMUS_TAGE,
- rhythmus: rhythmus(req.person.id),
+ rhythmus: takt,
punkte,
+ /* WIE VIELE FRAGEN ES INSGESAMT GIBT und wie viele diese Runde
+ dran sind. Ohne diese beiden Zahlen saehe eine kurze Runde aus
+ wie ein Katalog, aus dem etwas verschwunden ist. */
+ fragen_gesamt: (ENTWICKLUNG_PUNKTE[b.schluessel] || []).length,
+ /* DER GANZE KATALOG -- nur Schluessel und Titel, fuer den Verlauf.
+ Der Verlauf zeigt jede Frage, zu der es Antworten gibt, nicht
+ nur die dieser Runde: Was vor vier Wochen beantwortet wurde,
+ hoert nicht auf zu gelten, weil die Frage gerade pausiert.
+ Ohne diese Liste kennte die Seite die Titel dazu nicht. */
+ katalog: (ENTWICKLUNG_PUNKTE[b.schluessel] || [])
+ .map((pt) => ({ schluessel: pt.schluessel, titel: pt.titel, kern: !!pt.kern })),
+ kern_anzahl: diese.kern.length,
+ zusatz_anzahl: diese.zusatz.length,
+ runden_bisher: diese.runden,
verlauf,
/* DIE ANALYSE KOMMT MIT, sie holt sich niemand extra.
@@ -215,7 +377,12 @@ befindenRouter.get("/workspace/api/befinden", angemeldet, (req, res) => {
hier ohnehin schon steht. Ein zweiter Weg waere eine zweite
Stelle, an der die Rechte stimmen muessen -- und die zweite ist
immer die, die etwas durchlaesst. */
- analyse: analyseVon(verlauf, punkte),
+ /* DIE ANALYSE SIEHT ALLE FRAGEN, nicht nur die dieser Runde.
+ Sie handelt vom Verlauf, und der Verlauf hoert nicht auf,
+ wenn eine Frage gerade nicht dran ist. Ihr nur die acht
+ aktuellen zu geben hiesse, vier Muster zu verschweigen --
+ darunter womoeglich das einzige, das zaehlt. */
+ analyse: analyseVon(verlauf, ENTWICKLUNG_PUNKTE[b.schluessel] || []),
});
} catch (f) {
console.error("[befinden] Lesen:", f?.message);
@@ -233,13 +400,26 @@ befindenRouter.post("/workspace/api/befinden/runde", express.json({ limit: "8kb"
angemeldet, (req, res) => {
try {
const b = block();
- const punkte = ENTWICKLUNG_PUNKTE[b.schluessel] || [];
+ const takt = rhythmus(req.person.id);
+ /* DIESELBE RECHNUNG WIE BEIM ANZEIGEN. Eine zweite hier waere die
+ Stelle, an der die Seite acht Fragen zeigt und der Server neun
+ verlangt -- und niemand faende heraus, welche. */
+ const punkte = fragenFuer(req.person.id).alle;
const meine = new Map(db().prepare(
- `SELECT schluessel, stufe FROM entwicklung_stand
+ `SELECT schluessel, stufe, am FROM entwicklung_stand
WHERE person_id = ? AND von_id = ?`)
- .all(req.person.id, req.person.id).map((z) => [z.schluessel, z.stufe]));
+ .all(req.person.id, req.person.id).map((z) => [z.schluessel, z]));
- const fehlt = punkte.filter((p) => !meine.has(p.schluessel));
+ /* NUR FRISCHE ANTWORTEN ZAEHLEN -- siehe die Begruendung beim
+ Anzeigen. Eine Runde, die alte Antworten ein zweites Mal
+ festhaelt, zeichnet eine gerade Linie, die nicht "gleich
+ geblieben" heisst, sondern "niemand hat gefragt". */
+ const grenze = takt.letzte ? Date.parse(takt.letzte) : null;
+ const fehlt = punkte.filter((p) => {
+ const m = meine.get(p.schluessel);
+ if (!m) return true;
+ return grenze !== null && Date.parse(m.am) <= grenze;
+ });
if (fehlt.length) {
/* EINE HALBE RUNDE IST KEINE RUNDE. Sie wuerde im Verlauf wie
ein vollstaendiger Stand aussehen und das Muster verfaelschen. */
@@ -252,7 +432,9 @@ befindenRouter.post("/workspace/api/befinden/runde", express.json({ limit: "8kb"
const rein = db().prepare(
`INSERT INTO befinden_verlauf (person_id, runde, schluessel, stufe, am)
VALUES (?,?,?,?,?)`);
- for (const p of punkte) rein.run(req.person.id, runde, p.schluessel, meine.get(p.schluessel), runde);
+ for (const p of punkte) {
+ rein.run(req.person.id, runde, p.schluessel, meine.get(p.schluessel).stufe, runde);
+ }
/* IM PROTOKOLL STEHT NUR, DASS es passiert ist -- nicht was.
Das Protokoll liest DogFather; die Antworten gehen ihn nichts
@@ -481,7 +663,18 @@ export function analyseVon(verlauf, punkte) {
schluessel: pt.schluessel,
titel: pt.titel,
art: m.art,
- runden: m.runden || 0,
+ /* "MALE", NICHT "RUNDEN" (19.09.2026, mit der Rotation).
+
+ Vorher hiessen diese Zahlen Runden, und das stimmte, solange
+ jede Frage in jeder Runde drankam. Seit die Zusatzfragen
+ wechseln, ist "seit 2 Runden gleich" bei einer Frage, die nur
+ zweimal von vier Runden dran war, schlicht falsch -- sie waere
+ dazwischen vielleicht anders beantwortet worden.
+
+ Gezaehlt werden deshalb die MALE, die sie gestellt wurde. Das
+ ist die Zahl, die es wirklich gibt. */
+ male: m.runden || 0,
+ gefragt: verlauf.filter((r) => r.antworten[pt.schluessel]).length,
welt: e.welt || null,
/* WAS HILFT, STEHT NUR DA, WO ES ETWAS ZU TUN GIBT. Ein Rat an
einer Stelle, die laeuft, ist Laerm -- und er entwertet die
@@ -501,22 +694,22 @@ export function analyseVon(verlauf, punkte) {
let satz;
if (dauerhaft.length) {
satz = dauerhaft.length === 1
- ? `Eine Sache meldest du seit ${dauerhaft[0].runden} Runden gleich. `
+ ? `Eine Sache hast du die letzten ${dauerhaft[0].male} Male gleich beantwortet. `
+ "Das ist kein schlechter Tag mehr – das ist das Muster, auf das es ankommt."
- : `${dauerhaft.length} Sachen melden sich seit mehreren Runden gleich. `
+ : `${dauerhaft.length} Sachen beantwortest du mehrmals hintereinander gleich. `
+ "Das ist selten Zufall und fast nie deine Schuld.";
} else if (neu.length) {
satz = neu.length === 1
- ? "Eine Sache hakt seit dieser Runde. Einmal ist noch kein Muster – "
+ ? "Eine Sache hakt seit dem letzten Mal. Einmal ist noch kein Muster – "
+ "aber der richtige Moment, es anzusprechen, statt zu warten."
- : `${neu.length} Sachen haken seit dieser Runde. Noch kein Muster – `
+ : `${neu.length} Sachen haken seit dem letzten Mal. Noch kein Muster – `
+ "aber zwei auf einmal sind einen Satz wert.";
} else if (besser.length) {
satz = "Nichts hakt gerade – und "
+ (besser.length === 1 ? "eine Sache hat sich" : `${besser.length} Sachen haben sich`)
- + " seit der letzten Runde gelöst. Das gehört genauso festgehalten wie das Gegenteil.";
+ + " seit dem letzten Mal gelöst. Das gehört genauso festgehalten wie das Gegenteil.";
} else {
- satz = "Nichts hakt, und über die letzten Runden hat sich daran nichts geändert. "
+ satz = "Nichts hakt, und daran hat sich über die letzten Male nichts geändert. "
+ "Das ist die Antwort, für die diese Seite gebaut ist – nicht die Ausnahme.";
}
diff --git a/server/workspace-entwicklungs-punkte.js b/server/workspace-entwicklungs-punkte.js
index 66646075..953c03be 100644
--- a/server/workspace-entwicklungs-punkte.js
+++ b/server/workspace-entwicklungs-punkte.js
@@ -410,12 +410,39 @@ export const ENTWICKLUNG_PUNKTE = {
+ "Themenvorschlag, den die Zuschauer selbst gemacht haben." },
],
- /* ---- Block 7: Wie geht es dir damit? (nur die Person selbst) ------- */
+ /* ---- Block 7: Wie geht es dir damit? (nur die Person selbst) -------
+
+ KERN UND ROTATION (19.09.2026)
+
+ Filipe wollte zweierlei, das sich zu widersprechen scheint: "viel
+ mehr Fragen" und "kurz und knapp". Es loest sich ueber einen FESTEN
+ KERN plus WECHSELNDEN ZUSATZFRAGEN.
+
+ `kern: true` heisst: JEDE Runde. Das sind die fuenf, bei denen ein
+ Ausfall teuer waere -- die beiden meistgenannten Gruende fuers
+ Aufhoeren, die Erholung, die Sicherheit vor Anfeindung und der
+ beste Fruehindikator. Eine dieser Fragen nur jede dritte Runde zu
+ stellen hiesse, die Antwort im Schnitt sechs Wochen spaeter zu
+ bekommen.
+
+ Alle anderen rotieren. Dadurch bleibt eine Runde kurz (fuenf plus
+ drei), und ueber die Monate wird trotzdem alles abgedeckt -- und
+ der Katalog kann WACHSEN, ohne dass eine einzelne Runde laenger
+ wird. Das ist der eigentliche Gewinn: Wer jedes Mal dasselbe lange
+ Formular sieht, klickt durch, und dann misst die Abfrage nur noch
+ sich selbst.
+
+ WELCHE ZUSATZFRAGEN drankommen, rechnet workspace-befinden.js aus
+ der Zahl der bisherigen Runden -- nicht aus Zufall. Zufall waere
+ bei jedem Neuladen eine andere Liste, und eine Seite, die sich
+ unter den Fingern aendert, beantwortet niemand zu Ende. */
befinden: [
- { schluessel: "e-ich-menge-passt", stufe: "probe",
+ { schluessel: "e-ich-menge-passt", stufe: "probe", kern: true,
+ /* KERN: Die meistgenannte Ursache ueberhaupt. Wer sie nur jede dritte Runde fragt, erfaehrt sie im Schnitt sechs Wochen zu spaet. */
titel: "Die Menge passt gerade",
text: "Zu wenig Zeit ist der meistgenannte Grund, warum Moderatoren aufhören." },
- { schluessel: "e-ich-niemand-schwierig", stufe: "probe",
+ { schluessel: "e-ich-niemand-schwierig", stufe: "probe", kern: true,
+ /* KERN: Die zweithaeufigste -- und die, ueber die von selbst am wenigsten geredet wird. Genau deshalb muss sie gefragt werden. */
titel: "Es gibt gerade niemanden im Team, mit dem es schwierig ist",
text: "Der zweithäufigste Grund – und der, über den am wenigsten geredet wird." },
{ schluessel: "e-ich-weiss-an-wen", stufe: "probe",
@@ -439,7 +466,8 @@ export const ENTWICKLUNG_PUNKTE = {
ALLE AUF "probe": Diese Fragen sind keine Stufenleiter. Sie
gelten am ersten Tag genauso wie im dritten Jahr -- ein
Befinden hat keine Erwartungsstufe. */
- { schluessel: "e-ich-abschalten", stufe: "probe",
+ { schluessel: "e-ich-abschalten", stufe: "probe", kern: true,
+ /* KERN: Ob die Erholung traegt, sagt besser voraus, ob jemand aufhoert, als die Menge der Arbeit. */
titel: "Nach einer Schicht kann ich abschalten",
text: "Nicht ob du müde bist – ob es aufhört, wenn du aufhörst. "
+ "Das ist der Unterschied zwischen anstrengend und zehrend." },
@@ -451,7 +479,8 @@ export const ENTWICKLUNG_PUNKTE = {
titel: "Mir ist klar, was von mir erwartet wird",
text: "Unklarheit fühlt sich nicht wie Unklarheit an, sondern wie "
+ "das Gefühl, es nie ganz richtig zu machen." },
- { schluessel: "e-ich-nicht-angefeindet", stufe: "probe",
+ { schluessel: "e-ich-nicht-angefeindet", stufe: "probe", kern: true,
+ /* KERN: Der Punkt, an dem aus Belastung eine Gefahr wird. Er darf nie in einer Rotation warten. */
titel: "Ich werde außerhalb des Streams in Ruhe gelassen",
text: "Privatnachrichten, andere Plattformen, das Privatleben. Wer hier "
+ "„da hakt es“ setzt, braucht keine Umfrage, sondern ein Gespräch." },
@@ -459,7 +488,8 @@ export const ENTWICKLUNG_PUNKTE = {
titel: "Ich lerne hier etwas, das mir auch sonst nützt",
text: "Ehrenamt hält, wenn es etwas zurückgibt. Das muss kein Geld sein – "
+ "aber es muss etwas sein." },
- { schluessel: "e-ich-naechste-monate", stufe: "probe",
+ { schluessel: "e-ich-naechste-monate", stufe: "probe", kern: true,
+ /* KERN: Der beste einzelne Fruehindikator, den Befindensabfragen kennen -- er schlaegt an, bevor die anderen es tun. */
titel: "Ich kann mir gut vorstellen, in ein paar Monaten noch dabei zu sein",
text: "Die ehrlichste Frage der Liste. Wer hier zögert, hat es meistens "
+ "vorher schon gewusst – und niemand hat gefragt." },
diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html
index c3e936fa..d0cf7af8 100644
--- a/workspace/anruf-probe.html
+++ b/workspace/anruf-probe.html
@@ -16,15 +16,15 @@
verdeckt. Gefunden hat es pruef-struktur.
Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. -->
-
-
+
+
-
+