fix(chat): chat_backup ts auf UNIX-ms umgestellt + Doppelpost-Schutz

Bug-1: _append_chat_backup nutzte asyncio.get_event_loop().time() —
das ist Container-Monotonic (bei Restart wieder 0), NICHT UNIX-Zeit.
Bridge schrieb so Eintraege mit ts wie 394M (=6.5 min Uptime), App-side
generiert User-Bubbles mit Date.now() = 1.778e12. Beim Sortieren in
der App: Server-Bubbles landeten alle als "uralt" (kleine ts) ueber den
lokalen Bubbles und teilweise unter dem 500er-Cap raus — Symptom:
"alles nach Hello Kitty fehlt in der App".

Fix: _append_chat_backup nutzt jetzt time.time() * 1000 (UNIX-ms).

Bug-2: doppelte User-Bubble nach App-Hintergrund/Restart mit Retry-Knopf.
Race-Fix von vorhin (text+timestamp-Heuristik, 5-Min-Fenster) griff
nicht weil bei kaputten Server-ts (394M) und lokalen UNIX-ms (1.778e12)
das Diff 1.7 Billionen ms war → Fenster nie zutreffend → lokale Bubble
blieb als Duplikat.

Fix: Text-Match alleine reicht — wenn der Server irgendwo eine
textgleiche User-Bubble hat, ist es dieselbe Nachricht. Greift jetzt
unabhaengig von ts-Konsistenz.

Plus: tools/migrate_chat_backup_ts.py — repariert vorhandene jsonl
(284 von 299 Eintraege auf der VM hatten Container-Uptime-ts). Datei-
Reihenfolge bleibt erhalten (war eh chronologisch), ts werden ab File-
Mtime rueckwaerts 60s-Schritten vergeben. Idempotent, .bak-Backup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-15 11:26:39 +02:00
parent 71c60ade8a
commit 11b205ddaf
3 changed files with 116 additions and 15 deletions
+7 -2
View File
@@ -997,8 +997,13 @@ class ARIABridge:
"""Schreibt eine Zeile in /shared/config/chat_backup.jsonl.
Wird von Diagnostic + App als History-Quelle gelesen.
entry braucht mindestens {role, text}; ts wird ergaenzt.
Returns den ts (auch fuer Bubble-Loeschen-Tracking)."""
ts = int(asyncio.get_event_loop().time() * 1000)
Returns den ts (auch fuer Bubble-Loeschen-Tracking).
WICHTIG: ts ist UNIX-ms (time.time()*1000), NICHT loop-time.
Loop-time ist Container-monotonic — bei jedem Restart wieder 0.
Das brach die App-History-Sortierung weil App-side Date.now()
(echtes UNIX-ms) mit Bridge-Container-Uptime gemischt wurde."""
ts = int(time.time() * 1000)
try:
line = {"ts": ts}
line.update(entry)