51e39af967
The free tier depends on the account service (NAS) and the welcome inference host, and Hermes had no honest answer for most of the ways either can refuse or fail: the NAS codes it matched were never sent, the tier-dark 403 carried no message to match, a single boot-time blip disabled minting for the whole process, and a structured rate-limit refusal never reached the cross-session guard, so the "sign in for a bigger allowance" prompt was dead code. Backend - anon_auth: classify what NAS actually sends (404 not_found, 503 temporarily_disabled, 429 + Retry-After, 428 pow_*, 403 account_locked) into one ANON_* code each, carrying retry_after / retryable on AuthError. - Replace the process-lifetime mint memo with a per-profile cooldown that honours the server's wait, climbs a short ladder when the service is unreachable, never retries terminal codes, and yields to the user's own retry (force=True). - Bootstrap record carries error_code / retryable / retry_after; a bounded background loop retries transient failures and re-announces setup.ready. setup.status and free_tier.status expose the block; free_tier.provision is the forced retry. - Inference: a generic 403 from a welcome host is the tier refusing (keyed on the route); model_not_free moves onto the gateway's alternate once; anon_on_paid_host re-reads the route once; a long rate_limited refusal trips the cross-session guard; a locked account is retired but never replaced; terminal copy on the free route is one plain sentence. - Sign-in: Failed keeps the service's code and wait; account_busy is retryable; the OAuth poll reports retryable / retry_after. - All user-facing copy rewritten for first-time users: never "the free service is off" (what is unavailable is using Hermes without signing in, and signing in is free), no jargon, spoken waits. Desktop - A setup-failure notice above the provider picker: one sentence per code, a retry when the backend says one can work, the sign-in pointer only when the account service answered at all. The overlay re-checks readiness on setup.ready so a background success dismisses it. - Sign-in dialog gains busy / unreachable / unavailable screens. Rehearsal - scripts/free_tier_fault_server.py stands in for both services with the real wire contract and a CORS-open scenario switch; HERMES_EXTRA_WELCOME_HOSTS (dev-only, env-only) lets the route rules treat it as the welcome host. Walkthrough in website/docs/developer-guide/free-tier-fault-rehearsal.md. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>