Repository navigation
0.9.5 — Vollständige Evidence-Bindung & Report-Refactors
Version-Cut auf 9168e98c (main).
Das Zusammensetzen eines Provider-Requests und das Durchbringen dieses Requests gegen bekannte Provider-400er liegen nicht mehr in LLMClient.chat, sondern hinter build_request und execute im neuen Modul app/llm/request_plan.py. chat schrumpft von 315 auf 257 Zeilen und behält nur noch, was wirklich dazugehört: Stub-Pfad, Streaming-Reassembly, Budget- und Telemetrie-Buchführung.
Die Quirks stehen damit genau einmal im Code. Bisher standen sie viermal: chat, describe_image und tool_calls hatten je eine eigene Kopie des Request-Shapings, drei davon je eine eigene Fallback-Kaskade. Jede Kopie hatte eine andere Lücke — der Tools-Pfad kennt den temperature-Quirk aus #1096 nicht, der Vision-Pfad kennt MiniMax nicht. Diese Lücken bleiben unverändert bestehen, stehen jetzt aber als benannter Seam sichtbar da statt als stiller Unterschied zwischen drei Textstellen.
Was ein Request über seine Umgebung braucht, kommt über RequestOptions herein — Provider-Seams mit Default-Bindung an die echten Heuristiken. Ein Test setzt Fakes in die Options und prüft build_request und execute direkt am Interface, ohne patch() auf Modulnamen.
detect_provider bleibt Single Source of Truth für die Provider-Erkennung; request_plan erkennt nichts selbst, sondern bekommt das Ergebnis übergeben.
Verhalten unverändert — reiner Deepening-Refactor.
Fixed (Sim Tool-Skip für DISLIKE — 2026-08-11)
- DISLIKE_ ohne erzwungenen Tool-Aufruf:* Die Tool-Usage-Rule erlaubte den Tool-Skip nur für
LIKE_POST/DO_NOTHINGund zwang fürDISLIKE_POST/DISLIKE_COMMENTeinenweb_search/web_fetch-Aufruf, der bei Tool-Limit oder Tool-Fehler aufDO_NOTHINGzurückfiel — Reddit-Agenten dislike-ten nie (B2 aus #1215). Die Skip-Klausel nennt jetzt die volle Reaktionsmenge (LIKE_POST,DISLIKE_POST,DISLIKE_COMMENT,LIKE_COMMENT,FOLLOW,MUTE,REPOST,QUOTE_POST,DO_NOTHING) und fordert Tools nur, wenn Fakten fehlen, die das Modell nicht schon aus der Observation hat. (#1215)
Fixed (Persona-Slot-Verteilung und gender-konsistenter Dedup — 2026-08-11)
- Persona-Generierung verteilt Alter, Gender und MBTI jetzt vorab auf Slots: Gleichförmige LLM-Antworten werden auf eine geplante Kohorte normalisiert, und der Namens-Dedup zieht gender-konsistente Ersatznamen, ohne die bestehende Namens- und Nachnamens-Eindeutigkeit zu verlieren. (#1214)
Fixed (CI-Komplexitäts-Gate — 2026-08-11)
contract-gatesaufmainwieder grün: Fünf pre-existing D-Hotspots aus der kanonischen Evidence-Identität (#1147) und der seed_corpus-Evidence (#1166) fehlten inbackend/radon-allowlist.txtund hielten das radon-Komplexitäts-Gate seit mindestens achtpush:main-Läufen rot. Nachgezogen als Allowlist-Einträge mit# cc<=N-Obergrenze — sie dulden den Bestand und schlagen bei weiterem Wachstum an, ohne einen Refactor zu erzwingen. (#1213)
Added
- Komplexitäts-Gate im Pre-Push-Gate:
scripts/pre-push-gate.shruft im Backend-Scope jetztscripts/check_complexity.pyauf. Der Driftfall fällt damit lokal vor dem Push auf statt Tage später nur aufpush:main. (#1213)
Der Abschnitts-Durchlauf der Reportgenerierung liegt nicht mehr als Schleife in generate_report, sondern hinter process_section im neuen Modul app/services/report_agent/section_pipeline.py. generate_report schrumpft von 455 auf 322 Zeilen und behält nur noch die Orchestrierung: Abbruchprüfung, Akkumulation der fertigen Abschnitte und Statusableitung.
Was ein Abschnitt beim Verarbeiten braucht, kommt über SectionContext herein — Daten und Seams, mit Default-Bindung an die echten Implementierungen. Das Ergebnis steht in SectionResult und trägt beobachtbar, was gebunden und was vom Evidence-Gate verworfen wurde. ReportAgent._save_evidence_section gibt dieses Ergebnis dafür zurück, statt es nur als Seiteneffekt in der Evidenzkarte abzulegen; die Persistenz bleibt unverändert.
Verhalten unverändert — reiner Deepening-Refactor.
- Live-Feed: Reddit-Kommentare erreichen den Feed wieder. Der Emitter erwartete den
Elternpost in der OASIS-Trace-Zeile, die ihn nie enthält — er wird jetzt über die
comment-Tabelle aufgelöst. Damit bekommt der Reply-Tree Äste und die rund 86 %
der Reddit-Aktivität, die Kommentare sind, werden sichtbar (#1209 5c/5d). - Live-Feed:
scoreträgt den echten Voting-Stand aus der Simulations-DB
(num_likes - num_dislikes) statt einer hartkodierten 0; Twitter bleibt bei 0,
weil es kein Up-/Down-Voting kennt (#1209 5b). PostCreatedEvent: Feldsentimententfernt. Es gab nie einen Sentiment-Service,
das Feld trug nie einen Wert und wurde nirgends gerendert (#1209 5b).
Geändert
- Report-Statusmaschine aus
Step4Report.vuein das Composable
useReportGenerationgezogen (#1206). Neun offene Status-Refs, die
141-zeiligepollStatus()-Schleife samt Endzustands-Zweigen, die
Transportfehler-Zählung aus #1023 und die Koordination der drei
Polling-Instanzen liegen jetzt hinter dem Interface
{ status, progress, report, bootstrap(), start(), stop(), regenerate() };
usePollingist damit interne Abhängigkeit statt Detail der Komponente.
Frontend-Gegenstück zuRunLifecycle(#1204). Verhalten unverändert — der
Flow ist jetzt zusätzlich ohnemount()und ohne Modul-Mocks testbar.
Geändert
- Run-Zustandsführung zentralisiert: das handgeschriebene Muster „Run anlegen
(pending) → Arbeit → Endzustand" an sechs Stellen (Simulationsstart und
-vorbereitung, Run-Restarts, Report-Start) läuft jetzt über den
KontextmanagerRunLifecycle(#1204). Kein Abbruchpfad — auch
SystemExit-artige — hinterlässt mehr einen pending-Phantom-Run; ein nicht
persistierter Statusübergang wird als Fehler sichtbar (500) statt still
verschluckt.
Changed (Betriebs- und Security-Doku gegen den Code geprüft, Coverage neu gemessen — 2026-08-11)
- Die Doku beschrieb an mehreren Stellen einen Paketmanager, den das Projekt nicht mehr benutzt.
deployment-dev.mdführtenpm run dev,npm run setup:all,npm run check, einepackage-lock.jsonund Node 18 als Voraussetzung — real fährt das Projekt seit langembun(je einebun.lockin Root undfrontend/), verlangtbun >= 1.3.0und Node >= 20, und das Backend ist auf Python>=3.14,<3.15gepinnt, nicht auf 3.11. Auch die CI-Kommandos insecurity-hardening.md,security-threat-model.md,operations.md,release-process.mdunddependency-risk-register.mdnanntennpm audit, während der JobSecurity scansbun audit --audit-level=highausführt. release-process.mdbeschrieb einen Versionsprozess, den es nicht mehr gibt. Das Dokument führte „sechs Stellen halten die Versionsnummer", nannte zwei davon als bekannten Drift auf0.6.1und0.8.0, und gab einesed-Sequenz vor, die unter anderembackend/app/__init__.pybeschreibt — dort steht seit dem Umbau kein statischer Wert mehr, der Wert kommt aus den Paket-Metadaten. Maßgeblich istVERSIONpluscheck_version_drift.py --write; das Dokument verweist dafür jetzt aufrunbooks/release-versioning.mdund beschreibt nur noch, was nach dem Version-Cut passiert.auth.mdkannte nur einen von drei Auth-Wegen. Ergänzt sind die Workspace-API-Keys (Präfixago_, Status-Prüfung gegen den Key-Store) und der Open Mode, in dem ohne gesetztesAGORA_AUTH_TOKENjeder Aufruf durchgeht. Korrigiert ist außerdem die Aussage zu?token=: der Query-Parameter ist außerhalb des Debug-Modus abgeschaltet — der Wert wird verworfen und auf Log-Levelerrorprotokolliert —, nicht bloß „deprecated mit Warning". Die Ticket-TTL ist Default 60 s bei Maximum 300 s.deployment-dev.mdbehauptete ein Read-Only-Rootfs, das im Dev-Stack nicht gilt.docker-compose.ymlsetztread_only: false; erstdocker-compose.prod.ymlschaltet es scharf. Wer eine Änderung gegen den Prod-Pfad absichern will, muss deshalb gegen das Prod-Compose testen. Ergänzt sind außerdemAGORA_BIND_HOST,AGORA_FRONTEND_PORTundAGORA_BACKEND_PORT, die die Host-Bindung des Stacks steuern und in keiner Doku standen — auch nicht in der Env-Referenz.- Coverage-Baseline neu erzeugt statt weiter als „überholt" markiert: Backend 79,00 % (vorher 66,00 % vom 10.06.), Frontend 71,03 / 58,44 / 64,19 / 73,32 % für Statements / Branches / Functions / Lines (vorher 50,46 / 39,56 / 38,59 / 52,50 % vom 10.05.). Damit sind die CI-Schwellen wirkungslos: 28 % im Frontend liegen 30 bis 45 Punkte unter dem Istwert, 60 % im Backend 19 Punkte darunter. Das Anheben ist eine Code-Änderung und bleibt einem eigenen Issue vorbehalten.
- Neun tote Verweise entfernt, darunter zwei gelöschte Planungsdateien, ein nicht mehr existierendes
SECURITY_REVIEW_SUMMARY.mdund zwei Frontend-Dateien, die seit der TypeScript-Migrationindex.tsundmarkdown.tsheißen. - Der Prüfumfang steht in den Dokumenten selbst. Die acht Betriebs- und Security-Dateien tragen jetzt einen Vermerk, dass Pfade, Kommandos und Verweise am 11.08.2026 gegen den Code geprüft wurden — und dass die fachlichen Aussagen dabei nicht einzeln nachvollzogen worden sind. Ein „Stand"-Datum ohne diese Einschränkung hätte mehr Prüftiefe behauptet, als stattgefunden hat.
Fixed (Schaltflächen der Embedding-Konfiguration waren unsichtbar oder unformatiert — 2026-08-11)
- Die Schaltflächen im Seitenkopf wurden nie angezeigt.
PageHeaderrendert ausschließlich den benannten Slotright; die Ansicht übergab ihre Schaltflächen jedoch im Standard-Slot, dessen Inhalt die Komponente verwirft. Betroffen waren „Neue Konfiguration" und das ältere „Ollama-Modell herunterladen" — letzteres war seit seiner Einführung unsichtbar, ohne dass es auffiel. - Die übrigen Schaltflächen trugen Klassennamen, die es nicht gibt. Die Ansicht verwendete
btn-primaryundbtn-secondary; das Gestaltungssystem definiertbtn--primaryundbtn--secondarymit doppeltem Bindestrich. Alle zwanzig Vorkommen waren betroffen, weshalb etwa „Uebernehmen" als unformatierter Text erschien. - Der Test deckte das nicht ab, weil der Prüfaufbau großzügiger war als das Original. Der Platzhalter für
PageHeaderrendert im Test jetzt nur den Slotright— übergibt eine Ansicht ihre Schaltflächen künftig am falschen Slot, wird der Test rot statt grün.
Changed (Dokumentations-Sync auf den Stand nach 0.9.4 — 2026-08-11)
- Die Doku behauptete an mehreren Stellen offene Arbeit, die längst erledigt war. README (beide Sprachen) führte den fehlenden Dokumentanker für Seed-Korpus-Belege als offenen Punkt, obwohl #1154 seit dem 09.08. geschlossen ist;
docs/STATUS.mdnannte als erste Priorität das harte Run-Budget (#978, geschlossen am 31.07.) und die nicht normalisierenden Evidence-Sub-Routen (#967, geschlossen);ROADMAP.mdunddocs/troubleshooting.mdführten den Trivy-OS-Layer-Hardstop 30.08.2026, der mit #772 ersatzlos entfallen ist. Alle vier Stellen nennen jetzt den Istzustand mit Beleg. - Ein Überclaim ist entfernt: die README versprach in beiden Sprachen, Runs könnten „erneut abgespielt" werden. Replay ist nicht implementiert — der stochastische Anteil eines Laufs ist seit #1160 F geseedet und damit wiederholbar, ein Same-Seed-Same-Report verlangt zusätzlich eine Aufzeichnung der Modellantworten und steht offen unter #763. Der Text sagt das jetzt so.
- Testzähler und Routenzahl neu gemessen statt fortgeschrieben:
docs/STATUS.mdsteht auf 4954 gesammelten Backend-Tests (davon 7 deselektiert) und 188 Frontend-Testdateien;docs/api.mdauf 171 Routen und Referenzstand0.9.4statt0.8.0— derselbe veraltete Versionsanker stand auch inconfiguration.mdundtroubleshooting.md. docs/architecture.mdist als Zielbild kenntlich gemacht, nicht als Istzustand. Das Dokument stammt vom 22.04.2026, trug noch den Titel „Agora / MiroFish-Offline" und leitete sich aus zwei Dateien ab, die es im Repository nicht mehr gibt. Der Migrationspfad Phase 0–8 ist inzwischen umgesetzt; jede Phase trägt jetzt eine Belegzeile, und dort, wo der umgesetzte Schnitt anders benannt ist als geplant (WorkspaceLayout.vue→components/v4/shell/,SimulationRepository→simulation_manager.pyplus Config-Schemas), steht das ausdrücklich dabei. Was das nicht leistet: eine Ist-Architektur ist das weiterhin nicht — für den verifizierten Stand bleibtdocs/STATUS.mdzuständig.- Zwei tote Verweise entfernt:
docs/troubleshooting.mdverwies auf ein nie existierendesdocs/testing/.OPENAI_API_BASE/OPENAI_API_BASE_URLfehlten in der Env-Referenz und sind jetzt als das dokumentiert, was sie sind — an den OASIS-Subprozess durchgereichte Werte, keine Eingangskonfiguration.
Added (Embedding-Konfiguration lässt sich in den Einstellungen anlegen und übernehmen — 2026-08-10)
- Die Einstellungsseite zeigte Embedding-Konfigurationen an, ließ aber keine anlegen. Wer Agora ohne kanonische Konfiguration betrieb, sah dort den Hinweis „Quelle: Legacy Config.EMBEDDING_* — bitte übernehmen" und darunter „Noch keine Embedding-Konfigurationen vorhanden". Einen Weg, dieser Aufforderung nachzukommen, gab es nicht: Die Übernahme war im Backend seit der Einführung des kanonischen Lifecycles vorbereitet, aber nie mit einer Bedienoberfläche verbunden.
- Die Legacy-Werte lassen sich jetzt übernehmen. Der Hinweis trägt einen Schalter, der nach der Provider-Verbindung fragt, über die das Modell erreichbar ist. Modell und Dimension stammen unverändert aus der bestehenden Konfiguration. Die Verbindung wird bewusst abgefragt statt erraten — Verbindungen sind ein eigener Lebenszyklus und werden nie im Hintergrund angelegt. Existiert noch keine, verweist der Dialog auf die Anbieter-Einstellungen.
- Neue Konfigurationen entstehen über ein Formular aus Verbindung, Modellname und Dimension. Direkt nach dem Anlegen und nach der Übernahme läuft die Prüfung gegen den Anbieter; ihr Ergebnis steht auf der Karte. Schlägt sie fehl, bleibt die Konfiguration erhalten, statt den Vorgang abzubrechen.
- Eine falsch angegebene Dimension ist kein Sackgassen-Zustand mehr. Meldet die Prüfung eine andere Dimension als deklariert, bietet die Karte an, den gemessenen Wert zu übernehmen und erneut zu prüfen. Konfigurationen lassen sich außerdem nach Rückfrage löschen — außer der gerade aktiven, die geschützt bleibt.
Added (Ein Report sagt jetzt, auf welchem Simulationsstand er beruht — 2026-08-10)
- Eine Reportgenerierung darf weiterhin starten, während die Simulation noch läuft. Das bleibt erlaubt und bekommt weder eine Sperre noch eine Warteschlange — bei Einzelnutzung wäre beides mehr Apparat als Nutzen. Fragwürdig war nie der Start, sondern das Schweigen darüber: der Bericht analysierte dann einen Zwischenstand, und wie viele Runden dieser Zwischenstand umfasste, stand nirgends. Einem fertigen Bericht war nicht anzusehen, ob zehn Runden dahinterstehen oder vier.
- Der Stand steht jetzt im Bericht, gleich im Kopf. Ausgewiesen werden die abgeschlossenen Runden, die geplante Gesamtzahl und die Feststellung, ob die Simulation zum Startzeitpunkt noch weiterlief. Lief sie weiter, wird der Bericht ausdrücklich als Zwischenstand bezeichnet und vermerkt, dass spätere Runden nicht eingeflossen sind.
- Erfasst wird beim Start, nicht beim Abschluss. Das ist der Datenbestand, den die Auswertung tatsächlich gesehen hat. Runden, die während der Berichtserstellung noch dazukommen, stehen in keinem Satz des Berichts — sie hier mitzuzählen wäre die bequemere, aber falsche Zahl.
- Ist der Stand nicht ermittelbar, steht dort „unbekannt". Das betrifft Berichte aus der Zeit vor dieser Änderung und Simulationen, die nie über den Runner liefen. Eine erfundene Null wäre schlechter als ein ehrliches Fragezeichen. Bestehende Berichte laden, validieren und exportieren unverändert.
Fixed (Eine erfolglose Suche wird nicht mehr wiederholt — 2026-08-10)
- Der Berichtsagent suchte dreimal nach derselben Sache, die es nicht gab. In einem vermessenen Lauf ging er im Abschnitt „Unsicherheiten und Datenlücken" dreimal einer Stakeholdergruppe nach, die das Personen-Capping zuvor aus dem Pool verdrängt hatte — einmal mit der Panorama-Suche, zweimal mit der Schnellsuche. Er verbrauchte damit fünf statt vier Werkzeugaufrufe und lief in die Iterationsgrenze. Ausgerechnet der Abschnitt, der Datenlücken benennen soll, verlor sein Budget an die Suche nach einer solchen.
- Ein Leertreffer ist jetzt ein Befund, kein Grund zur Wiederholung. Bleibt eine Suche ohne Ergebnis, wird dieselbe Suche im selben Abschnitt nicht noch einmal ausgeführt — auch nicht mit einem anderen Werkzeug. Das Modell erhält stattdessen den Hinweis, dass der Gegenstand im Datenbestand nicht vorkommt, und die Aufforderung, das als Datenlücke zu benennen.
- Der unterdrückte Versuch zählt nicht gegen das Werkzeugbudget. Täte er es, wäre keine einzige Iteration gespart und die Änderung folgenlos.
- Als „dieselbe Suche" gilt die normalisierte Anfrage: Groß- und Kleinschreibung, Leerraum und Satzzeichen bleiben außer Betracht. Keine Ähnlichkeitsschätzung — die Regel ist damit vorhersagbar und prüfbar, statt von einem Schwellenwert abzuhängen. Die Merkliste gilt pro Abschnitt; ein anderer Abschnitt darf dieselbe Suche erneut versuchen.
- Am Evidenzmodell ändert sich nichts. Der Hinweis bleibt eine Mitteilung an das Modell und wird kein Eintrag in den Evidenzverträgen — das wäre eine eigene Entscheidung und ist bewusst nicht Teil dieser Änderung. Ergebnislose Interviews sind ebenfalls ausgenommen: dort ist ein zweiter Versuch mit anderem Zuschnitt durchaus sinnvoll.
Fixed (Evidence-Export bleibt sichtbar — 2026-08-10)
- Evidence-JSON-Button verschwindet nicht mehr spurlos: Solange die
Evidenzkarte eines Reports noch nicht vorliegt, bleibt der Export-Button in
der Report-Ansicht sichtbar, ist aber deaktiviert (aria-disabledplus
zugängliche Beschreibung).Step4Report.vuelädt die Evidenzkarte nach
Laufende mit exponentiellem Backoff (3 s bis 30 s gedeckelt) über ein
10-Minuten-Budget nach, statt sie nach wenigen Sekunden dauerhaft leer zu
belassen — dimensioniert auf die in #1187 gemessene Nachbearbeitungsdauer.
Ist das Budget ausgeschöpft, zeigt der Tooltip „nicht verfügbar" statt
weiterhin „wird noch erzeugt" zu behaupten. (#1188)
Fixed (Die stille Phase der Reportgenerierung meldet Fortschritt — 2026-08-10)
- Nach jedem fertigen Abschnitt arbeitete die Reportgenerierung minutenlang, ohne das mitzuteilen. In einem vermessenen Lauf lagen zwischen "Abschnittstext fertig" und "Abschnitt gespeichert" jedes Mal drei bis sechs Minuten ohne eine einzige Logzeile — zusammen 59 % der gesamten Laufzeit. Der Fortschrittsstand blieb derweil auf dem Wert stehen, den er beim letzten Abschnittswechsel hatte, mitsamt einem Zeitstempel, der Minuten alt war. Für den Nutzer war ein arbeitender Lauf damit nicht von einem abgestürzten zu unterscheiden.
- Diese Phase meldet sich jetzt. Die Nachbearbeitung ist in benannte Schritte zerlegt — Metadaten-Extraktion, Claim-Extraktion samt Evidenzbindung, Abschluss der Aussagen, Persistenz der Evidenzkarte. Jeder Schritt meldet Beginn und Ende mit seiner Dauer, und der Fortschrittsstand bewegt sich bei jedem Wechsel statt nur beim Abschnittswechsel. Innerhalb der langen Bindungsschleife hält ein Lebenszeichen im Zwanzig-Sekunden-Takt die Anzeige in Bewegung, ohne bei jeder einzelnen Aussage zu schreiben.
- Eine fehlgeschlagene Fortschrittsmeldung bricht den Lauf nicht ab. Sie wird protokolliert und die Nachbearbeitung läuft weiter — eine Anzeige darf den Bericht nicht kosten, den sie beschreibt.
- Was das ausdrücklich nicht leistet: schneller wird dabei nichts. Die Nachbearbeitung dauert genauso lange wie vorher, sie ist jetzt nur sichtbar und messbar. Die eigentliche Beschleunigung hängt an belastbaren Phasenzeiten aus einem Lauf mit dieser Instrumentierung — ohne die wäre jede Optimierung geraten. Ebenso unverändert bleiben sämtliche Evidenzbindungen und Vertrauenseinstufungen: gemessen wird, nicht eingegriffen.
Fixed (Persona-Profile verlieren beim Speichern keine Angaben mehr — 2026-08-10)
- Die Stimmlage einer Persona fehlte in jeder gespeicherten Profildatei. In 262 Profilen über sechs Simulationsläufe trug kein einziges das Feld — unabhängig davon, ob das Sprachmodell es erzeugt hatte oder die regelbasierte Erzeugung. Drei der betroffenen Läufe stammten vom selben Tag wie dieser Fix; die zugehörige Absicherung im Generator existiert seit Mai. Der Defekt war also aktuell und nicht ein Überbleibsel alter Daten.
- Ursache war das finale Speichern, nicht die Erzeugung. Während des Laufs wird die Profildatei fortlaufend korrekt geschrieben. Zum Abschluss speichert die Anwendung sie noch einmal — und baute dabei den Inhalt aus einer von Hand gepflegten Feldliste neu auf, statt das vollständige Profilformat zu verwenden. Jede Angabe, die in dieser Liste fehlte, ging beim Überschreiben verloren: neben der Stimmlage auch die Segmentzuordnung.
- Behoben ist nicht das einzelne Feld, sondern das Muster. Dasselbe Problem war schon einmal aufgetreten und damals durch Nachtragen einer einzelnen Angabe behoben worden — die nächste hätte es erneut getroffen. Das Speichern verwendet jetzt das vollständige Profilformat als Grundlage und ergänzt nur noch die Standardwerte, die die Simulationsumgebung zwingend braucht. Ein Test prüft die Vollständigkeit statt einer Aufzählung bekannter Felder: kommt eine Angabe hinzu, wird sie automatisch mitgespeichert.
- Damit ist die Voraussetzung für den Feed-Schnappschuss beim Öffnen einer laufenden Simulation geschaffen — der scheiterte bislang daran, dass die Stimmlage nicht auflösbar war und ein erfundener Wert nicht in Frage kommt.
Fixed (Personenauswahl verdrängt keine Stakeholdergruppen mehr — 2026-08-10)
- Die Begrenzung der Personenzahl schnitt die Kandidatenliste bisher stumpf ab. Wer die Zahl der Simulationsteilnehmer begrenzte, bekam nicht die wichtigsten Kandidaten, sondern schlicht die ersten — die Reihenfolge stammte unverändert aus der Datenbankabfrage, die keine Sortierung vornimmt. Der Kommentar im Code nannte die Sortierung als Voraussetzung; sie existierte nie. In einem gemeldeten Lauf belegte dadurch eine einzige, häufig genannte Gruppe alle 30 Plätze, während kleinere, fachlich wichtige Gruppen wie Betriebsrat und Honorarkraft komplett herausfielen.
- Jetzt wird zuerst bereinigt, dann verteilt. Mehrfachnennungen derselben Gruppe — auch in abweichender Schreibweise — zählen als eine und belegen keine Plätze mehr doppelt. Die verbleibenden Plätze werden reihum über die vorkommenden Gruppen vergeben: erst je ein Vertreter pro Gruppe, dann der zweite, und so weiter. Solange Plätze reichen, ist jede Gruppe vertreten.
- Was das nicht leistet: welcher Vertreter einer Gruppe gewinnt, bleibt willkürlich, solange die Datenbankabfrage nicht sortiert. Eine Auswahl nach Vernetzungsgrad oder Wichtigkeit wäre der nächste Schritt und erfordert eine Änderung am Lesepfad. Der irreführende Kommentar ist entfernt.
- Die Vorschau zeigt dieselbe Zahl wie der spätere Lauf. Sie bereinigt jetzt ebenfalls, statt Dubletten mitzuzählen — sonst kündigte sie mehr Personen an, als anschließend erzeugt werden.
- Eine Protokollzeile, die bei praktisch jeder Entität ansprang und dadurch nichts markierte, erscheint nur noch einmal je Durchlauf in zusammengefasster Form. Die eigentlichen Ausschlüsse gingen darin unter.
Fixed (Simulationsstart bleibt nicht mehr stumm hängen — 2026-08-10)
- Ein Startversuch endet jetzt immer sichtbar. Der Start legt zuerst einen Laufeintrag mit dem Status „wartet" an und startet erst danach den Simulationsprozess. Ging dabei irgendetwas schief, blieb der Eintrag auf „wartet" stehen: die Oberfläche zeigte weiterhin „Bereit", in der Laufliste sammelten sich Einträge, die nie etwas taten, und abbrechen ließen sie sich auch nicht. Im gemeldeten Fall waren neun solcher Einträge aufgelaufen. Jeder Abbruch nach dem Anlegen des Eintrags markiert ihn jetzt als fehlgeschlagen — unabhängig davon, woran es lag.
- Zuvor waren zwei bekannte Abbruchgründe einzeln behandelt worden. Das genügte nicht: der eigentliche Prozessstart lag außerhalb der Absicherung, und jeder neu hinzukommende Abbruchweg hätte dieselbe Lücke wieder geöffnet. Die Absicherung umschließt jetzt den gesamten Abschnitt, einschließlich des Falls, dass der Server die Anfrage nach zu langer Laufzeit selbst abbricht — genau dieser Fall hatte die stummen Einträge erzeugt.
- Hängengebliebene Einträge lassen sich abbrechen. „Abbrechen" war bisher nur für laufende Simulationen vorgesehen und wies Einträge im Wartezustand ab. Damit waren sie weder abbrechbar (weil nicht laufend) noch wurden sie je laufend (weil der Start nie durchlief). Sie werden jetzt direkt beendet; für bereits abgeschlossene Läufe bleibt „Abbrechen" wie bisher wirkungslos.
Changed (Mehr Platz für die Antwort — 2026-08-09)
- Jeder generative Modellaufruf bekommt jetzt mindestens 32.768 Ausgabe-Tokens statt der bisherigen 1.024 bis 4.096: Ein Berichtsabschnitt mit Belegen passte nicht zuverlässig in vier Kilotoken, und ein am Limit abgeschnittener Abschnitt war im fertigen Report nicht als abgeschnitten erkennbar. Die Untergrenze gilt zentral im Modell-Client, nicht mehr pro Aufrufer. Zwei Grenzen bleiben gewahrt: Modelle mit kleinerem Ausgabelimit werden auf ihr Limit gedeckelt statt mit einem Fehler abzubrechen, und bei lokal betriebenen Modellen wächst das Kontextfenster mit, weil dort Eingabe und Ausgabe sich einen Platz teilen — ohne das hätte die höhere Grenze den Prompt verdrängt statt mehr Text zu erlauben. Klassifizierende Aufrufe mit bewusst enger Antwort behalten ihr kleines Limit. Einstellbar über
LLM_MAX_TOKENS_FLOOR;0stellt das alte Verhalten her.
Added (Dokumentbelege im Report — 2026-08-09)
- Ein Fakt aus dem Wissensgraphen zählt jetzt als Dokumentbeleg, wenn seine Herkunft bekannt ist: Trägt ein gefundener Fakt die Dokument- und Chunk-Herkunft aus der Aufnahme, wird er als Beleg aus dem Seed-Korpus geführt und bekommt einen auflösbaren Anker auf die konkrete Stelle im Ausgangsdokument. Damit können Aussagen, die zusätzlich durch ein Agentenzitat gestützt sind, überhaupt erst mittlere Confidence erreichen — vorher war das strukturell unmöglich und jede solche Aussage blieb auf
low. Fakten ohne belegte Herkunft bleiben Graph-Relationen; geraten wird nichts. Die Identität eines Dokumentbelegs hängt an der Dokumentstelle, nicht am Wortlaut des Fakts: dieselbe Stelle bleibt derselbe Beleg, auch wenn das Modell sie beim nächsten Mal anders formuliert.
Changed (Seed-Status verlangt einen auflösbaren Anker — 2026-08-09)
- Bestehende Berichte verlieren beim Laden unbelegte Dokumentbezüge: Bis zu dieser Änderung war „Seed-Korpus“ die Standardgattung für alles, was aus dem Wissensgraphen kam — auch ohne jeden Bezug zu einem konkreten Dokument. Solche Belege behaupteten eine Nachprüfbarkeit, die es nicht gab. Sie werden beim Laden zu Graph-Relationen; eine Aussage, die dadurch ihre Grundlage für mittlere Confidence verliert, wird auf
lowgestuft. Berichte bleiben lesbar und laden ohne Fehler — sie zeigen den Belegstand ehrlicher an als zuvor. Aussagen, die von zwei unterschiedlichen Stakeholder-Gruppen gestützt werden, behalten ihre hohe Confidence unverändert.
Fixed (Report-Abbruch bei nicht agent-grounded medium-Claims — 2026-08-09)
- Ein Claim mit unverdientem
medium-Label beendet nicht mehr den ganzen Report: Die Confidence-Stufemediumverlangt laut ADR-0002 mindestens ein Agentenzitat (mit Originalzitat) und mindestens einen Beleg aus dem Seed-Korpus. Der Report-Builder hat das beim Zusammenstellen der Claims nicht geprüft — die Verletzung fiel erst der Schlussvalidierung der Evidence-Map auf, und die bricht die gesamte Report-Erzeugung ab. Der eingebaute Reparaturlauf half nicht: die Validierung meldet pro Durchgang nur den ersten Verstoß je Abschnitt, sodass nach der Reparatur des ersten Claims der nächste stehen blieb. Betroffene Claims werden jetzt beim Bauen ehrlich auflowabgestuft und mit Begründung im Gate-Protokoll vermerkt, statt den Lauf zu beenden. Die Prüfung folgt dabei den kanonischen Evidence-Records, nicht den Referenzeinträgen am Claim — sonst könnte sie zu einem anderen Urteil kommen als die Schlussvalidierung. Der Validator selbst bleibt unverändert streng.
Added (Evidence-Chain-Audit und Paper — 2026-08-09)
- Der Audit der Evidenzkette liegt als versionierte Quelle im Repository:
docs/paper/agora-evidence-chain-audit.mddokumentiert den geprüften Ist-Zustand von Ingest, Graph-Aufbau, Simulation, Evidence-Gating und Report — mit Belegstellen im Code statt aus README-Behauptungen abgeleitet. Die begleitenden Rechercheprotokolle unterdocs/paper/research-notes/halten je Teilbereich fest, welche Aussage an welcher Codestelle verifiziert wurde. - LaTeX-Quellen des Papers zur Evidenzkette: Kapitel, Literaturverzeichnis, Abbildung und
latexmkrc(LuaLaTeX + Biber) sind versioniert, das gebaute PDF liegt daneben. LaTeX-Zwischendateien und lokale Render-Ausgaben unteroutput/bleiben per.gitignoreaußen vor — sie enthalten absolute Maschinenpfade und ändern sich bei jedem Build.
Added (Simulationsläufe sind im Zufallsanteil wiederholbar — 2026-08-10)
- Ein Lauf trifft seine Zufallsentscheidungen nicht mehr aus dem Nichts. Wie viele Agenten pro Runde aktiv werden, welche davon in Frage kommen und welche schließlich gezogen werden, entschied bisher der ungeseedete globale Zufallsgenerator des Simulationsprozesses. Zwei Läufe derselben Konfiguration waren damit nicht vergleichbar — und ohne Vergleichbarkeit ist jede Wiederholung und jeder Baseline-Vergleich methodisch angreifbar. Der Lauf setzt jetzt vor der ersten Zufallsentscheidung einen Startwert: entweder das Feld
random_seedaussimulation_config.json, oder — wenn dort nichts steht — einen aus der Lauf-Kennung abgeleiteten Wert. Derselbe Lauf ergibt beim Neustart denselben Startwert, verschiedene Läufe verschiedene. - Einen Lauf gezielt wiederholen geht damit so: den protokollierten Startwert (
Random seed: …im Simulationslog) alsrandom_seedin die Konfiguration des neuen Laufs schreiben. Der Startwert wird über einen stabilen Hash abgeleitet, nicht über Pythons prozesslokalen String-Hash — sonst wäre er zwischen zwei Prozessen verschieden gewesen, also genau das Gegenteil von wiederholbar. - Was das ausdrücklich nicht zusichert: Die Antworten der Sprachmodelle bleiben unvorhersagbar. Gleicher Startwert heißt deshalb nicht gleicher Bericht. Reproduzierbar ist der Zufallsanteil des Laufs, nicht sein Ergebnis; für identische Berichte müssten zusätzlich die Modellantworten aufgezeichnet werden, was ein eigenes Vorhaben ist.
Added (Operative Zahlen weisen aus, woher sie kommen — 2026-08-10)
- Eine Zahl im Report sagt jetzt, wie sie zustande kam. Angaben wie „>90 % Traffic-Baseline" oder „14-Tage-Rankinggrenze" sahen im Fließtext alle gleich aus — unabhängig davon, ob sie so im Auftragsdokument standen, aus gemessenen Daten stammten, aus einer Norm, aus einer Festlegung des Betreibers oder schlicht daraus, dass ein Sprachmodell sie plausibel fand. Wer den Bericht las, konnte das nicht unterscheiden und behandelte im Zweifel alle gleich verbindlich. Der Report führt operative Zahlen deshalb in einem eigenen Abschnitt „Operative Zahlen" mit ihrer Rolle (Alarmschwelle, Zielwert, Obergrenze, Ausgangswert), ihrer Herkunft im Klartext und ihrer Beleglage.
- Sechs Herkunftsarten stehen zur Verfügung: Vorgabe aus dem Dokument, aus Daten abgeleitet, externer Standard, Betreiber-Festlegung, Modellvorschlag und Simulationsvorschlag. Im Zweifel gilt „Modellvorschlag" — eine Zahl ohne belegbare Herkunft ist ein Vorschlag, keine Anforderung. Die Beleglage steht daneben und ist standardmäßig „unbelegt"; eine Zahl als belegt auszuweisen, ohne einen Beleg zu nennen, weist der Vertrag zurück. Das wäre schlimmer als ehrliche Unbelegtheit, weil der Leser sich dann auf einen Beleg verlässt, den es nicht gibt.
- Die Herkunft einer Zahl ist bewusst getrennt von der Quellengattung eines Belegs geführt: die eine beschreibt, wie eine Zahl entstand, die andere, woher ein Beleg stammt. Eine Vermischung hätte die Evidenzregeln verwässert. Berichte ohne Zahlenangaben bleiben unverändert gültig.
Changed (Gegenprüfung bei entscheidungstragenden Reports — 2026-08-09)
- Die Red-Team-Gegenprüfung hängt nicht mehr allein am Echo-Kammer-Index: Bisher lief sie nur, wenn die simulierten Personas auffällig gleichgerichtet waren (Index über 0.6). Im Referenzlauf des Evidenzketten-Audits lag der Index bei 0.55 — die Gegenprüfung entfiel damit ausgerechnet bei einem vollständigen Report, obwohl der Index gar nichts über den Berichtstyp aussagt. Risiko-, Vergleichs- und Vollreports bekommen die Gegenprüfung jetzt immer; sie stützen eine Entscheidung, dort gehört der Widerspruch zum Produkt. Beim Meinungsbild und beim explorativen Report bleibt die Schwelle als Kostenbremse. Ein übersprungener Lauf hinterlässt weiterhin keinen Modelleintrag und ist dadurch von einem Lauf ohne Befunde unterscheidbar.
Added (Markdown-Report zeigt seine Belege, nicht nur Belegnummern — 2026-08-10)
- Der Markdown-Export löst seine Belegkennungen auf. Claim- und Multiplier-Tabellen führten bisher nur Kennungen wie
ev_00000…; wer den Report als Markdown las, sah Verweise ohne Belege. JSON- und ZIP-Export tragen die Herkunft seit jeher vollständig — ausgerechnet das Format, das weitergereicht und ausgedruckt wird, tat es nicht. Am Ende des Berichts steht jetzt ein Abschnitt „Evidenz-Nachweise": pro Kennung die Quellengattung im Klartext (etwa „Seed-Dokument" stattseed_corpus), der Produzent, die Quelle und der belegende Auszug. Wo ein Originalzitat vorliegt, steht es dort — es belegt die Aussage, während der umgebende Textausschnitt sie nur einbettet. - Der Abschnitt steht bewusst hinten und nicht in den Tabellen selbst: dieselbe Evidenz stützt oft mehrere Aussagen, und die Tabellen bleiben schmal genug zum Lesen. Lange Auszüge werden gekürzt — der Nachweis soll die Zuordnung ermöglichen, nicht die Quelle ersetzen. Die Reihenfolge ist stabil, damit zwei Exporte desselben Berichts nicht grundlos verschiedene Dateien ergeben.
Fixed (Export liefert keine ungeprüfte Evidenz mehr aus — 2026-08-10)
- ZIP- und CSV-Export prüften die Evidenz nie. Wer einen Report als ZIP oder als Claims-CSV zog, bekam eine Datei, die aussieht wie geprüfte Evidenz — ohne dass die Prüfung je stattgefunden hätte. Kein Hinweis, kein Vermerk. Der JSON-Export verhielt sich seit jeher korrekt und wies eine vertragswidrige Evidenz-Übersicht als ausgelassen aus; der Lese-Endpunkt
GET /api/report/<id>/evidencewiederum brach mit einem Serverfehler ab, an dem nicht zu erkennen war, ob die Anwendung defekt ist oder die Daten. Drei Wege, dieselbe kaputte Datenlage, drei verschiedene Antworten. - Alle vier Wege antworten jetzt gleich. Verletzt die Evidenz auch nach der Migration den Vertrag, tragen JSON-Envelope, ZIP-Archiv, CSV-Abruf und Lese-Endpunkt denselben Grund (
contract_violation), dieselbe Erläuterung und dieselbe Fehlerliste. Im ZIP liegt stattevidence-map.jsonundclaims.csveine Dateievidence-omitted.jsonmit der Begründung — auch lesbar für jemanden, der das Archiv später ohne Agora öffnet. Der Claims-CSV-Abruf wird abgelehnt statt beantwortet: eine CSV-Datei hat keine Stelle, an der ein Auslassungshinweis stehen könnte, und sähe damit wie eine vollständige Evidenzliste aus. Der Lese-Endpunkt antwortet mit einem Datenfehler statt mit einem Serverfehler. - Der Report-Rumpf bleibt in allen Fällen vollständig — Personas, Segmente, Markdown und Verbrauchsdaten sind unberührt. Betroffen ist ausschließlich der Evidenz-Teil, und nur dann, wenn er den Vertrag tatsächlich verletzt.
Changed (Confidence-Semantik: Geltungsbereich sichtbar, verified belastbar — 2026-08-10)
- Reports weisen jetzt aus, worauf eine Confidence beruht. Ein Befund, den ausschließlich simulierte Agenten stützen, konnte dasselbe Label tragen wie ein quellengebundener — die Skala allein unterscheidet das nicht, und im Report stand nur „high". Die Claim-Tabelle führt deshalb eine Spalte „Geltungsbereich": Simulationskonsens bei Aussagen, hinter denen nur Agentenstimmen stehen, Quellenbindung, sobald mindestens ein stützender Beleg aus Seed-Korpus, Wissensgraph oder Recherche stammt. Abgeleitet wird das aus derselben Evidenzmenge, aus der auch die Belegverweise entstehen; ein widersprechender oder nur thematisch verwandter Treffer begründet keine Quellenbindung. Berichte aus der Zeit vor dieser Änderung zeigen „-" statt einer Behauptung über einen Geltungsbereich, der nie erfasst wurde. Die Label-Semantik selbst bleibt unangetastet.
- Das oberste Vertrauenslabel hängt nicht mehr allein an Textähnlichkeit.
verifiedverlangte bisher nur einen Ähnlichkeitswert ab 0.85 — ein Wert, der beantwortet, ob es um dasselbe Thema geht, nicht, ob die Quelle die Aussage trägt. Die Schwelle bleibt Voraussetzung, genügt aber nicht mehr: dasselbe Belegstück muss zusätzlich das Prüfurteil „stützt die Aussage" tragen. Getrennte Belege dürfen die Bedingung nicht zusammenstückeln. Bestandsreports ohne dieses Urteil werden beim Laden aufhighabgestuft und mit einer Begründung im Prüfprotokoll versehen, statt abgelehnt zu werden — der Bestand wird ehrlicher, nicht unlesbar. - Zwei Schreibweisen derselben Stakeholder-Gruppe zählen als eine. Das oberste Vertrauenslabel verlangt Stimmen aus mindestens zwei unterschiedlichen Gruppen. Da die Gruppenbezeichnung ein freies Textfeld ist, ließ sich diese Bedingung bisher mit einer einzigen Gruppe erfüllen, indem ihr Name unterschiedlich geschrieben wurde. Verglichen wird jetzt ohne Groß-/Kleinschreibung und ohne Leerzeichenunterschiede. Angezeigt und gespeichert bleibt die Schreibweise der Quelle; eine feste Liste erlaubter Gruppenbezeichnungen ist ausdrücklich nicht eingeführt worden.
Fixed (Übersetzungsreste in Modell-Anweisungen und einer API-Antwort — 2026-08-10)
- Aus einem chinesischsprachigen Upstream stehengebliebene Schriftzeichen sind aus den Texten verschwunden, die an das Sprachmodell gehen: Betroffen waren die Hinweise, mit denen der Report-Agent auf noch ungenutzte Werkzeuge aufmerksam gemacht wird, sowie der Platzhalter für einen noch leeren Bericht im Chat. Dort standen halbseitig geöffnete, aber vollbreit geschlossene Klammern und ein ostasiatisches Aufzählungskomma als Trennzeichen. Das ist kein Schönheitsfehler: Diese Hinweise entscheiden mit darüber, ob der Agent seine Werkzeuge überhaupt einsetzt, und ein Zeichen, mit dem das Modell nicht rechnet, kann diese Wirkung kosten. Ebenfalls bereinigt ist eine Statusmeldung der Vorbereitungs-Schnittstelle, die unverändert an die Oberfläche durchgereicht wird. Die Formulierungen selbst sind absichtlich unangetastet geblieben — geändert wurde ausschließlich die Zeichensetzung, damit sich das Verhalten des Modells nachvollziehbar nicht aus einem anderen Grund verschiebt. Ein Test wacht künftig über beide Dateien.
Changed (Ingestion-Schutztest läuft ohne Netzzugang — 2026-08-10)
- Der Regressionstest für den nltk-Import-Schutz braucht keine Downloads mehr: Er hat bisher einen echten Parse-Aufruf gefahren und damit zwei Sprachmodelle nachgeladen, die auf einem frischen Rechner nicht vorliegen. Wo ausgehender Netzverkehr gesperrt ist — etwa in der CI —, schlug er deshalb fehl, obwohl der geprüfte Schutzmechanismus einwandfrei funktionierte; auf Entwicklerrechnern blieb er grün, weil die Modelle dort aus einem früheren Lauf im Nutzer-Cache lagen. Der Test prüft jetzt genau die Stelle, an der der Fehler tatsächlich auftritt: den nachgelagerten Import, den jeder Parse-Aufruf durchläuft. Er ist damit auf jedem Rechner und in jeder Umgebung gleich aussagekräftig und schlägt nur noch an, wenn der Schutzmechanismus wirklich versagt.
Fixed (Nachträglich abgestufte Aussagen weisen ihre Herkunft aus — 2026-08-10)
- Wird eine Aussage nachträglich herabgestuft, änderte sich bisher nur die Vertrauensstufe. Der Wortlaut blieb, wie er war — und der stammt vom Sprachmodell, das ihn unter der höheren Stufe geschrieben hat: deklarativ, ohne die Vorsicht, die die niedrigere Stufe verlangt. Der Bericht bestand seine Prüfung, transportierte im Fließtext aber weiterhin eine Behauptung in einer Sicherheit, die seine eigene Einstufung nicht mehr deckte.
- Solche Aussagen sind jetzt als solche erkennbar. In der Aussagentabelle steht neben der Stufe, unter welcher Stufe der Wortlaut entstanden ist. Die Übersicht am Anfang des Berichts — vor dem Fließtext — nennt zusätzlich, wie viele Aussagen davon betroffen sind. Bei mehrfacher Herabstufung bleibt die ursprüngliche Stufe stehen: unter ihr wurde formuliert, eine zwischenzeitliche wäre die falsche Bezugsgröße.
- Der generierte Text bleibt unangetastet. Das ist eine bewusste Entscheidung gegen die naheliegende Alternative, dem Satz nachträglich eine abschwächende Formulierung voranzustellen: die hätte Sprachfragen aufgeworfen, sich bei mehrfacher Herabstufung selbst verdoppelt und in einen Text eingegriffen, für den das Modell verantwortlich zeichnet. Was das nicht leistet: eine deklarativ formulierte Passage im Fließtext bleibt deklarativ formuliert. Sie steht dort aber nicht mehr unkommentiert — Tabelle und Übersicht weisen sie aus, und die Übersicht liest man zuerst.
Added — Feed-Snapshot beim Mount (#1009)
- Feed ist beim Öffnen sofort befüllt: Die Simulations-Feed-View lädt beim Mount den bisherigen Sim-Bestand aus der SQLite-DB über einen neuen
/feed-snapshot-Endpoint und ingestiert ihn vor SSE-Stream-Start.useSimFeed-Dedup perpost_idverhindert Doppeleinträge, wenn Live-Events für bereits geladene Posts eintreffen. (#1009)
Changed — PostCreatedEvent-Vertrag: persona_name + voice_register-Vokabular (#1216)
persona_nameist Pflichtfeld: Der Layer-0-Vertrag (PostCreatedEvent) führt den Anzeigenamen der Persona als Pflichtfeld; Frontend-Komponenten (RedditPost, TwitterPost, PersonaAvatar) zeigen den Namen statt der technischenpersona_id. (#1216 5a)voice_register-Vokabular an Profil-Generator angebunden: Die Enum-Werte sind jetztformal-de/neutral-de/technical-de/skeptisch-de(zuvorformal/casual/jugendsprache, was nie an den Generator angebunden war und per Fallback jede Persona verschleierte). Legacy-Werte werden vom Vertrag abgelehnt (Anti-Dekorations-Linie). Twitter-Profile (CSV persistiert keinvoice_register) erhalten dokumentiertneutral-deals Generator-Default. (#1216)- Kommentare als PostCreatedEvent: Der OASIS-Runner emittiert
CREATE_COMMENT-Aktionen mit plattformpräfixtempost_id(<platform>:comment:<id>) undparent_post_id= Elternpost, sodass der Reddit-Reply-Tree im Live-Feed Äste bekommt.post_idist plattformübergreifend eindeutig (<platform>:<id>), was Dedup-Kollisionen zwischen Reddit und Twitter auflöst. (#1216 5c)
Fixed (Routing-Audit hält den Fallback-Grund fest — 2026-08-10)
- Der Grund für einen Modell-Fallback verschwand aus dem Routing-Audit, sobald er nicht aus dem Provider-Fallback stammte: Die Routen-Auflösung leert das oberste
fallback_reasonfür jede Ebene außerprovider_fallback. Ein Modellverweis mitsource="fallback"landet aber in der Stage- oder Run-Ebene — sein Grund wurde damit verworfen, bevor das Audit ihn schreiben konnte, und im Protokoll stand nur nochnull. Wer im Nachhinein wissen wollte, warum ein Lauf auf ein Ersatzmodell ausgewichen ist, fand die Antwort nicht mehr. Der Grund reist jetzt im selben Legacy-Kanal mit, denai_model_ref_sourceschon nutzt, und das Audit liest ihn von dort. Bestandsprotokolle ohne den neuen Schlüssel bleiben gültig: fehlt er, gilt weiterhin das oberste Feld, sodass auch vor dieser Änderung geschriebene Läufe ihren Grund behalten.
Fixed (Barrierefreiheits-Prüfungen können nicht mehr die falsche Seite prüfen — 2026-08-10)
- Ein Prüflauf, der versehentlich auf dem Einrichtungs-Assistenten landet, bricht jetzt ab, statt grün zu melden: Solange die Ersteinrichtung nicht abgeschlossen ist, leitet die Anwendung jeden Aufruf einer anderen Seite dorthin um. Ein automatisierter Barrierefreiheits-Check, der das nicht bemerkt, prüft monatelang den Assistenten und bescheinigt der eigentlich gemeinten Seite Fehlerfreiheit — genau das war bei der Kostenübersicht passiert, wo nach dem Beheben sofort sechs echte Kontrastverstöße sichtbar wurden. Die Prüfung vergleicht nun die angeforderte mit der tatsächlich erreichten Adresse und nennt im Fehlerfall den fehlenden Schritt beim Namen. Wer den Assistenten absichtlich prüft, bekommt weiterhin keinen Fehlalarm. Eine Bestandsaufnahme aller vorhandenen Prüfläufe hat ergeben, dass aktuell keiner weiteren Seite dasselbe passiert.