hermes.provider_setup.count recorded every user cancel as event=failed
failure_class=cancelled, on every surface: Esc/Ctrl-C/Back in the CLI pickers,
Cancel on a Desktop/dashboard OAuth sign-in (DELETE /sessions), a cancel that
landed before the start response, and consent declined on the provider page.
A device code left to run out was also failed/other on the Nous, xAI and
Codex dashboard pollers (only the free-tier `timeout` reason and Codex
`expired` status were abandoned). Every provider's failure rate was inflated by
walk-aways (openai-codex desktop: 64 of 75 failed rows were `cancelled`).
- provider_setup_fields: failed + cancelled/expired is recorded abandoned, so
every emitter (CLI, web routers, pollers) gets the same answer.
- setup_failure_class: a lapsed device code (DeviceCodeExpired on the Nous poll,
AuthError code device_code_timeout/timeout, RFC 8628 expired_token) is
`expired`; access_denied is `cancelled`; an error whose __cause__ is a network
error is `network`.
- Dashboard/Desktop pollers keep the exception's closed class on the session
(note_oauth_failure) so `status=error` no longer collapses to `other`;
free-tier anon_unreachable is network, a start-route 504 is network.
- DELETE /sessions settles the metric immediately: a Nous/xAI poll blocks for
the code's lifetime, so the cancel row used to land minutes later or never.
Live (real dashboard server, Desktop-owned, isolated HOME, real providers):
base: nous/openai-codex cancel -> failed/cancelled (xai cancel never
settled); nous code left to lapse -> failed/other
fix: nous/xai-oauth/openai-codex cancel -> abandoned/none, each at cancel
Live (real `hermes model` in tmux, Ctrl-C at the OpenRouter key prompt):
base failed/cancelled, fix abandoned/none.