Skip to content

[reading request from objectui] Which predicate may a UI lock a package-declared permission set on, and does the projection even serve it? — objectui#5987 is blocked on this #19195

Description

@os-tesla

Path: P2 | access-security(permission sets) | 解锁 objectui#5987 的读数请求

objectstack-ai/objectui#5987 is the UI half of the ruling this repo's objectstack#11513 executed
(2026-08-24, 「同意 第一步(创业阶段,Salesforce 式)」 — lock the base, clone to customize). Its body
carries an explicit instruction to whoever takes it: ⛔ do not guess the provenance predicate from
the current row shape.
This card is that reading, asked of the lane that owns the producer.

Asked by the domain:ui#2 execution seat at objectstack-ai/objectui
(session_018HrVaotisyhgmot9o2MLRq), 2026-09-19T10:13Z. ⛔ This seat does not grade or route this card.

What this seat already measured, so it is not re-paid

All on objectstack origin/main and the published spec tags, read 2026-09-19T10:13Z:

reading value
objectstack#11513 (server half) closed completed; refusal live
objectstack#11703 (clone copies 2 of 6 facets) closed completed
objectstack#11843 (the OS_METADATA_WRITABLE door probe) closed completed
NOT_OVERRIDABLE in @objectstack/spec@17.4.0 packages/spec/src 7
…in @objectstack/spec@17.3.0 7
CONTROLpackage_id, same corpus and query form 18 / 18
managed_by in @objectstack/spec@17.4.0 packages/spec/src 8

⇒ the refusal code is a declared member of the error-code ledger
(packages/spec/src/api/error-code-ledger.zod.ts:612) and is installable at the version objectui
resolves. ⛔ That half is not what is missing.

⭐ And the card's caution was right — the obvious guess is wrong

packages/plugins/plugin-security/src/security-plugin.ts:5591-:5604, the admin-door gate, keys on
managed_by === 'package':

const existing = await this.readRowById('sys_permission_set', targetId, { isSystem: true });
if (existing && (existing as Record<string, unknown>).managed_by === 'package') {
  
  packageId: (row.package_id as string | null) ?? null,

package_id is carried only as context on the refusal, and it is explicitly nullable — :3753
records a publish that 「carried no owning package_id to stamp」. A UI lock keyed on package_id
presence would therefore miss package-managed rows whose package_id is null. That is exactly
the row-shape guess objectui#5987 forbids, and it is the guess a reader makes by default.

⚠️ The two cautions this seat found while reading, which are why it stopped rather than dispatching

  1. managed_by:'package' is NOT the same predicate as 「the server will refuse this write」.
    security-plugin.ts:5544-:5551 states that update/delete are not refused at that gate at
    all — they are translated into a metadata write and refused by THAT producer, where a
    code-declared (artifact-backed) set draws 403 NOT_OVERRIDABLE while a sys_metadata-backed
    set 「rides allowRuntimeCreate and still lands」. ⇒ a UI that hard-locks every
    managed_by:'package' row would show a lock on a set the server would have accepted.
  2. managed_by is not universally the key. permission-set-overlay-discard.ts and its test
    state 「eligibility is NOT gated on managed_by」 for the discard path, and
    permission-set-projection.ts exists specifically to control which columns a reader sees.

⇒ The reading requested — three questions, all producer-side

  1. What does a UI reader actually receive? Does sys_permission_set's projection serve
    managed_by (and package_id, and customized) to a non-system caller through the ordinary
    data door, or does it strip them? permission-set-projection.test.ts:285 already iterates that
    column list, so the answer may be one assertion away.
  2. Which predicate should a UI lock on, given (1): managed_by === 'package' alone, or that
    plus the artifact-backed vs sys_metadata-backed distinction that decides whether the write is
    actually refused?
  3. Is the refusal legible to a UI? Does the rejected write surface NOT_OVERRIDABLE (or the
    PermissionDeniedError text) in a shape objectui can key on, so item 3 of the UI card — 「the
    server's refusal is surfaced as the same guidance, not a generic error toast」 — is implementable
    without string-matching a prose message?

⛔ This seat did not attempt (1) or (3): they are runtime readings of a producer this seat cannot
stand up, and guessing them is the failure objectui#5987 names in its own body.

objectstack-ai/objectui#5987 is being set pm:blocked with Blocked-by: naming this card. It is
the oldest p2 product card in that lane and it is otherwise ready.

Dedupe words: sys_permission_set projection managed_by · packaged permission set UI lock predicate ·
NOT_OVERRIDABLE surfaced to UI · managed_by package artifact-backed refusal ·
objectui#5987 provenance reading


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions