hotato explain reads a finished result and produces a root-cause
attribution: which layer likely failed, whether a fix is safe to try, the
opposite-risk tradeoff, and a plain next command. It's compositional, not
a new scoring engine: it reframes hotato diagnose's per-event findings
and hotato plan's policy gate (a mapped knob, one bounded step, a
passing opposite-risk fixture, config-only-safe), plus, for a contract
bundle, its own trust report, policy bounds, and an attached voice trace
when present.
When the evidence can't support picking ONE root cause, explain states the reason plainly.
hotato run --suite barge-in --format json > result.json
hotato explain result.json| Input | Example | Behavior |
|---|---|---|
| Run envelope | hotato explain result.json |
Full diagnose + policy-gate attribution, per failing event. |
| Sweep/analyze candidate ref | hotato explain hotato-sweep.json#1 |
ALWAYS refused: a candidate carries no human label. |
| Contract bundle directory | hotato explain contracts/refund-cutoff-001.hotato |
Attributed from the contract's own measurement and policy bounds, or refused when it needs a signal the bundle lacks. |
Layer-general by design: turn_taking is the only populated layer today,
with room for the next (asr, tool, policy, latency, handoff, ...) without
a version bump.
{"event_id": the failing event, or null for a battery-level finding,
"failure_layer": "turn_taking",
"type": missed_real_interruption | false_stop_on_backchannel |
false_stop_on_ambient_noise | slow_yield |
excess_talk_over | endpointing_miss | threshold_funnel,
"turn_taking_layer": interruption_detection | endpointing,
"confidence": high | medium | low,
"fixability": safe_to_patch | needs_human | insufficient_evidence |
do_not_patch,
"opposite_risk": the tradeoff a fix on this axis trades against,
"evidence_for": measured fields and notes that support this attribution,
"evidence_against": the caveats against treating it as settled,
"unknowns": explicit gaps in the evidence (never silently assumed),
"safe_next_action": one concrete next command, never an auto-apply}
fixability reuses the SAME gate hotato plan already enforces:
safe_to_patch-- the failure maps to one setting AND the battery already has a passing opposite-risk fixture on that axis (the same coveragehotato planrequires before proposing a change).insufficient_evidence-- the failure maps to one setting but the opposite-risk fixture is missing, so a change couldn't be verified; or a contract bundle's policy-bound comparison found a violation with no companion moment to verify against.needs_human-- an audio-path problem (echo bleed).do_not_patch-- the threshold funnel: the battery missed an interruption it should have caught AND false-stopped on a backchannel. No single sensitivity threshold fixes both; the fix class is engagement-control. This adds one COMPOSITE battery-level attribution (event_id: null,type: threshold_funnel) alongside the two per-event attributions it explains.
A refusal states exactly which gap in the evidence blocks attributing ONE root cause:
- a not-scorable event -- an input problem.
- an ambiguous slow yield (
unknown_root_cause, no passing opposite-risk fixture) -- TTS buffering, transport latency, and VAD smoothing are indistinguishable from one recording. - an echo-tagged false stop -- the agent most likely heard its own TTS bleed, an audio-path problem.
- a sweep/analyze candidate ref -- ALWAYS refused (no human label); explain prints the promote command for BOTH labels and lets a human choose.
- a contract's false stop with no disambiguating
candidate_kind-- acontract.jsoncarries a narrower signal set than a run envelope'sdiagnose, so a false stop onholdcould be a backchannel-discrimination miss, ambient noise, or echo bleed. Explain names the ambiguity and points athotato run --dump-frames/hotato diagnoseon the original envelope for a definitive read.
{"event_id": the refused event, or null,
"reason": why the evidence cannot support one attribution,
"evidence_for": what IS known,
"unknowns": the specific gap,
"safe_next_action": one concrete next command}
A contract.json carries a narrower field set than a run envelope's raw
reasons text, so a contract-bundle attribution is narrower than a full
diagnose:
- a missed interruption (
expect: yield,did_yield: false) is unambiguous and always attributed; - a "yielded but still failed its policy" contract is attributed by
comparing the MEASURED
seconds_to_yield/talk_over_secagainst the contract's OWNpolicy.pass_conditionsbounds -- a bound comparison, never a guess; - a false stop on
holdis attributed as echo ONLY when the contract'ssource.candidate_kindsays so (created--from-candidateanecho_correlated_activitymoment); otherwise it's refused (see above); - a single bundle covers one moment only, so a contract-bundle
attribution caps at
insufficient_evidenceuntil a companion contract or fixture on the other axis exists.
A voice trace, when attached (hotato trace attach), folds its findings
(traces/voice_trace.jsonl) into evidence_for; without one, explain
adds an explicit unknown -- TTS-cancellation lag, transport latency, and
VAD smoothing stay indistinguishable from timing alone. See
TRACE.md.
| Format | Gives you |
|---|---|
| text (default) | a plain summary, per attribution and per refusal |
--format json |
the full machine shape, schema hotato.explain.v1 (src/hotato/schema/explain.v1.json) |
--html PATH |
a self-contained report, in the same house style (hotato.report's CSS and escaping) the other HTML reports use |
| Code | Meaning |
|---|---|
| 0 | explained: nothing attributable (no failing or ambiguous events) |
| 1 | explained: at least one attribution or refusal was produced |
| 2 | usage error or unusable input (a bad candidate ref, a file that is not a hotato result, or an unreadable contract bundle) |
Every attribution here is evidence-based: a measurement scoped to root
cause, with its evidence_against and unknowns stated on every record.
explain is read-only, like diagnose and plan -- applying a change
stays a human decision in your own stack. See
FIX-PLANS.md and FIX-LOOP.md for the
guarded ladder from a plan to a proven fix.