← Back to Blog

The Gedanken Experiment Before the Phone Call

By Erhan Bilal, PhD - CSO, Enkira AIJune 15, 2026
AI agentsvoice agentstestingtelephonysoftware engineering
Share:

Young Einstein imagining chasing a light beam

Why voice agents need imagination before execution

Late in 1895, in the Swiss town of Aarau, Albert Einstein is sixteen years old: no patent office yet, no equations on blackboards for tourists, not a dorm-room poster yet. Just a student with a stubborn visual imagination, picturing himself chasing a beam of light.

The scene is almost cute in its simplicity: a boy, a wave, a race that cannot quite be run. Suppose he could catch the beam. Would it hang there beside him as a frozen electromagnetic ripple? Late in life, Einstein remembered the paradox as one of the germs of special relativity. Historians are careful about the story, as they should be. John Norton has argued that the famous version is tangled up with hindsight and does not work as a clean argument against every theory then available. But the charm of the scene survives the caveat. A teenager imagines an impossible experiment, then refuses to let the imagined world violate the laws he is trying to understand.

That is the useful part. No laboratory was required, only disciplined imagination constrained by the physics as Einstein understood it. The scene was imaginary; the rules were binding.

Telephone voice agents have a small software version of the same problem. The physical experiment is available. You can place the call, listen to the agent, interrupt it, watch a webhook arrive late, run the transcript afterward, and try again. That experiment is expensive in the broad sense of the word: time, money, attention, phone numbers, SIP trunks, API quotas, operators, and patience. Worse, it is a poor instrument for discovering the first class of bugs.

Architectural bugs show up first: the call that reaches a terminal state twice, the answer that sounds correct while the database is one turn behind, the callback that arrives after the human has already hung up. A language model may recover conversationally from an interruption while the state machine fails to recover at all. Those failures do not need a phone line to be imagined, because they are already latent in the code.

The trick is to imagine them with discipline.

The phone call is the most expensive debugger

Telephone agents have an awkward property: the moment they become realistic, they stop being easy to test.

A chat agent can be exercised by pasting text into a prompt box. A web workflow can be clicked through with a browser, paused, inspected, and replayed. A voice call unfolds in time. The user can interrupt the agent in the middle of a sentence. Speech-to-text can produce a plausible transcript with the wrong meaning. Text-to-speech can still be speaking while the application has already chosen the next branch. A telephony provider can deliver the same webhook twice, or deliver the right webhook after the local state has moved on. Latency belongs to the product itself.

At small scale, the natural response is to test by calling. Someone dials the number. Someone pretends to be a patient, a customer, a receptionist, a tired person in a parking lot, a person trying to order while another person is talking in the background. The call either works or does not. Notes are taken. A patch is made. Another call is placed.

That loop is necessary, and much too slow to be the main instrument of design.

Cost is only the obvious danger. Live calls are memorable, which makes them misleading. A single dead-air call can take over the whole debugging session even when the underlying defect is a missing transition guard that would have appeared in six other scenarios. A call that sounds smooth can produce false confidence if the state underneath is wrong. Voice is persuasive. A system can fail politely.

By the time a voice agent is ready for live testing, the developer should already know what the dangerous branches are. Live testing should confirm the behavior of a system whose failure modes have been mapped. It should not be the first time the system is asked what happens when two events arrive out of order.

The useful version

The phrase thought experiment can sound like permission to speculate. In software, speculation is cheap enough to become a vice.

A better version starts narrower. A source-grounded thought experiment treats the local code as the physics of the world. You may invent the caller, the timing, the interruption, the webhook delay, the malformed transcript, the retry, the operator handoff, or the confused human on the other end of the line. Once the event enters the system, however, the imagined call has to run through the functions, prompts, callbacks, queues, reducers, database writes, and terminal states that exist on disk.

Our gedankenexperiment skill exists for that narrower job. It forces the developer through a structured rehearsal before touching the live system, without pretending that mental execution can replace objective testing.

Here the model stays out of Python, simulators, and the phone network. It reads the code, keeps the relevant functions in context, and traces a hypothetical event in language. A callback arrives after hangup. The handler receives it with stale state. The transition guard either catches the mismatch or lets finalization run again. That language-level trace is the sense in which the LLM is simulating in its "head."

