The transcript passed. The call failed. A walk from a green log to a red gate.
Every voice team has shipped this call. The transcript reads clean, the tool log says success, the dashboard is green, and the customer got the wrong outcome. The evidence you tested on and the evidence of what happened are two different things, and the gap between them is where the failures that reach production live.
The gap shows up the same way across stacks. A provider support thread documents an agent sending DTMF digits, the tool log recording them as sent, and far-end IVR trees never detecting the tones (support.vapi.ai, thread 22881851). A maintainer issue records a function-call timeout that does not cancel the handler: the tool keeps running past the deadline, its late result is silently dropped, and a non-idempotent action such as a charge or a booking can still land after the pipeline already recorded nothing, a double-side-effect risk (github.com/pipecat-ai/pipecat, issue 4936). A production report describes an agent that, after a tool call the system logged as successful, repeats an internal instruction more than twenty times and switches language mid-call (Retell community, thread 1769). In each one the log said one thing and the delivered call did another. A successful-sounding call is not evidence the action happened.
Hotato is built so the transcript never gets the last word. Here is the walk from a call to a gate.
You start with one recording:
$ hotato autopsy ./call.wav hotato autopsy [run 1]: call.wav input health: eligible for scan verdict path: eligible (a labeled event here can carry a yield/hold verdict) most likely failure (top-ranked candidate): [1] t=7.63s agent_stop_no_caller trailing_silence_sec=0.37, caller_proximity_sec=0.5 next: label it (use --expect hold instead if the agent was right to keep talking): hotato investigate label '.hotato/investigate-state.json#1' --expect yield
It ranks the moments from the audio, marks the top candidate, and prints the one command that comes next. You label the caught moment as a yield the agent owed or a hold it was right to keep, and that writes a content-addressed contract:
$ hotato investigate label '.hotato/investigate-state.json#1' --expect yield created hotato contract: call-8s-yield dir: contracts/call-8s-yield.hotato expect: yield passed: False measured: did_yield=False seconds_to_yield=n/a talk_over=0.00s next: hotato contract verify contracts
Then the gate scores the stored evidence, deterministically, in CI:
$ hotato contract verify contracts hotato contract verify: contracts (1 contract) [FAIL] call-8s-yield (expect yield): did_yield=False seconds_to_yield=n/a talk_over=0.00s | integrity: intact 0/1 contracts pass; exit_code=1 These contracts pin known failures. Each stays red until you fix the agent and recapture the call, the same way a snapshot test stays red until you update the snapshot. Path to green: fix the agent, then recapture with `hotato drive <bundle>` (vapi/twilio), or the manual path in docs/RECAPTURE.md.
That exit 1 is the part worth slowing down on. A committed contract is a pinned bad call, and it is meant to stay red. The frozen audio never changes, so the gate goes green only after you fix the agent and recapture the call, the same way a snapshot test stays red until you update the snapshot. The still-red state is a review checkpoint, not a failing test. Nothing recaptures automatically, on purpose: the recorded behavior is the source of truth in CI, and updating it is a deliberate, local, reviewed act.
Say-do is what turns a green transcript into a red gate. A tool_call assertion counts only the spans in your ingested trace, so an agent's words claiming a tool ran do not count. An outcome assertion combines those spans with a query against your system of record, so a refund the agent announced is checked against whether a refund row exists. The zombie tool that charged after its timeout, the DTMF the log swore it sent, the successful-sounding call that looped twenty times: each becomes a scored, offline regression instead of a support ticket you read after the customer did.
hotato prove composes every evidence lane into one fail-closed release proof.
Score the call your transcript passed:
hotato autopsy ./call.wav