fix(auth): env picker renders when fresh fetch returns asymmetric env keys (#797 follow-up)#805
Merged
Merged
Conversation
… keys (#797 follow-up) 8 PRs deep into the recurring "frozen-after-reset" bug. Live integration render exposed the actual gap: when `pendingEnvSelection=true` and the fresh `setOAuthComplete` brings back pendingOrgs where one of the two envs has lost its `app.apiKey` (provisioning lag, role change, key rotation, transient server response — many production races land here), `selectableEnvs.length === 1`, AuthScreen's auto-select effect fires, the credential-loading effect takes the "selected env has apiKey" path, and the deferral flag gets cleared. The env picker NEVER renders — router walks past Auth into Run. The user's "✓ Auth ─ ● Setup" stepper was actually `Screen.Run` (Run is in the "Setup" bucket of WIZARD_STEPS). Confirmed by the "Progress Logs Snake" tabs — those are RunScreen's tabs. Fix: - Gate the auto-select-when-1-env effect on `!pendingEnvSelection`. The resolver explicitly said "user must choose" — auto-selecting silently bypasses that intent. - Widen `needsEnvPick` to render the picker even with a single-env list when `pendingEnvSelection=true`. Without this, gating the auto-select alone would freeze the user on Auth with no actionable surface — fixes the auto-resolve bug but creates a new dead-screen bug. Integration test boots App via ink-testing-library, drives the post- deferral state through `setOAuthComplete` with asymmetric env keys, and asserts the router stays on Auth. Confirmed FAILS without the fix (router resolves to Run) and PASSES with it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 17, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
8th fix attempt at the recurring "frozen-after-reset" env-picker bug.
The prior 7 fixes all shipped passing unit tests; the bug kept
reproducing in production. Switching strategy: drove an actual
inkrender via
ink-testing-libraryagainst post-deferral state, exposedthe actual gap that mocked unit tests couldn't see.
Root cause (verified from live render trace)
When
pendingEnvSelection=trueandsetOAuthCompletebrings backfresh
pendingOrgswhere ONE env'sapp.apiKeyhas come back null(provisioning lag, key rotation, role change, transient server
response — many production races land here):
selectableEnvs.length === 1inAuthScreenapiKey" path, calls
setCredentials, clearspendingEnvSelectionSetup (skip — no setup questions yet) → Run
The user's "✓ Auth ─ ● Setup" stepper was actually
Screen.Run— Runis in the "Setup" bucket of
WIZARD_STEPS. Confirmed by the"Progress Logs Snake" tabs: those are
RunScreen's tabs, not Setup's.Why the prior 7 fixes didn't catch this
PRs #747 / #760 / #762 / #775 / #778 / #780 / #797 all reasoned about
post-deferral state with symmetric data shapes (both envs always have
keys). The mocked unit tests pinned that contract and passed. The
production failure mode involved asymmetric data between the
resolver's and authTask's two
fetchAmplitudeUserfetches —specifically one env's
apiKeyflipping null between calls. Pure-state assertions miss that because the React effect chain inside
AuthScreenonly runs when actually mounted.Fix
!session.pendingEnvSelection.The resolver explicitly said the user must choose — auto-selecting
here silently bypasses that intent.
needsEnvPickto render the picker even with a single-envlist when
pendingEnvSelection=true. Without this, gating theauto-select alone would freeze the user on Auth with no actionable
surface.
Both changes scoped to
AuthScreen.tsx. No new defensive gate layer(per the brief — 5 already exist; we found the actual gap).
Integration test
src/ui/tui/__tests__/env-picker-live-render.test.tsxboots the Appvia
ink-testing-libraryagainst the exact bug state (post-deferral,fresh
setOAuthCompletewith asymmetric env keys), waits for effectsto fire, and asserts the router parks on Auth with the picker visible.
Received: "run"vs expected"auth")The test file also pins 3 other scenarios (initial post-deferral,
same-orgs
setOAuthComplete, stale-IDs scenario from #797) so futureregressions in any of those paths get caught at the live-render level
too.
Test plan
pnpm exec vitest run src/ui/tui/__tests__/env-picker-live-render.test.tsx— 4 passpnpm test— 4473 tests pass (no regressions)pnpm tsc --noEmit— cleanpnpm lint— cleangit clean -fdxfollowed by re-running the wizard🤖 Generated with Claude Code
Note
Medium Risk
Touches
AuthScreenstate/effect routing during authentication, which can change wizard progression and unblock/impede users if logic is wrong. Changes are localized but cover a previously flaky production edge case involving mismatched environment API key availability across fetches.Overview
Fixes the “frozen-after-reset” env picker regression by preventing
AuthScreenfrom auto-selecting a single environment whensession.pendingEnvSelectionindicates the resolver deferred to an explicit user choice, and by rendering the env picker even when only one selectable env remains under that deferral.Adds a new
ink-testing-libraryintegration test (env-picker-live-render.test.tsx) that mounts the full TUIApp, lets effects run, and asserts the UI stays onScreen.Authwith the env picker visible across multiple scenarios, including the asymmetric “one env losesapiKeyon fresh fetch” case.Reviewed by Cursor Bugbot for commit 38cfa39. Bugbot is set up for automated code reviews on this repo. Configure here.