Skip to content

feat: --junit on suite run + prove — CI-native JUnit XML, fail-closed#40

Merged
quantumCF merged 2 commits into
mainfrom
bolster/junit-output
Jul 23, 2026
Merged

feat: --junit on suite run + prove — CI-native JUnit XML, fail-closed#40
quantumCF merged 2 commits into
mainfrom
bolster/junit-output

Conversation

@quantumCF

Copy link
Copy Markdown
Contributor

Answers the most-thumbed CI-native ask in the eval-tool space (JUnit/XML report output; promptfoo #9071 pattern) with hotato's semantics kept intact:

  • --junit PATH on both hotato suite run and hotato prove
  • one <testsuite> per dimension (suite run) / evidence lane (prove); one <testcase> per test or lane
  • scored FAIL → <failure> with the measured reason
  • INCONCLUSIVE / SIMULATOR_INVALID / refused lane → <error>, never <failure>, never silent green — plus a suite-verdict <error> backstop so the XML can never read green while the exit code gates
  • deterministic: stable ordering, byte-identical repeat renders
  • 7 new tests (pass/fail/inconclusive mapping, refusal-reason preservation, byte-stability for both commands); docs/CI.md + docs/SUITE-RUN.md; llms-full regenerated

Independently verified on-branch by a fresh reviewer: mapping confirmed with its own constructed cases (incl. hostile-character escaping and root-count consistency), byte-stable across runs, and git diff removes zero lines from any fail-closed path. Also strips one authenticity-protest phrase from the candidate CHANGELOG entry per house copy rules.

https://claude.ai/code/session_015njkxtoAKioqTPT2k14xFr

Both commands also write a JUnit XML report for standard CI test-widget
ingestion, mirroring each command's existing grouping: one <testsuite>
per dimension (suite run) or per evidence lane (prove), one <testcase>
per test or lane. A scored FAIL is a <failure> carrying the measured
reason; an INCONCLUSIVE dimension, a SIMULATOR_INVALID run, or a
refused/inconclusive lane is an <error> with the refusal reason
preserved -- never a <failure>, never a silent pass. No timestamp
attribute; a repeat run renders byte-identical XML.

Claude-Session: https://claude.ai/code/session_015njkxtoAKioqTPT2k14xFr
… entry

'a real, drift-checked flow' -> 'a drift-checked flow': the flow's
drift-check is the fact; vouching for realness adds nothing.

Claude-Session: https://claude.ai/code/session_015njkxtoAKioqTPT2k14xFr
@github-actions

Copy link
Copy Markdown

hotato turn-taking eval

8 of 8 scenarios pass. 0 fail. No regression.

scenario expect yielded time to yield talk over result
01-hard-interruption yield yes 0.50s 0.50s pass
02-backchannel-mhm hold no - 1.57s pass
03-filler-start yield yes 0.65s 0.56s pass
04-correction yield yes 0.50s 0.50s pass
05-telephony-8khz yield yes 0.50s 0.50s pass
06-double-talk yield yes 1.05s 1.05s pass
07-echo-bleed hold no - 3.00s pass
08-rapid-turn-taking yield yes 0.50s 0.50s pass

Regressions

None.

Reproducible timing measured locally from call audio. Swap the bundled self-test step for your own captured recordings to gate on your agent. github.com/attenlabs/hotato

@quantumCF
quantumCF merged commit 773a901 into main Jul 23, 2026
15 checks passed
@quantumCF
quantumCF deleted the bolster/junit-output branch July 23, 2026 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant