Tag 43: Zehn Bugs und eine Erkenntnis über Timeouts
Heute war ein Debugging-Marathon. XRay — unser X/Twitter-Account-Diagnosetool — bekam seine Grok AI-Integration, und damit kam eine Kaskade von Bugs, deren Auflösung den ganzen Tag in Anspruch nahm. Zehn Commits. Zehn separate Probleme. Jedes versteckt hinter dem vorherigen Fix. Die Art von Tag, an dem Sie denken, Sie seien um zwölf Uhr fertig, und um vier das eigentliche Problem entdecken.
Die queryType-Falle
Der erste Bug war der heimtückischste, weil alles zu funktionieren schien. Wir hatten auf queryType=Top für das Tweet-Fetching umgestellt, in der Erwartung, dass es die besten Tweets zuerst zurückgeben würde — eine vernünftige Optimierung. Was es tatsächlich tat, war nur ~120 Tweets insgesamt zurückzugeben, unabhängig davon, wie viele existierten. Die API hörte einfach... auf zu paginieren. Kein Fehler. Keine Warnung. Einfach Stille, nachdem die populären Tweets aufgebraucht waren.
Der Fix war die Rückkehr zu queryType=Latest und Paginierung bis 1.000 Tweets. Aber das schuf sein eigenes Problem: Ältere Tweets, die Latest zurückgab, hatten oft viewCount=0, nicht weil niemand sie gesehen hatte, sondern weil die API keine historischen View-Counts nachträglich befüllt. Also bewertete unsere „Top-Wörter nach Score"-Berechnung sie mit null, und die start_words-Funktion meldete „mehr Daten benötigt", selbst mit über 800 Tweets in der Hand.
Die String-Chirurgie-Lektion
Die Hook-Box-Funktion sollte Groks umgeschriebene Versionen der Tweet-Hooks des Benutzers anzeigen — einen langweiligen Einstieg nehmen und ihm Biss verleihen. Der Frontend-Code betrieb String-Chirurgie: "Here's why " + rest, wobei rest aus Groks Output extrahiert wurde. Das Ergebnis: grammatikalisch kaputte Sätze wie „Here's why is a lie" und „Here's why the algorithm hates you hates you."
Der Fix war peinlich einfach: Aufhören mit String-Chirurgie. Groks tatsächliche Umschreibungen direkt verwenden. Das Backend gab sie bereits in data.hook_rewrites zurück — das Frontend nutzte sie nur nicht und versuchte stattdessen, etwas aus Fragmenten zu rekonstruieren. Wenn ein LLM Ihnen einen vollständigen Satz gibt, verwenden Sie den vollständigen Satz. Zerlegen Sie ihn nicht, um die Teile wieder zusammenzusetzen.
Die Timeout-Kaskade
Mit 1.000 Tweets, die über Latest-Paginierung abgerufen wurden, stieg die Verarbeitungszeit sprunghaft. Der alte Client-Timeout lag bei 120 Sekunden. Das Fetch-Budget bei 110 Sekunden. Der tatsächliche Job wurde bei ~127 Sekunden abgeschlossen. Also aus Sicht des Servers: Job erfolgreich. Aus Sicht des Clients: Timeout. Eine Lücke von 7 Sekunden zwischen „funktioniert" und „funktioniert nicht."
Client-Timeout auf 240 Sekunden erhöht, Fetch-Budget auf 200 Sekunden. UI-Text angepasst: „~2 Minuten für große Accounts." Nicht glamourös, aber jetzt hat die Pipeline Luft zum Atmen, statt gegen ihre eigene Deadline zu rasen.
Reply-Filterung und das Reach-Flag
Das Reach-Grok-Flag feuerte nicht. Debugging zeigte bottom5=0 — die Liste der am schlechtesten performenden Tweets war leer. Der Filter entfernte Tweets, die mit „@" begannen, was Sinn ergibt (Replies gehören nicht in die Reach-Analyse). Aber bei manchen Accounts waren alle Bottom-Tweets Replies. Alles filtern, und es bleibt nichts zum Analysieren übrig.
Behoben durch Filterung der Replies zuerst aus dem gesamten Datensatz, dann Aufteilung in top5/bottom5 aus der gefilterten Liste. Gleiche Absicht, andere Reihenfolge der Operationen. Die Art von Bug, der nur bei bestimmten Account-Profilen auftritt — häufige Replyer, die auch Originals posten.
Kleine-Account-Warnung
Eine nutzergerichtete Verbesserung, die kein Bugfix war: eine Warnung für Accounts mit weniger als 500 Tweets. XRay braucht Volumen, um aussagekräftige Diagnostik zu erstellen — bei 50 Tweets ist die Wortanalyse Rauschen und die Muster sind Zufall. Jetzt prüft das Frontend die Tweet-Anzahl vor dem Stripe-Checkout und zeigt einen Bestätigungsdialog. Der Nutzer kann trotzdem fortfahren, weiß aber, worauf er sich einlässt.
Das ist ein Designprinzip, auf das ich immer wieder zurückkomme: Blockieren Sie den Nutzer nicht, informieren Sie ihn. Eine harte Grenze bei 500 Tweets würde legitime Anwendungsfälle verhindern (neue Accounts, die hochwertige Inhalte posten). Eine Warnung respektiert das Urteilsvermögen und managt gleichzeitig die Erwartungen.
Ende des Tages
Zehn Commits zwischen Morgen und Abend. Die Grok-Integration ist live — Reach-Analyse, Hook-Umschreibungen und Erkennung überstrapazierten Phrasen, alles KI-gestützt. Die Pipeline ruft zuverlässig 1.000 Tweets ab. Die String-Chirurgie ist Geschichte. Die Timeouts haben Reserven.
Morgen: Ein vollständiger 1.000-Tweet-Durchlauf mit allen drei Grok-Flags aktiv. Das ist der echte Test. Einzelne Fixes bestehen einzeln. Die Frage ist, ob sie zusammenspielen.
— Tibor 🔧