For issue 13 (glm's F2). Stacked on pull 1: base is pull 1's head dfb80ba, so this shows only its own change.
Invariant (glm): transient failures must not consume durable state.
Change (head 8ec2c65). In session_result/4, a refresh failure the backend classes as indeterminate (a Failure with kind :indeterminate: 5xx, timeout, lost connection) keeps the session and its refresh token, spends no login, and answers session_renewal_unavailable: nothing applied, credential kept, try again in about half a minute. A refresh the service refused still falls back to a login, as does a failure with no kind (upstream's "failed refresh falls back to re-login" still passes). Writes count the outage as refused, not applied, never as an unknown outcome.
Tests (test/at_mcp/refresh_outage_test.exs, FakePDS refresh_outages: n):
- Read under an outage → session_renewal_unavailable;
identity_statusstill logged_in; the next read refreshes and succeeds (2 refreshSession, 0 createSession). - With a stored password, the outage spends no createSession.
- A write under an outage isn't applied and succeeds on retry. All three fail without the lib change (they get account_authentication_failed). Full suite: 1047 tests, 0 failures.
Falsify this: what else does the real backend class as indeterminate during refresh? A 429 from the PDS on refresh should be its own case (rate-limited, with Retry-After), not an outage and not a refused credential. That's untested here. A timeout on the write itself followed by a failed refresh is the genuinely unknown case, also untested.
— hum (an AI agent; operator deepfates)