fix(auth): structural gate covers no-pre-selection case (env-picker hang follow-up)#780
Merged
Merged
Conversation
… no IDs selected When `git reset --hard` wipes `<installDir>/.amplitude/` and PR #778's `loadCheckpoint` invalidates the per-user checkpoint, the session reaches Auth with `selectedOrgId === null` AND `selectedProjectId === null` — `resolveCredentials` does NOT set those in the multi-env defer branch. PR #775's structural gate (`needsEnvPickStillRequired`) short-circuited to `false` in that case, leaving only `pendingEnvSelection` as a gate. The recurring "stuck on Setup with no env-picker" bug class then reproduces if anything clobbers that flag — exactly the symptom users keep reporting (`✓ Welcome ─ ✓ Auth ─ ● Setup ←`, no env picker rendered, TUI stuck). This commit extends the structural gate with a fallback path that mirrors `resolveCredentials`' own "first project of first org" heuristic (credential-resolution.ts ~line 483). When no specific selection has been made, the gate consults `pendingOrgs[0] .projects[0]` — the exact (org, project) tuple `resolveCredentials` walked when it issued the deferral. Once the user picks an org/project via AuthScreen, the existing specific-IDs guard takes over. Guard reordering: `pendingOrgs === null` short-circuit stays first (unchanged manual-API-key carve-out). `selectedEnvName !== null` short-circuit also stays — picking an env (real or auto-select) is still the canonical "we're done with this gate" signal regardless of which (org, project) tuple we resolved through. Regression coverage in `flow-invariants.test.ts`: - `structural gate alone holds Auth in restart-after-reset`: pins the smoking-gun scenario (credentials + names set, IDs null, pendingEnvSelection clobbered). Fails without the fix. - `structural gate does not block manual-API-key path`: counter-test keeping `pendingOrgs === null` carve-out intact. - `parks on Auth after checkpoint invalidation + multi-env defer`: wider integration test through the full bin.ts mutation sequence. - Plus the AuthScreen snapshot test confirming the env picker renders when `pendingEnvSelection: true`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6 tasks
kelsonpw
added a commit
that referenced
this pull request
May 15, 2026
…stale selectedOrgId/ProjectId (#797) Prior PRs #747 / #760 / #762 / #775 / #778 / #780 each tried to fix the recurring "stuck on Setup with no env-picker" hang after `git reset --hard` on a previously-instrumented project. Each landed a gate that worked at the unit-test level, but the live repro kept reproducing. This pins the actual gap PR #780 left behind. PR #780's structural fallback (`needsEnvPickStillRequired` → `pendingOrgs[0].projects[0]`) only fires when BOTH `selectedOrgId` AND `selectedProjectId` are null. In the real restart-after-reset sequence: 1. `resolveCredentials` populates `pendingOrgs` (first fetch) and defers on multi-env. 2. `applyEnvSelectionDeferral` sets `pendingEnvSelection=true`. 3. AuthScreen mounts and its single-org/single-project auto-resolve effect writes `selectedOrgId='org-1'`, `selectedProjectId='proj-1'` from that first snapshot. 4. `authTask` runs OAuth, `fetchAmplitudeUser` fetches a SECOND time, and `setOAuthComplete` REPLACES `pendingOrgs` with the fresh data. If the two snapshots' IDs don't match (re-fetch race, ordering, account changes, stale in-memory IDs), the existing `pendingOrgs.find(o => o.id === selectedOrgId)` lookup returns `undefined`. 5. The structural gate short-circuits to `false`. If anything clobbers `pendingEnvSelection=false` (the recurring failure-mode the 6 prior PRs chased — every fix relied on the flag staying true), Auth.isComplete returns true and the router walks past Auth into the Setup-bucket screens. User sees `✓ Auth ─ ● Setup ←` with no env picker on screen. Fix: when stale `selectedOrgId/ProjectId` don't resolve a project in `pendingOrgs`, fall through to the same `pendingOrgs[0].projects[0]` heuristic instead of bailing to `false`. The structural gate is now load-bearing across all three states: (a) no IDs picked yet (PR #780) (b) IDs picked and valid in pendingOrgs (existing happy path) (c) IDs picked but stale relative to fresh pendingOrgs (this PR) Regression test: src/ui/tui/__tests__/env-picker-restart-after-reset-hang.test.ts drives the complete bin.ts startup sequence — buildSession → store.session → resolveCredentials multi-env defer → applyEnvSelectionDeferral → concludeIntro → setOAuthComplete → AuthScreen's setOrgAndProject — and asserts the router parks on Auth at every step. The new "stale IDs" test fails without the fix (router resolves to data-setup) and passes with it. Pre-existing test in env-picker-repro.test.ts that asserted the OPPOSITE behavior ("does not block when the resolved project is missing from pendingOrgs") was inverted to match the new (correct) behavior — that test was inadvertently encoding the bug as expected behavior. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 16, 2026
Merged
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
When
git reset --hardwipes<installDir>/.amplitude/and PR #778'sloadCheckpointinvalidates the per-user checkpoint, the session reaches Auth withselectedOrgId === nullANDselectedProjectId === null—resolveCredentialsdoes NOT set those in the multi-env defer branch.PR #775's structural gate (
needsEnvPickStillRequired) short-circuited tofalsein that case, leaving onlypendingEnvSelectionas a gate. The recurring "stuck on Setup with no env-picker" bug class then reproduces if anything clobbers that flag — exactly the symptom users keep reporting (✓ Welcome ─ ✓ Auth ─ ● Setup ←, no env picker rendered, TUI stuck).This commit extends the structural gate with a fallback path that mirrors
resolveCredentials' own "first project of first org" heuristic (credential-resolution.ts~line 483). When no specific selection has been made, the gate consultspendingOrgs[0].projects[0]— the exact (org, project) tupleresolveCredentialswalked when it issued the deferral. Once the user picks an org/project via AuthScreen, the existing specific-IDs guard takes over.Why this is the right layer
Prior PRs in this bug class:
pendingEnvSelectionflag + gated post-Authshow:predicates on!s.pendingEnvSelectionsetKeyto mutate in-placeAuth.isCompleteblocks even whenpendingEnvSelectiongets clobbered#778 (the most recent fix) is doing its job — invalidating the stale checkpoint. But it surfaces a case PR #775's gate didn't cover: when no IDs are pre-selected. This commit plugs that gap precisely.
Files changed
src/ui/tui/flows.ts—needsEnvPickStillRequiredadds the IDs-null fallback topendingOrgs[0].projects[0]src/ui/tui/__tests__/flow-invariants.test.ts— adds smoking-gun regression test (fails without the fix), counter-test (manual-API-key carve-out), wider restart-after-reset router-resolve testsrc/ui/tui/screens/__tests__/AuthScreen.snap.test.tsx— pins env picker rendering whenpendingEnvSelection: trueTest plan
pnpm tsc --noEmitcleanpnpm lintcleanpnpm test— all 4258 tests pass (after one flaky unrelated re-run on agent-interface MCP auth refresh test)structural gate alone holds Auth in restart-after-resetfails without the flows.ts change (verified via stash + re-test)wizard-abort.tsuntouched🤖 Generated with Claude Code
Note
Medium Risk
Changes the Auth completion gating logic in the TUI wizard, which can affect routing between major setup steps; however it’s a targeted fallback with added regression tests covering the affected restart scenarios.
Overview
Prevents the wizard from advancing past
Auth(intoSetup/post-auth screens) when multi-environment selection is still required butselectedOrgId/selectedProjectIdarenull(e.g. after checkpoint invalidation on restart).Updates
needsEnvPickStillRequiredto fall back to the samependingOrgs[0].projects[0]target used by credential resolution, and adds regression/counter tests plus anAuthScreensnapshot to pin env-picker rendering and correct router parking behavior.Reviewed by Cursor Bugbot for commit 5dccb96. Bugbot is set up for automated code reviews on this repo. Configure here.