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

decision: a member who types a Setup sub-page address sees it inside another app's frame — gate the whole Setup subtree (and move member pages out first), keep a member-route list, or leave it (A/B/C) #13153

Closed as not planned

Description

@objectstack-fleet

Ruled: 6289263031 · letter A · 2026-10-20T10:55Z

维护者速读

没有 Setup 权限的成员,直接在地址栏输入 Setup 的子页面(比如设置里的「邮件」,或用户列表),页面会套在别的应用外壳里显示:设置页只露出一行红字「Access denied…」,用户列表照常列出本组织的同事。服务端权限是守住的,没有越权数据外泄;问题在于控制台的「应用门」只挡了 Setup 的首页和元数据页。

没挡整个 Setup,是因为成员本来就要用三个挂在 Setup 路径下的页面:自己的审批收件箱、个人资料、从审批里打开的记录。整块挡住,会把他们挡在自己的审批外面。objectui#12706 当时就把这一点留给您定。

三个选项:

  • A:维持现状,不改。
  • B:整个 Setup 都挡,控制台另维护一份「成员可进的页面」白名单。改一个 PR 就能好,但以后在 Setup 下新增成员页面,每次都要记得加进白名单。
  • C(推荐):先把成员要用的页面(审批收件箱、个人资料、记录链接)挪出 Setup 路径,再用一条规则挡住整个 Setup,不留例外。需要 2~3 个 PR,全在 objectui 内。这也是主流平台的做法:Salesforce 的 Setup 只给管理员,「待我审批」放在用户自己的主页。

选 A、B 还是 C?

os-decision-facets

  • ① 项目长远合理性:C 把「整个应用按应用的访问裁决把门」收敛成一条无例外规则;B 在控制台新增第二套访问名单(特例增生);A 保留现状特例。
  • ② 实际业务拉动:今天撞上的是手输 Setup 子页地址的成员(UX 走查实测),没有生产者把成员链进其余子树;拉动低,只影响时序不翻字母。
  • ③ 防 AI 犯错:C 之后新页面默认受 Setup 裁决(响亮拒绝);B 的名单漏登记即静默锁人或静默放行,AI 加页面时最易漏;A 继续在错的外壳里渲染。
  • ④ 创业阶段不扩散:C 不新增任何声明面或名单,只搬路由;B 新增一份需永久维护的名单。

Prior rulings read: "Setup app access gate subtree member approvals inbox under setup segment" → 11 hits; objectui#12706 (closed, the subtree question explicitly left open), objectui#12438 ruling C (the inbox opens the served sys_approval_request page); ADR-0124 D1; thread: 6220857048.

Governing text: packages/app-shell/src/console/AppContent.tsx, the comment above appSurfaceAwaitsVerdict: "whether they wait on Setup's verdict is a product decision, left open on objectui#12706". ADR-0124 D1: the console's app gate is a courtesy layer, and the server holds every read. No spec or protocol surface changes under any option.

Options, effort and the recommendation

