From 5410371b9cf6d5798e1a4d0a3083c7c09eefb270 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Mon, 6 Jul 2026 10:28:35 +0200 Subject: [PATCH] =?UTF-8?q?fix(voice):=20App=20uebernimmt=20Server-project?= =?UTF-8?q?Id=20der=20STT-Bubble=20=E2=80=94=20App/Diagnostic-Sync?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Symptom: Frage im Projekt gestellt, Antwort nur in der App sichtbar, Frage nur in der Diagnostic — Frage und Antwort scheinbar in verschiedenen Kontexten. Ursache: die App taggt die lokale Voice-Bubble optimistisch mit dem App-Focus, waehrend der Server (Voice-Router) die autoritative Zuordnung macht. Weichen die ab (Registry-Race aus 3e88eec, Sticky, „fuer X:"-Prefix, Fallback), landet die lokale App-Bubble in einem anderen Kontext als die serverseitig getaggte Frage/Antwort → App- und Diagnostic-Ansicht divergieren. Fix: beim Eintreffen des sender=stt-Broadcasts uebernimmt die App die projectId des Servers fuer die Bubble (alle drei Match-Zweige). Nur wenn das Feld mitkommt — altes Bridge-Format ohne projectId → App-Focus behalten. Primaerursache bleibt 3e88eec (Router liefert wieder den korrekten Kontext). Co-Authored-By: Claude Opus 4.8 (1M context) --- android/src/screens/ChatScreen.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/android/src/screens/ChatScreen.tsx b/android/src/screens/ChatScreen.tsx index e129c42..dd3baed 100644 --- a/android/src/screens/ChatScreen.tsx +++ b/android/src/screens/ChatScreen.tsx @@ -1060,6 +1060,17 @@ const ChatScreen: React.FC = () => { if (sender === 'stt') { const sttText = (message.payload.text as string) || ''; const sttAudioReqId = (message.payload.audioRequestId as string) || ''; + // Autoritative Projekt-Zuordnung vom Server (Voice-Router). Die App + // hatte die lokale Bubble optimistisch mit dem App-Focus getaggt; + // wenn der Router anders entschieden hat (Sticky, \u201Efuer X:"-Prefix, + // oder Fallback), uebernehmen wir hier den Server-Wert \u2014 sonst + // divergieren App- und Diagnostic-Ansicht (Frage im einen Kontext, + // Antwort im anderen). Nur uebernehmen wenn das Feld mitgeliefert + // wurde (leer/undefined = altes Bridge-Format \u2192 App-Focus behalten). + const hasServerPid = typeof (message.payload as any).projectId === 'string'; + const sttProjectId = ((message.payload as any).projectId as string) || ''; + const applyPid = (m: ChatMessage): ChatMessage => + hasServerPid ? { ...m, projectId: sttProjectId } : m; if (!sttText) { return; } @@ -1072,7 +1083,7 @@ const ChatScreen: React.FC = () => { const idxById = prev.findIndex(m => m.audioRequestId === sttAudioReqId); if (idxById >= 0) { const next = prev.slice(); - next[idxById] = { ...next[idxById], text: newText }; + next[idxById] = applyPid({ ...next[idxById], text: newText }); return next; } } @@ -1083,7 +1094,7 @@ const ChatScreen: React.FC = () => { ); if (idx >= 0) { const next = prev.slice(); - next[idx] = { ...next[idx], text: newText }; + next[idx] = applyPid({ ...next[idx], text: newText }); return next; } // Letzter Fallback: gar keine Placeholder \u2192 neue Bubble einfuegen @@ -1093,6 +1104,7 @@ const ChatScreen: React.FC = () => { text: newText, timestamp: message.timestamp, attachments: [{ type: 'audio', name: 'Sprachaufnahme' }], + projectId: hasServerPid ? sttProjectId : focusedProjectIdRef.current, }]); }); return;