Zusammenfassung
DiscourseAi::Translation::PostLocalizer (Inhaltslokalisierung) erzeugt gelegentlich
abgeschnittene Übersetzungen, wobei nirgendwo ein Fehler protokolliert wird (Rails-Log,
Sidekiq-Log, Sidekiq Dead/Retry-Warteschlangen). Der Abbruch erfolgt mitten im Satz,
still und das unvollständige Ergebnis wird so gespeichert, als wäre es eine vollständige,
erfolgreiche Übersetzung.
Beobachtet bei: Discourse Core + discourse-ai 46bea6613 (2026-07-09), LLM:
Gemini 2.5 Flash über Google Provider.
Reproduktionsnachweis
Zwei reale Fälle auf unserer Instanz:
- Ein ~2090 Zeichen langer deutscher Beitrag wurde ins Spanische übersetzt, ergab jedoch
nur 50 Zeichen und brach sofort vor einem zitierten Wort („aufwendiger“) im Quelltext
ab. - Ein ~1830 Zeichen langer deutscher Beitrag wurde ins Englische (83 Zeichen) und
Slowakische (97 Zeichen) übersetzt – beide brachen an der genau gleichen Stelle
im Satz ab, unmittelbar vor einem Emoji-Shortcode (
) im Quelltext.
Alle anderen Lokalisierungen (fr, it, pt, ru, he) für denselben Beitrag wurden
vollständig übersetzt (1600–1950 Zeichen).
Ursache (soweit ich sie nachverfolgen konnte)
In lib/completions/structured_output.rb fällt StructuredOutput#read_buffered_property
auf DiscourseAi::Utils::BestEffortJsonParser.extract_key zurück, sobald
@partial_json_tracker.broken? true ist. Dieser Fallback gibt alles zurück, was
vor dem Abbruch des JSON-Streams geparst wurde – ohne Ausnahme, ohne Warnung und
ohne jegliche Andeutung, dass die Ausgabe unvollständig ist. In
lib/translation/base_translator.rb#get_translation wird dieser Wert unverändert als
endgültige Übersetzung verwendet und über PostLocalization#save! gespeichert.
Beide Abbruchstellen in unseren Daten liegen unmittelbar vor einem „speziellen"
Zeichen im Quelltext (ein gerades Anführungszeichen, ein Emoji-Shortcode),
woraufhin der JSON-Streaming-Tracker durch bestimmte Zeichen/Folgen in der
gestreamten Ausgabe des Modells verwirrt wird und den Stream vorzeitig als
broken? markiert.
Auswirkungen
Inhalte werden mit sichtbar unvollständigen, manchmal unsinnigen Übersetzungen
veröffentlicht, und es gibt kein operationales Signal (Log, Dead-Job, Admin-Benachrichtigung),
um dies zu erkennen. Wir haben es nur entdeckt, weil ein Community-Mitglied
Müll mitten im Satz in der UI bemerkte.
Vorgeschlagene Korrekturen
- Eine Warnung/einen Fehler (Rails.logger + Discourse-error-log) ausgeben, wenn
StructuredOutput#broken? true ist und der Best-Effort-Fallback verwendet wird, sodass
Administratoren dies erkennen können, anstatt stillschweigend unvollständige Inhalte
zu veröffentlichen. - In Betracht ziehen, die Länge der Übersetzung vor dem Speichern einer PostLocalization
anhand einer Plausibilitätsschwelle relativ zur Quelltextlänge zu validieren.
Ich kann bei Bedarf vollständige Roh-/Übersetzungstextpaare privat zur Verfügung stellen,
um beim Debuggen des JSON-Trackers zu helfen.