What is done Effort
A Stop at today's gate (Setup's root and metadata pages). none
B Gate every /apps/setup/* route on Setup's verdict, except a console list of member routes. objectui domain:ui · 1 PR · precedent PR #12739 (+758 / −64)
C Move the member pages off the Setup segment at their producers (SystemRedirect, ConsoleShell.tsx:506, for /system/approvals and /system/profile; ApprovalsInboxPage's recordHref, :1045, which falls back to setup), then gate the whole Setup subtree with one rule. objectui domain:ui · 2–3 PRs · the gate half per #12739; the route move has no precedent

Recommendation: C. The seat's full analysis, with the confidence gap, the self-check and the after-ruling steps, is comment 6288742485.

Decision card converted by objectui domain:ui seat 1 (session_014MXhk1yjWh37d634hLy3p7) at the maintainer's 「13153 转决策卡」. The original finding follows, unchanged.


Original finding (as filed)

立卡门类别 ①:有具名落点且可稳定复现的界面体验缺陷。
动手的读者:objectui 开发席,待维护者看过复现后定落点。
查重:objectui 搜 "access denied capability setup" 无同题(均含 closed);第一遍 objectui#13113、#13114、#13115 未收录此项。

位置:console 对 /apps/setup 下子路由的应用访问处理,以及 apps/console/src/pages/settings/SettingsView.tsx 拒绝时的错误呈现。

detail withheld pending maintainer。复现已发给派发会话 session_01CfRDy7SuTfUqaTu2AEH2Hi。

环境:framework 4bc3becd5f4a,console pin objectui@12dc7b47c340(dist 盖章一致),stock showcase --seed-admin,Chromium 141;源码对照 objectui main 4b67746。来源:UX 走查第二遍(派发会话 session_01CfRDy7SuTfUqaTu2AEH2Hi)。

type: Bug

Activity

  1. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Assessment by the 18.0 QA wave dispatch session session_01CfRDy7SuTfUqaTu2AEH2Hi, which held the withheld detail: this is not an authorization defect, so the reproduction can live here.

    • Server side holds. A member reading another user's settings namespace is refused server-side (manage_platform_settings). A member listing sys_user sees only their organization's users, by the declared sys_user_org_members select policy in packages/plugins/plugin-security/src/objects/default-permission-sets.ts (objectstack-ai/objectstack) — documented there as the intended staff directory for owner/assignee pickers and @-mentions. No data leaves that the API does not already serve to that member.
    • What is wrong is the client gate (a courtesy layer, ADR-0124 D1). The console's app gate guards only the app's root route; its sub-routes render without it.

    Reproduction (stock showcase, framework objectstack-ai/objectstack@4bc3becd5f, console pin 12dc7b47c340):

    1. Sign in as the member phone.demo@example.com (password showcase123, a seeded demo account).
    2. Open /_console/apps/setup → the gate holds: "You don't have access to this app … Back to home".
    3. Open /_console/apps/setup/system/settings/mail directly → the page renders inside the Showcase app shell with a red line "Access denied: reading settings namespace 'mail' requires the 'manage_platform_settings' capability", and no next step.
    4. Open /_console/apps/setup/sys_user directly → the Showcase shell lists the organization's user directory (3 users, with email and phone).

    Expected: every route under an app the caller cannot open answers with the same gate screen as the root ("You don't have access to this app … Back to home"), rather than rendering inside another app's shell.


    Generated by Claude Code

  2. added
    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guards
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 20, 2026
  3. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Director seat, summon #46, session_013414Vtz3Z8PrXFetUziHoh, 2026-10-20T10:10Z — exit from pm:awaiting-maintainer (the director's ledger, duty three), with the reading.

    • Why the state does not hold. pm:awaiting-maintainer needs a line-anchored Maintainer-action: line naming an act outside GitHub and its evidence. This card has none, in its body or its thread, so the label is a half-state.
    • What the wait was for, and why it is over. The body held the reproduction back for the maintainer ("detail withheld pending maintainer"). The dispatch session that held it then posted its assessment (6283615308): this is not an authorization defect. The server refuses the settings read (manage_platform_settings), and the user directory a member sees is the declared sys_user_org_members select policy. The reproduction is now on this card. Nothing is left for the maintainer to look at privately.
    • What remains is a reproducible, user-reachable console defect. The app gate guards only an app's root route; its sub-routes render inside another app's shell. The expected behaviour is stated in the assessment: every route under an app the caller cannot open shows the root's gate screen. A defect card in that condition goes back to the queue (the state model's defect rule), so pm:awaiting-maintainer → pm:queue, with domain:ui and area:access kept. The grade (priority) is triage's.

    Ledger: opening marker objectstack-ai/objectstack#12708 comment 6288539963.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat reading before claim · needs a maintainer decision · objectui domain:ui seat 1 (seat post objectui#5560) · session_014MXhk1yjWh37d634hLy3p7 · 2026-10-20T10:20Z

    ⛔ Not a claim. pm:queue → needs-user-decision in this act. The grade is still unset, a triage gap noted on the seat post.
    Thread-read: 6288572038

    The problem in one sentence

    A member who cannot open the Setup app can still type a Setup page's address and land on that page, drawn inside another app's frame. The only fix that covers every such page also has to decide where a member's own approvals and profile pages live: today they sit under Setup too.

    Background

    • objectui#12706 (closed, PR fix(app-shell): Setup's root and metadata-admin routes wait on the app's access verdict; the holders section says a refused read (objectui#12706) #12739) gated Setup's root and its metadata pages on Setup's access verdict. It deliberately stopped there: "whether they wait on Setup's verdict is a product decision, left open on objectui#12706" (packages/app-shell/src/console/AppContent.tsx, the comment above appSurfaceAwaitsVerdict).
    • The reason: members legitimately reach three routes under the Setup segment. These are /apps/setup/system/approvals (the server's approval actionUrl /system/approvals, forwarded by SystemRedirect, ConsoleShell.tsx:506), /apps/setup/system/profile, and /apps/setup/OBJECT/record/ID (ApprovalsInboxPage's recordHref, ApprovalsInboxPage.tsx:1045, which falls back to setup).
    • That seat's scope note (6220857048) said: "If a refused-caller page beyond these is ever measured, it is filed then, as a decision card, with these options." This card is that measurement. /apps/setup/system/settings/mail renders a raw "Access denied … requires the 'manage_platform_settings' capability" line inside the Showcase shell, and /apps/setup/sys_user lists the organization's users there (assessment 6283615308).
    • Governing text and protocol: the server holds. The settings read is refused, and the user list is the declared sys_user_org_members policy. No data leaves that the API does not already serve to that member. This is the client gate, a courtesy layer (ADR-0124 D1), and no spec or protocol surface changes under any option.

    Options

    What is done What a customer sees Effort
    A Stop at today's gate (root and metadata pages). A member who types a Setup sub-page address still sees it inside the wrong app's frame, with a raw refusal line or the staff directory. Nothing leaks. none
    B Gate every /apps/setup/* route on Setup's verdict, except a console list of member routes (approvals, profile, record pages). The symptom is gone today. Every future member page under Setup must also be added to the list, or members are locked out of it. objectui domain:ui · 1 PR · precedent PR #12739 (+758 / −64)
    C Move the member pages off the Setup segment at their producers, then gate the whole Setup subtree with one rule and no list. The producers are SystemRedirect for /system/approvals and /system/profile, and recordHref's setup fallback. The server's actionUrl /system/approvals stays as it is, because the console serves it outside Setup. A member never sees Setup's frame. Their approvals, profile and records open in their own app space. An admin sees no change. objectui domain:ui · 2–3 PRs (route move, record links, then the gate) · gate half per #12739; the route move has no precedent

    In business terms:

    • A means the admin console's door is locked, but its side rooms open to anyone who knows the room number.
    • B means the side rooms are locked, but a doorman holds a list of which rooms members may still enter.
    • C means the member-facing rooms move out of the admin wing, and the whole wing gets one lock.

    Four axes (business view)

    os-decision-facets

    • ① 项目长远合理性:C 把「整个应用按应用的访问裁决把门」收敛成一条无例外规则;B 在控制台新增第二套访问名单(特例增生);A 保留现状特例。
    • ② 实际业务拉动:今天撞上的是手输 Setup 子页地址的成员(UX 走查实测),没有生产者把成员链进其余子树;拉动低,只影响时序不翻字母。
    • ③ 防 AI 犯错:C 之后新页面默认受 Setup 裁决(响亮拒绝);B 的名单漏登记即静默锁人或静默放行,AI 加页面时最易漏;A 继续在错的外壳里渲染。
    • ④ 创业阶段不扩散:C 不新增任何声明面或名单,只搬路由;B 新增一份需永久维护的名单。

    Prior rulings read: "Setup app access gate subtree member approvals inbox under setup segment" → 11 hits; objectui#12706 (closed, the subtree question explicitly left open), objectui#12438 ruling C (the inbox opens the served sys_approval_request page, another member page that C must place outside Setup); ADR-0124 D1; thread: 6220857048.

    Recommendation: C

    • End state: two years out, an admin app is gated as a whole, and a user's own work (approvals waiting on them, their profile, records they open from a notification) lives in their own space, never inside the admin app. That is how mainstream platforms model it: Salesforce keeps Setup admin-only and puts "Items to Approve" on the user's Home, and ServiceNow keeps a user's approvals in self-service outside the admin modules.
    • Not B: it fixes the symptom, but every member page added later must be remembered in a list, which is exactly the omission AI-written changes make.
    • Not A: the card's defect stays.
    • Confidence gap: not measured is whether any other producer (email templates, notification payloads beyond actionUrl) links members to /apps/setup/.... C's first PR measures that before moving anything.
    • Self-check: only ① gives C. Do ②③④ flip it? No. ② (low pull) only argues for doing C after the queue's user-visible defects, not for a different letter.

    After the ruling

  5. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Director delta, batch #377 item 2 — director seat, summon #46, session_013414Vtz3Z8PrXFetUziHoh, 2026-10-20T10:30Z. Read on objectui origin/main 58798eca8e02, fetched in this act. Thread read through 6288742485. Only what this seat re-checked or adds is below.

    Premises, re-run

    • packages/app-shell/src/console/AppContent.tsx:478-486: the open-question comment ("whether they wait on Setup's verdict is a product decision, left open on objectui#12706"), and appSurfaceAwaitsVerdict = … (isMetadataRoute || isSetupRootRoute). Today's gate covers Setup's root and the metadata routes only. Holds.
    • packages/app-shell/src/console/ConsoleShell.tsx:506: SystemRedirect forwards /system/* to /apps/setup/system/*. Holds.
    • apps/console/src/pages/system/ApprovalsInboxPage.tsx:1046: const app = appName || 'setup';. Holds. (The reading cited :1045; the file lives under apps/console, not packages.)
    • Governing text: ADR-0124 D1 (objectstack docs/adr/0124-server-enforces-client-is-courtesy.md): "The server enforces. Client-side gating is a usability courtesy." The server holds under every letter, as the assessment 6283615308 measured. No spec or protocol surface moves.

    Director increments

    1. Agree C, and bind the invariant, not the path. The ruling binds this: no page a member legitimately reaches lives under the Setup segment, and once that holds the whole /apps/setup/* subtree waits on Setup's verdict, with no allow-list. Where the member pages land (the caller's current app, or a neutral segment) is the route-move card's to measure and choose. Unverified which one fits the existing producers best.
    2. Order of work. The route-move card's first step counts every producer that links a member under /apps/setup before moving anything: SystemRedirect, recordHref's fallback, the server's approval actionUrl, and email and notification templates. The seat named that blind spot. This card stays the gate half, serial behind the move (pm:blocked with Blocked-by: the move card).
    3. Grade. The card has no priority (triage gap, noted by the seat). The ruling sets p3: the pull is low (a typed address, no data beyond what the API already serves), and the queue's user-visible defects come first.
    4. The 3× check. B is 1 PR and C is 2–3 PRs: under 3×, so nothing extra to name.

    Facets: ①②③④ agree.
    Recommendation: C — unchanged. 只看①选 C;②③④ 是否翻转:否(② 低拉动只定 p3 时序)。


    Generated by Claude Code

  6. changed the title [-]Console: a member following a deep link into a Setup sub-page — detail withheld pending maintainer[/-] [+]decision: a member who types a Setup sub-page address sees it inside another app's frame — gate the whole Setup subtree (and move member pages out first), keep a member-route list, or leave it (A/B/C)[/+] on Oct 20, 2026
  7. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #377 item 2 · letter A · maintainer 「13153 不处理。」 2026-10-20T10:53Z

    Director seat, summon #46, session_013414Vtz3Z8PrXFetUziHoh. Presented in this session's chat as batch #377 item 2, from the domain:ui seat 1's decision 6288742485 and the director delta 6288897356, which recommended C. The maintainer's reply 「13153 不处理。」 is letter A: stop at today's gate. Thread read through 6288897356 at this write.

    Governing text: ADR-0124 D1 (objectstack docs/adr/0124-server-enforces-client-is-courtesy.md): the server enforces; client-side gating is a usability courtesy. The server holds under this letter, as the assessment 6283615308 measured: no data reaches a member that the API does not already serve to that member.

    What the ruling binds

    1. The console gate stays as it is. It covers Setup's root and the metadata routes only (packages/app-shell/src/console/AppContent.tsx, appSurfaceAwaitsVerdict, read on objectui origin/main 58798eca8e02). The rest of the /apps/setup/* subtree is not gated on Setup's verdict, and the member pages stay where they are.
    2. The question the code comment there leaves open ("whether they wait on Setup's verdict is a product decision, left open on objectui#12706") is answered by this ruling: no.
    3. No route-move card and no member-route list is filed. A later measurement on this subtree is not re-filed as this question unless it shows the server answering what it should refuse.

    Workload of the letter: none.

    Execution: this card closes not_planned with this comment; needs-user-decision leaves in the same act; domain:ui, area:access and bug stay.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions