Sechs Fragen mehr (jetzt 18), und alle in sechs Feldern gegliedert: Last & Erholung, Miteinander, Sinn & Anerkennung, Klarheit & Rueckhalt, Grenzen & Sicherheit, Weiterkommen & Ausblick. Die Felder sind nicht ausgedacht -- es sind die Gebiete, die die Forschung zu belasteten Rollen durchgehend abfragt. Die drei neuen Luecken, die sie schliessen: Schlaf (zeigt Erschoepfung frueher als jede andere Frage), Widersprechen (der Kern dessen, was psychologische Sicherheit heisst) und Mitreden (viel Anforderung bei wenig Einfluss ist die Kombination, aus der Erschoepfung entsteht). Jede neue Frage hat ihre belegte Einordnung -- eine Frage ohne Grundlage ist eine Frage, die jemand gut fand. DIE ROTATION MUSSTE NEU. Der Katalog ist nach Themen sortiert; wer daraus drei aufeinanderfolgende nimmt, bekommt drei aus demselben Feld. Jetzt wird der Ring vorher verzahnt -- erst je eine Frage aus jedem Feld, dann je eine zweite. Ein Fenster trifft damit von selbst verschiedene Felder. Ein erster Anlauf reservierte feste Plaetze fuer die kernlosen Felder. Begruendet mit einer Auswertung je Feld, die es gar nicht gibt -- und er kostete: zwoelf Runden, bis jede Frage einmal gestellt war, fast ein halbes Jahr. Gefunden hat das pruef-befinden.mjs, nicht das Nachdenken. Mit dem verzahnten Ring und vier Plaetzen je Runde sind es vier Runden. DIE EINE ZUSAMMENFASSUNG AM ENDE, nicht eine je Kategorie. Sie sagt in dieser Reihenfolge: die Lage in einem Satz, was traegt (benannt, nicht als Zahl), hoechstens EINE Sache zum Hinschauen, ein Schluss, der zur Lage passt. Umgekehrt waere es eine Maengelliste mit Trostpflaster, und so etwas beantwortet man beim naechsten Mal nicht mehr ehrlich. ZUR FRAGE NACH DER BESTEN KOSTENLOSEN MOEGLICHKEIT: bewusst KEINE KI. Das sind Gesundheitsdaten (wer nachts wach liegt, wer angefeindet wird, wer ans Aufhoeren denkt) -- deshalb sind sie im ganzen Haus als nurSelbst markiert. Kostenlose KI-Angebote bezahlt man mit den Daten. Ein Sprachmodell erfindet ausserdem, und zwar ueberzeugend. Und ein fremder Dienst faellt aus. Jeder Grund reicht einzeln. Die Begruendung steht ausfuehrlich in workspace-befinden-resuemee.js. Nebenbefund behoben: Die Zusammenfassung blieb direkt NACH einer abgeschlossenen Runde leer -- da ist keine Antwort mehr "frisch". Genau der Moment, in dem man sie sehen will. Auch eine Pruefung korrigiert: Sie verbot den Text "entwicklung.js" irgendwo in der Datei und schlug an einem Kommentar an, der die Serverdatei benennt. Sie misst jetzt die Skript-Quellen. pruef-befinden.mjs 112/0, pruef-resuemee.mjs 35/0 (neu). Offener Befund, aelter als diese Aenderung: pruef-entwicklung.mjs meldet "ein Modi: keine Kachel fuehrt mehr ersatzweise auf die Entwicklungsseite" -- auch ohne diese Commits. Co-Authored-By: Claude Opus 5 <[email protected]>
257 lines
12 KiB
JavaScript
257 lines
12 KiB
JavaScript
/* =====================================================================
|
||
workspace-befinden-resuemee.js — Eine Zusammenfassung am Ende
|
||
(20.09.2026)
|
||
|
||
Filipe: „und am ende von allen fragen will ich eine gesamte
|
||
zusammenfassung, nicht bei jeder frage oder kategorie eine, sondern
|
||
EINE gesamte am ende. eine motivierende zusammenfassung für die
|
||
person. hol die beste der beste möglichkeiten dafür die man beutzen
|
||
kann kostenlos."
|
||
|
||
---------------------------------------------------------------------
|
||
DIE FRAGE NACH DER „BESTEN KOSTENLOSEN MÖGLICHKEIT" — EHRLICH
|
||
BEANTWORTET
|
||
|
||
Naheliegend wäre eine der kostenlosen KI-Schnittstellen (Groq,
|
||
Gemini, HuggingFace). Sie wäre hier die FALSCHE Wahl, und zwar aus
|
||
drei Gründen, von denen jeder einzelne reicht:
|
||
|
||
1. ES SIND GESUNDHEITSDATEN. Die Antworten sagen, wer nachts wach
|
||
liegt, wer angefeindet wird, wer ans Aufhören denkt. Genau
|
||
deshalb sind sie im ganzen Haus als `nurSelbst` markiert und
|
||
liegen in einer eigenen Tabelle, die kein anderer Weg liest.
|
||
Sie an einen fremden Dienst zu schicken, damit er einen netten
|
||
Satz daraus baut, würde diese ganze Sorgfalt in einer Zeile
|
||
aufheben. Kostenlose KI-Angebote bezahlt man mit den Daten —
|
||
in ihren Bedingungen steht meist ausdrücklich, dass Eingaben
|
||
zum Training verwendet werden dürfen.
|
||
|
||
2. EIN SPRACHMODELL ERFINDET. Es schreibt ohne Weiteres „du hast
|
||
dich diesen Monat deutlich erholt", wenn das Gegenteil dasteht,
|
||
und es klingt dabei überzeugend. Eine Zusammenfassung über das
|
||
eigene Befinden, die etwas Falsches behauptet, ist schlimmer
|
||
als keine: Man glaubt ihr ja, und beim nächsten Mal glaubt man
|
||
ihr nicht mehr — auch dann nicht, wenn sie recht hat.
|
||
|
||
3. SIE FÄLLT AUS. Ein fremder Dienst hat Störungen, Kontingente
|
||
und Kündigungen. Dieser Text hier funktioniert in zehn Jahren
|
||
noch, ohne Schlüssel, ohne Rechnung, ohne Netz.
|
||
|
||
DIE BESTE KOSTENLOSE MÖGLICHKEIT IST DESHALB KEINE KI, SONDERN
|
||
SORGFÄLTIG GESCHRIEBENE SPRACHE ÜBER GERECHNETEN ZAHLEN. Sie läuft
|
||
auf Filipes eigenem Server, kostet nichts, lügt nie und kann nicht
|
||
ausfallen. Was ein Sprachmodell hier besser könnte — Abwechslung im
|
||
Wortlaut — ist gegen die drei Punkte oben kein Argument.
|
||
|
||
---------------------------------------------------------------------
|
||
WIE MAN MOTIVIERT, OHNE ZU LÜGEN
|
||
|
||
Das ist die eigentliche Schwierigkeit. Eine Zusammenfassung, die bei
|
||
sechs von acht „da hakt es" fröhlich bleibt, ist keine Ermutigung,
|
||
sondern Hohn — und beim nächsten Mal antwortet man ihr nicht mehr
|
||
ehrlich. Drei Regeln, und sie gelten in jeder Lage:
|
||
|
||
ZUERST, WAS TRÄGT — und zwar benannt, nicht als Zahl. „Dass du
|
||
nach der Schicht abschalten kannst, ist das, was das hier
|
||
zusammenhält" sagt etwas. „5 von 8 grün" sagt nichts.
|
||
|
||
DANN HÖCHSTENS EINE SACHE. Wer fünf Probleme auf einmal vorgelegt
|
||
bekommt, sieht keine fünf Aufgaben, sondern einen Berg. Die Liste
|
||
aller Punkte steht ohnehin darüber; hier steht die EINE, bei der
|
||
sich das Hinsehen am meisten lohnt.
|
||
|
||
UND EIN SCHLUSS, DER ZUR LAGE PASST. Nicht „weiter so" für alle.
|
||
Wer gerade viel trägt, braucht einen anderen letzten Satz als
|
||
jemand, bei dem alles läuft.
|
||
|
||
---------------------------------------------------------------------
|
||
KEINE ZAHLEN, DIE JEMAND PFLEGEN MUSS
|
||
|
||
Jede Zahl in diesem Text wird gerechnet — auch „acht Fragen" und
|
||
„sechs Felder". Ein fester Satz „alle sechs Felder sind ruhig" wäre
|
||
beim siebten Feld still falsch, und niemand würde es merken.
|
||
===================================================================== */
|
||
|
||
/** Welche Stufe zählt als „läuft", welche als „hakt".
|
||
*
|
||
* Abgeleitet aus dem Schlüssel und nicht als eigene Liste gepflegt:
|
||
* `unklar` ist ausdrücklich WEDER gut noch schlecht — „kann ich nicht
|
||
* sagen" ist eine ehrliche Antwort und darf nicht als halbes Problem
|
||
* gezählt werden. Wer sie zu den Sorgen schlägt, erzeugt Sorgen, die
|
||
* niemand geäußert hat. */
|
||
const TRAEGT = new Set(["laeuft"]);
|
||
const WAECHST = new Set(["waechst"]);
|
||
const HAKT = new Set(["hakt"]);
|
||
|
||
/** Ein Satzende ohne doppelten Punkt. */
|
||
const satz = (t) => {
|
||
const x = String(t || "").trim();
|
||
if (!x) return "";
|
||
return /[.!?…]$/.test(x) ? x : x + ".";
|
||
};
|
||
|
||
/** Der erste Buchstabe klein — für Halbsätze, die angehängt werden.
|
||
* (Deutsche Substantive bleiben groß; deshalb nur dort benutzt, wo
|
||
* ein Verb oder Pronomen folgt.) */
|
||
const klein = (t) => (t ? t[0].toLowerCase() + t.slice(1) : t);
|
||
|
||
/**
|
||
* Die eine Zusammenfassung am Ende einer Runde.
|
||
*
|
||
* @param antworten { schluessel: stufe } — die Antworten DIESER Runde
|
||
* @param punkte Die Fragen dieser Runde (mit titel, feld, kern)
|
||
* @param felder BEFINDEN_FELDER
|
||
* @param vorher Die Antworten der VORIGEN Runde, oder null
|
||
* @returns {{moeglich, kopf, traegt, thema, schluss, zahlen}}
|
||
*/
|
||
export function resuemeeVon(antworten, punkte, felder, vorher = null) {
|
||
const gefragt = punkte.filter((p) => antworten?.[p.schluessel]);
|
||
|
||
/* DRITTER AUSGANG. Ohne Antworten gibt es nichts zusammenzufassen --
|
||
und das muss dastehen, statt dass ein freundlicher Satz über
|
||
nichts erscheint. */
|
||
if (!gefragt.length) {
|
||
return {
|
||
moeglich: false,
|
||
grund: "Noch keine Antworten in dieser Runde.",
|
||
kopf: null, traegt: [], thema: null, schluss: null,
|
||
zahlen: { gefragt: 0, traegt: 0, waechst: 0, hakt: 0, unklar: 0, felder: 0 },
|
||
};
|
||
}
|
||
|
||
const mit = (menge) => gefragt.filter((p) => menge.has(antworten[p.schluessel]));
|
||
const traegtP = mit(TRAEGT);
|
||
const waechstP = mit(WAECHST);
|
||
const haktP = mit(HAKT);
|
||
const unklarP = gefragt.length - traegtP.length - waechstP.length - haktP.length;
|
||
|
||
const feldName = (k) => felder.find((f) => f.schluessel === k)?.name || k;
|
||
|
||
/* ---- WELCHES FELD IST DAS THEMA? --------------------------------
|
||
Nicht die erste Frage mit „hakt", sondern das FELD mit den
|
||
meisten. Drei Haken quer über alles heißen „schwerer Monat";
|
||
drei Haken in EINEM Feld heißen „hier ist etwas". Nur das zweite
|
||
ist ein Befund, und nur darüber lohnt ein Satz.
|
||
|
||
Bei Gleichstand entscheidet die Reihenfolge der Felder, und die
|
||
geht von außen nach innen — das schwerere Thema gewinnt. */
|
||
const proFeld = new Map();
|
||
for (const p of haktP) {
|
||
proFeld.set(p.feld, (proFeld.get(p.feld) || 0) + 1);
|
||
}
|
||
let themaFeld = null, themaN = 0;
|
||
for (const f of felder) {
|
||
const n = proFeld.get(f.schluessel) || 0;
|
||
if (n > themaN) { themaFeld = f; themaN = n; }
|
||
}
|
||
|
||
/* ---- WAS TRÄGT ---------------------------------------------------
|
||
Höchstens zwei, und benannt. Eine Aufzählung von fünf Dingen liest
|
||
niemand; zwei bleiben hängen. Kernfragen zuerst — sie sind die,
|
||
die in jeder Runde gestellt werden, und damit die, deren „läuft"
|
||
am meisten bedeutet. */
|
||
const traegtListe = [...traegtP]
|
||
.sort((a, b) => (b.kern ? 1 : 0) - (a.kern ? 1 : 0))
|
||
.slice(0, 2)
|
||
.map((p) => ({ schluessel: p.schluessel, titel: p.titel, feld: p.feld }));
|
||
|
||
/* ---- HAT SICH SEIT DEM LETZTEN MAL ETWAS GEBESSERT? -------------
|
||
Nur echte Verbesserungen, und nur bei Fragen, die BEIDE Male
|
||
gestellt wurden. Seit die Fragen rotieren, wäre „war letztes Mal
|
||
nicht dabei" sonst eine Verbesserung — und das ist keine. */
|
||
const besser = [];
|
||
if (vorher) {
|
||
const rang = { hakt: 0, waechst: 1, laeuft: 2 };
|
||
for (const p of gefragt) {
|
||
const a = rang[vorher[p.schluessel]];
|
||
const b = rang[antworten[p.schluessel]];
|
||
if (a !== undefined && b !== undefined && b > a) besser.push(p);
|
||
}
|
||
}
|
||
|
||
/* ---- DER KOPFSATZ ------------------------------------------------
|
||
Vier Lagen, vier Sätze — und keiner davon behauptet etwas, das
|
||
nicht in den Zahlen steht. */
|
||
const n = gefragt.length;
|
||
let kopf;
|
||
if (!haktP.length && !waechstP.length) {
|
||
kopf = unklarP === n
|
||
? "Diesmal konntest du zu fast allem nichts sagen. Das ist eine ehrliche "
|
||
+ "Antwort – und beim nächsten Mal weißt du vermutlich mehr."
|
||
: `Alle ${n} Fragen dieser Runde stehen auf „Läuft". Das ist selten, und `
|
||
+ "es ist kein Zufall – irgendwas machst du gerade richtig.";
|
||
} else if (!haktP.length) {
|
||
kopf = `Nichts hakt gerade. ${waechstP.length === 1 ? "Eine Sache wächst" : `${waechstP.length} Sachen wachsen`} `
|
||
+ "noch – das heißt, sie sind unterwegs, nicht liegengeblieben.";
|
||
} else if (haktP.length === 1) {
|
||
kopf = `Von ${n} Fragen hakt genau eine. ${n - 1} laufen oder wachsen – `
|
||
+ "das ist der Boden, auf dem du stehst, und der ist tragfähig.";
|
||
} else if (haktP.length < n / 2) {
|
||
kopf = `${haktP.length} von ${n} Sachen haken gerade. Die anderen ${n - haktP.length} `
|
||
+ "nicht – und das ist die Hälfte der Auskunft, die man beim Draufschauen "
|
||
+ "meistens übersieht.";
|
||
} else {
|
||
/* DIE SCHWERE LAGE. Hier NICHT aufmunternd werden -- das ist der
|
||
Moment, in dem eine fröhliche Zusammenfassung alles Vertrauen
|
||
kostet. Stattdessen: benennen, entlasten, und den Weg zeigen.
|
||
„Fast nie an dir" ist keine Beschönigung, sondern das, was die
|
||
Forschung zu Belastung in Ehrenämtern durchgehend findet. */
|
||
kopf = `${haktP.length} von ${n} Sachen haken. Das ist viel, und es liegt `
|
||
+ "fast nie an der Person, die es aushält. Es ist ein guter Moment, "
|
||
+ "das jemandem zu sagen, statt es noch eine Runde mitzunehmen.";
|
||
}
|
||
|
||
/* ---- DER SCHLUSSSATZ ---------------------------------------------
|
||
Er gehört zur Lage. „Weiter so" für alle wäre ein Satz, der nie
|
||
jemanden meint. */
|
||
let schluss;
|
||
if (besser.length) {
|
||
schluss = besser.length === 1
|
||
? `Und etwas hat sich seit dem letzten Mal gebessert: ${klein(besser[0].titel)}. `
|
||
+ "Das hat sich nicht von allein gemacht."
|
||
: `Und ${besser.length} Sachen haben sich seit dem letzten Mal gebessert. `
|
||
+ "Das hat sich nicht von allein gemacht.";
|
||
} else if (haktP.length >= n / 2) {
|
||
schluss = "Du musst das hier nicht allein lösen. Dass du es aufgeschrieben "
|
||
+ "hast, ist der erste Teil – der zweite ist ein Satz an jemanden.";
|
||
} else if (haktP.length) {
|
||
schluss = "Das musst du heute nicht lösen. Es reicht, dass du es weißt – "
|
||
+ "beim nächsten Mal siehst du, ob es geblieben ist.";
|
||
} else {
|
||
schluss = "Nächste Runde in zwei Wochen. Bis dahin: nichts zu tun.";
|
||
}
|
||
|
||
return {
|
||
moeglich: true,
|
||
kopf,
|
||
traegt: traegtListe,
|
||
thema: themaFeld && themaN > 0
|
||
? {
|
||
feld: themaFeld.schluessel,
|
||
name: feldName(themaFeld.schluessel),
|
||
anzahl: themaN,
|
||
/* MEHRERE IN EINEM FELD SIND ETWAS ANDERES ALS EINES. Der Satz
|
||
sagt, welches von beidem es ist -- daran hängt, ob man mit
|
||
einer Sache spricht oder mit einem Thema. */
|
||
satz: themaN > 1
|
||
? satz(`Wenn du nur an einer Stelle hinschaust, dann hier: „${feldName(themaFeld.schluessel)}" `
|
||
+ `– da stehen ${themaN} der Haken beieinander. Das ist selten Zufall`)
|
||
: satz(`Wenn du nur an einer Stelle hinschaust, dann hier: „${feldName(themaFeld.schluessel)}"`),
|
||
titel: haktP.filter((p) => p.feld === themaFeld.schluessel).map((p) => p.titel),
|
||
}
|
||
: null,
|
||
schluss,
|
||
zahlen: {
|
||
gefragt: n,
|
||
traegt: traegtP.length,
|
||
waechst: waechstP.length,
|
||
hakt: haktP.length,
|
||
unklar: unklarP,
|
||
besser: besser.length,
|
||
/* GERECHNET, nicht eingetragen: Wer ein siebtes Feld ergänzt,
|
||
bekommt hier automatisch die 7. */
|
||
felder: new Set(gefragt.map((p) => p.feld).filter(Boolean)).size,
|
||
},
|
||
};
|
||
}
|