fix(acpmux): preserve expired harness auth evidence
A failed harness auth check currently collapses an explicit expired-token answer into signedOut, so the composer cannot distinguish a session that needs re-authentication from an ordinary first login. This PR keeps the failed check's output inside the daemon long enough to classify an explicit credential expiration as expired, while preserving unknown when the daemon has no evidence. It does not read the keychain or change active-session send policy.
Leo: “you gotta re-authenticate. You gotta log in again on the modal picker before the user even sends a prompt.”
The test covers “OAuth token has expired,” a Codex refresh-token expiry, ordinary “Not logged in,” a bare “session expired” (stays signedOut), and serialization.
Adopted by the acpmux daemon area (second commit):
- Fixes the clippy red (E0004):
cmux setup's harness report now matchesAuth::Expired(signed_in: false, with the same login action as signed out). - The expired-credential matcher moves to
claude_auth::is_expired_credential, so the failed-turn classification (auth.expired, next PR) uses the same words and the two cannot drift. It no longer counts a bare "session ... expired" as a credential.
Risk: low. harness/health rows can now say auth: "expired"; the web settings card and the Swift settings row read auth as a string and show it as not signed out (no decode failure).
Related: #26526 owns the selected-harness signed-out UI. The per-session _acpmux/session/auth method builds on this.
Agent session: agent session
🤖 Generated with Claude Code