The workflow is deliberately plain. Establish the source of truth, identify the real runtime path, and generate plausible scenarios from how the system is built. Walk each scenario through the local code. Build a bank of failure modes before proposing fixes, then cluster those failures by missing invariant. The fix should make the system harder to break at the ownership boundary where the break occurs.

That last clause matters. Bad voice-agent fixes are usually one transcript too specific. They add another prompt instruction, another special case, another check that happens after the wrong module has already accepted impossible state. The good fix usually looks less dramatic: one transition guard, one idempotency boundary, one terminalization rule, one place where the system refuses to infer data that the user has not provided.

Its job is to expose the shape of the call flow well enough that the invariant becomes visible.

The bugs that imagination finds first

A telephone voice app is full of failures that are hard to catch by happy-path testing and easier to find by disciplined rehearsal.

Consider a survey call. The agent asks a patient whether they had a scan. The patient answers, starts to correct themselves, then says something that sounds like approval. A human listener can usually track the correction. The code may not. One layer may hold the corrected semantic state while another layer holds the earlier slot value. The agent's next sentence can sound right because the model saw the correction, while finalization writes the stale value because the reducer never received the same update.

Or take an ordering agent. The customer asks for a change after hearing the readback. The model handles the conversation gracefully, perhaps even apologizes in a way that sounds competent, but the order object has already crossed a terminal boundary. The next webhook or background job sees a completed order and treats the correction as a fresh side channel instead of a mutation to the original state. The call sounds like a service interaction. The backend has split reality in two.

Or take dead air. The user hears silence. The first temptation is to investigate audio. Sometimes that is right. But a thought experiment asks a more annoying question first: which code path is allowed to produce no speech while still considering the turn alive? Did the TTS request start? Did the transport accept frames? Did the agent await a tool call that can hang? Did a cancellation path swallow the event that should have moved the system to a repair prompt? Before opening a dashboard, the developer has to name the possible owners of silence.

This is the normal weather of voice systems. Speech arrives incrementally. People interrupt. External providers retry. Models produce soft commitments. State machines prefer hard ones. Testing at scale will surface all of this eventually, but "eventually" is an expensive test strategy.

The source-grounded thought experiment turns those cases into a cheap inventory. Its economy comes from strictness, not looseness.

Close relatives

The word gedankenexperiment gives the practice a little philosophical theater. In software, the closest precedents are usually external machines for disciplined imagination rather than mental experiments in the Einstein sense.

Scenario-based testing starts from the user's story and turns it into testable behavior. In the late 1990s, Johannes Ryser and Martin Glinz described a procedure for taking natural-language scenarios, formalizing them into statecharts, annotating those statecharts, and traversing paths through them to derive concrete system tests. The scenario begins in human language. The discipline comes from forcing that story into a state model.

Model-based testing makes the point more directly. The developer writes a model of the system, usually as states and transitions, and tools generate or execute paths through it. Modbat, for example, is a model-based tester for APIs of stateful systems; the user defines a model, the tool explores it, and failed runs are returned as traces. XState, in the JavaScript world, became popular because it gives application logic a form that can be modeled, visualized, and reasoned about instead of scattered across callbacks and flags. Plain engineering keeps relearning that state is where the bodies are buried.

Formal methods are the severe version of the same instinct. AWS engineers have written publicly about using TLA+ on large distributed systems, where the value was not that the specification replaced testing but that it found subtle design bugs they did not expect ordinary techniques to catch. TLA+ is math with a model checker attached. The posture, though, is familiar: before trusting the running system, construct a constrained world in which possible events can be explored cheaply.

Property-based testing comes from another direction. QuickCheck asked programmers to state properties and let the harness generate many inputs in search of counterexamples. Modern stateful variants extend that idea to sequences of operations. Again, the important shift is economic. The human does not handwrite every test case. The human writes the rule, the model, or the invariant, and the system searches for the case that breaks it.

An LLM-based thought experiment changes the medium of that search. Rather than a formal checker or literal program execution, the model offers something closer to constrained imaginative computation: given the local source, the named actors, the event boundaries, and the invariants, it proposes and walks through plausible traces before the expensive runtime has to be invoked. Loosely, some exploratory work moves from the CPU-shaped world of scripts, test runners, providers, and dashboards into GPU-driven inference, where a neural network is good at generating human-shaped sequences under constraints. The metaphor has limits, but the engineering shift is real: some of the search happens inside the model before the live system spends money, time, or operator attention.

