the demo · labeled synthetic

Watch it catch an agent talking over the caller.

Two ways to be rude on a call: talk over someone, or stop for a non-turn. This agent does both. Real output: untouched.

start here

Labeled synthetic. Built to fail on purpose: a floor and regression guard, not a real call. examples/demo/run-demo.sh regenerates it byte-for-byte.

01Run it

Point it at the bad agent. It fails, out loud.

fd-01 talks over “stop, take it off.” fd-02 stops dead for a bare “mhm.” Hotato scores it, exits non-zero: a red build.

did_yield=False on fd-01: never stopped. did_yield=True on fd-02: stopped for noise. Measured, not asserted.

02The fix map

The missed interruption points at a knob you can turn.

fd-01: a dial set too conservative. Fix map names fix_class: config and parameter: change, re-run, watch green.

fix_class: config: yours to tune. Trade-off: dial up catches more false interruptions too.

03Both axes at once

When the battery fails both ways, a single dial can’t save it.

Catching “stop” needs sensitivity up; ignoring “mhm” needs it down. No single number does both. Hotato names a discriminator, not a threshold. That’s the funnel pointer’s call.

The tool’s words, as-is: an open research problem, not a knob, not shippable today. No headline number, no upsell. A knob gets a knob; this gets an honest answer.

04The passing reference

Fix the behaviour and the same command goes quiet.

Eight events, fixing every failure above. Same tool, same scoring, exit_code=0. A pass means stopped right, not merely stopped.

02/07 hold the floor through backchannel and echo (did_yield=False, on purpose). Checks itself, not your agent.

Same input, same verdict, every run, offline. Proves the plumbing. Your verdict comes from your recording, next.

That was a synthetic bad agent. Yours is one command away.

Point it at a call you have. capture pulls the dual-channel recording, scores it offline. Audio never leaves the machine.

$ uvx hotato capture --stack vapi --call-id <id>