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 |
CONTROL — package_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
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.
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
- 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.
- 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?
- 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
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#2execution 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/mainand the published spec tags, read 2026-09-19T10:13Z:completed; refusal livecompletedOS_METADATA_WRITABLEdoor probe)completedNOT_OVERRIDABLEin@objectstack/spec@17.4.0packages/spec/src@objectstack/spec@17.3.0package_id, same corpus and query formmanaged_byin@objectstack/spec@17.4.0packages/spec/src⇒ 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 objectuiresolves. ⛔ 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 onmanaged_by === 'package':⇒
package_idis carried only as context on the refusal, and it is explicitly nullable —:3753records a publish that 「carried no owning package_id to stamp」. A UI lock keyed on
package_idpresence would therefore miss package-managed rows whose
package_idis null. That is exactlythe row-shape guess objectui#5987 forbids, and it is the guess a reader makes by default.
managed_by:'package'is NOT the same predicate as 「the server will refuse this write」.security-plugin.ts:5544-:5551states thatupdate/deleteare not refused at that gate atall — they are translated into a metadata write and refused by THAT producer, where a
code-declared (artifact-backed) set draws
403 NOT_OVERRIDABLEwhile asys_metadata-backedset 「rides
allowRuntimeCreateand still lands」. ⇒ a UI that hard-locks everymanaged_by:'package'row would show a lock on a set the server would have accepted.managed_byis not universally the key.permission-set-overlay-discard.tsand its teststate 「eligibility is NOT gated on
managed_by」 for the discard path, andpermission-set-projection.tsexists specifically to control which columns a reader sees.⇒ The reading requested — three questions, all producer-side
sys_permission_set's projection servemanaged_by(andpackage_id, andcustomized) to a non-system caller through the ordinarydata door, or does it strip them?
permission-set-projection.test.ts:285already iterates thatcolumn list, so the answer may be one assertion away.
managed_by === 'package'alone, or thatplus the artifact-backed vs
sys_metadata-backed distinction that decides whether the write isactually refused?
NOT_OVERRIDABLE(or thePermissionDeniedErrortext) in a shape objectui can key on, so item 3 of the UI card — 「theserver'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:blockedwithBlocked-by:naming this card. It isthe 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 readingGenerated by Claude Code