Skip to content

feat: Setup catalog pages read the registry (editable under single, read-only under a wall); assignment pages stay data pages; pickers list the registry (objectstack ADR-0131 D3/D7) #7611

Closed

Description

@hotlong

⛔ BLOCKED — the v18 development line is not open.

Blocked-by: objectstack-ai/objectstack#15193, objectstack-ai/objectstack#15196

Part of the ADR-0131 execution tree (objectstack-ai/objectstack#15194). ⛔ Do not claim, assign or dispatch this card while that gate card is open, whatever the labels here say. The record is docs/adr/0131-total-organization-ownership-no-null-organization-id.md in objectstack-ai/objectstack (merged 2026-09-04).


In one sentence. Positions, permission sets and capabilities come from exactly one list — the registry. Under single-tenant an administrator can create and edit them in Setup (they are environment-level); on a shared-database multi-tenant deployment they are read-only. Assignment pages (who holds which position, who holds which set) stay ordinary data pages for the caller's own organization, with native search, sort and paging. Pickers list the registry. There is no merged two-source list.

The maintainer's Steedos lesson is the reason for that last sentence: a UI that merges an in-memory list with a database list has to re-implement search, sort and paging itself, and it drifts.

Scope. Setup catalog pages read /api/v1/meta/<type> — managed items read-only with a provenance badge, environment-authored items editable for capability holders under single, everything read-only for tenants under a wall (the server refuses anyway; the UI explains why). Assignment pages (sys_user_position, sys_user_permission_set) read /api/v1/data/… with native search/sort/paging and write the catalog item by name. Pickers — assign a user to a position or a set, sharing recipients, the capability matrix — list the registry. Remove every dependence on sys_position / sys_permission_set / sys_position_permission_set / sys_capability rows.

Acceptance. Against a framework build with C2 and C3 landed: Setup catalog pages render from the registry with the four tables gone; assigning a declared or Studio-authored position through the picker succeeds end to end and lands a name-keyed row; under isolated a tenant admin sees the catalog read-only and can still assign; no request fetches a merged list.

⭐ Parity gate (ADR-0131 §4 — this card fails without it). Under single, an organization administrator with no Studio capability creates, edits, deactivates and reactivates an environment-authored permission set from the same Setup page as today, with the list views, the filters, the object × CRUD / field-level matrix editor and the active switch all intact; a managed set opens read-only with a clone action. A JSON textarea in place of the matrix editor fails this card.

Absorbs: objectui#7205 — clicking a column header silently persisting an org-wide view overlay. That overlay axis is exactly what ADR-0131 D6/C5 retires, so the fix is not a save gesture on the old mechanism; read that card before starting.

Refs: ADR-0131 D3, D6, D7, §4 parity criterion · ADR-0094 D1 · objectui#7205.

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Sep 4, 2026
  2. claude commented on Sep 4, 2026

    @claude
    Contributor

    Blocked-by: objectstack-ai/objectstack#15193

    Blocked-by: objectstack-ai/objectstack#15196

    Canonical unblock lines added on the #7041 census (objectui#7674); the blocker is as the card states above — no state change. The body already carries both targets, but on one line wrapped whole in inline backticks, so nothing matches at line start; split here, one line per blocker. The ADR-0131 execution-tree parent the body also names (objectstack-ai/objectstack#15194, open) is recorded as context, not added as a third blocker — objectstack#15193 is the gate card.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    Contributor

    v18 pre-opening re-verification (C9): HOLDS. Nothing is implemented, and the blocker lines are incomplete

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-06T14:38Z. ⛔ Not a claim, ⛔ not a dispatch. Read-only re-verification on objectstack main 6befe19c6e and objectui main c910630cf9. The cut base was 2026-09-04, 3,298 commits earlier. The maintainer asked for this pre-opening preparation in the triage seat's chat: 「现在就可以处理吧」. Classes, positions and functions only. The claiming seat applies these corrections before building. The body is not rewritten.

    Blocked-by: objectstack-ai/objectstack#15204
    Blocked-by: objectstack-ai/objectstack#15206

    Holds:

    • The Setup catalog pages still read rows: apps/console/src/AppContent.tsx:269-271 routes positions to sys_position and permissions to sys_permission_set.
    • No objectui code reads the catalog's metadata for Setup.
    • PermissionMatrixEditor already lists permission metadata (:481), but its clone path reads the row (:952, permission-set-clone-dispatch.ts:35).

    Additions:

    • The runtime dependence is about 11 sites in 10 files. The card did not enumerate it. It includes:
      • AssignedUsersSection.tsx:127,149,154 (by permission_set_id);
      • CapabilityMultiSelectField.tsx:177;
      • RecipientPickerField.tsx:54;
      • RecordDetailView.tsx:2881;
      • core/actions/recordDelete.ts:96;
      • data-objectstack/src/index.ts:5128;
      • the approval-approver pickers, which the card's picker list does not name: approverIdentity.ts:100, decisionOutputParams.ts:73, useApproverDirectory.ts:114.
    • The server-side Setup nav entries are objectstack's (plugin-security/src/security-plugin.ts:1464-1466), not this card's. They move with C2/C3 on the framework side.
    • The new Blocked-by lines:
      • the acceptance "the four tables are gone" needs C3 (#15204);
      • absorbing objectui#7205 (sort persisting an org-wide overlay, still live at ObjectView.tsx:3194-3195/:3525-3526) needs C5's retirement of the overlay axis (#15206);
      • ADR §8 lists only C2 for C9, so these two record the card's own acceptance, not a new order.

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    Contributor

    target:v18 added, executing decision card objectstack-ai/objectstack#22010 (ruling 6020197009, batch #282 item 6, maintainer 「同意」). The label is a release-board view, not a gate: this card's gate stays its Blocked-by: / Restart-when: line on objectstack-ai/objectstack#15193. Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U. ⛔ Not a claim; no other label changes.

  5. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    Contributor

    Ruling: batch #310 item 1 · letter A · maintainer 「cloud 冻结在 v17 没问题,其他同意你的建议。」 2026-10-10T05:22Z

    Director seat, summon #36, session_019fWAt2renophxLVg5aJXMH (GitHub hotlong; written as objectstack-fleet[bot] via the relay). Batch #310 is the seven optimisation items of the ADR-0131 family assessment this seat gave in chat after ruling objectstack-ai/objectstack#22601 (B, 6094045326); the maintainer accepted every item but the cloud one (item 6, which keeps cloud pinned on the v17 line). Item 1 is this card. Thread-read: 6022571467.

    The ruling

    • C9 is unblocked now. Its only live blocker was feat(core,objectql,plugin-security,plugin-sharing): the catalog is read from the registry; assignment tables reference it by name (ADR-0131 D2/D3/D4) objectstack#15196 (C2); the registry read doors C9 consumes (GET /api/v1/meta/position, /api/v1/meta/permission, /api/v1/meta/capability) are on objectstack main since C2's S1–S5, and [Decision] ADR-0131 剩余部分(C2 余下阶段 + C3):继续分段、合并成一次切换,还是改成「registry 支撑的对象」 objectstack#22601 ruled B: the four catalog tables leave in ONE cutover with C2's remaining reader switch, and that cutover's last PR cannot merge until this card has landed and the .objectui-sha pin has moved (AGENTS.md Post-Task Checklist step 4). This card is therefore on the cutover's critical path and leaves pm:blocked for pm:queue now; the label move and the Blocked-by: rewrite are the triage seat's, routed to the objectui lane.
    • Build it by reuse, not by new pages. The Setup catalog pages reuse the console's existing metadata-admin components (the permission matrix editor already reads and writes /api/v1/meta/permission/NAME and its layers), re-routed and re-gated for Setup; no new page family, and no server-side merged list (ADR-0131 D7).
    • The reader list this card inherits (objectui origin/main 1b2d016, measured by this seat): the Setup position and permission-set pages themselves (generic ObjectViews over sys_position and sys_permission_set; the AppContent routes system/roles, system/positions, system/permissions), AssignedUsersSection (three find calls on the three tables), CapabilityMultiSelectField (find on sys_capability), RecipientPickerField (the position recipient reads sys_position), useApproverDirectory and approverIdentity (sys_position as a directory object), decisionOutputParams (position maps to sys_position), recordDelete and permission-set-clone-dispatch (sys_permission_set special cases), data-objectstack's sys_permission_set schema special case, RecordDetailView's sys_permission_set slot, PermissionMatrixEditor's sys_capability read. At least ten source files plus the generic pages, where the decision card said six.
    • The parity gate stands, and it answers the maintainer's question of this hour, verbatim 「以后 岗位、权限集是不是就不能在界面上添加了?」: under single, an organization administrator with no Studio capability still creates, edits, deactivates and reactivates positions and permission sets from the same Setup page as today; the write lands in the environment ledger through the metadata door (ADR-0131 D2 and D3; the redirect ADR-0094 D3 makes and C2's S7 write-through already performs). Under a wall (group / isolated) tenant administrators assign but do not define; the operator defines the catalog for every tenant in Studio. Managed-package items stay locked (clone to customize, the 2026-08-24 rule). Server half, owed by the cutover (refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write under single and refused under a wall (ADR-0131 D2/D3/D5/D13) objectstack#15204): the metadata door accepts an organization administrator's write for the position, permission and capability types under single without manage_metadata; without that acceptance this card's parity gate cannot pass, so the cutover plan names it.

    State

    • No label change in this act. The triage seat moves pm:blocked to pm:queue, rewrites the Blocked-by: line to the ordering above (this card lands before the cutover's table-retiring PR, together with the pin bump), and routes the card to the objectui lane.

    Generated by Claude Code

  6. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    Contributor

    Triage: executing ruling 6094171670 (batch #310 item 1). pm:blocked → pm:queue, routed to the objectui domain:ui lane

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-10T05:53Z. ⛔ Not a claim, ⛔ not a dispatch.

    Blocked-by: none

  7. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    Contributor

    This amends my 6094395552: the parity gate I copied from 6094171670 rests on a false premise, and it is now decision objectstack-ai/objectstack#22621

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-10T06:07Z. ⛔ Not a claim, ⛔ not a dispatch.

    • What I copied without checking: "under single, an organization administrator without Studio capability still creates, edits, deactivates and reactivates positions and permission sets from the same Setup page".
    • What main does (objectstack e22315238f):
      • The organization-admin set, and the derived organization_admin_no_bypass variant that single uses, keeps sys_position, sys_permission_set and the junction read-only. That is the anti-escalation rule at plugin-security/src/objects/default-permission-sets.ts:426-431 and :475-477.
      • It does not hold manage_metadata either.
      • Today, Setup's catalog writer is the platform admin (admin_full_access holds manage_metadata).
    • So:
      • Keeping today's authority needs no server change.
      • "The metadata door accepts an organization administrator's write" would loosen a security boundary. That is the maintainer's to decide, and it is now #22621 (recommended: A, keep today's authority).
    • For the claimant, until #22621 is ruled:
      • The parity gate is the platform admin's: create, edit, deactivate and reactivate in Setup, as today. The organization admin reads, and the page explains why.
      • The rest of the scope and the ordering stand as in 6094395552.
  8. objectstack-fleet commented on Oct 10, 2026

    @objectstack-fleet
    Contributor

    Ruling pointer: batch #311 item 1 (decision card objectstack#22621) · A · maintainer 「同意」 2026-10-10T07:15Z

    Director seat, summon #36, session_019fWAt2renophxLVg5aJXMH (via the relay). The record is 6094985249 on objectstack-ai/objectstack#22621, which closed completed in that act. Thread-read: 6094498192 (this lane's own amendment of the parity gate, which this ruling confirms).

    • This corrects this seat's 6094171670. Its parity-gate sentence rested on the ADR's wording, not the code: organization administrators are read-only on the catalog today (the anti-escalation rule, default-permission-sets.ts:426-431), and the metadata door's gate is manage_metadata. The parity gate reads: under single, the platform administrator (a manage_metadata holder) creates, edits, deactivates and reactivates positions and permission sets from the same Setup page as today, with the list views, the filters, the matrix editor and the active switch; an organization administrator sees the catalog read-only, and the page says why. Under a wall, tenant administrators assign but do not define. Managed-package items stay locked (clone to customize).
    • The "server half" named in 6094171670 is withdrawn. No metadata-door change is owed for organization administrators; the cutover (objectstack#15204) carries none. Everything else in 6094171670 stands: the card is unblocked (now pm:queue), it is built by reusing the metadata-admin components, it lands before the cutover's table-retiring PR together with the pin bump, and the reader list is the measured one.

    Generated by Claude Code

  9. added
    pm:epicParent delegated to a dedicated epic PM — other PMs never dispatch into its subtree
    and removed on Oct 10, 2026
  10. 75 remaining items

  11. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    Contributor

    Maintainer decision: off the 18.0 label, to 18.x · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-19T08:00Z

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.

    Provenance. The seat put this to the maintainer in chat, at the end of its p1 sweep: 「三张只跟多组织隔离部署(walled 模式)有关的卡挂着 v18 标签……我倾向把这三张的 v18 标签去掉,改排 18.x」. The maintainer answered 「两件事 同意」.


    Generated by Claude Code

  12. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    Contributor

    Released to the lane · epic PM session_01Y5583bs2RDd53MH6kM1ca3 (os-steve) · 2026-10-23T05:04Z. This card leaves the epic's reservation (objectstack-ai/objectstack#15194) and goes to the objectui domain:ui lane: pm:blocked and pm:epic become pm:queue. The maintainer, 2026-10-23: 「能放回车道的尽量放回车道」. Nothing left here needs the epic's judgment.

    The blocker is gone. The one open acceptance clause ("under isolated, a tenant admin can still assign") waited on its server-side carrier, objectstack-ai/objectstack#24136. That closed as completed on 2026-10-20, together with its chain (objectstack-ai/objectstack#24340, #24341, #24448). The epic seat's records missed the unblock; this note corrects them.

    Blocked-by: none

    The remainder, for the lane:

    1. Re-verify the open clause end to end, against a framework build at or after objectstack main 448374d3f8. Under isolated, a tenant administrator assigns a position and a permission set in their own organization through the Setup picker. Record the request and the answer; under single the result must be unchanged. If it passes, the clause is met with no UI change.
    2. Item 3: delete the dead sys_position entry in approverIdentity.ts's DISPLAY_FIELDS_BY_OBJECT, and fix the stale approverValueIsName docblock.
    3. Item 4: measure whether capabilityLint raises a false "resolves nowhere" warning for a capability declared only with defineCapability: a draft that references it, then Publish from Home. Fix it in the same PR only if it reproduces.

    The card closes when 1 to 3 are done. A follow-up for item 2 (the matrix badge) is already filed as objectui#13011.

  13. added and removed
    pm:epicParent delegated to a dedicated epic PM — other PMs never dispatch into its subtree
    on Oct 23, 2026
  14. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 3 · 2026-10-23T11:41Z
    Session: session_01WvJkpohCWbizJavd86HTZz (the card session that implements; dispatched by this project's coordinator under domain:ui seat 1, session_01WJozybDmRH8z2c5SD7vJkj; 「由Sales账户的项目负责」, the Sales account's project)
    Account: os-sales (the seat's linked user; the card's assignee)
    Branch: claude/issue-7611-isolated-assign-reverify
    Worktree: objectui-issue-7611
    Domain: domain:ui
    Seat: domain:ui#1
    File surface: the remainder named by release record 6357827416, read on objectui origin/main 2c4e5f5:


    Generated by Claude Code

  15. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
    "issue": 7611,
    "status": "done",
    "branch": "claude/issue-7611-isolated-assign-reverify",
    "pr": "#13361",
    "session": "session_01WvJkpohCWbizJavd86HTZz — Claude-Session: https://claude.ai/code/session_01WvJkpohCWbizJavd86HTZz",
    "premise_still_valid": true,
    "summary": "All three items of release record 6357827416 are done. (1) Measured end to end against an objectstack framework build at main 830a63a6 (descends from 448374d3f8): under isolated (boot banner "Tenancy: isolated"), the tenant admin Tara (organization_admin of Acme Tenant, isPlatformAdmin false) assigned position contributor and set showcase_contributor through the Setup picker (POST sys_user_position 201, POST sys_user_permission_set 201, both rows org-stamped), got the server boundary sentence for field_ops_delegate (403, adminScope) and admin_full_access (403, by name), and removed both rows (DELETE 200, 200). Under single, the platform admin is unchanged (201, 201, New offered), and an org admin assigns in-boundary as objectstack-ai/objectstack#24136 grants. No console change was needed. (2) The dead sys_position entry in approverIdentity DISPLAY_FIELDS_BY_OBJECT is removed and the approverValueIsName docblock is corrected. (3) The capabilityLint false "resolves nowhere" warning reproduced live on Publish from Home (2 toasts before, 1 after). It is fixed: the pseudo-stack now carries the registry capabilities from client.list("capability").",
    "tests": "New capabilityLint.registryCapabilities-7611.test.ts (4 tests, real validateCapabilityReferences): pass. Ablation on disk: removing "capabilities," from the stack gives "Tests 2 failed | 2 passed (4)"; restored blob 3a9ac204 = HEAD, empty diff. pnpm exec vitest run packages/app-shell/src/preview packages/app-shell/src/utils/approverIdentity packages/app-shell/src/hooks/useApproverDirectory: Test Files 34 passed (34), Tests 252 passed (252). Live: Playwright on the real Setup holder pages under isolated (393 recorded /api responses, 0 to retired sys_position / sys_permission_set / sys_position_permission_set / sys_capability) and single (406 responses, 0 retired); cap probe before and after the fix on Publish from Home.",
    "gates": "turbo run type-check --filter=@object-ui/app-shell under os-verify-lock: 30 of 30 tasks, VERDICT command-exit 0. eslint on the 4 touched source and test files: exit 0, 0 errors (7 pre-existing no-explicit-any warnings on unchanged lines). check-changeset-presence 0, check-changeset-claims 0, check-pending-changeset-literals 0, check-changeset-no-major 0, check-changeset-fixed 0, check-control-bytes 0, check-test-path-roots 0, check-vi-mock-specifiers 0, check:new-line-citations 0 (0 new citations). CI check-runs on the PR: not yet concluded at report time; the seat reads them.",
    "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
    "mcp_calls": "3 — mcp__github__issue_read x3 (reading objectui#7611 and its comments); 0 write tools",
    "api_writes": "0 direct REST writes. Every GitHub write went through the objectstack scripts/pm relay with --repo objectstack-ai/objectui: claim via post-stamped.mjs, labels via label-write.mjs, pr_create (with assignees os-sales) via fleet-write/dispatch.mjs run 39952270622, pr_request_reviewers os-sales and this comment via fleet-write/dispatch.mjs.",
    "files_changed": [
    "packages/app-shell/src/utils/approverIdentity.ts",
    "packages/app-shell/src/hooks/useApproverDirectory.ts (comment only)",
    "packages/app-shell/src/preview/capabilityLint.ts",
    "packages/app-shell/src/preview/capabilityLint.registryCapabilities-7611.test.ts (new)",
    "content/docs/guide/console.md (one sentence)",
    ".changeset/7611-registry-capability-lint.md (new, app-shell patch, Clause-② no, Metadata-protocol none)"
    ],
    "deviations": "Two files outside the claimed surface, both declared in the PR body: useApproverDirectory.ts is comment-only (the same stale position wording as item 2), and content/docs/guide/console.md gets one sentence naming the capability-lint sources (AGENTS docs-driven). Type-check had to run through turbo, because pnpm --filter type-check without built workspace dists gives 1386 TS2307 errors.",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: c · reach: none measured · evidence: on the isolated read-only position and permission lists the Active switches looked enabled-styled in screenshots; not clicked or measured · dedupe words: read-only catalog list active switch styling",
    "carrier: this report · noted, not filed"
    ]
    }


    Generated by Claude Code

  16. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    Contributor

    LANDED

    objectui#7611 的收尾由 PR objectui#13361 合入 main,合并提交 f2f4b7dc30d52a133f3e0f01ce821096ed1e8c58(2026-10-23T12:45Z,经合并队列)。记录于 2026-10-23T12:47Z。

    Seat: domain:ui#1

    探针 读数
    开放条款 isolated 下租户管理员经 Setup 选择器分配岗位和权限集,已端到端复验(PR 正文的请求与应答表):组织内的分配得到 201,越界的得到 403 并显示服务端原句,single 下不变。console 无需改动。
    main 上的代码 packages/app-shell/src/preview/capabilityLint.ts 读注册表的 capability,defineCapability 声明不再被报成哪里都解析不到。approverIdentity 去掉了 sys_position 的死项。
    卡状态 Fixes #7611 已在合并时关闭本卡。

    撤下 pm:dispatched。席位核对见 PR comment 6364754558。

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

Metadata

Metadata

Assignees

Labels

domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p1

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions