Skip to content

console: show a user's effective permission sets and where each comes from on the user page #31216

Closed

Description

@objectstack-fleet

domain:server#3 · marchtian · session_017ihL2dFb2QdZEHEJ83cR2B

Filing gate: ② missing capability, split from #30209 row 1 during its delivery (PR #31207, dev report 6710717748). ⛔ Not a claim. Triage sets the grade and the lane.
Reader: the ui seat for the console widgets (ui/packages/*), plus a one-line page edit in packages/platform-objects/src/pages/sys-user.page.ts.
Dedupe (open AND closed): "effective access" → 20 hits, "permission set" origin user page → 518; the only open match is #30209 (the source card). #27433 (closed) is the add-user picker, not this tab.
reach: the console's user record page, 权限集 tab; read from the code on main, not run.
type: Enhancement

维护者速读

用户记录页的「权限集」页签只列直接分配的行,所以通过默认权限集或岗位拿到权限的人显示为 0 条。本卡在这个页面放一个新组件,列出这个人实际生效的权限集,并注明每一个是默认、岗位还是直接分配来的。数据来自配套的 server 卡。

What to build

  • A console widget, for example security:effective-access (an unclaimed namespace). Precedent: mcp:authorized-assistants on the same page, whose zod arm lives in ui/packages/types and needs no packages/spec edit. A type inside a claimed namespace such as record: would need spec vocabulary; this one does not.
  • Place it on sys-user.page.ts next to, or instead of, the record:related_list over sys_user_permission_set, which can only list stored rows.
  • Each row: set label, origin (default / position name / direct). Direct rows can keep their remove action; the others link to where they come from.

Acceptance

  • A user with access only through the default binding and a position shows those sets, not 暂无相关记录.
  • A CONTROL user with one direct set shows exactly that set.

Blocked-by: #31215
Suggested-grade: p3 · from a Setup walkthrough (#30209).

Activity

  1. added
    enhancementNew feature or request
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guards
    domain:uiDomain lane — seat card indexed by label:pm:seat
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Nov 7, 2026
  2. objectstack-fleet commented on Nov 7, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: audit · p2 · domain:ui · pm:blocked · 2026-11-07T18:55Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Nov 8, 2026
  4. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-project-manager · session_01FEkQ5nLA7wiVY5YWjT9Svr

    Claim: PM loop round 4 · 2026-11-08T03:37Z
    Session: session_01FEkQ5kxrRdCiSKcPqREG4w (card thread, dev) · seat session_01FEkQ5nLA7wiVY5YWjT9Svr
    Account: os-project-manager
    Branch: claude/project-thread-7r280u
    Worktree: objectstack-issue-31216
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: the new console widget and its tests under ui/packages/** (widget registration, its ui/packages/types zod arm), ui/packages/i18n/src/locales/* (new widget strings), the one-line placement in packages/platform-objects/src/pages/sys-user.page.ts (cross-seat file, carried by triage 6711632939), root .changeset/. ⛔ No packages/spec edit, ⛔ no server code.
    Container & model: M, mode:thread, model: default tier, effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the user page's permission-set tab lists stored rows only | none (a missing capability; the read landed in PR #31336) | every administrator reading a user's access
    Thread-read: 6711632939
    Premise: holds: PR #31336 (merged 2026-11-08T03:35Z) serves GET /api/v1/security/users/:id/effective-access and security.describeEffectiveAccess, and the 权限集 tab is still a record:related_list over sys_user_permission_set
    Serial constraints cleared: no other domain:ui card is pm:dispatched on the user page or sys-user.page.ts

    Scope: the card's What-to-build and Acceptance as written, one PR, Fixes #31216; the declaration lines start at no / none and the dev measures them on the diff (a new widget key, zod arm or i18n key is yes (widening)), and the seat amends this claim. Order: /mnt/project-files/pm-orders/ui/order-31216.md. Summons: the maintainer's 「devxUI 任务很多为什么不派发,并发5」 (this project, 2026-11-07T23:53Z).

  5. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-project-manager · session_01FEkQ5kxrRdCiSKcPqREG4w

    os-dev-report
    {
    "issue": 31216,
    "status": "done",
    "branch": "claude/project-thread-7r280u",
    "pr": "#31370",
    "session": "session_01FEkQ5kxrRdCiSKcPqREG4w",
    "premise_still_valid": true,
    "summary": "New console widget security:effective-access (@object-ui/app-shell) reads security.describeEffectiveAccess(userId) for the bound sys_user record and lists each effective permission set once, by catalog label with its name, with every origin the answer carries (direct, Position: NAME, default binding, configured platform administrator, AI access). A 403 or 501 leaves one quiet line and no list; other failures name themselves; it re-reads when sys_user_permission_set or sys_user_position data changes. It is placed above the unchanged grant related_list on the sys_user page's Permission Sets tab (one node line plus one comment line in sys-user.page.ts), so direct grants keep their remove action there. The zod arm and TS twin land in @object-ui/types, the CLI known-types list is regenerated, and effectiveAccess.* lands in all eleven i18n packs (zh-Hant generated). No packages/spec edit, no server code.",
    "tests": "Head ce83a53. Widget (UserEffectiveAccess.test.tsx, rendered through SchemaRenderer inside RecordContextProvider + MetadataCtx, client answer stubbed): 13/13 pass, covering default+position only shows both sets with origins (not empty), CONTROL one direct set shows exactly that set, a set reached two ways is one row with both origins, 403 and 501 show no list, 500 named, empty answer, off-record renders nothing, re-read on notifyDataChanged. Arm test 10/10; page pin sys-user-effective-access.test.ts 5/5. pnpm --dir ui exec vitest run --maxWorkers=2 packages/types/ packages/cli/ packages/i18n/ packages/app-shell/src/console/: 784 passed, 2 failed (parser-tier clause pins: the arm refusal text lacked the not-a-container clause), fixed in ce83a53, rerun of the 4 affected files 72/72. platform-objects vitest 120 files / 1751 tests pass, typecheck exit 0. type-check of app-shell, types, i18n, cli exit 0 (app-shell first red on an untyped test node literal, fixed). Ablation A (widget, head cf2908d, ablation-replace.mjs, rows filtered to sets with a direct origin = stored rows only; anchor 1->0, blob 8525c107->36529e68): 4/13 red (the three section-1 cases and the two-ways case), CONTROL green; restored blob == HEAD, git diff HEAD empty; test reads the widget from src by relative import, no build in between. Ablation B (page, head 5959bfa, widget node deleted; blob 3b5c6540->c70ae662): 4/38 red (3 placement pins + the exemption-liveness pin), restored blob == HEAD.",
    "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack derived 82 families, re-derived on head ce83a53 (identical). All 82 exit 0 on ce83a53, codes captured before any pipe; pnpm --dir ui exec vitest run scripts/ under the lock: 170 files passed, 2 skipped; 4996 tests passed. --ran: 82 derived, 82 run, 0 NOT-MEASURED, 0 UNRUN. First pass on an earlier head had three exit-3 prerequisite refusals (teardown self-test on a shallow clone, check:dual-build-cjs-loads and check:i18n without dist), all cleared by fetch/builds and exit 0 on the final head. Also: eslint on ui/packages/app-shell/src/console/security/ exit 0, check:new-line-citations 0 new, exit 0. CI check-runs: in_progress at report time (not waited on). Gates file: /mnt/project-files/pm-orders/ui/31216-gates-ran.txt.",
    "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
    "mcp_calls": "5 — all reads: issue_read get #31216, issue_read get_comments #31216 (twice), pull_request_read get_files #31084, pull_request_read get_files #31125. No MCP write. Plus one gh search/issues read (precedent PRs).",
    "api_writes": "2 — relay pr_create (dispatch fw-20261108T044237Z-9482a2, run 42447899280 success, read back identical 12639 bytes, PR #31370, no labels key, no assignees) and this os-dev-report comment via post-stamped. Plus one git push (not REST). Write budget: 3 of 3 strokes (push, pr_create, report).",
    "open_questions": [
    {
    "question": "Claim amendment (seat): the declaration lines measured on the diff are Clause-②: yes (widening) (new registered widget key security:effective-access, new @object-ui/types zod arm and TS twin, 12 new @object-ui/i18n keys per pack) and Metadata-protocol: none (the page edit places a node with no props; precedent mcp:authorized-assistants placement shipped none). The PR body and changeset already carry these; the claim still says no/none.",
    "options": [
    "A amend the claim to yes (widening) / none and run the contract review owed",
    "B other"
    ],
    "recommendation": "A, because each widening item is measured on the diff and matches the precedent changeset 30894-assistant-revoke.md."
    },
    {
    "question": "Claim file-surface amendment (seat): beyond the named surface the diff touches packages/platform-objects/src/pages/canonical-expression-envelopes.test.ts (the UNMAPPED_TYPE_EXEMPTIONS entry every unmapped widget on a shipped page needs, as the mcp precedent PR #31125 did) and adds packages/platform-objects/src/pages/sys-user-effective-access.test.ts (placement pin). sys-user.page.ts itself is one node line plus one comment line.",
    "options": [
    "A amend the surface to include the two platform-objects test files",
    "B drop the placement pin file"
    ],
    "recommendation": "A, because the exemption is required for the existing door-3 test to stay green and the pin is what ablation B reads."
    }
    ],
    "security_findings": "none",
    "out_of_scope_findings": [
    "carrier: none · noted, not filed: ui/packages/types/src/zod/README.md heading 'Cloud Widgets (1)' now lists three entries, two of them not cloud: widgets (mcp:authorized-assistants landed under it before this PR; security:effective-access follows that precedent). Polish, docs count; not a defect class.",
    "carrier: none · reading recorded in PR Acceptance notes: 'Direct rows keep their remove action' is held by the unchanged grant related_list below the widget; the widget writes nothing. Card allowed next to or instead of; instead-of would drop New and the validity-window columns."
    ],
    "deviations": "os-dev.md rule 2 says pr_create carries the claim Account as assignee; the order says no assignees. Sent none, per the order. Changeset and PR body declare the measured yes (widening) instead of copying the claim's no, flagged in open_questions for the seat to amend."
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-project-manager · session_01FEkQ5nLA7wiVY5YWjT9Svr

    席位核对 · Claim amendment · 2026-11-08T04:46Z · claim 6716801764 declarations and file surface measured

    The card thread measured its diff (PR #31370, head ce83a535, report 6717366902). The diff adds published surface:

    • a new registered widget key, security:effective-access (@object-ui/app-shell);
    • a new @object-ui/types zod arm, SecurityEffectiveAccessSchema, with its TS twin;
    • the effectiveAccess.* keys in all eleven @object-ui/i18n packs;
    • one generated @object-ui/cli known-types entry.

    Clause-②: yes (widening)
    Metadata-protocol: none

    The page edit places a node on a shipped page. It changes nothing a metadata author writes or a save door judges, the same as the mcp:authorized-assistants placement.

    File surface, as delivered: the claimed surface, plus two files in packages/platform-objects/src/pages/, both accepted:

    • canonical-expression-envelopes.test.ts: one UNMAPPED_TYPE_EXEMPTIONS entry. The new page node requires it, as it did for the mcp: precedent.
    • sys-user-effective-access.test.ts: a new placement pin read from the shipped page metadata.

    Neither is packages/spec or server code. check-governed-merges --pr 31370: not governed, 1,082 changed lines.

    The seat owes the TIER_DEFAULT declaration review on this head before the queue. Everything else in claim 6716801764 stands.

  7. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-project-manager · session_01FEkQ5nLA7wiVY5YWjT9Svr

    ACCEPT → PR #31370 comment 6717561043 · 2026-11-08T05:07Z · head ce83a535 (the user page's Permission Sets tab shows the person's effective permission sets and their origins; 1,082 lines, not governed, Fixes #31216). Landing through the merge queue.

  8. objectstack-fleet commented on Nov 8, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#1 · os-project-manager · session_01FEkQ5nLA7wiVY5YWjT9Svr

    Landed · 2026-11-08T05:39Z

    Reading Value
    PR #31370 MERGED 2026-11-08T05:38Z, merge commit 1f370858a927127e8d60dccd67d8bb84b506efa5 on main
    #31216 closed completed by Fixes #31216; no other domain:ui card left the open inventory

    State: pm:dispatched removed, assignee cleared.

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 guardsdomain:uiDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions