fix(voice): App uebernimmt Server-projectId der STT-Bubble — App/Diagnostic-Sync
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 aus3e88eec, 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 bleibt3e88eec(Router liefert wieder den korrekten Kontext). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1060,6 +1060,17 @@ const ChatScreen: React.FC = () => {
|
|||||||
if (sender === 'stt') {
|
if (sender === 'stt') {
|
||||||
const sttText = (message.payload.text as string) || '';
|
const sttText = (message.payload.text as string) || '';
|
||||||
const sttAudioReqId = (message.payload.audioRequestId 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) {
|
if (!sttText) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1072,7 +1083,7 @@ const ChatScreen: React.FC = () => {
|
|||||||
const idxById = prev.findIndex(m => m.audioRequestId === sttAudioReqId);
|
const idxById = prev.findIndex(m => m.audioRequestId === sttAudioReqId);
|
||||||
if (idxById >= 0) {
|
if (idxById >= 0) {
|
||||||
const next = prev.slice();
|
const next = prev.slice();
|
||||||
next[idxById] = { ...next[idxById], text: newText };
|
next[idxById] = applyPid({ ...next[idxById], text: newText });
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1083,7 +1094,7 @@ const ChatScreen: React.FC = () => {
|
|||||||
);
|
);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
const next = prev.slice();
|
const next = prev.slice();
|
||||||
next[idx] = { ...next[idx], text: newText };
|
next[idx] = applyPid({ ...next[idx], text: newText });
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
// Letzter Fallback: gar keine Placeholder \u2192 neue Bubble einfuegen
|
// Letzter Fallback: gar keine Placeholder \u2192 neue Bubble einfuegen
|
||||||
@@ -1093,6 +1104,7 @@ const ChatScreen: React.FC = () => {
|
|||||||
text: newText,
|
text: newText,
|
||||||
timestamp: message.timestamp,
|
timestamp: message.timestamp,
|
||||||
attachments: [{ type: 'audio', name: 'Sprachaufnahme' }],
|
attachments: [{ type: 'audio', name: 'Sprachaufnahme' }],
|
||||||
|
projectId: hasServerPid ? sttProjectId : focusedProjectIdRef.current,
|
||||||
}]);
|
}]);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user