Ctrl K
ComunidadGuías…

docs/novaberg-bugs-archiv.md

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Novaberg — Bugs & Limitationen, Archiv

**Stand:** 19. September 2026, 19:17 UTC (`date -u`) — **das Archiv ist nach Gegenstand geteilt**: die 148 Einträge mit eigenem Abschnitt stehen in sechs Teilen `novaberg-bugs-archiv-<gegenstand>.md` nach ihrer Kategorie (GED 21, HGR 19, CHA 22, ANT 47, WIS 24, BAU 15); diese Datei behält Kopf, Formregel und die **81 Kurzeinträge** der alten Tabelle (gezählt 19.09.2026; der Absatz unten nennt 74 vom 30.08.2026). Das Findemittel `novaberg-bugs-index.md` führt jetzt offene und abgeschlossene Kennungen zusammen, 383 Zeilen; 9 Kennungen stehen als Kurzeintrag und als Abschnitt — die Tabellenzeile ist die Kurzfassung, der Index nennt sie einmal. Zeilenprobe gegen den Stand davor: fehlend 2 — die ersetzten Kopfzeilen *Stand* und *Inhalt*, deren Text hinter dem neuen Glied steht —, zusätzlich 144. Kein Eintrag ist inhaltlich oder im Zustand verändert. Davor 19. September 2026, 19:06 UTC — **jeder Eintrag mit eigenem Abschnitt trägt eine `**Kategorie:**`-Angabe** (die sechs Gegenstände des Backlogs), als Vorbereitung der Teilung nach Gegenstand. Davor 19. September 2026, 16:09 UTC — **`GV-FARBTON-SUBJEKTWECHSEL` aus dem Register übernommen** (behoben am 10.09.2026, Rest in der Fundliste). Davor 19. September 2026, 15:59 UTC — **`THEMENZEILEN-NUR-IM-INSERT-ZWEIG` aus dem Register übernommen** (behoben am 19.08.2026, stand dort ohne Überschrift). Davor 17. September 2026, 19:40 UTC — **`ENRICH-NULLTERM-IST-EINE-ZAHL` aufgenommen und behoben** (ein Paar ohne aktive Ziele verlor jeden Turn). Davor 17. September 2026, 10:58 UTC — **`PLANNER-ZEITWORT-UEBERSTIMMT-DIENSTWAHL` aus dem Register übernommen, behoben mit Scheibe 12 D1.** Davor 13. September 2026, 15:55 UTC — **Nachtrag an `LAGE-FORMPRUEFUNG-UNVOLLSTAENDIG` nach der zweiten Kontrolle**: Der Vergleichsschluessel der Form schrieb mit `lower`, die Datenbank mit `casefold`, und die Ansprueche des Frame-Aufloesers liefen an der Wertpruefung vorbei; beides behoben, 31 Zeugen, Suite 3663 gruen. Davor 15:11 UTC — **`LAGE-FORMPRUEFUNG-UNVOLLSTAENDIG` umgezogen**, am Tag nach seinem Befund: Die Formpruefung der Sachlage haelt jedes Objektfeld, auch die vorige Blase beim Laden; nach der Entscheidung des Eigentuemers ist eine Eigenschaft ohne Wert offen, nichts mit Aussage wird verworfen. 29 Zeugen, Suite 3656 gruen, im Labor 0 Abstuerze, zwei Betriebsturns durchgelaufen. Davor 12. September 2026, 23:22 UTC — **Nachtrag an `ZUORDNUNG-ANDERER-ABSENDER-FREMD`**: die Ausfallmeldung nennt ihre Kennungen, der Client gibt die Frage frei. Davor 22:54 UTC — **`ZUORDNUNG-ANDERER-ABSENDER-FREMD` neu und abgelegt**, am Tag seines Befundes: Eine offene Frage im Desktop-Client machte jede Antwort an einen anderen Absender zu `fremd`; 16 falsche Warnungen, gemessen am Server-Log, behoben und am echten Handler gegen HEAD nachgemessen. Davor 12. September 2026 — **`GV-LAENGE-RUNDUNG-ZUR-GERADEN` umgezogen**, am Tag seiner Behebung: `_vektor_laenge_berechnen` rundet zur naechsten statt zur geraden Zahl, 68 von 1434 Rohturns gewinnen einen Schritt, die Quote des Strategie-Tors bleibt bei 36,6 %. Davor 11. September 2026 — `PIXIE-PAUSE-OHNE-ZUSTELLRIEGEL` am Tag seines Befundes behoben und abgelegt: Der Pausenschalter hielt den Erzeuger an und nicht die Auslieferung; bei bestaetigtem `paused: true` liefen fuenf Zustellungen durch und ein vollstaendiger Fremdturn mitten in einer Messreihe. Danach 0 Fremdturns in 20 Turns. Davor 9. September 2026 — `GRAVITATIONSTERM-OHNE-OBERGRENZE` am Tag seines Befundes behoben und abgelegt
**Inhalt, seit 19.09.2026 in sechs Teilen** ([Wo die Eintraege stehen](#wo-die-eintraege-stehen--seit-dem-19092026)): **148 abgeschlossene Eintraege mit eigenem Abschnitt**, `[gemessen]` 19.09.2026 mit `grep -cE '^#{3,4} (`|[A-Za-z0-9-]*[A-Z0-9][A-Z0-9][A-Za-z0-9-]* )'` (die Zählvorschrift erfasst auch die Einträge unter den alten Herkunftsabschnitten und zwei Kennungen mit Kleinbuchstaben); davor **60** (30.08.2026, ohne angegebene Zählweise — woher der Unterschied kommt, ist nicht untersucht) (56 + `PLANNER-ZEITWORT-UEBERSTIMMT-DIENSTWAHL` und `ENRICH-NULLTERM-IST-EINE-ZAHL` am 17.09.2026 + `THEMENZEILEN-NUR-IM-INSERT-ZWEIG` und `GV-FARBTON-SUBJEKTWECHSEL` am 19.09.2026) plus **74 historische Kurzeintraege in Tabellenform** — behoben, geschlossen, gegenstandslos oder verworfen. `[gemessen]` 30.08.2026. **Die frueheren 123 waren die Summe beider Formen**, ohne dass der Kopf das sagte; deshalb stehen sie jetzt getrennt.

> **Die Formregel vom 30.08.2026** (`novaberg-bugs.md`, Abschnitt *Die Form eines Eintrags*) verlangt
> fuer jeden Eintrag einen eigenen Abschnitt. **Der Bestand hier wird dafuer nicht umgebaut:** Bei den
> 74 Kurzeintraegen aus frueher Zeit steht der Befund in der Tabellenzeile und sonst nirgends — sie
> auszuformulieren hiesse, Belege zu erfinden. Die Regel gilt fuer neue Eintraege und fuer jeden, der
> ohnehin angefasst wird.
**Das offene Register:** [`novaberg-bugs.md`](novaberg-bugs.md)

---

## Wo die Eintraege stehen — seit dem 19.09.2026

**Diese Datei traegt keine Eintraege mit eigenem Abschnitt mehr.** Die abgeschlossenen Defekte stehen nach Gegenstand in sechs Teilen, wie das offene Register; jeder Eintrag traegt eine Kategorie, und die Datei, in der er steht, folgt ihr. Hier bleiben Kopf, Formregel und die 81 Kurzeintraege der alten Tabelle (Abschnitt *Behobene Bugs*). Gesucht wird im Findemittel [`novaberg-bugs-index.md`](novaberg-bugs-index.md), das offene und abgeschlossene Kennungen zusammen fuehrt.

| Gegenstand | Datei | Eintraege |
|---|---|---|
| Gedächtnis (`GED`) — KZG, LZG, Promotion, Entitäten, Salienz, Verfall | [`novaberg-bugs-archiv-gedaechtnis.md`](novaberg-bugs-archiv-gedaechtnis.md) | 24 |
| Hintergrund (`HGR`) — Pixie, Queue, Agenten, Recherche, Zustellung | [`novaberg-bugs-archiv-hintergrund.md`](novaberg-bugs-archiv-hintergrund.md) | 19 |
| Charakter (`CHA`) — Profile, Räder, Haltung, Emotion, Destillation | [`novaberg-bugs-archiv-charakter.md`](novaberg-bugs-archiv-charakter.md) | 22 |
| Antwortpfad (`ANT`) — Gesprächsvektor, Responder, Verfasser, Prompts | [`novaberg-bugs-archiv-antwortpfad.md`](novaberg-bugs-archiv-antwortpfad.md) | 47 |
| Wissen (`WIS`) — Bibliothek, Dateien, Notizen, Timeline, Fakten | [`novaberg-bugs-archiv-wissen.md`](novaberg-bugs-archiv-wissen.md) | 24 |
| Bauart (`BAU`) — Code, Schema, Werkzeug, Tests, Doku, Register | [`novaberg-bugs-archiv-bauart.md`](novaberg-bugs-archiv-bauart.md) | 15 |

---

## Wozu diese Datei

**Ein behobener Defekt bleibt mit Vermerk stehen — er erklaert, warum der Code so aussieht.** Er muss dafuer nicht in derselben Datei stehen wie die offene Arbeit: Die Kennung ist die Klammer zwischen Featureliste und Register, und sie ist ein Grep.

**Getrennt wurde, weil die Last gemessen war.** Das ungeteilte Register trug 558 kB und rund 113.000 Token — zusammen mit Backlog und Chronik 1,8 MB und rund 378.000 Token. Eine Datei dieser Groesse wird nicht mehr am Stueck gelesen, sondern nur noch durchsucht, und der Zustand ihrer Eintraege altert genau daran: Am 25.08.2026 waren von 116 seit ihrem Befund nicht mehr nachgeprueften offenen Eintraegen **23 nicht mehr offen**. Nach der Teilung traegt das offene Register 289 kB.

**Die Abschnittsueberschriften stammen aus der Quelldatei** und sagen, *wann und wobei* ein Eintrag entstanden ist — nicht, welchen Zustand er hat. Jeder Eintrag hier ist abgeschlossen; ein Abschnitt namens `## Offene Bugs` beschreibt in dieser Datei nur die Herkunft seiner Eintraege.

**Hier wird nicht gearbeitet.** Wer einen dieser Befunde wieder aufmachen muss, verschiebt den Eintrag zurueck nach `novaberg-bugs.md` — mit neuem Zustand und neuem Datum. Eine Kennung wird nie wiederverwendet und steht nie in beiden Dateien.

---

## 20.08.2026 — aus der Klassifikation der Fundliste

**70 Eintraege sind aus `novaberg-fundliste.md` hierher gewandert** und haben eine stabile Kennung bekommen. Die Fundliste ist roh und vergaenglich; wer einen Defekt sucht, sucht ihn hier.

> **Der Umzug uebertraegt den Wortlaut, er prueft ihn nicht.** Jeder Befund ist die Diagnose seines Tages — das Datum steht an jedem Eintrag, und die Pflicht, ihn vor der Umsetzung gegen den heutigen Code zu halten, gilt unveraendert. Wer das ueberspringt, baut gegen einen Zustand, den es nicht mehr gibt.

**Die Zeile `Geschlossen, wenn` ist neu und stammt nicht aus der Fundliste.** Sie sagt, woran der Abschluss erkennbar waere — ohne sie ist ein Eintrag nicht abschliessbar, sondern nur ablegbar.

### Der Durchgang vom 20.08.2026 — alle 70 gegen den Code gehalten

**Am 20.08.2026 ist jeder der 70 Eintraege gegen HEAD `00c16b6` geprueft worden**, bevor irgendeiner von ihnen einen Rang bekommt. Das Ergebnis steht je Eintrag in einer eigenen Zeile `**Zustand:**` unmittelbar unter der Ueberschrift:

| Zustand | Zahl | Was er sagt |
|---|---|---|
| `offen` | 50 | der Befund steht, mit der Stelle im heutigen Code als Beleg |
| `offen, unbelegt` | 8 | der Code hat sich nicht bewegt, aber die Aussage haengt an einer Messung, die seit dem Befund niemand wiederholt hat |
| `behoben` | 12 | der Befund ist erledigt, mit Beleg — der Eintrag bleibt stehen und erklaert, warum der Code so aussieht |

**Die zwoelf erledigten sind nicht nebenbei erledigt worden**, sondern von Auftraegen, die sie nicht kannten: **vier** am Responder-Prompt, zwei am Haltungsraum, zwei an der Bibliothek, zwei in der Doku, einer am Etikett des eigenen Gedankens und einer am Router-Prompt. Das ist der Grund fuer diesen Durchgang — **ein Register, das nicht gegen den Code gehalten wird, sammelt Befunde, die es laengst nicht mehr gibt.**

**Drei Zahlen des Bestandes haben sich seit ihrem Befund bewegt** und stehen jetzt am Eintrag: die Schichtimporte von 39 auf **52**, die leeren EVA-Sektionen von 25 auf **36** (gemessen mit derselben Pruefung; die 20 des Befundes sind anders gezaehlt), die Loeschregeln von 3/3/2 auf **4/3/2**.

> **Warum der Zustand an genau einer Stelle steht.** `BUGREGISTER-ZUSTAND-NICHT-LESBAR` (Backlog) hielt fest, dass jede Zahl ueber offene Defekte eine Schaetzung ist, solange der Zustand nirgends steht. Die Zeile unter der Ueberschrift ist die Antwort darauf: **ein Ort je Eintrag, ein festes Vokabular, mit `grep` zaehlbar.** Sie traegt Datum und HEAD, gegen den geprueft wurde — ohne beides ist ein *offen* von einem *war einmal offen* nicht zu unterscheiden.

---

## Behobene Bugs

| # | Problem | Lösung | Behoben in |
|---|---------|--------|-----------|
| ENDPUNKT-STATUS-UNEINHEITLICH | Beide Chat-Endpunkte gaben in der Bestätigung von Pfad 1 einen **verschiedenen `status`** zurück — `processing` im synchronen, `event_created` im streamenden. Gelesen hat den Wert niemand: Der Client reagiert auf den SSE-Ereignistyp, nicht auf das Feld. Zwei Werte für dieselbe Aussage, die auseinanderliefen, weil beide Endpunkte die Nutzlast getrennt bauten. *Beim Zusammenführen der Nutzlast in Chat 124 auf `processing` vereinheitlicht.* | Beim Zusammenfuehren der Nutzlast auf `processing` vereinheitlicht | Chat 124 |
| VEKTOR-INTENSITAET-NAMENSMENGE | **Ein hoffnungsvolles Wort konnte einen Krisenmarker auslösen.** Was `negativ→negativ` zu `spirale` und `positiv→positiv` zu `eskalation` macht, war in `_emotions_vektor_bestimmen` die Bedingung „eine Emotion, die vorher nicht vorkam". Sie verglich **Namen** und nicht Gruppen, und die Größe, für die sie ein Stellvertreter war, lag die ganze Zeit im selben Turn-Dict: `arousal`. **Reproduktionsweg:** Die Folge `freude, wut, hoffnung, wut` ergab `spirale`, ausgelöst von `hoffnung`; `freude, freude, wut, freude` ergab `eskalation`, ausgelöst von `wut`. Über den vollständig ausgezählten Eingaberaum betraf das **12,0 %** der `spirale`- und **18,2 %** der `eskalation`-Fälle. **Warum es teuer war:** `spirale` ist einer der beiden Krisenmarker — bei Erregung ab 0,7 setzt `_ist_krise` die Vektorlänge auf 0 und `aufnahmebereitschaft_berechnen` die Bereitschaft auf exakt 0,00, den Wert, der der Krise vorbehalten ist. **`config.py` sagte schon vorher etwas anderes:** Der Kanon führt `spirale` als „negativ -> negativ, mit neuen **negativen** Gefuehlen". Code und Festlegung waren auseinandergelaufen. | Der Anstieg wird an der **mittleren Erregung** der beiden Fensterhälften gemessen (`GV_VEKTOR_INTENSITAET_SCHWELLE = 0,10`, abgeleitet aus dem Zehntelraster der Perzeption und 769 gemessenen Fenstern). Der Namensvergleich bleibt als benannter Rückfall für Fenster ohne Erregung und ist dort auf die Gruppe des Übergangs verengt; über 849 Bestands-Turns lief er **0 Mal**. Gerundet wird **vor** dem Vergleich: `0.6 - 0.5` ergibt 0.09999999999999998, und weil Arousal in Zehnteln kommt, wäre der Grenzfall der Normalfall gewesen. Am Bestand nachgespielt: `eskalation` 151 → 67, `spirale` 44 → 20, die sieben Vektoren über Gruppengrenzen ±0. Gegenprobe: Verengung heraus → 1 rot; Rundung heraus → 1 rot | Chat 133 |
| VEKTOR-PLATEAU-OHNE-GRUNDLAGE | **`plateau` trug vier Bedeutungen, und eine davon war „keine Aussage".** Der Name entstand aus einem gemessenen Gleichstand zweier neutraler Hälften, aus zwei gleichen Gruppen ohne Anstieg — **und aus weniger als zwei verwertbaren Turns**. Der vierte Fall ist keine Richtung, sondern das Fehlen ihrer Grundlage, und er trug keine Marke; über `GV_RICHTUNG_MAP` fiel er wie die drei anderen auf Achse R = 0. **Zu Beginn eines Paars ist er der Regelfall und nicht die Ausnahme:** Novas Vektor rechnet über die `assistant`-Turns, und im ersten Turn gibt es keinen. Dieselbe Klasse wie die Landschafts-Ablesung vor `F-LAGE-1`. **Gegenstück im selben Achsensatz:** Die Initiative benennt jedes fehlende Maß in `Fuehrung.fehlend`, Achse V ihre Emotion in `valenz_quelle` — R war die einzige der sechs ohne Herkunftsangabe. | Die Richtung trägt ihre Grundlage als `Stimmungsvektor.quelle` und reist als `richtung_quelle` in dieselbe Protokollzeile wie das Ergebnis: `gemessen`, `gleichstand`, `zu_wenig_turns`, `nicht_gesetzt`. Der Wert bleibt unverändert — zählbar ist ab jetzt, worauf er beruht. Über 849 Bestands-Turns: `gemessen` 51,1 %, `gleichstand` 46,5 %, `zu_wenig_turns` 2,4 %. `nicht_gesetzt` deckt auch den Rückfall in `achsen_berechnen` ab, wo ein leerer Vektor zu `plateau` wird. Festlegung `F-LAGE-3`. Gegenprobe: 2 bzw. 3 rot | Chat 133 |
| HALTUNG-NAHT-OHNE-ABBILDUNG | **Die Naht zwischen Landschaft und Zuwendungsrad verließ an den Enden in 62 von 62 Zellen die Spanne.** `haltung_berechnen()` verrechnete den Cluster-Grundwert additiv mit der Radsumme (`grund + summe`). Der Grundwert liegt in [0,1], die Radsumme hat eine eigene, nirgends benannte Spanne — aus `SPEICHEN_BEITRAG` gerechnet: `umfang` −1,00…+0,80 · `fragen` −0,90…+0,70 · `naehe` −1,20…+0,50 · `waerme` −1,50…+0,50 · `draengen` −0,50…+1,20. Über die volle Charakterspanne verließ **jede** der 62 Nicht-Grenz-Zellen [0,1]; `feuerwerk/draengen` erreichte 1,90. **Die bekannte Angabe „10 von 14 Landschaften laufen über" war am Mittelwert erhoben** und unterschätzte den Fall. Auch die im Konzept vorgesehene Sättigungsformel war ohne Normierung nicht geschlossen. | Sättigung **plus Normierung**, der Abbildungsfaktor aus der Beitragstabelle abgeleitet statt gesetzt, damit er mit ihr mitwandert. Nicht gekappt — Kappen macht aus zwei verschiedenen Lagen dieselbe Zahl und erzeugt genau die toten Enden, die der Raum nicht haben darf. Ergebnis: 62 von 62 außerhalb → **0 von 70**, bei gemessenem wie bei vollem Rad, ordnungserhaltend. Festlegung `F-NAHT-1`. Elf Tests waren dabei rot, und das war die Spezifikation | Chat 132 |
| CLIENT-EINGABESPERRE-OHNE-RUECKWEG | **Blieb die Antwort aus, blieb der Client gesperrt — unbegrenzt.** `_send_current_input` sperrt die Eingabe; freigegeben wird sie ausschließlich von `_handle_answer` (eine `character_response`) oder `_handle_error` (ein SSE-Fehler). **Ein Impuls gibt nicht frei** — er zeigt eine Bubble und lässt die Sperre stehen, für den Nutzer also eine Antwort, nach der er trotzdem nicht schreiben kann. Ein Timeout oder Wächter existierte nicht; `_handle_done` ließ bei offener Erwartung ausdrücklich gesperrt. **Das ist die dritte Stufe des Leer-Defekts** und war in keinem der drei Einträge dazu benannt: Nicht nur ist der Turn weg und die nächste Antwort falsch zugeordnet — die Oberfläche ist danach unbenutzbar, bis irgendeine `character_response` eintrifft oder der Client neu startet. Am 01.08.2026 beim Nutzer eingetreten. | Beide Sperren gefallen — die sichtbare und der stille Riegel, der eine zweite Äußerung nur mit einer Logzeile verwarf. Der Endpunkt bestätigt in Millisekunden, und was während eines Turns eintrifft, trägt die Eingangs-Queue | Chat 124 |
| OLLAMA-THINKING-NULL | **Jeder Turn endete in einem `TypeError`, der Client zeigte nur noch „Fehler:".** `nachricht.get("thinking", "")` in `services/llm_provider.py` sieht aus wie eine Absicherung gegen ein fehlendes Feld, ist aber keine gegen ein gesetztes: Ein Default in `.get` greift bei **abwesendem** Schlüssel, nie bei einem Schlüssel mit Wert `None`. Ollama lässt das Feld nicht weg, es sendet `"thinking": null`. Also kam `None` durch, traf die am selben Tag ergänzte Typprüfung und löste sie aus. **Reproduktionsweg:** Eine Ollama-Antwort mit `{"message": {"content": "…", "thinking": None}}` durch `OllamaProvider.chat` schicken. **Warum 16 Tests grün blieben:** Die Attrappe konnte den Fall nicht bilden — sie bildete `thinking=None` auf einen **weggelassenen** Schlüssel ab und damit genau die Unterscheidung weg, an der der Code scheiterte. | `None` und fehlender Schlüssel werden ausdrücklich auf denselben Leerfall abgebildet; jeder andere falsche Typ kracht weiterhin laut mit genanntem Typ. Die Attrappe bekommt mit `THINKING_NULL` einen eigenen Ausdruck für „Schlüssel gesetzt, Wert null", dazu zwei Tests: der Leerfall und der positive Zwilling, der beide Schreibweisen gegeneinander hält. Gegenprobe: Fix heraus → beide neu rot | Chat 119 |
| KALIBRIER-INTENTIONEN-UNGEPARST | Der Kalibrier-Korpus splittete das Feld `intentionen` des KZG-Hash an Kommas, obwohl es mit `json.dumps` geschrieben wird. Aus `["reflexion", "information_teilen"]` wurden Bruchstücke mit Klammer und Anführungszeichen, die `GV_INITIATIVE_FUEHREND` nie treffen — und weil die Liste dabei **nicht leer** war, galt M1 als „nicht führend" statt als „fehlend": ein harter Beitrag von −1.0 in jedem Turn. **0 von 144 Turns** trugen eine führende Intention, geparst **40 von 99**. Der Korpus reproduzierte damit nie die Achse, die sein Docstring zusagt. **Reproduktionsweg:** `HGET kzg:<user>:<char>:<ts> intentionen` liefert eine JSON-Liste; `_intentionen_laden` gab daraus `['["reflexion"', '"information_teilen"]']` zurück. Der Live-Pfad war nie betroffen — er liest die Intentionen aus den Session-Turns, wo sie als echte Liste liegen. **Folge:** zwei widerlegte Befunde, siehe `novaberg-lesson_l_teilmenge-verdeckt-muell.md` §6. | `json.loads` statt `split(",")`; ein vorhandenes, aber unlesbares Feld gilt laut gemeldet als *fehlend* statt als *nicht führend*; sechs Tests, darunter die Zusicherung, dass eine führende Intention nach dem Lesen `GV_INITIATIVE_FUEHREND` trifft. Gegenprobe mit dem alten Split: 3 rot | Chat 117 |
| P5 | Doppelspeicherung Notiz + Fakt | Guard: `if facts and not planner_aktiv` | Chat 11 |
| P6 | Doppelspeicherung Timeline | Guard: `if temporal_fact and not planner_aktiv` | Chat 11 |
| P7 | Timezone in Lesepfaden (Nova sagt "13:00" statt "14:00") | Timezone-Konvertierung im Repository zentralisiert | Chat 11 |
| P7b | Range-Query in falscher Timezone | Range-Grenzen in lokaler Zeit, Repository konvertiert | Chat 11 |
| O1–O18 | Etappe 1–4 Fixes | Diverse | Chats 8–11 |
| O17a–e | Planner, Router, FaktenManager, Entity Resolution | Diverse | Chat 11 |
| P8 | Uhrzeit bei Verschieben verloren ("Freitag" → 00:00 statt 14:00) | ZeitVektor + Referenz-Modus + Zwei-Phasen-Parsing | Chat 14 |
| SYS1 | System-Prompt "hilfreicher KI-Assistent" überschrieb echten Prompt | Default in models.py auf minimalen Prompt geändert | Chat 20 |
| STATE1 | nova_kern/nova_beziehung fehlten im ConversationState TypedDict | Felder in state.py ergänzt | Chat 20 |
| AGT-FIX1 | `callable \| None` Type-Error in `agents/__init__.py` | `Callable` aus `typing` importiert | Chat 22 |
| AGT-FIX2 | Intent-Mismatch: Planner prüfte `intent == "notizen_management"` | Agent-Check nach Manager-Auflösung statt Intent-Check | Chat 22 |
| AGT-FIX3 | Endlosschleife Planner ↔ Agent-Dispatch (Recursion Limit 25) | Schleifen-Schutz: `bereits_gelaufen`-Dict aus `agent_results` | Chat 22 |
| AGT-FIX4 | Bidirektionale Suche fehlte: "Einkaufsliste" fand "Einkauf" nicht | Dreistufige Suche: Stichwort → bidirektionales LIKE → Volltext | Chat 22 |
| AGT-FIX5 | Delete setzte nur `aktiv = FALSE`, nicht `status = 'archiviert'` | Beide Felder im UPDATE synchron setzen | Chat 22 |
| AGT-FIX6 | `_bestaetigen` überschrieb Rückfrage-Status blind auf `abgeschlossen` | Prüft aktuellen Status, lässt `rueckfrage`/`fehler` stehen | Chat 22 |
| AGT1 | Rückfrage-Kette nicht funktional | PFLICHT-RÜCKFRAGE Block + Redis-Pending Resume-Flow | Chat 23 |
| AGT2 | LLM verändert Notiz-Namen | management_target als Name + pg_trgm Fuzzy-Suche | Chat 23 |
| AGT3 | Responder halluziniert bei Agent-Erfolg ("doppelt erstellt") | Kontext-Schnitt: memory_context + web_context bei Agent-Erfolg weglassen | Chat 23 |
| ROUTE1 | Router halluziniert management_target | Neue Regel: Target muss aus Wortlaut kommen | Chat 23 |
| ROUTE2 | "Setz X mit drauf" nicht als Management erkannt | 5 neue Trigger-Beispiele + 6 neue Verben | Chat 23 |
| AGT-FIX4b | LIKE-Suche versagte bei deutschen Komposita | pg_trgm Extension + kumulative Suche | Chat 23 |
| AGT5 | Update schreibt rohen Prompt als Notiz-Inhalt | Update-Prompt geschärft: 3-Schritt-Anweisung | Chat 25 |
| AGT7 | Router klassifiziert Inhalts-Operationen als Notiz-Delete | AGT6: Aktionsklassifikation im Agent | Chat 26 |
| PROMPT2 | Turn-Nummerierung leakt in Output ([Turn 2/2]) | JSON-Transport (Chat 25), dann Textblock-Format (Chat 30) | Chat 25/30 |
| RESP-TIMELINE1 | Responder halluziniert bei Timeline-Delete | Strukturierte Kontextualisierung + Session-Turns zurück | Chat 27 |
| KZG-REDIS1 | Vektorsuche liefert 0 Ergebnisse im KZG-Agent | `config.redis_client` (Raw-Client) statt `redis_manager.client` | Chat 29 |
| PROMPT1 | Interne Salienz-Tags in Session-Turns und Antwort | Enricher reicht Originaltext durch (Wurzel-Fix) + `_strip_salienz_tags()` als Sicherheitsnetz | Chat 30 |
| JSON-LEAK | Responder gibt JSON statt Text aus (ab Turn ~9) | Session-Turns als Textblock statt separate JSON-Messages, [DATENFORMAT]-Block entfernt | Chat 30 |
| SNAPSHOT1 | Test-Runner Backup-Tabellen driften bei Schema-Änderungen ab | DROP+CREATE statt CREATE IF NOT EXISTS | Chat 30 |
| SIEZ1 | Sporadischer Siez-Bruch (Cocktail-Problem) | Persona-Isolation: Eigene user_id + handgeschriebene Charakter-Hashes pro Test-Persona | Chat 31 |
| HALL1 | Responder halluziniert Recherche-Ergebnisse (Fonds-Namen, Headhunter) | DelegationsAgent (VENT1): PostgreSQL-Akten + Beruhigungs-Signal. Yin-Yang-Prinzip — Umleitung statt Unterdrückung | Chat 32 |
| PAPAGEI1 | Halluzinierte Inhalte in Papagei-Schleife (7/9 Turns) | Folge-Bug von HALL1 — durch VENT1 mitgelöst | Chat 32 |
| TAG-LEAK2 | Interne Block-Tags ([AKTION]) in der Antwort | Folge-Bug von HALL1 — durch VENT1 mitgelöst | Chat 32 |
| RECH1 | Token-Budget bei Iteration — `alle_ergebnisse` akkumuliert Rohtexte, sprengt CPU-Kontext | Zwischen-Destillation nach jeder Suchrunde. Neue Funktion `zwischen_destillieren()` komprimiert auf ~~~2000 Tokens~~ — **die Zahl hat nie gehalten:** kein `max_output_tokens` uebergeben, `num_predict` blieb ungesetzt, gemessen am 16.08.2026 bis 4176 Ausgabe-Token bei einem Median von 1330. Seither greift eine Obergrenze, siehe `novaberg-pixie-research.md` §5 und §7. Bewertung bekommt Zusammenfassung statt Rohtexte. | Chat 36+37 |
| PRIO0 | Queue-Einträge mit Priorität 0.00 — Queue-Agenten werden nie abgeholt | `shadow_queue_push()` bekam `prioritaet` nie übergeben. Fix: `prioritaet=neue_salienz` in `queues.py`, Type-Hint `int` → `float` in `utils.py`. | Chat 37 |
| STREAM1 | `event_generator()` crasht bei `chunk.items()` + `agent_results` als Dict statt List | Doppel-Fix: 1. `isinstance(chunk, dict)`-Guard vor `.items()`. 2. SSE-Builder iteriert über Liste mit isinstance-Check für Dataclass vs. Dict. | Chat 39 |
| ZEIT1 | Monat/Tag vertauscht bei "morgen um HH:MM Uhr" — Block 2 matchte "00" aus "08:00 Uhr" als Stunde | Block 1b: HH:MM vor "Uhr" bereinigen. Block 2: `(?<!:)` Lookbehind. | Chat 41 |
| ZEIT2 | Fuzzy-Korrektur: "Montag" → "Sonntag" (Levenshtein-Distanz 2) | Early-Out: `if wort_lower in _ALLE_WOERTER: continue` | Chat 41 |
| REDIS-PERSIST | Redis schrieb nach `/var/lib/redis-stack` statt ins Volume `/data` | `--dir /data` im Redis-Command | Chat 41 |
| KONTEXT1 | Aktions-Kontamination in Session-Turns | Zwei Flags (aktion_erledigt + aktion_erfolgreich), [ERLEDIGT]/[FEHLGESCHLAGEN]-Marker in Turn-Formatierung. Rückfragen nicht markiert. | Chat 43 |
| RESP2 | Responder ignoriert Agent-Read-Ergebnis (Direktiven) | Aufgelöst durch KONTEXT1-Marker + Resume-Bug-Fix + saubere Session-Verwaltung. Kein direkter Responder-Fix nötig. | Chat 43 |
| RESP3 | KZG-Kontamination bei Agent-Read | Aufgelöst durch KONTEXT1-Marker + Resume-Bug-Fix + saubere Session-Verwaltung. Kein direkter Responder-Fix nötig. | Chat 43 |
| DELEG-REG | DelegationsAgent nicht in Registry | Doppeltes Präfix `DELEGATION_DELEGATION_SIMILARITY_SCHWELLE` in `deduplizierung.py`. Korrekt: `DELEGATION_SIMILARITY_SCHWELLE`. Ursache: Config-Zentralisierung Chat 34. | Chat 44 |
| RESP-CHAR1 | Base-Charakter-Prompt fehlte im Responder → Leblosigkeit | nova_kern/nova_beziehung in [IDENTITAET] konsolidiert, [CHARAKTER]-Block entfernt, Destillation für nova gefixt | Chat 45 |
| ROUTE-CHAR1 | Router klassifiziert rhetorische Charakter-Bemerkungen als Management-Befehl | CLASSIFY-REJECTED: Classify fängt rhetorische Fragen/Komplimente mit action="rejected" ab, Dispatch gibt AgentResult ohne Inhalt zurück | Chat 48 |
| CLASSIFY-CONFIRM | Bestätigung/Erinnerung ("Vergiss das frech sein nicht") wird als Update klassifiziert | Ergänzungen in `classify_charakter.task.txt`: neue Regel im VORPRUEFUNG-Block + zwei Beispiele. Bestätigt durch Live-Tests (Tests 1–3 grün, Regressions-Test "Sei nicht mehr das kleine Mädchen" → update bleibt). | Chat 49 |
| RESUME-REJECT | Resume-Node für CharakterIdentitaetAgent: `resume.py` mit Strategy-Hook, Routing in `agent.py`. Vier Live-Tests bestanden (replace/update/delete Ablehnung + update Bestätigung). | Chat 50 |
| HALL2-Reject | Status "dismissed" + Prompt-Block responder.aufgabe_verworfen | Chat 54 |
| SEARX1 | SearXNG Engines timen aus — transient, kein Code-Fix nötig. Code prüft korrekt `len(results)` statt `number_of_results`. | Chat 57 |
| E.1 KZG-INDEX | RediSearch-Index fehlten 6 Felder (`arousal`, `emotions_vektor`, `sprach_stil`, `tone`, `emotion`, `modus`). Werte wurden geschrieben, aber nicht indiziert — Filter lieferten 0 Treffer. Index um die Felder erweitert. | Chat 62 |
| E.2 KZG-VERST | KZG-Verstaerkung aktualisierte `emotion` und `modus` nicht — Eintrag blieb auf dem Erst-Wert festgenagelt. Beide Felder werden jetzt mit jedem Verstaerkungs-Schreiben nachgezogen. | Chat 62 |
| E.3 SALIENZ-LEER | Salienz im HumanGraph las eine leere LLM-Response (Token-Limit, JSON-Abbruch) ohne Fallback. Folge: kein KZG-Eintrag, obwohl salienter Turn. Fix: leere/truncated Response abfangen und Salienz-Default setzen. | Chat 62 |
| KZG-KERN-BLIND | Verstärkung aktualisierte Scores aber nicht den Kern — Promotion bekam unreife Version | Obsolet: Keine Merge-Verstärkung mehr. Jeder Eintrag behält seinen originalen Kern. Thematische Verstärkung boosted nur Metadaten (Salienz, Häufigkeit, TTL). Cluster-Promotion destilliert alle Kerne bei der Zusammenführung. | Chat 64 |
| KZG-DEDUP | 8 KZG-Einträge statt 1 bei Lumi-Gespräch | Re-framed als Feature: Verschiedene Facetten desselben Themas werden als eigenständige Einträge behalten. Die Cluster-Promotion sammelt sie ein und destilliert sie zu einem kohärenten LZG-Eintrag. | Chat 64 |
| ROUTE-CHAR-NOTIZ | CharacterGraph-Router dispatched Konversation an NotizenAgent | Genereller Dispatch-Guard in router.task.txt + Notizen-Plugin-Regel verschärft. Verifikation ausstehend. | Chat 65 |
| WS-SINGLE | WebSocket verdrängt bestehende Verbindung — Dict erlaubte nur einen Slot pro User | `aktive_verbindungen` auf `dict[str, list[ClientConnection]]` mit `ClientConnection`-Dataclass. `broadcast()`/`broadcast_threadsafe()` mit `character_id`-Filterung und `exclude_client`. User-Message-Broadcast über alle Clients. 12 Dateien. | Chat 68 |
| CAIRO-PHANTOM | Phantom-Linien zwischen Goal-Indikatoren im Gravitationsgraph | `cr.new_sub_path()` vor jedem `cr.arc()` — Cairo zieht impliziten `line_to(arc_start)` vom Current Point nach `show_text()` | Chat 69 |
| MODUS-LEER | `gespraechs_modus` im GV-Node immer leer (Tiefe-Achse + Neugier-Modus-Faktor falsch). `enricher.py:98` überschreibt bedingungslos mit leerem `letzter_modus` aus Redis-Session, Dispatcher schreibt leeren Wert zurück → selbstverewigender Bug | Guard `if letzter_modus:` in enricher.py | Chat 72 |
| VEKTOR-LEER | `emotions_vektor` im GV-Node immer leer (Richtungs-Achse 0, Drive 0.0). HumanGraph berechnet korrekt, aber `chat.py` hängt Feld nicht ans Event-Payload, `event_consumer.py` listet es nicht in `perzeption_felder` | `emotions_vektor` in chat.py (Payload) + event_consumer.py (perzeption_felder) ergänzt | Chat 72 |
| AROUSAL-330 | Novas Arousal in `[EIGENE_EMOTION]` zeigt 330% statt max 100%. LLM-Halluzination (`"arousal": 3.3`) im Salienz-Node → ungekappt in KZG persistiert → Gravitations-Aktivierung injiziert korrupten Wert in Nova-Verlauf bei jeder Aktivierung erneut | 3× Defense-in-Depth: (1) `berechnung.py:84` universal-Cap beim Lesen, (2) `salience.py:174` Cap nach LLM-JSON-Parse, (3) `kzg.py:278` Cap beim Schreiben | Chat 72 |
| ZIEL-LABEL-LEER | Gravitationsgraph-Panel: manche Ziel-Knoten ohne Beschriftung. DB-Spalte `ziele.thema` existierte, aber kein Code-Pfad hat sie je gesetzt — Labels nur manuell per SQL eingetragen | Architektonisch: `thema` bei Ziel-Destillation via LLM generiert (CharakterAgent + RechercheAgent). Fallback `_kurzlabel_aus_zielsatz` im Endpoint für Altbestand | Chat 72 |
| AROUSAL-367 | Gravitations-Injektor schrieb arousal * gravitation ungecappt in Novas Verlauf → a=3.67 | 4. Defense-in-Depth Cap: `min(1.0, ...)` an 2 Stellen in `ei/gravitation.py` | Chat 73 |
| CHAR-HASH-FILTER | `_kzg_laden()` filterte nicht nach beobachter → Profil-Mischperspektive | `beobachter_filter`-Parameter, invoke() setzt Perspektive + 20 Altdaten migriert | Chat 73 |
| urllib3-RETRY | Client-urllib3 machte automatischen Retry → Doppel-Turns | `HTTPAdapter(max_retries=0)` in `stream_handler.py` | Chat 65 (verifiziert Chat 73) |
| IMPULS-KOPIE | GV-VORSCHLAG war fertiger Satz, Responder kopierte 1:1 | VORSCHLAG→IMPULS: Richtungsangabe statt Text, Leitgedanke im Prompt | Chat 73 |
| THINK-MEM-CONFLICT | `[VERARBEITUNG]`-Block im Thinker-Reasoning-Input, Helper `format_success_lines` in `graph/format/agent_results.py`, Reasoning-Regel in `thinker.rules.txt` | Chat 79 |
| CHAR-LZG-LEAK | `beobachter`- und `character_id`-Filter in `_lzg_kern_laden`, `_lzg_intentionen_laden`, `_lzg_emotionen_laden`. LZG-Lookup ueber kanonisches Paar statt `subjekt_user_id` | Chat 79 |
| MIGRATION-PIX-PAIR | IDs getauscht in `nova_gedaechtnis.py`: `user_id=gegenueber_id, character_id=ASSISTANT_USER_ID`. Pre-Chat-60-Kommentar ersetzt | Chat 79 |
| MIGRATION-AGENTGRAPH-PAIR | `shadow_delivery.py`: `user_id` des menschlichen Users durchgereicht, `ei_calc_rolle="character"` explizit gesetzt. GraphBase-Default unangetastet (Option B) | Chat 79 |
| ECHO-BUG | Reducer-Umbau (STRUCT-1 bis STRUCT-6, Chat 75) hat Memory-Context strukturiert dedupliziert und Kontext-Volumen reduziert. Live-Verifikation im 38-Turn-Chat in Chat 81: kein Echo-Verhalten mehr. | Chat 81 |
| THINK-MEM-LOOP | Per-Turn-Tool-Cache `ThinkerToolCache` (graph/nodes/thinker_cache.py), strikt lokal in `think()` instanziiert. Stufe 1 (generisch fuer alle 5 Tools): Argument-Cache in `_execute_tool_call`. Stufe 2 (nur `memory_search`): Result-Hash ueber stabile Felder (inhalt, subtyp, dimension, beobachter, vektor) — effektives Gewicht und Arousal wegen Decay-Volatilitaet ausgeschlossen. FIFO-Verdraengung bei MAX_GROESSE=20. | Chat 82 |
| NORMALIZER-CONNECTOR-NOOP | `get_thinking_normalizer()` matchte gegen den Connector-Namen (`frozenset({"gemma4"})`). Der live aktive Connector `qwen36` fährt im CharacterGraph `gemma4-gpu` auf der GPU und zeigt den Ollama content/thinking-Split (#10976), wurde aber als No-Op behandelt, weil `"qwen36" != "gemma4"`. | Match per Substring gegen das aufgelöste `OLLAMA_MODEL` (`gemma4-gpu`/`gemma4-cpu`). Live verifiziert (Modell=`gemma4-gpu`, aktiv). | Chat 100 |
| LZG-RESONANZ-STATE-DEKL | `lzg_resonanz` war nicht als Channel im `ConversationState`-TypedDict deklariert. Da der Haupt-Graph `StateGraph(ConversationState)` nutzt und den State pro Node aus den Channels rekonstruiert, wurde der vom Enricher per Mutation gesetzte Key am Node-Übergang Enricher→Reducer still verworfen → Reducer sah `None` → kein Resonanz-Block im Prompt, trotz `lzg_resonanz_count: 3`. Wurzel von P5-REDUCER-RESONANZ-BLIND. | `lzg_resonanz: dict \| None` als Channel deklariert (`f14c8b4`). Live verifiziert (erinnerungen=3 am Reducer, Resonanz-Block mit Spreading-Pfaden im Responder-Prompt). Hinweis: Chat-99-Einschätzung „Prio niedrig, läuft trotzdem" war falsch — bei `StateGraph(TypedDict)` ist das TypedDict die Channel-Definition, kein bloßer Typhinweis. | Chat 100 |
| DOPPEL-GEDAECHTNIS-HEADER | Bei aktiver Resonanz erschien `[GEDAECHTNIS]` zweimal im Responder-Prompt (Wrapper-Template `responder.gedaechtnis.txt` + innerer Header in `_format_lzg_resonanz`). | Innerer Header entfernt, Einleitungszeile bleibt (`5087de9`). Verifiziert (Header-Zahl = Turn-Zahl). | Chat 100 |

---