Skip to content

fix(install): show a gateway key refusal plainly and skip the retry prompt - #266

Merged
quickbeard merged 2 commits into
mainfrom
fix/key-refusal-no-retry
Sep 10, 2026
Merged

quickbeard merged 2 commits into
mainfrom
fix/key-refusal-no-retry

Conversation

@quickbeard

@quickbeard quickbeard commented Sep 10, 2026

Copy link
Copy Markdown
Owner

Why

The gateway refused the email domain. That is a policy decision, not an outage, so the retry hint was wrong and the actual reason was buried inside a nested status chain. The companion backend PR (quickbeard/codev-backend) now reports this as 403 with code: "key_refused"; this PR makes the hub act on it.

What

  • fetchApiKey throws a BackendError carrying the backend's status, reason and code. isKeyRefusal is the check components branch on.
  • FetchApiKey renders a refusal as the gateway's own sentence, a line saying retrying won't change it, and "Press Enter to enter your own API key". Enter goes straight to manual credentials.
  • FetchApiKey now gates its useInput on !succeeded && !handedOff. The parent keeps the Step mounted as read-only history, and the live listener used to answer every later Enter by calling onFallback again — reproducible today on the empty-key → manual fallback path by pressing Enter during the smoke-test spinner, which yanks the wizard back to a fresh manual-creds form.
  • CLAUDE.md documents the key_refused wire contract with the backend.

Tests

  • lib: a 403 key_refused becomes a BackendError with the code and reason; isKeyRefusal rejects a plain 502 and a bare Error.
  • component: the refusal frame has no retry hint, Enter hands off exactly once and does not re-fetch; the listener is off after handoff so extra Enters don't re-fire onFallback.
  • InstallApp: refusal → manual creds → model → "Happy coding".

pnpm fix, pnpm typecheck, pnpm test (1496 passed), pnpm build && node dist/index.js --version.

Rollout

Against an old backend the hub keeps its current behaviour (generic 502 + retry prompt). The user in the report stays blocked until the gateway team widens its allowlist or issues them a key by hand.

🤖 Generated with Claude Code

https://claude.ai/code/session_01DFzDyvc2uV1Vp1WoHBkiPB

quickbeard and others added 2 commits September 10, 2026 15:31
…rompt

When the gateway's mint endpoint declines a user (an email domain outside
its allowlist), the backend now answers 403 with code "key_refused". The
"Get a new API Key" step used to print the nested status chain and offer
"Press Enter to retry" — a retry that can never succeed.

fetchApiKey throws a BackendError carrying the backend's status, reason and
code; isKeyRefusal is what FetchApiKey branches on. A refusal renders the
gateway's own sentence, says retrying won't change it, and Enter goes
straight to the manual-credentials step.

FetchApiKey also switches its key listener off once it has succeeded or
handed off. The parent keeps the Step mounted as history, and the live
listener used to answer every later Enter (model pick, smoke-test spinner)
by calling onFallback again and yanking the wizard back to manual creds.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFzDyvc2uV1Vp1WoHBkiPB
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DFzDyvc2uV1Vp1WoHBkiPB
@quickbeard
quickbeard force-pushed the fix/key-refusal-no-retry branch from 8327114 to 5b1e8ce Compare September 10, 2026 08:32
@quickbeard
quickbeard merged commit b381342 into main Sep 10, 2026
2 of 4 checks passed
@quickbeard
quickbeard deleted the fix/key-refusal-no-retry branch September 10, 2026 08:37
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