By Juste Thales Gnimavo (CEO, ZeroSuite) and Claude Opus 5.5 (Claude Code)
Déblo Duo is a real-time voice interpreter: each person speaks their language and hears the other in theirs. Why Déblo Duo exists explains the product. This post covers one session, on November 4, 2026. It is the story of a measurement that broke a rule the CEO had set, and of why we shipped anyway.
The problem: each turn arrived alone
Duo runs on Gemini Live Translate. One live session per direction: one listens to the host and speaks to the guest, the other does the reverse. Each session knew only what it was hearing. It had no idea what the other person had just said.
For most languages that is fine. For Chinese it is not. Spoken Chinese has many words that sound the same and mean different things. A human interpreter resolves them with the conversation. In our test, the word to get right was « sac », a bag. Our interpreter had no conversation. It had one sentence at a time.
The CEO had moved this item ahead of the queue on purpose. Juste also set the constraint before any code: the fix could cost at most +300 ms of latency.
The first bench was not conclusive
There was already a bench from an earlier session the same day. Claude read it before building on it, and it did not hold.
The brief said "Spanish and Arabic correct in every variant". The earlier bench showed the Arabic test item at 5/6 with context and 8/8 without, which would mean context made Arabic worse. But each cell had between 2 and 8 runs, and 58 sessions out of 180 had been lost to 1011 disconnects. You cannot conclude anything from 5/6 against 8/8 at those sizes. The bench code also lived only in the scratchpad of a closed session. Claude recovered it, moved it into the repository, excluded it from the production images, and ran it again.
The new bench used 15 pre-generated audio clips, at most two connections at a time, and three variants:
- A: today's behaviour, no context.
- S: one session per direction, refreshed with the other side's last sentences.
- P: a fresh, pre-warmed session for every turn, with context.
What the numbers said
The table is partial: 246 result lines out of about 450, because the bench was still running when the decision was made. The gaps it shows are not close calls.
| Language | Test item, A | Test item, S | Median first word, A → S | p90, A → S |
|---|---|---|---|---|
| Chinese | 0/14 | 14/14 | 2.2 → 3.1 s | 3.9 → 4.0 s |
| Japanese | 11/13 | 14/14 | 2.0 → 3.1 s | 4.7 → 4.8 s |
| Spanish | 14/14 | 14/14 | 2.0 → 1.9 s | 3.8 → 3.8 s |
| Arabic | 12/12 | 12/12 | 3.3 → 3.5 s | 4.3 → 5.0 s |
Chinese went from 0 out of 14 to 14 out of 14. Japanese went from 11/13 to 14/14. Spanish and Arabic were already right and stayed right. The earlier Arabic scare was noise.
Variant P gave the same accuracy as S, with a first word at 4.4 to 5.2 s median: two to three seconds slower than today. That is seven to ten times the CEO's limit. We rejected it.
Variant S cost about one second of median latency in Chinese and Japanese. The p90 barely moved. That is still more than three times the limit.
Why we broke the limit
Claude did not hide the gap and did not round it down. The log names it: "écart assumé au critère de latence", a deliberate gap against the latency criterion.
The argument was simple. A wrong word is not a small error. When the interpreter turns "bag" into another word that sounds the same, the host does not understand, asks again, and waits for a new answer. That round trip costs more than five seconds. One extra second on every Chinese turn, against more than five seconds on every turn the word comes out wrong, which was every time in the bench.
The CEO accepted the trade, and accepted that it would not be perfect either: « l'hôte redemande, comme dans la vie réelle ». Between two people with a human interpreter, a misheard word gets a second question too. The goal is not zero repeats. The goal is not to make the repeat the normal case.
One thing context does not fix. The Japanese price "10 dollars 50" stayed wrong in both variants: right 1 time out of 6 without context, 0 out of 7 with it. That is a property of the model, not of what we send it. We wrote it down and left it.
How the context goes in
The design choices, each recorded in the log with how to undo it:
- Each direction keeps the last 3 final sentences of each side, at most 240 characters per line.
- The other side's lines enter the session's instructions when it opens, under a short preamble: use them to resolve ambiguity, never say them aloud, keep numbers exact.
- Only the source sentences go in, not their translations. The brief asked for both. The bench measured source only (14/14), and translations double the length with no new information.
- The first switch happens once the other side has said 30 characters in total. That skips a lone "Bonjour.".
- At most two attempts per direction. Then the context is refreshed at each natural rotation.
Open before you close
The more interesting change was not the context. It was the rotation.
To change a live session's instructions, you need a new session. The old code closed the current one, then opened the next. Our reconnect buffer covers 3 seconds of audio. Opening a session takes 2 to 7 seconds. So every rotation already had a hole in it, before this work started. The log also found that voluntary rotations were counted against the reconnect limit, as if they were failures.
The new code opens the next session first, in reserve, feeds it silence, and swaps it in at the next pause. If the reserve fails to open, the old session keeps running. If no pause comes within 45 seconds, the reserve is dropped. One reserve per direction, three per minute at most. Billing did not change.
The first CEO trial in production, between 13:42 and 13:50 UTC, showed no switch in two calls out of three. The log said standby_dropped reason=no_pause. The pause detector watched for any activity, and the model emits output audio continuously, so the session never looked idle. The only context that arrived came through a reconnect after a cutoff. The offline simulation, with a fake Live client, had not modelled continuous output audio. The fix was to measure pauses on transcripts instead. Claude then replayed the five offline scenarios with continuous audio output: 5 out of 5.
The proof, at 13:55 UTC
The worker restarted at 13:54 UTC. The CEO called again, French to Chinese, two devices. The worker logs, read-only:
13:55:40 interpreter.context_wanted direction=b_to_a chars=84 attempt=1
13:55:42 interpreter.switch direction=b_to_a why=context waited_s=1.9 context_lines=1
13:55:42 interpreter.session_open direction=b_to_a connection=2 connect_ms=326 context_lines=1 prewarmed=true
13:55:58 interpreter.session_close direction=a_to_b connection=1 lifetime_s=32.5 reason=server_closed:APIError
13:55:59 interpreter.session_open direction=a_to_b connection=2 connect_ms=490 context_lines=1 prewarmed=falseThe switch came 1.9 s after the host's sentence. The old session closed and the new one took over in the same millisecond, because it was already open. The other direction received context too, through a reconnect after a cutoff on Google's side. On that call, at 13:56 UTC, the CEO heard « sac », the right word. Over all of Juste's trials, the verdict was the context good: « sac » recognised most of the time, residual errors accepted.
That is what was proven, where and when: one direction switching with context on a pre-warmed session, the other receiving context on reconnect, and the target word right on a real call. It is not a rate over a day of traffic.
Sidebar: the same morning, 10 characters into 8
Earlier that day, in another session, the CEO reported that a presentation's transcript was empty. The worker logs showed the call had ended with 5, 3 and 5 turns, and the transcript upload answered 422 three times.
The cause was one field. In presentation mode, the direction is written to-<language>. to-zh-Hans is 10 characters. The field allowed 8. All four sessions of that day included Chinese. Earlier successes did not. The limit went to 24, and a probe at 01:54 UTC confirmed the server now accepts to-zh-Hans and still rejects a 30-character value. The transcripts of those four sessions were held only in the worker's memory. They are gone for good.
What stays open
- The 1011 disconnect rate in production is not measured. The container logs only keep the current container, 171 lines after a restart. The design protects the reserve against it, since the old session keeps running, but we have no rate.
- Recurring
APIErrorcutoffs from Google: sessions lived 57 s and 32 s in two calls that day. Reconnect covers them within the 3-second buffer, but each one is a possible audio gap. We will count them over a full day before touching anything. - Presentation mode is outside the reserve on purpose: up to three sessions per presentation would double its exposure to 1011. Its own soft rotation still measures pauses on activity, so with continuous output audio it only rotates at the hard limit, 570 s.
- The bench table is partial, 246 lines out of about 450.
- Context comes from the other participant's speech. It can only steer the translation of their own call.
The lesson
The CEO set +300 ms before any measurement. The measurement said one second. There were two easy ways out: quietly keep the rule and ship a Chinese interpreter that gets a word wrong every time, or quietly break it and hope nobody checked. The log does neither. It writes the gap, the reason, and the CEO's answer next to each other.
A latency limit exists to protect the conversation. When the cheaper option breaks the conversation more often than the slower one, the limit has done its job by forcing the comparison. It does not get to win it.