You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
console: the first-run setup wizard's completion redirect bypasses the console basename #4181
Found while working objectui#2794 (the /setup deep link). Not fixed there — that card is about who reaches /setup, this is about where the wizard sends you once it is done. Filed unassigned.
What
apps/console/src/pages/auth/SetupPage.tsx finishes the first-run owner bootstrap with a full-page navigation to the site root, twice:
line 88 — the already-signed-in bounce: window.location.assign('/')
line 148 — the success path, after signUp() and the bootstrap-org rename: window.location.assign('/')
window.location.assign bypasses React Router's basename. The console resolves its basename from an injected base href (App.tsx:resolveBasename), and the framework CLI injects one for every embedded deployment — so on a console served at /_console/, both calls land on the ORIGIN root rather than the console root.
Why this is a real class, not a nitpick
apps/console/src/pages/auth/LoginPage.tsx already carries the fix for exactly this, as a named helper with a comment that states the rule:
function withConsoleBase(path: string): string
window.location.assign bypasses React Router's basename, so a path produced by the router […] or a literal like /organizations would resolve to http://host/settings, missing the /_console mount and 404-ing.
SetupPage makes the same call and does not use that helper. Same defect the helper exists to prevent, one file over.
Severity / reachability
Low reach, and that is why it is filed rather than smuggled into #2794's PR:
it only fires on a deployment that has no owner yet, i.e. genuinely first-run;
under the default / mount the two spellings coincide, so a standalone os dev run cannot see it — this needs an embedded / base href-mounted console to reproduce, which is why nothing has hit it.
The outcome, when it does fire, is a completed bootstrap that lands the brand-new owner outside the SPA — the worst possible moment for a dead end, since it is the first screen after creating the account.
Suggested fix
Route both calls through withConsoleBase (or lift that helper somewhere both pages can import it — it is currently module-private to LoginPage). Worth a quick grep for other window.location.assign / window.location.href = producers in apps/console at the same time; this one was found by reading, not by a sweep, so the set may be larger.
Claim: PM loop round 6 (rolling slot refill; graded bug — concrete on every framework-CLI deployment, which injects the base href automatically; invisible only under bare / mounts)
Session: session_017Qqyix2QcnpUC9XeYVDzx3 · Branch: claude/issue-4181-setup-exit-basename · Worktree: objectui-issue-4181
File surface: apps/console/src/pages/auth/SetupPage.tsx (:88 and :148, the two window.location.assign('/') exits) + wherever withConsoleBase() gets lifted from LoginPage's module-private scope so both callers share one implementation + tests. Serial constraints: PR #4180 (armed, same app) touched App.tsx/components but deliberately NOT SetupPage — branch off main; rebase if #4180's landing moves shared files.
Container & model: S, mode:subagent, model: opus
Direction (the filing names its own fix): route both exits through the withConsoleBase() treatment LoginPage already carries — lift the helper to a shared module rather than duplicating it (two module-private copies of a basename fix is the next drift), convert the exits to router navigation if the surrounding code allows it (a full-page assign may be deliberate post-bootstrap — READ why it reloads before deciding; if the reload is load-bearing, keep the assign but base-prefix it and say why), and pin the base-href case red→green (the #4168/#4180 basename test idiom is the worked precedent).
The dispatch's "read why it reloads before deciding" clause earned its keep: the reload is load-bearing for a measured reason (MetadataProvider mounts on auth RESOLUTION and re-keys on language alone, so a router navigation would hand the new owner an appless console) — both exits stay assigns, base-prefixed, with the rationale pinned on the constant so the next refactorer inherits the WHY. Two card corrections reported straight: the third private copy of the helper in RegisterPage (the predicted drift had already happened — the lift covers three sites), and the verification that the helper's mechanism actually holds (BASE_URL vs injected base href are different sources that agree because Vite 8 resolves ./ literally — documented, because without that fact the fix would be theatre). The test design matches the mechanism: targets resolved against document.baseURI as location.assign itself resolves them, across all three real mount configurations. Reverse verification predicted 4-red exactly with the lift proven behavior-neutral by the seven untouched pins. The location.assign sweep's per-site verdicts (OAuth targets external by design; the storage URL server-prefixed) recorded in #4190 so nobody re-chases them, with #4190's own submitBehavior.url contract question correctly held for a ruling.
First-run owners on mounted consoles now land inside the SPA. Flipping ready + auto-merge.
Activity
yinlianghui commentedon Aug 10, 2026
Claim: PM loop round 6 (rolling slot refill; graded
bug— concrete on every framework-CLI deployment, which injects the base href automatically; invisible only under bare/mounts)Session:
session_017Qqyix2QcnpUC9XeYVDzx3· Branch:claude/issue-4181-setup-exit-basename· Worktree:objectui-issue-4181File surface:
apps/console/src/pages/auth/SetupPage.tsx(:88 and :148, the twowindow.location.assign('/')exits) + whereverwithConsoleBase()gets lifted from LoginPage's module-private scope so both callers share one implementation + tests. Serial constraints: PR #4180 (armed, same app) touched App.tsx/components but deliberately NOT SetupPage — branch off main; rebase if #4180's landing moves shared files.Container & model: S,
mode:subagent,model: opusDirection (the filing names its own fix): route both exits through the
withConsoleBase()treatment LoginPage already carries — lift the helper to a shared module rather than duplicating it (two module-private copies of a basename fix is the next drift), convert the exits to router navigation if the surrounding code allows it (a full-page assign may be deliberate post-bootstrap — READ why it reloads before deciding; if the reload is load-bearing, keep the assign but base-prefix it and say why), and pin the base-href case red→green (the #4168/#4180 basename test idiom is the worked precedent).Generated by Claude Code
yinlianghui commentedon Aug 10, 2026
ACCEPT (objectui seat PM, session
session_017Qqyix2QcnpUC9XeYVDzx3, review of record) — PR #4186.The dispatch's "read why it reloads before deciding" clause earned its keep: the reload is load-bearing for a measured reason (MetadataProvider mounts on auth RESOLUTION and re-keys on language alone, so a router navigation would hand the new owner an appless console) — both exits stay assigns, base-prefixed, with the rationale pinned on the constant so the next refactorer inherits the WHY. Two card corrections reported straight: the third private copy of the helper in RegisterPage (the predicted drift had already happened — the lift covers three sites), and the verification that the helper's mechanism actually holds (BASE_URL vs injected base href are different sources that agree because Vite 8 resolves
./literally — documented, because without that fact the fix would be theatre). The test design matches the mechanism: targets resolved against document.baseURI as location.assign itself resolves them, across all three real mount configurations. Reverse verification predicted 4-red exactly with the lift proven behavior-neutral by the seven untouched pins. The location.assign sweep's per-site verdicts (OAuth targets external by design; the storage URL server-prefixed) recorded in #4190 so nobody re-chases them, with #4190's own submitBehavior.url contract question correctly held for a ruling.First-run owners on mounted consoles now land inside the SPA. Flipping ready + auto-merge.
Generated by Claude Code
fix(console): the first-run setup exits land inside the console mount (…