Skip to content

Share one managed refresh and confirm rejection with the provider - #143

Merged
squarepots merged 3 commits into
mainfrom
fix/managed-refresh-outcome
Sep 30, 2026
Merged

squarepots merged 3 commits into
mainfrom
fix/managed-refresh-outcome

Conversation

@squarepots

Copy link
Copy Markdown
Member

Summary

With Codex 0.159.2, v1.0.19 reports a saved sign-in whose refresh token no longer works as "temporarily cannot verify … retry when the connection is available" on Switch, and as "try again later" on a manual quota refresh. Only Wake reported it as needing sign-in. Each path ran its own isolated refresh and classified its failure separately.

Codex does not report a refresh outcome in a supported form. Read from the app-server source at both tags:

  • rust-v0.144.5 (minimum supported): account/read {refreshToken: true} discards the refresh result and answers from the cached account.
  • rust-v0.159.2 (installed here): the refresh result is still discarded; the workspace discovery that follows fails with -32603 for a rejected refresh and for a network failure alike.

Switch, manual quota refresh, and Wake now share quota::refresh_saved_sign_in:

  1. copy the saved credential into an isolated profile and ask the App Server for one refresh;
  2. reread the profile, require the saved identity, and commit a rotated credential immediately (protected recovery if the commit fails);
  3. return the credential; the caller repeats its own provider request once.

A second 401 or 403 is the confirmed rejection and marks the account as needing sign-in. An App Server that cannot start or answer, an unreadable profile, and every non-authentication provider failure stay "unavailable". The typed failure is Unavailable, IdentityChanged, or NotSaved { recovery_retained }.

Other behavior changes:

  • A rotated credential is no longer lost when the App Server call or the following provider request fails after the refresh succeeded.
  • The manual quota refresh reads quota through the read-only usage endpoint after the refresh instead of account/rateLimits/read in the isolated profile.
  • Wake reports Failed, not Needs sign-in, when the refresh could not run.
  • A refreshed credential must pass the account check before Switch writes it to the live profile.

docs/workflows.md gains a Managed refresh section; docs/architecture.md, docs/security.md, and docs/testing.md are updated.

Validation

  • pnpm run ci:source linux on Windows: formatting, Clippy with -D warnings, 147 Rust tests passed, 1 existing ignored test, version check, and frontend build.
  • New Rust tests use a local HTTP fixture: 401 then 200 switches with the refreshed credential; 401 then 401/403 returns account_needs_sign_in and leaves the saved credential untouched; 401 then 429/500/malformed returns target_check_unavailable and keeps the rotated credential; each typed refresh failure maps to its switch and Wake result; another identity is never saved.

Limits

  • No real account, App Server refresh, or provider request was used. The isolated-profile call itself is not covered by a test; only its result handling is.
  • A refresh that fails transiently at the identity provider while ChatGPT stays reachable is reported as needing sign-in. A later successful refresh or a new sign-in clears it.
  • Real-account acceptance is needed before release, in particular Switch and Refresh on an account whose saved sign-in no longer works.

🤖 Generated with Claude Code

squarepots and others added 3 commits September 30, 2026 20:15
Switch, manual quota refresh, and Wake each ran their own isolated token
refresh and classified its failure differently, so the same dead saved
sign-in was "needs sign-in" in Wake, "temporarily unavailable" in Switch,
and "try again later" for quota.

Codex does not report a refresh outcome in a supported form: 0.144.5
answers account/read from its cached account after a failed refresh, and
0.159.2 rejects the read without a typed reason. Use one shared refresh
that never reads the outcome from that reply. It keeps a rotated
same-identity credential immediately, then the caller repeats its own
provider request once. Only a second 401 or 403 marks the account as
needing sign-in; an App Server that cannot start or answer, and every
non-authentication provider failure, stay "unavailable".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@squarepots
squarepots merged commit 36d09a1 into main Sep 30, 2026
12 checks passed
@squarepots
squarepots deleted the fix/managed-refresh-outcome branch September 30, 2026 12:55
@squarepots squarepots mentioned this pull request Sep 30, 2026
squarepots added a commit that referenced this pull request Sep 30, 2026
Version change only. Releases #141, #142, and #143; the maintainer accepted the 1.0.20-rc.1 preview built from 87916f0 with real accounts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant