Skip to content
This repository was archived by the owner on May 18, 2026. It is now read-only.

fix(onboarding): close race that lets the wizard redirect mid-action when picking Ollama - #7

Merged
roadhero merged 1 commit into
masterfrom
fix/wizard-redirect-race
May 6, 2026
Merged

roadhero merged 1 commit into
masterfrom
fix/wizard-redirect-race

Conversation

@roadhero

@roadhero roadhero commented May 6, 2026

Copy link
Copy Markdown

Summary

useLocalOllama() schedules a 800ms-delayed redirect to / after marking onboarding complete, but it left the wizard fully interactive during that window. The user could click Next during the 800ms, advance to Step 2, click into the API-key input, and then get yanked to chat when the timer fired — appearing as if clicking the input itself caused the redirect.

Surfaced by FITB#122 — the user reported "clicked into the OpenRouter API key field, redirected to chat instantly". Reproduced exactly: pick Ollama → click Next → click input → race fires → chat.

The change

When the user clicks "Use [model]", synchronously replace step-container with a "Setting up [model]" loading state. The disabled spinner button is the only control while the API calls + redirect are in flight, so there's no stale UI to interact with.

Error paths (use-model returns ok:false, or fetch throws) now also call renderStep(1) so a failed swap leaves the user with a working Welcome step instead of a stuck "Setting up…" screen.

Test plan

  • Built test container with the patch, walked the full flow via curl: POST /api/ollama/use-model → POST /api/setup/complete → GET / returns 200 (no redirect, gate lifted)
  • Confirmed patched setup.js is served (the new "Setting up..." HTML appears in the response body)
  • Manual browser retest: pick Ollama → wizard immediately replaces with "Setting up gemma4:latest" → click attempts during the 800ms have no effect → lands cleanly in chat
  • Error path: simulated use-model failure → alert dismissed → wizard re-rendered to Step 1 (not stuck on spinner)

This is the second of two FITB#122 fork-side fixes. PR #6 (merged) added the redirect exempt list; this PR closes the race UX bug. After merge, the FITB main repo will bump forks/hermes-webui to consume both.

…when picking Ollama

useLocalOllama() schedules a 800ms-delayed redirect to / after marking setup
complete, but it left the wizard fully interactive during that window. The
user could click Next, advance to Step 2, click into the API-key input, and
then get yanked to chat when the timer fired — appearing as if clicking the
input itself caused the redirect.

Fix: synchronously replace the step container with a "Setting up <model>"
loading state the moment the user clicks the Use button. The disabled
spinner button is the only control while the API calls + redirect are in
flight, so there's no stale UI to interact with.

Error paths (use-model returns ok:false, or fetch throws) now also call
renderStep(1) so the user lands back on a working Welcome step instead of
a stuck "Setting up…" screen.

Surfaced by FITB#122 ("clicked into the OpenRouter API key field, redirected
to chat").
@roadhero
roadhero merged commit b72173f into master May 6, 2026
0 of 3 checks passed
@roadhero
roadhero deleted the fix/wizard-redirect-race branch May 6, 2026 01:55
roadhero added a commit that referenced this pull request May 6, 2026
… on late enable (#10)

Two related FITB#122 bugs in the local-fallback UX surface:

nesquena#122 #6 — Reactive failover modal never appears on provider failure

The frontend ELIGIBLE_TYPES set was {stream_interrupted, rate_limit,
no_response, unknown}. The original comment said auth/quota errors are
excluded because "local model can't fix the user's wrong key / empty
wallet." That misread the value: local fallback REPLACES broken cloud
entirely so the user can keep working, regardless of why cloud broke.
Auth and quota are exactly when the fallback offer makes sense.

Backend (api/streaming.py) actually emits these types: 'auth_mismatch',
'quota_exhausted', 'stream_interrupted', 'no_response'. The previous
'rate_limit' entry was dead — backend never emits it. Reconciled with
the real backend vocabulary.

nesquena#122 #7 — Recovery banner never appears after enabling fallback

startRecoveryPolling() was only called from boot, gated on the
/api/local-fallback/status check at page load. The most common user
flow — provider failure → enable fallback in Settings → correct API
key → expect banner — never started polling, because at page-load
fallback was off.

Fix: panels.js's onLocalFallbackToggle now dispatches a
'fitb:fallback-enabled' window event after a successful enable,
fallback-polish.js's boot listens for it and calls
startRecoveryPolling. The function is already idempotent (returns
early if the timer is set), so this is safe alongside the existing
boot-time call for the steady-state case.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant