Summary
Korean realtime voice transcripts sporadically render U+FFFD replacement characters on the Codex voice screen (e.g. 가볍게 얘기핼봐요 → 가볍게 ��기핼봐요). This is an upstream tracking issue: the opencodex relay has been eliminated as the corruption point, and the root cause is being pursued upstream in openai/codex#35161.
Evidence that eliminates opencodex
- Relay transparency (runtime-proven). The live/realtime sideband relay (
src/server/index.ts::attachLiveSidebandUpstream) forwards frames verbatim. A regression test driving Korean text, binary UTF-8, and ~1.3 MB TCP-segmenting frames through the relay passes byte-identically in both directions (tests/server-live.test.ts, dev ccc059a8).
- Clean upstream on the public GA Realtime API. Streaming synthesized Korean speech (24 kHz PCM16) directly to
wss://api.openai.com/v1/realtime returned 25/25 clean input_audio_transcription deltas, zero U+FFFD.
- codex-rs chain is string-safe (source audit @
4462b9dee). tungstenite Message::Text (protocol-validated UTF-8) → serde as_str transcript deltas → serde app-server notifications → string concatenation in the app renderer. No lossy decode in any inspectable hop.
The corruption signature (one 3-byte Hangul syllable → exactly two U+FFFD) points to a lossy UTF-8 decode at a byte-chunk boundary in either the internal Frameless/AVAS transcription pipeline (server side) or the bundled realtime consumer in the Codex desktop app.
What we shipped
ccc059a8 — regression tests pinning sideband relay multibyte UTF-8 transparency, plus env-gated frame forensics: with OCX_LIVE_FRAME_LOG=/path/frames.jsonl, each relayed sideband frame appends one JSONL record (direction, kind, byte length, U+FFFD presence + short context excerpt; never full payloads).
Next step
Run one real Korean voice session with OCX_LIVE_FRAME_LOG set. If FFFD frames arrive from upstream → confirms server-side corruption, attach the capture to openai/codex#35161. If upstream frames are clean → the bundled client consumer is at fault, attach that evidence instead.
Close this issue when the upstream issue is resolved or the frame-log capture lands as evidence there.
Summary
Korean realtime voice transcripts sporadically render U+FFFD replacement characters on the Codex voice screen (e.g.
가볍게 얘기핼봐요→가볍게 ��기핼봐요). This is an upstream tracking issue: the opencodex relay has been eliminated as the corruption point, and the root cause is being pursued upstream in openai/codex#35161.Evidence that eliminates opencodex
src/server/index.ts::attachLiveSidebandUpstream) forwards frames verbatim. A regression test driving Korean text, binary UTF-8, and ~1.3 MB TCP-segmenting frames through the relay passes byte-identically in both directions (tests/server-live.test.ts, devccc059a8).wss://api.openai.com/v1/realtimereturned 25/25 cleaninput_audio_transcriptiondeltas, zero U+FFFD.4462b9dee). tungsteniteMessage::Text(protocol-validated UTF-8) → serdeas_strtranscript deltas → serde app-server notifications → string concatenation in the app renderer. No lossy decode in any inspectable hop.The corruption signature (one 3-byte Hangul syllable → exactly two U+FFFD) points to a lossy UTF-8 decode at a byte-chunk boundary in either the internal Frameless/AVAS transcription pipeline (server side) or the bundled realtime consumer in the Codex desktop app.
What we shipped
ccc059a8— regression tests pinning sideband relay multibyte UTF-8 transparency, plus env-gated frame forensics: withOCX_LIVE_FRAME_LOG=/path/frames.jsonl, each relayed sideband frame appends one JSONL record (direction, kind, byte length, U+FFFD presence + short context excerpt; never full payloads).Next step
Run one real Korean voice session with
OCX_LIVE_FRAME_LOGset. If FFFD frames arrive from upstream → confirms server-side corruption, attach the capture to openai/codex#35161. If upstream frames are clean → the bundled client consumer is at fault, attach that evidence instead.Close this issue when the upstream issue is resolved or the frame-log capture lands as evidence there.