You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
A page cannot declare its related lists read-only — "+ New" / row edit / row delete are host-resolved from the CHILD object, so a deliberately read-only record page still offers writes #7300
Measured on objectui at the current checkout, against a live seeded app: a read-only "member detail" record page (objectstack-ai/duly#13) rendered 8 "+ New" buttons it had no way to decline.
The gap
PageComponentSchema has no readonly / disabled, and that is a deliberate boundary — ruled 2026-08-12, "editability lives on fields", with EDITABILITY_BOUNDARY_KEYS redirecting an author who writes one. The prescription is right for a field.
It does not reach a related list's CRUD affordances, because those are not fields. RelatedRecordActionsBridge resolves them from the child object:
— the child's userActions bucket, intersected with API operations and the principal's grant. Nothing on the page participates. RecordRelatedListProps can decline the opt-in Add-existing picker (add) and row actions, but "+ New", row edit and row delete arrive from the host regardless.
So for a child object that any user may create — here duly_task, where every position holds allowCreate because people do create their own tasks elsewhere in the app — a page whose entire premise is "the manager enters nothing" is handed a create affordance on every task list on it.
The only lever available is object-level (duly_task.userActions.create), which would close creation everywhere — including the screens where it is correct. That is not a workaround, it is a different and wrong change.
Why it is worth a key rather than a doc note
The affordance is not merely cosmetic on a page like this: a manager pressing "+ New" on someone else's task list creates work for that person from a screen documented as read-only, and the write is legal server-side. The page is the only layer that knows this surface is a read surface — the child object is used correctly elsewhere, and the principal's grant is correct too.
Suggested shape
A per-component switch on record:related_list — readonly: true, or affordances: 'none' — consumed where the bridge's handlers are wired in RecordRelatedListBody, narrowing only (never re-opening something the bucket/API/grant already closed, matching the posture createPredicates already takes). A page-level readonly: true that defaults every component would be even better for this use case, but the per-component key is the smaller change and composes.
Related but distinct, both closed: #4646 (related-list "+ New" not consuming userActions.create predicates) and #5153 (the object-list toolbar's half). Those made the object's verdict reach the button. This is about the page having no verdict to give.
Activity
os-zhuang commentedon Sep 5, 2026
分诊 —
domain:ui/priority:p2/pm:blocked/enhancement锚定 (anchoring):消费点在
packages/app-shell(bridge +RecordRelatedListBody)⇒domain:ui。但新键本身写不进本仓 ——packages/types/src/record-components.ts:94的 docblock 明写 "Aligned with @objectstack/specRecordRelatedListProps",packages/types/src/index.ts:1288再导出SpecRecordRelatedListProps。授权面在上游。在
origin/maina472b07上复核的锚点 —— 逐字成立:350-351与卡片引的两行一字不差。三个输入 —— 子对象的userActions桶、API operations、principal 的 grant —— 页面一个都不参与,这是从:350的实参就能读出来的,不需要推断。RecordRelatedListProps的完整已声明键(读packages/types/src/record-components.ts:94起的声明体):objectName/relationshipField/columns/sort/limit/filter/title/showViewAll/actions/add/aria。没有readonly,没有disabled,没有affordances。 正控制:同文件:71-79确实有一个readonly,但那是record:highlights的 chip 级 inline-edit 开关,不是本卡要的东西 —— 这正好印证卡片的论点:"editability lives on fields" 的处方对字段是对的,但够不到 related list 的 CRUD affordance,因为那些不是字段。EDITABILITY_BOUNDARY_KEYS在本仓git grep0 命中(全仓,不限目录)。它是 spec 侧的东西。所以"2026-08-12 那条裁决 + 重定向机制"我只能采信卡片,没有本仓证据。这一点对定级不影响(缺陷本身在本仓可验),但对谁来裁很关键。为什么是
pm:blocked卡片给的形状(
record:related_list上的readonly: true/affordances: 'none')是一个新的公开可授权键,而PageComponentSchema/RecordRelatedListProps都在上游。更要紧的是:这条边界是被明确裁决过的("editability lives on fields"),本卡实质上是在主张"那条裁决没覆盖到 related list 的 CRUD affordance"。⛔ 这不是 objectui 席能单方面推翻的。objectstack-ai/objectstack未找到对应 issue 的读数。接手第一步是去上游开裁决卡,不是在本仓动手。Restart-when(可执行探针) —— ⛔ 判据是装得上,不是"上游 PR 合了":
定级理由
priority:p2:duly_task.userActions.create会到处关掉创建,包括那些本该开着的屏幕 —— 那不是绕法,是另一个(错误的)改动。不上 p1:没有权限越界(服务端仍按 grant 判定),没有数据损坏,是"提供了不该提供的入口"而非"绕过了应有的检查"。
⛔ 定型与边界
新增授权键 = 加宽公共可授权面 ⇒ Feature ⇒ 踩 manual floor;⊕ 落在协议/契约(spec 的组件 props)⇒ 双重。⛔ 分诊席不裁决、不派单。
给接手者三条硬要求:
:358的createPredicates,照它对齐。readonly。 卡片自己排了序:"per-component key is the smaller change and composes"。页面级默认值是更大的裁决(它会影响每一个组件类型),⛔ 不要夹带;真要,另起。给分诊席自己的记录
本轮已出现第三张"objectui 侧诊断完整、但解锁动作在上游且上游无卡"的卡片(#6947、#7297、本卡)。这不是三次巧合,是一个缺失的例行动作。⛔ 本席不代开上游卡(那属于 objectstack 的 intake),但会在本轮收尾简报里点名,交由席位主帖处理。
Generated by Claude Code
objectstack-fleet commentedon Sep 24, 2026
分诊 — 维护者裁决:不做 · 按 not planned 关闭
分诊席 #6015,2026-09-24T18:05Z。
维护者裁决(原文)
分诊席今天把本卡作为待决事项③提给维护者:
record:related_list能不能声明「只读」?RecordRelatedListProps上新增一个键。本席建议做。维护者答复原文:
⇒ 本卡不做,按
not_planned关闭。关闭后的现状(照实记录)
RelatedRecordActionsBridge里的resolveEffectiveCrudAffordances。页面层没有开关。什么情况下重开
维护者改变主意时,由维护者重开。重开后先在 objectstack 开上游 spec 卡(
RecordRelatedListProps新键),本卡挂Blocked-by:。Generated by Claude Code
test(plugin-form): pin object-master-detail-form dataSource, details …