An expired Claude login refuses every turn with a **synthetic** assistant message (`Login expired · Please run /login`, `error: authentication_failed`, zero tokens, 16ms) and then goes idle. The pane is alive and the agent process is running, so every liveness check passes forever — which is how #867 cost `memory-manager` 7217s and `ai-morning-briefing` 14400s on the same 2026-08-04 outage, reported as `incomplete — Timeout waiting for task completion`. **The detector reads the TRANSCRIPT, never the pane** (`agentwire/auth_expired.py`): Claude renders this inline, not as a select-menu, so the phrase also appears in any pane merely *quoting* the incident, and a false positive here halts the whole board. Keyed on the structured `error` field, and on the **LAST** assistant turn only — so recovery needs no reset mechanism. **Field-proven across two outages that render DIFFERENTLY** (`Login expired` 08-04 / `Not logged in` 07-07, same `error`), which is the argument for the structured field; the residual risk is a future RESTRUCTURING of that field, not a rewording. All 16 real `rate_limit` rows are structurally identical to an auth refusal and reach the same predicate — only the error-value check keeps a transient blip from gating the machine. Transcripts are located by `conversation_ids` (#871) or, when the record predates that, by files in the project's history dir written since **the attempt began** — never "the newest `.jsonl`". That anchor is load-bearing: the refusal lands ~15ms after the prompt submits, seconds before the completion wait is entered, so anchoring at the wait misses it entirely. Detection is **machine-wide** (`~/.agentwire/auth-expired/state.json`) — one outage, one owner email (throttled 1h, shared Resend wiring), `detected_at` carried forward, an `OUTAGE_TTL` so a stale flag can never wedge the scheduler, and a `clear_state()` on the completion success path so a successful turn genuinely reopens the gate rather than the docs merely claiming it does. Surfaces: ensure exits **8** (`auth_expired`) and never retries, scheduler dispatch skips without consuming `last_run`, worktree finalize opens no PR, `agentwire doctor` reports it. No credential pre-flight: the secret is Keychain-gated on macOS, and `expiresAt` is the *access* token's, which lapses routinely and refreshes silently. Full reference: [`docs/wiki/auth-expired.md`](docs/wiki/auth-expired.md).
0 commit comments