Skip to content

Don't flash sign-in modal at signed-in users during Agents window startup - #329269

Merged
Tyler James Leonhardt (TylerLeonhardt) merged 2 commits into
mainfrom
tyleonha/signed-in-startup-signin-modal
Aug 5, 2026
Merged

Don't flash sign-in modal at signed-in users during Agents window startup#329269
Tyler James Leonhardt (TylerLeonhardt) merged 2 commits into
mainfrom
tyleonha/signed-in-startup-signin-modal

Conversation

@TylerLeonhardt

Copy link
Copy Markdown
Member

The bug

With chat.agentHost.allowSignedOutWhenUsable: true and already signed in to GitHub, launching the Agents window produced a broken sequence:

  1. Window launches (auth state not loaded yet)
  2. A Claude discovered-config notification flashes
  3. The sign-in modal dialog appears
  4. In the background, auth finally resolves
  5. …but the modal stays up — nothing retires it.

Root cause

The conditional-auth UI added in #328990 conflates "auth not resolved yet" with "signed out."

IDefaultAccountService.currentDefaultAccount is a synchronous getter that returns null for everyone until the first async resolution completes — and that initial null → account assignment fires no onDidChangeDefaultAccount event. So during the startup gap a signed-in user reads as signed-out. Meanwhile Claude churns native → proxy as the host forwards the token (advertising required:false, then required:true), repeatedly re-driving the reaction. The modal gets raised on the transient null, and because resolution is event-silent, nothing ever tears it back down.

The fix

Gate both reactive consumers on a resolved-auth signal, learned via a one-shot getDefaultAccount() await — the only reliable indicator that resolution happened, since the initial assignment is event-silent:

  • sessionsSetUpService.ts (the modal): _onUsableWithoutGitHubChanged now no-ops unless the state is genuinely SignedOut, so gap-time Claude churn is inert and the normal sign-in watch owns the signed-in path.
  • agentHostDiscoveredConfigNotification.ts (the nudge): _update() returns early while Unresolved instead of flashing the signed-out nudge.
  • Shared logic both consumers were duplicating is consolidated into a unit-tested conditionalAuthState() helper (Unresolved | SignedIn | SignedOut) in sessionsAuthGate.ts — single source of truth for the unresolved-vs-signed-out distinction.

The intended signed-out conditional-auth behaviour from #328990 is fully preserved; the change only suppresses action during the unresolved window.

Validation

  • Unit: new conditionalAuthState test covers all four (resolved, signedIn) combinations; existing nudge test still passes (2/2).
  • Live (signed-in, allowSignedOutWhenUsable: true):
    • Showing sign-in dialog log lines: 0 — modal never raised.
    • Claude churn confirmed active during the gap (26 required:false + 10 required:true protected-resource transitions, plus token-forward/proxy markers) — so the reaction was exercised repeatedly and stayed inert.
    • Steady-state DOM: dialogCount:0, no "Sign in to use Agents" text, no loading overlay, signed-in button present.

🤖 Generated with Claude Code

Copilot AI balanced review requested due to automatic review settings August 5, 2026 21:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prevents transient sign-in UI while the Agents window’s GitHub account state is unresolved.

Changes:

  • Adds a shared conditional-auth state helper.
  • Gates the setup modal and configuration notification until authentication resolves.
  • Adds a truth-table unit test.
Show a summary per file
File Description
src/vs/sessions/browser/sessionsAuthGate.ts Defines resolved authentication states.
src/vs/sessions/browser/sessionsSetUpService.ts Gates modal reactions during startup.
src/vs/sessions/contrib/providers/agentHost/browser/agentHostDiscoveredConfigNotification.ts Suppresses unresolved-state notifications.
src/vs/sessions/test/browser/sessionsAuthGate.test.ts Tests authentication-state classification.

Review details

  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread src/vs/sessions/browser/sessionsSetUpService.ts
@TylerLeonhardt
Tyler James Leonhardt (TylerLeonhardt) marked this pull request as ready for review August 5, 2026 21:27
The conditional-auth UI added in #328990 conflated "auth not resolved
yet" with "signed out". IDefaultAccountService.currentDefaultAccount is a
synchronous getter that returns null for everyone until the first async
resolution completes — and that initial resolution fires no change event.
During the startup gap a signed-in user therefore reads as signed-out, so
the sign-in modal and the discovered-config nudge flash. Worse, once auth
finally resolves nothing retires the already-raised modal, so it stays up.

Gate both reactive consumers (sessionsSetUpService and the discovered
config notification) on a resolved-auth signal, learned via a one-shot
getDefaultAccount() await — the only reliable indicator that resolution
happened, since the initial null->account assignment is event-silent.
While unresolved, neither consumer acts, so gap-time Claude native<->proxy
churn is inert and the normal sign-in watch owns the signed-in path.

Consolidate the shared unresolved-vs-signed-out logic both consumers were
duplicating into a unit-tested conditionalAuthState helper. The intended
signed-out conditional-auth behaviour from #328990 is preserved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Addresses review feedback: gating _onUsableWithoutGitHubChanged on
_accountResolved dropped any usability transition that landed during the
unresolved window without replaying it. The native paths re-read the
current usability after they await the account (via _showWelcome ->
_mustForceGitHubSignIn), but the web path (_checkWebAuth) has no such
post-resolution re-check, so a genuinely signed-out, opted-in user whose
agent became usable during the gap would stay stranded on the sign-in
dialog that nothing else retires.

When the account resolves, replay the current usability state — scoped to
usable === true, the only transition that was wrongly dropped; a not-usable
state is still owned by the initial setup flow. Signed-in users remain a
no-op (the handler early-returns), so the original fix is unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@TylerLeonhardt
Tyler James Leonhardt (TylerLeonhardt) merged commit 63d59d2 into main Aug 5, 2026
29 checks passed
@TylerLeonhardt
Tyler James Leonhardt (TylerLeonhardt) deleted the tyleonha/signed-in-startup-signin-modal branch August 5, 2026 23:34
@vs-code-engineering vs-code-engineering Bot added this to the 1.133.0 milestone Aug 5, 2026
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.

4 participants