Symptom
A. Post-login landing ignores isDefault
With an app published carrying isDefault: true, four cold sign-ins in fresh browser contexts all landed on /_console/home instead of the default app.
- Observed:
/_console/home (the multi-app launcher), 4/4 cold sign-ins.
- Expected:
/apps/<the isDefault app>.
- Control that isolates it: navigating to
/_console/ while already authenticated redirects correctly to the default app. So the resolver's policy is fine; the unauthenticated entry path is what breaks.
B. AppManagementPage's Disable app and Set as default are client-only stubs (confirmed)
Both controls show a success toast with zero non-GET requests on the wire and no server change on reload. Nothing in section A was credited off those toasts — the isDefault: true app was published through metadata, not set via this UI.
Root cause
A — the chain
- On the unauthenticated first paint,
GET /meta/app 401s.
apps/console/src/components/RootLandingRedirect.tsx resolves with an empty app list. resolveLandingPath([]) has no isDefault entry and no single visible app, so it falls through to rule 3 and returns /home. The resolver is auth-unaware — it only distinguishes loading from resolved, not "resolved empty because 401".
- The auth guard then captures that already-wrong path into
?redirect=%2Fhome, and honors it after sign-in.
- So the
isDefault branch never re-runs once the app list is actually available.
Verified still present on objectui origin/main @ bb68488: resolveLandingPath is unchanged (const defaultApp = list.find((a) => a.isDefault === true) on a list that is empty at that moment), and RootLandingRedirect still renders Navigate as soon as loading is false.
Not a stale bundle — the pin contains the routing (apps/console/src/components/RootLandingRedirect.test.ts asserts the isDefault policy at the pure-function level, which is exactly why the policy tests stay green while the live landing is wrong: the tests never feed it the empty-because-401 list).
B — the stubs
apps/console/src/pages/system/AppManagementPage.tsx — the handlers behind Set as default, Disable/bulk toggle and Delete each carry a literal // TODO: Replace with real API call when backend supports app management immediately before their toast.success(...), then call refresh(). No mutation is ever issued. Still present verbatim on origin/main @ bb68488 (the file's only recent touch is the i18n pass in #4208, which did not change the handlers).
Note the interaction between the two halves: because B never writes, an operator cannot even work around A from the console UI — isDefault has to be set in metadata.
Reproduction
Framework a86db175, vendored console 09987b68, showcase app.
A:
- Publish an app with
isDefault: true.
- Open a fresh browser context (no session) and go to
/_console/.
- Sign in.
Observed: lands on /_console/home; the sign-in URL carries ?redirect=%2Fhome. Repeated in 4 independent fresh contexts — 4/4.
Control: with an existing authenticated session, navigate to /_console/ — redirects correctly to the default app.
B:
- Go to the Applications page (AppManagementPage) as an admin.
- Click Disable app on an app, and Set as default on another.
- Watch the network panel; then reload.
Observed: success toast both times, zero non-GET requests, no server-side change after reload.
Dedup
Searched objectstack-ai/objectui for RootLandingRedirect, post-login landing / default-app landing, and AppManagementPage disable / set-as-default stub symptoms — no open or closed duplicate found.
Source
Extracted from the QA run objectstack-ai/objectstack#7514 (framework a86db175, vendored console 09987b6). Root-cause re-verification is against objectui origin/main @ bb68488.
Symptom
A. Post-login landing ignores
isDefaultWith an app published carrying
isDefault: true, four cold sign-ins in fresh browser contexts all landed on/_console/homeinstead of the default app./_console/home(the multi-app launcher), 4/4 cold sign-ins./apps/<the isDefault app>./_console/while already authenticated redirects correctly to the default app. So the resolver's policy is fine; the unauthenticated entry path is what breaks.B. AppManagementPage's Disable app and Set as default are client-only stubs (confirmed)
Both controls show a success toast with zero non-GET requests on the wire and no server change on reload. Nothing in section A was credited off those toasts — the
isDefault: trueapp was published through metadata, not set via this UI.Root cause
A — the chain
GET /meta/app401s.apps/console/src/components/RootLandingRedirect.tsxresolves with an empty app list.resolveLandingPath([])has noisDefaultentry and no single visible app, so it falls through to rule 3 and returns/home. The resolver is auth-unaware — it only distinguishesloadingfrom resolved, not "resolved empty because 401".?redirect=%2Fhome, and honors it after sign-in.isDefaultbranch never re-runs once the app list is actually available.Verified still present on objectui
origin/main@bb68488:resolveLandingPathis unchanged (const defaultApp = list.find((a) => a.isDefault === true)on a list that is empty at that moment), andRootLandingRedirectstill rendersNavigateas soon asloadingis false.Not a stale bundle — the pin contains the routing (
apps/console/src/components/RootLandingRedirect.test.tsasserts theisDefaultpolicy at the pure-function level, which is exactly why the policy tests stay green while the live landing is wrong: the tests never feed it the empty-because-401 list).B — the stubs
apps/console/src/pages/system/AppManagementPage.tsx— the handlers behind Set as default, Disable/bulk toggle and Delete each carry a literal// TODO: Replace with real API call when backend supports app managementimmediately before theirtoast.success(...), then callrefresh(). No mutation is ever issued. Still present verbatim onorigin/main@bb68488(the file's only recent touch is the i18n pass in #4208, which did not change the handlers).Note the interaction between the two halves: because B never writes, an operator cannot even work around A from the console UI —
isDefaulthas to be set in metadata.Reproduction
Framework
a86db175, vendored console09987b68, showcase app.A:
isDefault: true./_console/.Observed: lands on
/_console/home; the sign-in URL carries?redirect=%2Fhome. Repeated in 4 independent fresh contexts — 4/4.Control: with an existing authenticated session, navigate to
/_console/— redirects correctly to the default app.B:
Observed: success toast both times, zero non-GET requests, no server-side change after reload.
Dedup
Searched objectstack-ai/objectui for
RootLandingRedirect, post-login landing / default-app landing, and AppManagementPage disable / set-as-default stub symptoms — no open or closed duplicate found.Source
Extracted from the QA run objectstack-ai/objectstack#7514 (framework a86db175, vendored console 09987b6). Root-cause re-verification is against objectui
origin/main@bb68488.