# Novaberg — Konvention: Abgeleitete Werte **Projekt:** Novaberg — The Nova Anima Resonance System **Dokument:** Konzept — Verbindliche Konvention für Werte, die aus anderen Werten berechnet werden **Stand:** 7. September 2026 (§4: `faszinations_faktor` aufgenommen — **Regel (6) war beim ersten Anlauf verletzt**, der Schwellwert stand auf einer anderen Skala als die eingespeiste Groesse; die Konvention haette den Fehler vorhergesagt, gefunden hat ihn eine Messung). Davor 1. September 2026, 18:30 UTC (§4: drei Eintraege der Praegungs- und Salienzschicht aufgenommen — `ausschlag_absolut`, `ausschlag_aktuell` und der Zielsog-Zug; alle drei erfuellen die Regeln, und der verworfene Mittelwert-Entwurf haette Regel 5 verletzt). Davor 16. August 2026 (gegen den Code gehalten: alle sieben Regeln stehen, die Bestandstabelle stimmt — **zwei nach ihr entstandene Speicher fehlten darin**). Davor: 27. Juli 2026, Chat 111 **Pfad:** novaberg/docs/novaberg-convention-abgeleitete-werte.md **Typ:** Convention **Anlass:** `KZG-SALIENZ-SKALENBRUCH`, `ZIEL-DECAY-FORMEL-KUMULATIV` — dieselbe Bauart, zwei Fundorte **Erste Anwendung:** `novaberg-kzg-salienz_k.md` --- ## 1. Die Fehlerklasse Ein System speichert eine Zahl, die aus anderen Zahlen entsteht. Zwei Bauarten sind möglich, und nur eine ist tragfähig. **Akkumulator (untauglich):** ``` neu = f(alt, zuwachs) speichere neu in dasselbe Feld, aus dem alt gelesen wurde ``` **Reine Funktion (verbindlich):** ``` wert = f(eingabe_1, eingabe_2, …) wobei keine Eingabe je aus wert berechnet wurde ``` Der Unterschied wird erst sichtbar, wenn etwas schiefgeht — und dann ist es zu spät, weil die Historie nicht mehr existiert. ## 2. Was der Akkumulator kostet **Er ist nicht idempotent.** Läuft die Berechnung zweimal, steht ein anderer Wert da. Ein doppelt zugestelltes Event, ein Retry, ein zweimal verarbeiteter Queue-Eintrag — jeder verfälscht dauerhaft. **Er ist pfadabhängig.** Zwei Einträge mit derselben Vorgeschichte können verschiedene Werte tragen, je nachdem, in welcher Reihenfolge die Verstärkungen kamen. Der Wert beschreibt dann nicht mehr die Sache, sondern die Historie ihrer Verarbeitung. **Er ist nicht nachrechenbar.** Ist der Wert einmal falsch, gibt es keinen Weg zurück. Die Eingaben, aus denen er entstand, sind überschrieben. Eine Migration kann ihn nicht reparieren, nur ersetzen — und dafür fehlt die Grundlage. **Er verbirgt Skalenfehler.** Genau das ist in `KZG-SALIENZ-SKALENBRUCH` passiert: Eine Dämpfungsformel war auf einen Wertebereich kalibriert, den die Eingangsgröße nie hatte. Weil der gedämpfte Zuwachs in dasselbe Feld zurückfloss, wuchs der Wert über seine eigene Skala hinaus, ohne dass eine einzige Prüfung anschlug. 68 % eines Korpus von 775 Einträgen standen am Ende über dem dokumentierten Maximum. ## 3. Die Regeln **(1) Speichere die Eingaben, nicht nur das Ergebnis.** Jede Größe, aus der sich ein Wert berechnet, ist ein eigenes Feld. Das Ergebnis darf zusätzlich gespeichert werden — nie stattdessen. **(2) Eine Eingabe wird nie aus dem Ergebnis berechnet.** Das ist die eigentliche Regel. Ein Zähler, der hochgezählt wird (`haeufigkeit + 1`), ist eine zulässige Eingabe: Er hängt nicht vom Ergebnis ab. Ein Gewicht, das aus dem alten Gewicht entsteht, ist es nicht. **(3) Das Ergebnis ist jederzeit von Grund auf nachrechenbar.** Prüfkriterium: Lässt sich der Wert aus den gespeicherten Feldern neu berechnen, ohne den bisherigen Wert zu kennen? Wenn nein, ist es ein Akkumulator. **(4) Zweimal rechnen ändert nichts.** Die Berechnung ist idempotent. Ein Wiederholungslauf über den gesamten Bestand ist ein zulässiger Wartungsvorgang, kein Datenverlust. **(5) Eine Formkurve ist eine Umbenennung, kein Rechenschritt.** Wird ein Wert durch eine monotone Kurve geschickt — Dämpfung, Sättigung, Normalisierung —, ändert das keine Reihenfolge und keinen Zeitpunkt, nur die Beschriftung. Daraus folgt zweierlei: - Die Kurve wird **genau einmal** angewandt, beim Lesen oder beim Schreiben, nie an beiden Stellen. - **Zuwächse greifen vor der Kurve an**, am Anker. Ein Zuwachs auf den gekrümmten Wert bedeutet an jeder Stelle der Skala etwas anderes. **(6) Schwellwerte stehen auf der Skala, die tatsächlich gespeichert ist.** Wird eine Kurve angewandt, müssen alle Tore durch dieselbe Kurve abgebildet werden. Ein Schwellwert auf der Rohskala und ein zweiter auf der gekrümmten Skala sind zwei Skalen im selben System — der Zustand, den `KZG-SALIENZ-KONSUMENTEN-DISSENS` beschreibt. **(7) Jede so entstandene Konstante nennt ihr Roh-Äquivalent im Kommentar.** `KZG_SALIENZ_MINIMUM = 0.6738` ist für sich unlesbar. Dass die Zahl „das Modell bewertete mit 0.3" bedeutet, steht nirgends im Wert. Ohne den Kommentar ist die Konstante beim nächsten Lesen wieder eine offene Frage. ## 4. Der Bestand, ehrlich eingeordnet Diese Konvention beschreibt einen Zielzustand, den heute kein Modul vollständig erfüllt. | Ort | Bauart | Bewertung | |---|---|---| | `memory/lzg_knoten.py` — `gewicht_absolut` | reine Funktion von `gewicht_roh` | Regel (3) erfüllt | | `memory/lzg_knoten.py` — `gewicht_roh` | Akkumulator (`+= BOOST`) | Regel (2) verletzt | | `memory/lzg_knoten.py` — `gewicht_decay` | reine Funktion aus `gewicht_absolut` und `verstaerkt_am` | erfüllt | | ~~`memory/kzg.py`, `agents/kzg/speicher.py` — `salienz`~~ | ~~Akkumulator mit Skalenfehler~~ → **reine Funktion aus `salienz_eingang` und `haeufigkeit`** (Chat 113) | erfüllt | | ~~Ziel-Decay~~ | ~~Akkumulator~~ → **reine Funktion aus `motivation_basis` und `motivation_basis_am`** (Chat 113) | erfüllt | Das LZG-Gewicht ist damit **halb** konform: Die Kurve ist sauber, der Anker darunter nicht. Es taugt als Vorbild für die Formkurve und ausdrücklich **nicht** als Vorbild für den Anker. **Stand 16.08.2026 — zwei Speicher sind nach dieser Konvention entstanden und standen nicht in der Tabelle:** | Ort | Bauart | Bewertung | |---|---|---| | `memory/repositories/shadow_auftrag_repository.py` — `salienz_roh` | Akkumulator mit Umkehrfunktion (`salienz_roh += BOOST`, `salienz_roh_zurueckrechnen`) | **halb** — wie `gewicht_roh`, siehe unten | | dieselbe Datei — `salienz_absolut`, `salienz_decay` | reine Funktionen aus `salienz_roh` bzw. aus `salienz_absolut` und `verstaerkt_am` | erfüllt | | `autonomous_wissen` — `gewicht_roh` / `_absolut` / `_decay` | dieselbe Dreiteilung | erfüllt, soweit geprüft | | `praegung_faden` — `ausschlag_absolut` | Formkurve über `ausschlag_eingang`, **einmal** angewandt | erfüllt — Regel (5) mustergültig: die Kurve steht am Eingang, nicht am Leser | | `praegung_faden` — `ausschlag_aktuell` | Faltung über `ausschlag_absolut`, `entstanden_am` und die vollständige Berührungsliste; **der vorige Wert geht nicht ein** | erfüllt — materialisiertes Ergebnis nach Regel (1), von Grund auf nachrechenbar (3) und idempotent (4). Der Wiederholungslauf über den Bestand ist gebaut (`alle_faeden_nachfuehren`) | | `ei/salienz.py` — der Zielsog-Zug | `antrieb + β(sog) × sog × (1 − antrieb)` | erfüllt — hebt auf die Lücke nach oben, **ohne Normierung und ohne Kappung** in [0,1] geschlossen. Der verworfene Mittelwert-Entwurf hätte Regel (5) verletzt: Er hätte die ganze Skala umgedeutet und jede darauf kalibrierte Schwelle mitgezogen | | `ei/haltung.py` — `faszinations_faktor` | lineare Abbildung der Faszination auf [0,60 … 1,40] um einen neutralen Punkt | erfüllt — rein, idempotent, ohne Speicher. **Regel (6) war beim ersten Anlauf verletzt und die Konvention hätte es vorhergesagt:** Der neutrale Punkt stand auf 0,50, abgelesen an der **Turn**-Faszination (mit den sechs Modulatoren, Spanne Faktor 16,2); eingespeist wird die **Trägerseite**, die eine halbe Spanne tiefer liegt. Zwei Skalen im selben System, genau der Zustand, den die Regel benennt. `[gemessen 07.09.2026]` über 25 echte Turns: 12 von 15 unter dem Punkt, Median-Faktor 0,8895 — der Modulator hätte **verschoben statt moduliert**. Auf **0,36** korrigiert, den Median der tatsächlich eingespeisten Größe; danach 6 dämpfend / 9 hebend, Median 1,0012. Regel (7) erfüllt: Die Konstante trägt die gemessene Verteilung im Kommentar | **Die Queue erfüllt Regel 5 sauber:** Der Zuwachs greift am **Anker** (`salienz_roh += BOOST`), nicht auf dem gekrümmten Wert. Das ist genau die Bauart, die §3 (5) verlangt und die dem LZG-Gewicht als Vorbild dient. > **Eine Eigenheit, die über `gewicht_roh` hinausgeht und benannt gehört.** Beim Einreihen gibt es keinen Vorgängerwert; der Anker wird aus der übergebenen — bereits gekrümmten — Salienz **zurückgerechnet** (`salienz_roh_zurueckrechnen`). Das ist kein selbstbezüglicher Akkumulator, sondern eine Skalenumrechnung an der Grenze, und sie ist wohldefiniert, solange die Kurve monoton bleibt. > > **Der Preis ist trotzdem einer.** `salienz_roh` wird an keiner Stelle unabhängig gemessen — er ist immer eine Funktion der Kurve. Die Umkehrung bei `gewicht_roh` setzt voraus, dass der **Zuwachs** nie geändert wurde; diese hier setzt voraus, dass die **Kurve** nie geändert wurde. Ändert jemand `QUEUE_SALIENZ_CAP` oder die Sättigungsform, werden alle bestehenden Anker still falsch, und es gibt keinen gemessenen Wert, gegen den man das prüfen könnte. **Stand 28.07.2026:** Von den fünf Zeilen erfüllen vier die Regeln. Offen bleibt allein `gewicht_roh` — ein Akkumulator, der sich nur deshalb nicht rächt, weil sein Zuwachs konstant ist und `haeufigkeit` danebensteht: `initial_roh = gewicht_roh − (haeufigkeit − 1) × BOOST` rechnet ihn zurück, und `knoten_gewichte_zuruecksetzen()` tut genau das. Ein Akkumulator mit Umkehrfunktion ist die mildeste Form des Problems, aber er bleibt einer: Die Umkehrung setzt voraus, dass der Zuwachs nie geändert wurde. **Was die beiden Reparaturen gemeinsam hatten:** In beiden Fällen war die *Zeitbasis* oder der *Multiplikand* aus dem Ergebnis abgeleitet, und in beiden Fällen fiel es erst auf, als jemand die Zahlen gegen ihre eigene Skala hielt. Der Ziel-Decay las sein Alter aus `erstellt_am` statt aus einem eigenen Ankerzeitpunkt — `aktualisiert_am` wäre als Referenz ebenso untauglich gewesen, weil jeder Schreiber sie setzt, auch der Decay-Lauf selbst. **Ein Anker braucht seinen eigenen Zeitstempel, der nur mit ihm zusammen geschrieben wird.** Sonst hängt die Rechnung an einem Feld, das jemand anders aus einem anderen Grund berührt. Der KZG-Salienz-Neubau ist der erste vollständig konforme Fall: `salienz` wird aus einem unveränderlichen Eingangswert und einem Zähler berechnet, von denen keiner je aus `salienz` entstanden ist. ## 5. Prüffragen für neuen Code Vor jedem Feld, das eine berechnete Zahl hält: 1. Aus welchen gespeicherten Feldern entsteht der Wert? 2. Ist eines davon selbst aus diesem Wert entstanden? → Bauart ändern. 3. Kann ich den Wert für den gesamten Bestand neu berechnen? → Wenn nein, fehlt ein Feld. 4. Was passiert bei doppelter Ausführung? 5. Wenn eine Kurve im Spiel ist: Auf welcher Skala steht der gespeicherte Wert, und stehen alle Schwellwerte auf derselben? **Zusammenhang:** `novaberg-kzg-salienz_k.md` (erste Anwendung) · `KZG-SALIENZ-SKALENBRUCH` · `ZIEL-DECAY-FORMEL-KUMULATIV` · `KZG-SALIENZ-KONSUMENTEN-DISSENS` · `novaberg-mem-lzg.md` (Ebbinghaus-Decay) --- ## Versionshistorie - **v0.2 — 16.08.2026:** Gegen den Code gehalten. **Alle sieben Regeln stehen**, und die Bestandstabelle stimmte für ihre fünf Zeilen: `gewicht_roh` ist weiterhin ein Akkumulator mit Umkehrfunktion, `knoten_gewichte_zuruecksetzen` existiert. **Regel 7 ist vorbildlich eingelöst** — `KZG_SALIENZ_MINIMUM` trägt sein Roh-Äquivalent inline (`# roh 0.3`) und vier Zeilen Herleitung darüber. **Was fehlte, war der Geltungsbereich:** Zwei Speicher sind nach dem 27.07. entstanden und standen nicht in §4 — die Auftrags-Queue und die Wissens-Bibliothek. Beide tragen die Dreiteilung roh/absolut/decay, und die Queue erfüllt Regel 5 sauber. **Neu benannt ist ihre Eigenheit:** Ihr Anker wird beim Einreihen aus einem bereits gekrümmten Wert zurückgerechnet und damit nie unabhängig gemessen — wo `gewicht_roh` voraussetzt, dass der Zuwachs nie geändert wurde, setzt sie voraus, dass die Kurve nie geändert wurde. - **v0.1 — 27.07.2026, Chat 111:** Erstfassung aus zwei Fundorten derselben Bauart.