Useful as that shift is, it is easy to overstate. A neural rehearsal can find a class of bug before a simulator does. It can suggest that a state owner is split, that a terminal transition is underguarded, or that a callback has no safe landing place after hangup. Proof, audio quality, and failing regression tests still belong to objective verification. Sequencing is the point: let LLM imagination improve the hypotheses before the tests begin.

The agent ecosystem is moving in the same direction, though in a more practical and tool-shaped way. Microsoft's Playwright MCP gives LLMs structured browser automation through accessibility snapshots rather than screenshots. Browser Use gives agents a real browser action space and recovery loops. These are rehearsal spaces, places where an agent can act against a cheaper proxy for the world before the consequenceful version of the task begins.

Voice agents are late to this party because the real world is so seductive. You can always place the call. But the fact that the experiment is available does not make it the right first experiment.

The right order of operations

The practical workflow for a hard voice feature begins with reconstruction. Read the entrypoint, the prompt boundary, the state owner, the event handlers, the terminalization path, the external side effects, and the tests that already exist. Diagrams can help, provided the code agrees with them.

Scenarios should then come from the architecture itself. A system with retries deserves duplicate events. Tool calls bring latency and failure. Human correction means correction after readback. A final state needs an event that arrives just after finalization. Operator handoff requires the moment when responsibility changes hands.

Only then should the developer walk the scenarios through the code, without fixing anything yet. This is the step developers most want to skip, because the first plausible fix usually appears early. Resist it. Early fixes often patch the first symptom. Better fixes emerge after the failures have been banked together.

Synthesis is where the value appears. Five failures caused by an ambiguous prompt call for prompt work. Five failures caused by two modules claiming the same transition leave the prompt innocent; the ownership boundary needs repair.

Testing comes last, in layers: unit tests for invariants, simulator tests for call flow, local audio checks for timing and turn-taking, live calls for the last mile. The phone call belongs at the end of the stack. Its importance is exactly why it should not be wasted on bugs the code could have confessed earlier.

The small dignity of not dialing

Einstein's light-beam story is easy to romanticize. A young mind imagines the impossible and the universe yields. Software is less grand. A developer imagines a caller interrupting a synthetic voice while a webhook arrives late, and the reward is a failing test that would have been cheaper to write yesterday.

Still, the family resemblance is real. A good thought experiment is imagination under law, not daydreaming. For Einstein, the law was electrodynamics. For a voice agent, the law is the local runtime: the reducer, the queue, the callback, the prompt, the transport, the state machine, the database row.

Telephone voice apps will always need real calls. The ear matters. Timing matters. People matter. But before asking whether the agent can survive the world, ask whether the world you are about to test is even internally coherent.

The cheapest call is the one you do not place because the code already told you how it would fail.


Further reading

  • Einstein, A. (1949). Autobiographical Notes. In P. A. Schilpp (Ed.), Albert Einstein: Philosopher-Scientist. The Library of Living Philosophers, Volume 7: 1-96.
  • Norton, J. D. (2013). Chasing the light: Einstein's most famous thought experiment. In J. R. Brown, M. Frappier, and L. Meynell (Eds.), Thought Experiments in Philosophy, Science, and the Arts. Routledge: 123-140.
  • Ryser, J. and Glinz, M. (1999). A scenario-based approach to validating and testing software systems using statecharts. Proceedings of the 12th International Conference on Software and Systems Engineering and their Applications.
  • Artho, C., Seidl, M., Gros, Q., Choi, E., Kitamura, T., Mori, A., Ramler, R., and Yamagata, Y. (2015). Model-based testing of stateful APIs with Modbat. Proceedings of the 30th IEEE/ACM International Conference on Automated Software Engineering: 858-863.
  • Newcombe, C., Rath, T., Zhang, F., Munteanu, B., Brooker, M., and Deardeuff, M. (2015). How Amazon Web Services uses formal methods. Communications of the ACM, 58(4): 66-73.
  • Claessen, K. and Hughes, J. (2000). QuickCheck: a lightweight tool for random testing of Haskell programs. Proceedings of the Fifth ACM SIGPLAN International Conference on Functional Programming: 268-279.
  • Stately. (n.d.). @xstate/test: model-based testing utilities for XState. Stately documentation.
  • Microsoft. (n.d.). Playwright MCP. GitHub repository.
  • Browser Use. (n.d.). Browser Use. GitHub repository.