# Novaberg — EI: Plutchik-Emotionsmodell **Projekt:** Novaberg — The Nova Anima Resonance System **Dokument:** Technik Plutchik-Emotionsmodell (Oktagon, sektorabhängige Normalisierung, Arousal-Radius) **Stand:** 23. August 2026 (**die zweite `NEGATIVE_EMOTIONEN` ist fort** — der Zustelldienst importiert die abgeleitete Menge; §11 nachgezogen). Davor: 16. August 2026 (gegen den Code geprüft), 17. April 2026, Chat 52 (Code-Alignment) **Pfad:** novaberg/docs/novaberg-ei-plutchik.md **Quellen:** nova-04-t-a.md **Dateien:** `config.py` (Sektor-Map, Distanzmatrix, Exponenten), `graph/nodes/enricher.py` (Normalisierung), Perzeption-Prompt (16+1 Emotionen), `client/ui/emotionen_tab.py` (Oktagon-Radar) --- ## 1. Das Prinzip Robert Plutchik beschrieb 1980 acht Primäremotionen, kreisförmig angeordnet mit diametralen Gegenpaaren. Jede Emotion hat drei Intensitätsstufen — von mild (Außenring) über moderat (Mittelring) bis intensiv (Innenring). Benachbarte Emotionen auf dem Rad sind psychologisch verwandt, gegenüberliegende sind Antagonisten. Nova adaptiert dieses Modell als **Oktagon**: Acht Sektoren mit je zwei kanonischen Emotionen (intensiv und moderat), Arousal als Radius, und eine sektorabhängige Normalisierung im Enricher, die benachbarte Emotionen schützt und gegenüberliegende verdrängt. ### Warum Plutchik? Das bisherige Modell teilte Emotionen in drei Gruppen: positiv, negativ, neutral. Die Normalisierung war uniform — alle Emotionen wurden durch denselben Maximalwert geteilt, unabhängig von ihrer Beziehung zueinander. Das führte zu zwei Problemen: 1. **Kannibalisierung innerhalb der Gruppe:** Akkumulierte Zufriedenheit (3 Turns) erdrückte einmalige Begeisterung durch die uniforme Division — obwohl beide positiv sind und sich gegenseitig stützen sollten. 2. **Fehlende Antagonismus-Wirkung:** Frustration und Freude wurden gleich behandelt wie Frustration und Ärger — obwohl die erste Beziehung antagonistisch ist und die zweite verstärkend. Plutchiks Rad liefert die fehlende Topologie: Eine wissenschaftlich fundierte Anordnung, die definiert, welche Emotionen sich stützen (benachbart), neutral zueinander stehen (diagonal) oder einander verdrängen (gegenüber). --- ## 2. Das Oktagon ### 2.1 Acht Sektoren Anordnung im Uhrzeigersinn, strikt nach Plutchik. Positive und negative Emotionen sind interleaved — nicht auf Hälften getrennt: ``` 1 Freude 8 Neugier 2 Zuversicht 7 Ärger 3 Angst 6 Enttäuschung 4 Überraschung 5 Trauer ``` ### 2.2 Gegenpaare Jedes Paar bildet einen psychologisch fundierten Antagonismus (Plutchik 1:1): | Gegenpaar | Plutchik-Original | Begründung | |-----------|-------------------|------------| | 1 Freude ↔ 5 Trauer | Joy ↔ Sadness | Grundlegende Valenz-Achse | | 2 Zuversicht ↔ 6 Enttäuschung | Trust ↔ Disgust | Vertrauen erfüllt ↔ Vertrauen gebrochen | | 3 Angst ↔ 7 Ärger | Fear ↔ Anger | Flight ↔ Fight | | 4 Überraschung ↔ 8 Neugier | Surprise ↔ Anticipation | Unerwartetes ↔ Erwartetes | ### 2.3 Nachbarschaften Die Übergänge zwischen benachbarten Sektoren bilden natürliche emotionale Verläufe. Plutchiks Kombinations-Emotionen bestätigen die Nachbarschaft: | Nachbarn | Plutchik-Kombination | Beispiel | |----------|---------------------|---------| | 1–2 Freude–Zuversicht | Liebe (love) | „Ich bin glücklich und vertraue dir" | | 2–3 Zuversicht–Angst | Unterwerfung (submission) | „Ich vertraue, aber habe Angst enttäuscht zu werden" | | 3–4 Angst–Überraschung | Ehrfurcht (awe) | „Das macht mir Angst und fasziniert mich zugleich" | | 4–5 Überraschung–Trauer | Missbilligung (disapproval) | „Das hätte ich nicht erwartet — das tut weh" | | 5–6 Trauer–Enttäuschung | Reue (remorse) | „Ich bin traurig und enttäuscht von mir selbst" | | 6–7 Enttäuschung–Ärger | Verachtung (contempt) | „Das ist widerlich und macht mich wütend" | | 7–8 Ärger–Neugier | Aggressivität (aggressiveness) | „Ich bin wütend und will es ändern" | | 8–1 Neugier–Freude | Optimismus (optimism) | „Ich bin gespannt und freue mich darauf" | --- ## 3. Sechzehn kanonische Emotionen Perzeption klassifiziert in 16 kanonische Emotionen plus `neutral`. Zwei pro Sektor — eine intensive (hoher Arousal) und eine moderate (niedrigerer Arousal): | Sektor | Kern | Plutchik | Intensiv | Moderat | |--------|------|----------|----------|---------| | 1 Freude | hoch-positiv, aktiv | Joy | begeisterung | freude | | 2 Zuversicht | stabiles Vertrauen | Trust | dankbarkeit | zufriedenheit | | 3 Angst | aktiviert-negativ | Fear | stress | unsicherheit | | 4 Überraschung | ambivalent, kurzlebig | Surprise | ueberrascht | verwundert | | 5 Trauer | passiv-negativ | Sadness | verzweiflung | traurigkeit | | 6 Enttäuschung | gerichtet-negativ | Disgust | frustration | enttaeuschung | | 7 Ärger | aggressiv-negativ | Anger | wut | aerger | | 8 Neugier | explorativ, nach außen | Anticipation | hoffnung | neugierig | Sektorlos: `neutral` (keine emotionale Richtung, Arousal unter Schwellwert) ### 3.1 Synonym-Mapping Die Perzeption soll die 16 kanonischen Emotionen verwenden. Liefert sie eine Variante, greift das Synonym-Mapping: ```python EMOTION_SYNONYM_MAP: dict[str, str] = { # → Sektor 1 Freude "glueck": "freude", "euphorie": "begeisterung", "heiterkeit": "freude", "ekstase": "begeisterung", # → Sektor 1 Freude (ehemals eigener Sektor "Stolz") "stolz": "freude", "triumph": "freude", "genugtuung": "freude", "selbstvertrauen": "freude", "selbstsicherheit": "freude", # → Sektor 2 Zuversicht "erleichterung": "zufriedenheit", "gelassenheit": "zufriedenheit", "geborgenheit": "zufriedenheit", "vertrauen": "zufriedenheit", # → Sektor 3 Angst "angst": "stress", "furcht": "stress", "panik": "stress", "sorge": "unsicherheit", "nervositaet": "unsicherheit", "beklemmung": "unsicherheit", "anspannung": "stress", # → Sektor 4 Überraschung "schock": "ueberrascht", "ueberraschung": "ueberrascht", "fassungslos": "ueberrascht", "verbluefft": "verwundert", "perplex": "verwundert", "baff": "ueberrascht", # → Sektor 5 Trauer "resignation": "traurigkeit", "einsamkeit": "traurigkeit", "melancholie": "traurigkeit", "kummer": "verzweiflung", "niedergeschlagenheit": "traurigkeit", "nachdenklich": "traurigkeit", "leere": "traurigkeit", # → Sektor 6 Enttäuschung (inkl. Ekel-Achse) "frust": "frustration", "ernuechterung": "enttaeuschung", "verbitterung": "frustration", "desillusionierung": "enttaeuschung", "abscheu": "frustration", "ekel": "frustration", "verachtung": "frustration", "langeweile": "enttaeuschung", "ablehnung": "enttaeuschung", "desinteresse": "enttaeuschung", "gleichgueltigkeit": "enttaeuschung", # → Sektor 7 Ärger "zorn": "wut", "aggression": "wut", "gereizt": "aerger", "genervt": "aerger", "empoerung": "wut", "hass": "wut", "groll": "aerger", # → Sektor 8 Neugier "neugier": "neugierig", "neugierde": "neugierig", "interesse": "neugierig", "erwartung": "hoffnung", "vorfreude": "hoffnung", "gespannt": "neugierig", } ``` ### 3.2 Fehlerbehandlung Drei Stufen: 1. **Kanonisch:** Emotion ist eine der 16 — direkt verwenden. 2. **Synonym:** Emotion steht im Synonym-Mapping — auf kanonische Form mappen. 3. **Unbekannt:** Emotion ist weder kanonisch noch Synonym — **Error-Log** werfen, damit sie ergänzt werden kann. Fallback auf Exponent 1.0 (sektorlos). → **Am 06.10.2026 entschieden:** Der unbekannte Wert wird durch `neutral` ersetzt, statt roh weiterzulaufen — in dieser Rechnung dieselbe Wirkung (§6.4), aber kein Wert außerhalb des Kanons mehr im Verlauf; die Fehlerzeile bleibt. `zuversicht` wird auf `zufriedenheit` gezogen (`PERZEPTION-EMOTION-AUSSER-KANON` in [`novaberg-bugs-charakter.md`](novaberg-bugs-charakter.md)). ```python sektor = EMOTION_SEKTOR_MAP.get(emotion) if sektor is None and emotion != "neutral": logger.error( f"Enricher: Unbekannte Emotion '{emotion}' — " f"nicht in EMOTION_SEKTOR_MAP und nicht in EMOTION_SEKTORLOS. " f"Muss in config.py ergänzt werden." ) ``` ### 3.3 Zuordnung zu Plutchik Die Sektorreihenfolge folgt Plutchik 1:1. Die einzige inhaltliche Adaption: | Plutchik | Nova | Begründung | |----------|------|------------| | Disgust (Ekel) | → Enttäuschung (Sektor 6) | Ekel als Primäremotion ist im Kontext eines KI-Assistenten selten. Enttäuschung (gebrochenes Vertrauen) tritt häufig auf und besetzt die gleiche antagonistische Position zu Zuversicht/Vertrauen. Die Plutchik-Varianten Abscheu, Langeweile und Verachtung werden als Synonyme in Sektor 6 (Enttäuschung) gemappt. | Stolz und Erleichterung sind keine eigenen Sektoren mehr, sondern Synonyme: `stolz` → `freude` (Sektor 1), `erleichterung` → `zufriedenheit` (Sektor 2). Überraschung hat einen eigenen Sektor (4) erhalten — Plutchik-konform. ### 3.4 Nachdenklich als Traurigkeit `nachdenklich` wird auf `traurigkeit` (Sektor 5) gemappt. Begründung: Nachdenklichkeit im Gesprächskontext ist ein Rückzug nach innen — grüblerisch, verlangsamend, leicht melancholisch. In Plutchiks Terminologie entspricht das der Schwermütigkeit (Außenring von Traurigkeit). Die explorative, neugierige Variante von „nachdenken" wird durch `neugierig` (Sektor 3) abgedeckt. **Implikation für den Emotions-Vektor:** Im alten Modell war `nachdenklich` neutral und erzeugte den Vektor `stabilisierung` nach einer Krise. Im neuen Modell ist es Sektor 5 (negativ) und erzeugt `plateau` oder `spirale`. Das ist realistischer — Grübeln in der Krise ist kein Zeichen von Besserung. --- ## 4. Das Radar-Modell: Arousal als Radius ### 4.1 Grundidee Plutchiks Rad zeigt intensive Emotionen innen und milde außen. Novas Radar **invertiert** das: Hoher Arousal liegt außen (größerer Radius), niedriger Arousal innen. Im Zentrum entsteht eine neutrale Zone. ``` Außen (hoher Arousal): Intensive Emotionen — weit auseinander Mitte (mittlerer Arousal): Moderate Emotionen — näher beieinander Zentrum (Arousal < Schwellwert): NEUTRAL — keine Sektor-Zuordnung ``` ### 4.2 Warum invertiert? Drei Gründe: 1. **Gegenüber-Distanz skaliert mit Arousal:** Begeisterung (Sektor 1, Arousal 0.8) und Verzweiflung (Sektor 5, Arousal 0.8) liegen maximal weit auseinander. Leichte Freude und leichte Traurigkeit (beide Arousal 0.3) sind räumlich näher — sie können koexistieren. Bitteres Lächeln, melancholische Zufriedenheit. Begeisterung und Verzweiflung können das nicht. 2. **Neutrale Mitte:** Bei Arousal unter dem Schwellwert (`EMOTION_NEUTRAL_SCHWELLE` — ~~in `config.py`~~, **am 16.08.2026 berichtigt: die Konstante existiert dort nicht**, siehe die Parametertabelle weiter unten, die sie seit jeher als offen führt) sind alle Sektoren verschmolzen. Ein Mensch im neutralen Zustand ist nicht „freudig-neutral" oder „ärgerlich-neutral" — er ist einfach da. Keine Richtung, nur Ruhe. 3. **Radar-Darstellung:** Größere Ausschläge nach außen = intensivere Emotion. Intuitiv lesbar: Ein ruhiges Radar (kleine Fläche) = neutraler Zustand. Ein zackiges Radar (große Ausschläge) = emotionale Aktivierung. ### 4.3 Arousal-skalierte Exponenten Die sektorabhängige Normalisierung (Abschnitt 5) nutzt Exponenten, die selbst vom Arousal abhängen. Niedrige Arousal-Werte ziehen alle Exponenten Richtung 1.0 — weniger Separation, mehr Koexistenz. Hohe Arousal-Werte verstärken die Separation. Formel: ``` effektiver_exponent = 1.0 + (basis_exponent - 1.0) × arousal_der_dominanten_emotion ``` Beispiel für den Gegenüber-Exponent (Basis 1.4): | Arousal der Dominante | Effektiver Exponent | Effekt | |-----------------------|---------------------|--------| | 0.2 | 1.08 | Kaum Verdrängung — Koexistenz möglich | | 0.5 | 1.20 | Moderate Verdrängung | | 0.8 | 1.32 | Starke Verdrängung | | 1.0 | 1.40 | Maximale Verdrängung | Beispiel für den Nachbar-Exponent (Basis 0.7): | Arousal der Dominante | Effektiver Exponent | Effekt | |-----------------------|---------------------|--------| | 0.2 | 0.94 | Kaum Schutz — fast normal | | 0.5 | 0.85 | Moderater Schutz | | 0.8 | 0.76 | Starker Schutz | | 1.0 | 0.70 | Maximaler Schutz | > **Geometrische Intuition:** Im Zentrum des Radars (niedriger Arousal) sind alle Emotionen nah beieinander — sie interagieren kaum. Am Rand (hoher Arousal) sind die Abstände maximal — Gegenüber verdrängen sich, Nachbarn stützen sich. Die Exponenten bilden diese Geometrie mathematisch ab. --- ## 5. Arousal-Decay: Emotionsspezifischer Energieverlust ### 5.1 Das Problem Der bisherige Arousal-Wert einer Emotion bleibt konstant — der Arousal des neuesten Vorkommens wird gespeichert und nie verändert. Begeisterung mit Arousal 0.8 bei Turn 0 hat nach 10 Turns immer noch Arousal 0.8. Aber ein Mensch, der vor 10 Turns begeistert war, hat längst kein Dopamin mehr — die Begeisterung ist noch *da* (Gewichtung), aber sie *glüht nicht mehr* (Arousal). Gleichzeitig gräbt sich Verzweiflung ein — Cortisol baut sich langsam ab. Nach 10 Turns ist die Verzweiflung immer noch heiß. Das bisherige System behandelt beides gleich. ### 5.2 Zwei unabhängige Decay-Dimensionen | Dimension | Regelt | Mechanismus | Vorhanden? | |-----------|--------|-------------|------------| | **Gewichtungs-Decay** | Ist die Emotion noch *da*? | Arousal-basierter logarithmischer Decay (novaberg-pixie-decay.md) | ✅ Seit Chat 16 | | **Arousal-Decay** | Wie viel *Energie* hat sie noch? | Emotionsspezifische exponentielle Abnahme | ✅ Seit Chat 18 | ### 5.3 Formel ``` gedämpfter_arousal = original_arousal × e^(-rate × position) ``` Die Rate bestimmt, wie schnell die Energie einer Emotion verfällt. Hohe Rate = schneller Energieverlust (Dopamin-Peak), niedrige Rate = langsamer Verlust (Cortisol). ### 5.4 Decay-Raten pro Emotion ```python EMOTION_AROUSAL_DECAY: dict[str, float] = { # Sektor 1 — Freude: Dopamin-Peak, verfliegt schnell "begeisterung": 0.15, "freude": 0.10, # Sektor 2 — Zuversicht: stabile Grundstimmung "dankbarkeit": 0.08, "zufriedenheit": 0.05, # Sektor 3 — Angst: setzt sich fest "stress": 0.04, "unsicherheit": 0.05, # Sektor 4 — Überraschung: extrem kurzlebig "ueberrascht": 0.20, "verwundert": 0.15, # Sektor 5 — Trauer: gräbt sich ein (Cortisol) "verzweiflung": 0.02, "traurigkeit": 0.03, # Sektor 6 — Enttäuschung: bleibt als Groll "frustration": 0.04, "enttaeuschung": 0.05, # Sektor 7 — Ärger: intensiv aber abbaubar (Adrenalin) "wut": 0.08, "aerger": 0.06, # Sektor 8 — Neugier: flüchtig, springt weiter "hoffnung": 0.08, "neugierig": 0.12, } ``` ### 5.5 Energiekurven (validiert) Anteil der verbleibenden Energie nach N Turns: | Emotion | Rate | T=3 | T=5 | T=10 | T=20 | |---------|------|-----|-----|------|------| | verzweiflung | 0.02 | 94% | 90% | 82% | 67% | | frustration | 0.04 | 89% | 82% | 67% | 45% | | zufriedenheit | 0.05 | 86% | 78% | 61% | 37% | | wut | 0.08 | 79% | 67% | 45% | 20% | | freude | 0.10 | 74% | 61% | 37% | 14% | | begeisterung | 0.15 | 64% | 47% | 22% | 5% | | ueberrascht | 0.20 | 55% | 37% | 14% | 2% | **Asymmetrie:** Verzweiflung nach 20 Turns: noch 67% Energie. Begeisterung nach 10 Turns: nur noch 22%. Negative Emotionen graben sich ein, positive verfliegen — neurochemisch korrekt. **Wichtig:** Die Emotion *bleibt im Verlauf* — der Gewichtungs-Decay regelt die Präsenz. Der Arousal-Decay regelt nur, wie viel Durchschlagskraft sie noch hat. ### 5.6 Dominanz-Exponent Die Bestimmung der dominanten Emotion nutzt einen **Effektivwert** statt des reinen Gewichts: ``` effektiv = gewicht × (gedämpfter_arousal ^ EI_AROUSAL_DOMINANZ) ``` `EI_AROUSAL_DOMINANZ` = 2.0 (konfigurierbar in `config.py`). Der Exponent verstärkt den Arousal-Effekt exponentiell: Ein Schock (Arousal 0.9) hat Effektivwert 0.81 × Gewicht. Zufriedenheit (Arousal 0.3) hat Effektivwert 0.09 × Gewicht. Der Schock braucht also nur ein Neuntel des Gewichts um zu dominieren. **Validierte Kipppunkte (n=2.0):** | Szenario | OHNE Arousal-Decay | MIT Arousal-Decay | |----------|-------------------|-------------------| | 3× Begeisterung → Herzinfarkt (Verzweiflung 0.9) | ✗ block (0.81 < 1.74) | **✓ DURCH** (0.81 > 0.71) | | 5× Zufriedenheit + 2× Begeisterung → Schock (Enttäuschung 0.8) | ✗ block (0.64 < 0.67) | **✓ DURCH** (0.64 > 0.27) | | 5× Verzweiflung → Leise Hoffnung (Freude 0.4) | ✗ block | ✗ block (korrekt) | | 5× Verzweiflung → Euphorie (Begeisterung 0.9) | ✗ block | ✗ block (korrekt) | | 8× Zufriedenheit → Schock (Verzweiflung 0.9) | ✓ DURCH | ✓ DURCH (korrekt) | --- ## 6. Sektorabhängige Normalisierung ### 6.1 Einordnung in die Berechnung Die Verlaufsberechnung im Enricher hat jetzt 6 Schritte: ``` Schritt 1: Nur User-Turns mit nicht-neutraler Emotion filtern Schritt 2: Turn-0-Prinzip (Perzeption als neuester Datenpunkt) Schritt 3: Arousal-basierter Gewichts-Decay + Akkumulation gleicher Emotionen Schritt 4: ████ Arousal-Decay pro Emotion (NEU) ████ Schritt 5: ████ Sektorabhängige Normalisierung mit Effektivwert (NEU) ████ Schritt 6: Filter (EMOTION_MIN_WEIGHT) + Sortierung ``` ### 6.2 Distanzmatrix Die Distanz zwischen zwei Sektoren bestimmt den Basis-Exponent. In der Plutchik-Reihenfolge (1=Freude, 2=Zuversicht, 3=Angst, 4=Überraschung, 5=Trauer, 6=Enttäuschung, 7=Ärger, 8=Neugier): | Von \ Zu | 1 Fr | 2 Zu | 3 An | 4 Üb | 5 Tr | 6 En | 7 Är | 8 Ne | |----------|------|------|------|------|------|------|------|------| | 1 Freude | — | 0.7 | 1.0 | 1.2 | **1.4** | 1.2 | 1.0 | 0.7 | | 2 Zuversicht | 0.7 | — | 0.7 | 1.0 | 1.2 | **1.4** | 1.2 | 1.0 | | 3 Angst | 1.0 | 0.7 | — | 0.7 | 1.0 | 1.2 | **1.4** | 1.2 | | 4 Überraschung | 1.2 | 1.0 | 0.7 | — | 0.7 | 1.0 | 1.2 | **1.4** | | 5 Trauer | **1.4** | 1.2 | 1.0 | 0.7 | — | 0.7 | 1.0 | 1.2 | | 6 Enttäuschung | 1.2 | **1.4** | 1.2 | 1.0 | 0.7 | — | 0.7 | 1.0 | | 7 Ärger | 1.0 | 1.2 | **1.4** | 1.2 | 1.0 | 0.7 | — | 0.7 | | 8 Neugier | 0.7 | 1.0 | 1.2 | **1.4** | 1.2 | 1.0 | 0.7 | — | Die Matrix ist symmetrisch. Gegenpaare (Distanz 4, fett): Freude↔Trauer, Zuversicht↔Enttäuschung, Angst↔Ärger, Überraschung↔Neugier. ### 6.3 Algorithmus ``` 1. Kanonisierung: Alle Emotionen über EMOTION_SYNONYM_MAP normalisieren 2. Gewichts-Decay + Akkumulation (wie bisher) 3. Arousal-Decay: Für jede Emotion den Arousal positions-abhängig dämpfen: gedämpfter_arousal = original_arousal × e^(-EMOTION_AROUSAL_DECAY[emotion] × position) 4. Dominante Emotion bestimmen via Effektivwert: effektiv = gewicht × (gedämpfter_arousal ^ EI_AROUSAL_DOMINANZ) 5. Sektor der Dominanten bestimmen (aus EMOTION_SEKTOR_MAP) 6. Für jede andere Emotion: a. Sektor bestimmen b. Basis-Exponent aus Distanzmatrix lesen c. Effektiven Exponent berechnen: eff_exp = 1.0 + (basis_exp - 1.0) × gedämpfter_arousal_dominante d. Normalisiertes Gewicht berechnen: norm = (raw / max_raw) ^ eff_exp 7. Dominante Emotion auf 1.0 setzen 8. Filter: Emotionen unter EMOTION_MIN_WEIGHT entfernen 9. Sortieren nach Gewicht absteigend ``` ### 6.4 Sektorlose Emotionen `neutral` hat keinen Sektor. Liefert Perzeption `neutral`, wird die Emotion in den Verlauf aufgenommen, aber mit Exponent 1.0 zu allen Sektoren behandelt — wie bisher. In der Praxis filtert der bestehende Code neutrale Emotionen bereits vor der Verlaufsberechnung heraus (Zeile „emotion != neutral" im Enricher). Unbekannte Emotionen (nicht in EMOTION_SEKTOR_MAP, nicht in EMOTION_SYNONYM_MAP, nicht `neutral`) erzeugen einen Error-Log und werden mit Exponent 1.0 behandelt. → **Seit dem 06.10.2026 entschieden:** Sie werden zu `neutral` (§3.2, Punkt 3). --- ## 7. Emotions-Gruppen (Vektor-Berechnung) Die bestehenden 9 Emotions-Vektoren (absturz, spirale, stabilisierung, erholung, aufbluehen, eskalation, abkuehlung, einbruch, plateau) bleiben unverändert. Die Gruppen-Zuordnung leitet sich aus `SEKTOR_GRUPPE` ab — einem expliziten Dict, da positive und negative Sektoren in der Plutchik-Reihenfolge interleaved sind: ```python SEKTOR_GRUPPE: dict[int, str] = { 1: "positiv", # Freude 2: "positiv", # Zuversicht 3: "negativ", # Angst 4: "neutral", # Überraschung (ambivalent) 5: "negativ", # Trauer 6: "negativ", # Enttäuschung 7: "negativ", # Ärger 8: "positiv", # Neugier } ``` Die Funktion `_emotion_zu_gruppe()` nutzt dieses Dict: ```python def _emotion_zu_gruppe(emotion: str) -> str: sektor = EMOTION_SEKTOR_MAP.get(emotion) if sektor is None: return "neutral" return SEKTOR_GRUPPE.get(sektor, "neutral") ``` Die drei separaten Sets `POSITIVE_EMOTIONEN`, `NEGATIVE_EMOTIONEN`, `NEUTRALE_EMOTIONEN` im Enricher entfallen. Eine Quelle der Wahrheit (die Sektor-Map) statt drei synchron zu haltende Listen. > ⚠ **Am 16.08.2026 gegen den Code geprüft: Der Vorschlag ist nicht ausgeführt, und die Hälfte davon ist ein Defekt.** > > `ei/utils.py` leitet `POSITIVE_EMOTIONEN` und `NEGATIVE_EMOTIONEN` tatsächlich aus `EMOTION_SEKTOR_MAP` und `SEKTOR_GRUPPE` ab — insofern ist die eine Quelle der Wahrheit da. `NEUTRALE_EMOTIONEN` gibt es nirgends; der Name in diesem Absatz ist der Grund, warum die Doku-Prüfung hier angeschlagen hat. > > **Was sie dabei gefunden hat, wiegt schwerer:** ~~`services/shadow_delivery.py` schreibt **eine zweite** `NEGATIVE_EMOTIONEN` als Literal hin~~ — vier Emotionen gegen die acht der abgeleiteten Menge. Es fehlten `enttaeuschung`, `stress`, `verzweiflung` und `wut`. Diese zweite Fassung bediente den Emotions-Riegel der Zustellung, also **genau die Entscheidung, bei negativer Stimmung zu schweigen** — und drei der vier fehlenden fielen dort auf *erlaubt* durch. > > → **Am 23.08.2026 behoben** (`NEGATIVE-EMOTIONEN-DOPPELT`). Der Zustelldienst importiert die abgeleitete Menge; `stress` bleibt vor der Kanon-Prüfung stehen, weil dort auch die empathische Nachfrage zu viel ist, und die Reihenfolge trägt diese Unterscheidung. Zeuge über den ganzen Baum, dass es bei **einer** Definition bleibt: `tests/test_emotionsriegel_kanon.py::KanonquelleTest`. > > **Im Bestand ist der Fall nie eingetreten** — 729 `turn_roh`-Zeilen, 0 mit einer der drei durchgelassenen Emotionen. Der Riegel war nicht wirkungslos, sondern unvollständig, und nichts hätte es gemeldet. **Auswirkung auf `EI_PASSIV_NEGATIVE`:** Die passiv-negativen Emotionen, die im EI-Plausibilitäts-Gate den Modus `emotional` erzwingen, werden ebenfalls über den Sektor definiert: Sektor 5 (Trauer) erzwingt immer `emotional`, unabhängig vom Arousal. Die übrigen negativen Sektoren (6–8) erzwingen ab Mid-Arousal. --- ## 8. Config-Variablen Alle neuen Konfigurationswerte: | Variable | Typ | Default | Beschreibung | |----------|-----|---------|-------------| | `EMOTION_SEKTOR_MAP` | `dict[str, int]` | siehe Abschnitt 3 | Kanonische Emotion → Sektor (1–8) | | `EMOTION_SYNONYM_MAP` | `dict[str, str]` | siehe Abschnitt 3.1 | Variante → kanonische Emotion | | `EMOTION_KANON` | `set[str]` | 16 Emotionen + neutral | Gültige kanonische Emotionen | | `EMOTION_SEKTOR_DISTANZ` | `dict[tuple, float]` | 8×8 Matrix | (sektor_a, sektor_b) → Basis-Exponent | | `EMOTION_AROUSAL_DECAY` | `dict[str, float]` | 16 Raten | Emotion → Arousal-Decay-Rate | | `SEKTOR_GRUPPE` | `dict[int, str]` | 8 Einträge | Sektor → positiv/negativ/neutral | | `EI_NORM_BENACHBART` | `float` | 0.7 | Exponent für Distanz 1 | | `EI_NORM_NAH_DIAGONAL` | `float` | 1.0 | Exponent für Distanz 2 | | `EI_NORM_FERN_DIAGONAL` | `float` | 1.2 | Exponent für Distanz 3 | | `EI_NORM_GEGEN` | `float` | 1.4 | Exponent für Distanz 4 (gegenüber) | | `EI_AROUSAL_DOMINANZ` | `float` | 2.0 | Exponent für Effektivwert-Berechnung | | `EMOTION_NEUTRAL_SCHWELLE` | `float` | 📐 offen | Arousal-Schwellwert für neutrales Zentrum — noch nicht in config.py, Bedarf wird nach Smoking Tests bewertet | Die Distanzmatrix wird aus den vier Exponenten und der Kreistopologie automatisch generiert — kein manuelles Befüllen nötig. --- ## 9. Betroffene Komponenten | Komponente | Änderung | Umfang | |------------|----------|--------| | `config.py` | Sektor-Map, Synonym-Map, Kanon-Set, 4 Exponenten, Distanzmatrix | Neue Konstanten | | Perzeption-Prompt | 16+1 statt 20+ Emotionen | Prompt-Anpassung | | `enricher.py` → `_emotions_verlauf_berechnen()` | Potenz-Transformation nach Akkumulation (Schritt 4 ersetzt) | ~30 Zeilen | | `enricher.py` → `_emotion_zu_gruppe()` | Sektor-Lookup statt 3 Sets | ~5 Zeilen | | `enricher.py` → Emotion-Sets | `POSITIVE_EMOTIONEN`, `NEGATIVE_EMOTIONEN`, `NEUTRALE_EMOTIONEN` entfallen | Löschen | | `enricher.py` → `_modus_plausibilitaet()` | Passiv-negative über Sektor 5 statt `EI_PASSIV_NEGATIVE` Set | ~5 Zeilen | | `client/ui/emotionen_tab.py` | Oktagon statt Hexagon, Sektoren nach Plutchik, Arousal als Radius | QPainter-Umbau | | TEST0 Testfälle | Emotionsnamen auf kanonische Form anpassen | YAML-Dateien | ### Was sich NICHT ändert - Arousal-basierter Decay (Formel, `EI_AROUSAL_PERSISTENCE`) - Akkumulation gleicher Emotionen (Spacing Effect) - Vektor-Berechnung (9 Vektoren, 8-Turn-Fenster) - Turn-0-Prinzip (Perzeption als neuester Datenpunkt) - Ebbinghaus-Decay im LZG - Responder bekommt die feingranulare kanonische Emotion, nicht den Sektor --- ## 10. Wissenschaftliche Grundlagen | Quelle | Beitrag zu Novas Modell | |--------|------------------------| | Plutchik, R. (1980). *Emotion: A Psychoevolutionary Synthesis.* | 8 Primäremotionen, Kreisanordnung, Gegenpaare, Intensitätsringe | | Russell, J.A. (1980). *A Circumplex Model of Affect.* | Valenz × Arousal als zwei Achsen; bestätigt Plutchiks Distanzen | | Ekman, P. (1992). *An Argument for Basic Emotions.* | 6 Basisemotionen (zu negativ-lastig für Novas Zweck, aber Grundlage für die Reduktion von 20+ auf wenige Primärkategorien) | --- ## 11. Ausblick: Geometrische Vektor-Berechnung ### 11.1 Von Labels zu Geometrie Die aktuelle Vektor-Berechnung (`_emotions_vektor_bestimmen()`) vergleicht die dominante Emotions-Gruppe älterer und neuerer Turns und mappt den Übergang auf eines von 9 Labels. Das funktioniert, verliert aber Information: Die *Stärke* der Verschiebung ist unsichtbar. Das Oktagon mit Arousal als Radius bietet eine geometrische Alternative. Jede aktive Emotion hat eine Position auf dem Kreis (Sektorwinkel: Sektor × 45°) und eine Amplitude (Gewicht × Arousal als Radius). Der gewichtete Schwerpunkt aller aktiven Emotionen ergibt einen Punkt auf dem Radar. Zwei Schwerpunkte (ältere vs. neuere Turns) ergeben einen **Differenzvektor** mit Richtung und Länge. ``` Schwerpunkt_alt: Sektor 4 (Zuversicht), Radius 0.6 Schwerpunkt_neu: Sektor 5.5 (zwischen Trauer und Ärger), Radius 0.7 Vektor: Richtung = 4 → 5.5 = Absturz Länge = 0.73 = starke Verschiebung ``` ### 11.2 Labels als Winkelbereiche Die 9 bestehenden Vektor-Labels bilden sich als Winkelbereiche und Radius-Änderungen auf dem Kreis ab: | Verschiebung | Vektor | |-------------|--------| | Positiv → Negativ (Sektoren 1–4 → 5–8) | absturz | | Negativ → Positiv (5–8 → 1–4) | erholung | | Innerhalb negativ, Radius wächst | spirale | | Innerhalb positiv, Radius wächst | eskalation | | Gleiche Position, kaum Bewegung | plateau | | Negativ → Zentrum (Radius sinkt) | stabilisierung | | Positiv → Zentrum (Radius sinkt) | abkuehlung | | Zentrum → Negativ | einbruch | | Zentrum → Positiv | aufbluehen | ### 11.3 Vektorlänge als neues Signal Die **Länge** des Differenzvektors quantifiziert, wie dramatisch eine emotionale Verschiebung ist. Dieses Signal fehlt im aktuellen System: | Länge | Bedeutung | Responder-Signal | |-------|-----------|-----------------| | 0.0–0.2 | Kaum Bewegung | Sanfte Anpassung, Grundstimmung stabil | | 0.2–0.5 | Moderate Verschiebung | Spürbare Tonänderung | | 0.5–0.8 | Starke Verschiebung | Deutliche Reaktion | | > 0.8 | Emotionaler Schock | Alarm — unabhängig von der Richtung | **Emotionaler Schock:** Eine heftige Verschiebung ist in *jeder* Richtung ein Schock — nicht nur bei Abstürzen. Auch ein plötzlicher Sprung von Verzweiflung zu Begeisterung (Länge > 0.8) ist keine sanfte Erholung, sondern ein emotionaler Umschwung, der Aufmerksamkeit verdient. Der Responder sollte darauf reagieren: nicht mit Euphorie mitgehen, sondern den Umschwung wahrnehmen und dem Moment Raum geben. ### 11.4 Einordnung Die geometrische Vektor-Berechnung ist eine Verfeinerung, kein Ersatz. Voraussetzung ist das stabile Oktagon-Modell mit sektorabhängiger Normalisierung. Implementierungsreihenfolge: 1. ✅ Sektoren, 16 Emotionen, Distanzmatrix, Normalisierung (dieses Dokument) 2. 📋 Geometrische Schwerpunkt-Berechnung und Differenzvektor 3. 📋 Vektorlänge als Responder-Signal --- → EI-Konzept (Gesamtrahmen): novaberg-ei.md → Perzeption (erkennt Emotion + Arousal): novaberg-node-perception.md → Enricher (berechnet Verlauf + Normalisierung): novaberg-node-enricher.md → Arousal-basierter Decay: novaberg-pixie-decay.md, novaberg-ei-plutchik_l.md → Charakter-Profile (nutzt Emotions-Daten): novaberg-ei-character-profiles.md → Emotions-Vektoren (nutzt Gruppenlogik): novaberg-node-perception.md → Responder (nutzt Verlauf + Vektor): novaberg-node-responder.md