The conversation that survives dropouts
A phone loses its link to the server far more often than you would think: a tunnel, the switch from wifi to mobile data, a weak signal. The app reconnects by itself, within seconds. But until 19 May, it came back from every dropout without the thread of the last few minutes, because that thread lived inside the link itself. Since then, the conversation in progress belongs to the person, not to the cable: a reconnection within half an hour finds it intact, history and speaker included. And a passing error on the server side no longer wipes it either.
Ten seconds of tunnel
Hannah is on the train, planning her weekend. "Note that Owen arrives Friday evening, he is staying with us." The app confirms, the card is created. "And remind me to get the spare bed out on Thursday." Another confirmation, then a question back: "for one night or two?". The train enters a tunnel. At the top of the screen, the small dot that shows the link goes from green to red. Ten seconds. The train comes out, the dot turns green again. Hannah answers: "two".
Before 19 May, what followed was awkward. "Two what?" Or worse: an answer that started over from long-term memory, found Owen's card, and embroidered around it, no longer aware that a question had just been asked. The memories were all there. Owen's name, the date, the spare bed, nothing had been lost. What was missing was the minute before.
This defect has a peculiarity: it only shows on a phone that is moving. On a train, in a lift, walking out of the house, the link breaks all the time, and that is exactly where you want to talk rather than type.
What a dropout means for a phone
The phone and the server talk through a channel that stays open for the whole session. That is what lets the voice travel both ways without re-establishing a connection at every sentence. But an open channel has a weakness: it depends on the network carrying it, and a phone changes network constantly.
You step out of the front door: the wifi lets go, mobile data takes over, and the channel does not survive the handover. You cross a patch of weak signal: the channel is declared dead by some piece of equipment between the phone and the server, without anyone deciding anything. You stay quiet for a few minutes: some networks close a line that says nothing. None of these events is a breakdown. It is the normal life of a device you carry in your pocket.
The app knows how to recover, and it does so on its own. When the channel drops, it tries to reopen it after one second. If that fails, it tries again after two seconds, then four, then eight, never waiting more than fifteen seconds between two attempts. Meanwhile the small dot at the top of the screen turns red, amber for the duration of an attempt, then green again. That is all you see, and it is deliberate: a reconnection should not be an event.
Once the channel is open again, the server starts by saying hello: a first message carrying a conversation identifier. The whole matter hangs on that identifier. If it is new, the conversation starts from scratch. If it is the same as before the tunnel, the thread is found again.
Before: a thread tied to the cable
On the server side, the thing that receives your sentences, puts the model to work, runs its tools and sends the answer back is a kind of conductor. It holds the conversation in progress: the latest exchanges, in a sliding window that comfortably covers a few dozen turns; the person declared as holding the phone, when it is not you talking; and the list of cards created since the conversation began, the ones a tap under the answer reopens.
Until 19 May, a conductor was built for each channel. One channel, one conductor, one conversation. As long as the channel lived, all was well. But every tunnel produced a new channel, hence a new conductor, hence an empty conversation. The server saw an unknown identifier arrive and did what it does for a stranger: it started from nothing, with long-term memory alone.
There was worse. The closing of the channel was taken as the end of the conversation: at that instant, it was summarised, archived into long-term memory and removed from working memory. Hannah's tunnel did not merely erase the question about the spare bed, it closed the conversation, as if she had said goodbye.
Hence the symptoms. A "yes" thrown out after a dropout got "yes to what?". A request made in two halves, the first before the tunnel and the second after, no longer had a first half. And a borrowed phone became, without warning, its owner's phone again, with the risk of filing under the wrong name what the passing person had just said.
Since then: the thread belongs to the person
The fix of 19 May is a relocation. There is now a single conductor for the whole server, and it holds every conversation in progress, one per person, regardless of the channels that come and go. Whatever depended on the channel, the screen to send a card to, the way to schedule a reminder on this particular phone, is handed to it at every turn instead of being sealed into its construction.
Alongside, the server keeps a small table: for each person, the conversation in progress and the time of its last activity. "Person" has a precise meaning. If you have an account, it is the account. If you use the app without an account, it is the device, recognised by the identifier it carries. In both cases, the key does not change when the channel does.
When a channel opens, the server looks at that table. If the person had an active conversation less than thirty minutes ago, it hands back the same identifier, and the conductor finds everything again: the history, the declared speaker, the session's cards. Otherwise it creates a new one. In the server logs, that is one line per opening: "resuming conversation, age 9 s", or "new conversation". Hannah's tunnel became a line of the first kind.
And "two" becomes an answer again. The model has the question in front of it, it knows what the word answers, it adjusts the reminder. Nothing spectacular: it is exactly what would have happened without the tunnel.
Why thirty minutes
The number did not fall from the sky. It is the same one as the phone-loan rule, learned that very morning: after half an hour of silence, the app assumes the device is back with its owner. A conversation follows the same logic. Thirty minutes without a word is no longer a dropout, it is a pause, and a pause of that length is the natural signal that you have moved on to something else.
One detail matters in the calculation. The time of last activity is refreshed the moment your sentence arrives, before the model gets to work, not after. A long answer, a web search, a chain of tools taking its time, cannot push you out of the window while you wait.
What goes past thirty minutes is not lost either. The conversation is archived, and another mechanism takes over: past exchanges, read as they were and dated, are handed to the model at the start of the next conversation. That is what answers "what were we talking about last time?", and it is the subject of another article, from the same day. Two mechanisms, two time scales: surviving the dropout covers the minute, recalling past conversations covers the days.
Leaving is not being cut off
Two things must be told apart that the server did not tell apart. Being cut off is something you suffer: the tunnel, the wifi letting go, the line closed by the network. Leaving is something you decide: you quit the app to open another one, or you go back to the home screen.
When you really leave, the app tells the server the conversation is over. It is archived, and the next opening starts a fresh conversation, with the summaries of the previous ones within reach. That is a choice: a conversation you walked away from is a finished conversation, and picking it up word for word an hour later would be more disorienting than useful.
But "really leaving" is narrower than it seems. Opening the keyboard, pulling down the notification shade, a system window popping up: none of that is a departure, and the app had to learn to stop treating them as one. Only fully going to the background counts. The rest, tunnels included, is not your decision, and the thread holds.
An ending that is no longer a door closing
If closing the channel no longer means the end of the conversation, another moment is needed to archive it, otherwise two problems appear. Abandoned conversations, the ones where the person simply put the phone down, would never reach long-term memory. And the server's working memory would fill up with conversations nobody will come back for.
So every five minutes, the server goes through its table of conversations in progress. Those whose person has been silent for more than thirty minutes are archived, just as they would have been when the channel closed in the old days, then removed from working memory. An abandoned conversation still ends up in the database, with a summary, and nothing piles up. Archiving no longer happens the second the channel drops, but at the end of the window: for the person who comes back, that is the point; for the one who does not, nothing changes.
The other dropout, the one that does not come from the network
The same afternoon repaired a second family of dropouts, invisible ones, because they happen between the server and the services it depends on. Hannah's network is perfect, the dot is green, and yet the app answers as if it had lost the thread.
The first case is the model itself. The remote service would occasionally return an empty answer on the first call of a turn, an overload dressed up as success. The server took that for a failure, and you heard the fallback line, the one announcing a technical hitch. That first call is now retried once, after a short pause, before giving up. Once only, and only the first call of the turn. In the middle of a chain of tools, replaying a call would mean doing twice what has already been done: two cards, two reminders. A failed answer can be repaired. A duplicate card cannot, not without someone noticing.
The second case is the memory handed to the model. It is assembled from several sources queried at the same time, and a single late source was enough to blank the whole thing. The model then received an empty memory and answered, in good faith, that it did not remember. The rule became "whatever answers is kept", and the detail of that change is told in the neighbouring article. What matters here is the kinship: a coughing source and a tunnel produce the same sentence in the app's mouth, and deserved to be dealt with on the same day.
Finally, at every turn, the server notes in its logs what it actually handed to the model: recent conversations, memories from each layer, rules, and the size of the whole. Before, "it forgot" was a report impossible to investigate. Now one can tell whether the thread was there and misread, or absent.
What does not survive yet
That day set a frame, it did not solve every case, and it is better to say which ones remain open.
A sentence spoken during the ten seconds themselves does not leave. If the dot is red when you release the orb, the app cannot send your sentence, and you say it again once the dot is green. The thread is intact, but that turn has to be redone. Holding those sentences and sending them when the network returns is a separate piece of work.
A server restart takes away conversations not yet archived, since they live in working memory between two archivings. Writing every turn to the database as it happens, so that a restart costs at worst one sentence, is the logical next step, and it waits for this one to prove itself.
Beyond thirty minutes, it is a new conversation, on purpose. And the answer itself needs the network: understanding your voice, thinking, replying out loud, all of that happens on the server. What survives the dropout is the thread. Not the ability to talk inside the tunnel.
For Hannah, the day sums up simply. She can hold a conversation on a train, and the train is allowed to enter a tunnel. When it comes out, the question asked before is still asked, the person who was talking is still talking, and "two" means two nights. It is a small thing to state. It was the difference between an app you use sitting down and an app you use while walking.
