Skip to content

Fix onboarding's credential validation and mid-session provider connect - #405

Merged
TheGreatAxios merged 3 commits into
mainfrom
cl-5687-5688-5689-5690-onboarding-fixes
Aug 8, 2026
Merged

Fix onboarding's credential validation and mid-session provider connect#405
TheGreatAxios merged 3 commits into
mainfrom
cl-5687-5688-5689-5690-onboarding-fixes

Conversation

@TheGreatAxios

@TheGreatAxios TheGreatAxios commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Two of the four bugs in the onboarding cluster, landed as separate commits:

  • Model picker no longer overwrites the persisted default provider (src/tui/runner.ts): trying a model to browse it was silently rewriting defaultProvider for future launches, not just updating the recents list.
  • Credential validation at the shared submit funnel (src/tui/onboarding.ts, new src/tui/provider-setup-submit.ts, src/tui-opentui/provider-connect.ts): an empty API key on a key-required preset was downgraded to keyless: true, and resolveProvider skips the missing-key check once that's set — so a broken config loaded as "configured" and only failed on the first real send. The "save anyway" bypass had the same shape: an unvalidated credential got persisted indistinguishably from a verified one. The submit logic (empty-key rejection, connection test, verified: false marking) now lives in one module both first-run onboarding and the mid-session "connect a new provider" flow share, instead of three separate copies of the same logic.

Not included: CL-5687 ("connect a new provider" mid-session)

This turned out to already have a fix on main (connectProviderInline/provider-connect.ts, landed independently). Live-testing that fix in a real terminal (not just the headless test harness) found it still crashes with "stdin is already used by another CliRenderer" — a second CliRenderer can't share the terminal with the session's live one.

I built a fix (reuse the host's own renderer, paused for the duration) that resolved the crash, but further live testing surfaced a worse regression: after the sub-flow completed, the host's prompt began double-inserting every keystroke ("x" became "xx"). I could not root-cause this confidently within scope, and shipping a fix that corrupts the live session's own input afterward is worse than the known crash. I'm not including that commit here. Filed for follow-up separately from this PR rather than shipping something I verified was broken.

Verification

Both included flows were driven in a real terminal (tmux + a fresh $HOME/settings fixture), not just the test suite:

  • Empty key on a key-required preset (OpenAI): rejected with a clear error at submit, including through the Ctrl+S "save anyway" bypass.
  • "Save anyway" with a key that fails its connection test: persists verified: false, and the session shows a plain-language startup notice instead of a raw adapter error.
  • Trying a different model in the picker while a different provider is default: defaultProvider is left untouched.

Test plan

  • bun run typecheck
  • bun run build
  • bun run test (full suite, 4177 pass)
  • Live verification in a real terminal for both flows above

@linear-code

linear-code Bot commented Aug 8, 2026

Copy link
Copy Markdown

CL-5687

@TheGreatAxios
TheGreatAxios force-pushed the cl-5687-5688-5689-5690-onboarding-fixes branch from 1d9360e to dd527d5 Compare August 8, 2026 19:31
Trying a model in the picker recorded it in recentModels but also
carried defaultProvider into the same settings write, so browsing a
model became an implicit "set as default" — every model tried in a
session silently became the new default for future launches.
An empty API key on a key-required preset was written as keyless:
true, and resolveProvider skips the missing-key check entirely once
keyless is set, so a config that should have failed validation loaded
as configured and only broke on the first real send. The submit
funnel now rejects an empty key on any preset that isn't genuinely
keyless-capable (the custom/manual endpoint), instead of downgrading
it.

The "save anyway" escape hatch had the same failure shape one step
further along: a credential that failed its connection test still
got persisted, indistinguishable from a verified one. It's now marked
verified: false, and the running session surfaces a one-time startup
notice pointing back to setup instead of letting the first send fail
with a raw adapter error.

Both bugs existed twice over: first-run onboarding and the mid-session
"connect a new provider" flow each reimplemented the same submit
logic, so a fix to one alone would have left the other silently
broken. The submit logic moves into its own module and both callers
now share it.
An empty API key on a key-required preset was written as keyless:
true, and resolveProvider skips the missing-key check entirely once
keyless is set, so a config that should have failed validation loaded
as configured and only broke on the first real send. The submit
funnel now rejects an empty key on any preset that isn't genuinely
keyless-capable (the custom/manual endpoint), instead of downgrading
it.

The "save anyway" escape hatch had the same failure shape one step
further along: a credential that failed its connection test still
got persisted, indistinguishable from a verified one. It's now marked
verified: false, and the running session surfaces a plain-language
startup notice instead of letting the first send fail with a raw
adapter error.

Both bugs existed twice over: first-run onboarding and the mid-session
"connect a new provider" flow each reimplemented the same submit
logic, so a fix to one alone would have left the other silently
broken. The submit logic moves into its own module and both callers
now share it.

verified defaults to trusted (absent, not false) so this doesn't
retroactively flag every existing user's already-working setup; only
a path that persists a credential without testing it sets it false.
The OAuth submit path is exempt from the same marking on purpose — a
completed OAuth login is a stronger signal than a pasted key (the
provider's own server just issued it), though it doesn't confirm the
resulting token carries API scope, which is tracked as a separate
follow-up rather than faked here.
@TheGreatAxios
TheGreatAxios force-pushed the cl-5687-5688-5689-5690-onboarding-fixes branch from dd527d5 to 76c24c1 Compare August 8, 2026 21:20
@TheGreatAxios
TheGreatAxios merged commit 21ae5a4 into main Aug 8, 2026
3 checks passed
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