状态:已决策并关闭(2026-08-01,not_planned)。出现下述「翻转条件」时 reopen。
关闭不是搁置——正文是一份完整的决策记录:事实核实、不做的理由、若要做的最低门槛、以及绑定的产品立场。关闭的理由见「传感器」一节:原本打算靠发布门的 fire 频次当需求传感器,核实后该通路不存在 ,一个 open issue 对唯一剩下的信号(用户主动反馈)没有任何帮助,反而会被下一个 agent 误读成待办工作——正是 #4413 刚消灭的那种「声明与现实不符」。本 issue 从「设计提议」两次改写至此,历史见编辑记录。
决策
kind:'react' 页面上的 record:* 家族维持 #4413 的撤回状态(PR #4450 ,ebb209c)。不 引入 <RecordScope>(会取数的记录作用域组件),直到下述翻转条件成立。
背景事实(对 objectui a8ad6c0 / framework ebb209c 核实)
原语已存在且被复用两次,只是没有公开名字。 RecordContextProvider(objectui packages/react/src/context/RecordContext.tsx:167)是纯值 provider,自己不取数。挂载点两个:记录路由 RecordDetailView.tsx:2033,以及不是记录路由 的元数据编辑器预览 PagePreview.tsx:192(自己 fetch 样本 + objectSchema 再喂进 provider,注释原话 "The metadata editor has no record route" )。
react 页不是记录路由。 usePageAssignment 把记录路由解析到记录页;react 页拿不到 URL 里的 recordId,只能从自身状态(ListView 选中等)造出一个。这给"react 页蚕食记录页"设了机械上界——没有任何平台导航会带着记录 id 进入 react 页。
FLS 在服务端裁剪。 plugin-security/src/field-masker.ts 的 maskResults 在查询结果返回前剥掉不可读字段;objectui 渲染器里的 readableFields 过滤是体验层。所以"作者手写 JSX 面板"的损失是格式化 / i18n / 失效刷新等一致性 问题,不是安全问题。
四个撤回块里真正不可替代的只有 record:details (FLS 分区、内联编辑保存栏、OCC)。record:related_list ≤ <ListView filters>;record:highlights / record:path 手写成本低。这扇门实质上是为一个 block 开的。
为什么不做
传感器:核实结论是「没有」
原设想是把 react-block-needs-record-context 的 fire 频次当需求计数器。核实后该通路不存在 (framework ebb209c):
validate / lint / compile 三条命令都在本地调 validateReferenceIntegrity,findings 只走 console.log 或 --json(供本地 CI 消费),到此为止;
CLI 的全部出站请求与校验结果无关:auth-flows.ts 的设备登录流、plugin/publish.ts 的插件包发布、cloud/ 下只有 login/logout/whoami、environments/ 不传元数据;
名字最像的 packages/cli/src/utils/telemetry-datasource.ts 是 ADR-0057 §3.6 的客户侧 事务——把 telemetry/event/audit 类对象路由到第二个本地 SQLite 文件,防止平台生成的数据撑爆业务库,与回传无关;
commands/dev.ts:372 记着 CLI 已经不再 POST /api/v1/dev/metadata-events——方向是在减少回传。
所以唯一的需求信号是用户主动反馈 (issue / 支持渠道)。建这条遥测通路要碰产品定位(是否收集客户构建期数据)、隐私声明与 opt-out 机制,分量远超一个 record block,不应由本议题驱动——若将来因别的原因建了,本节即失效,届时可把 fire 频次纳入信号。
翻转条件(任一成立即 reopen 并重启设计)
用户反馈中出现指名 record:details 的真实需求——它是唯一不可替代块,也是首要触发条件;
或需求虽指向其他块、但频次高到 hint 里的替代写法(<ListView filters> / <ObjectForm mode="view"> / 手写 JSX)被反复投诉不够用。
record:path 单独出现的需求不触发 翻转:正确形状是不需要记录身份的 value-bound 展示块(<StageBar objectName field value>,picklist 选项+译名来自对象元数据、当前值来自作者已有标量),不是 prop-bound 记录块,更不是 RecordScope。
若翻转,最低门槛(不打折)
失效总线集成。 RecordDetailView.tsx:317/319/531 的 useDataInvalidation / notifyDataChanged 必须接上,否则页面上别处的 <ObjectForm onSuccess> 保存后 scope 数据不刷——"陈旧但看起来正确"比 kind:'react' 页面上 record:* 四个 block 全部失效——契约 publish 的 objectName/recordId 渲染器根本不读(#4340 后续) #4413 修掉的"渲染成空"更难发现 。取数不是成本,接总线才是。
prop 形状 lint 全套。 scope 内的 record 块不得携带 objectName/recordId(RecordRelatedList 子对象 objectName 除外),违者 error + hint;react-block-needs-record-context 从"一律拒绝"改为"不在 <RecordScope> 祖先链内才拒绝"(JSX 祖先链静态可查)。
只进 react scope,不进注册表。 它会是 buildComponentScope(react-page.tsx:64,从 getPublicConfigs() 推导)之外第一个手工成员——这是明确接受的偏离:做成公共 SDUI block 更糟(记录页上无意义,Studio 面板里徒增困惑)。
framework 侧连带:REACT_BLOCKS 重新收录 record 块(这次不带绑定 prop)、REACT_RECORD_BLOCK_ALTERNATIVES ledger 改写、SKILL.md 与 validating-metadata §10b 同步。
可以独立做的零暴露准备(不依赖翻转,objectui 内部事务)
把 RecordDetailView 与 PagePreview 各自的"取数 + 喂 provider"收敛成一个内部 core。两个消费者已在漂移(PagePreview 手写了第二套取数),提取是纯卫生改动、不发布任何契约,却让将来的 <RecordScope>(若翻转)从"新实现"降为"薄包装"。这一项与本决策无关,可随时单独进行。
与此决策绑定的产品立场
在翻转之前,平台的立场是:要完整的记录明细体验,去 type:'record' 页 ;react 页负责的是更大场景里的主从面板,父记录是普通 React state,用读自身 props 的块绑定。此立场已随 #4450 落到出厂产物里(skills/objectstack-ui/SKILL.md 的 react 档一节、content/docs/deployment/validating-metadata.mdx §10b、以及 lint 报错的 hint),不依赖本 issue 存续。
/cc objectstack-ai/objectui(零暴露准备项 + 若翻转的实现侧)
决策
kind:'react'页面上的record:*家族维持 #4413 的撤回状态(PR #4450,ebb209c)。不引入<RecordScope>(会取数的记录作用域组件),直到下述翻转条件成立。背景事实(对 objectui
a8ad6c0/ frameworkebb209c核实)RecordContextProvider(objectui packages/react/src/context/RecordContext.tsx:167)是纯值 provider,自己不取数。挂载点两个:记录路由RecordDetailView.tsx:2033,以及不是记录路由的元数据编辑器预览PagePreview.tsx:192(自己 fetch 样本 + objectSchema 再喂进 provider,注释原话 "The metadata editor has no record route")。usePageAssignment把记录路由解析到记录页;react 页拿不到 URL 里的 recordId,只能从自身状态(ListView 选中等)造出一个。这给"react 页蚕食记录页"设了机械上界——没有任何平台导航会带着记录 id 进入 react 页。plugin-security/src/field-masker.ts的maskResults在查询结果返回前剥掉不可读字段;objectui 渲染器里的readableFields过滤是体验层。所以"作者手写 JSX 面板"的损失是格式化 / i18n / 失效刷新等一致性问题,不是安全问题。record:details(FLS 分区、内联编辑保存栏、OCC)。record:related_list≤<ListView filters>;record:highlights/record:path手写成本低。这扇门实质上是为一个 block 开的。为什么不做
objectName/recordId必须消失(除了RecordRelatedList的子对象objectName),而 AI 的训练分布(Salesforce 惯例 + 我们自己的旧契约)都说"block 自带绑定",静默忽略就是在低一层复刻 kind:'react' 页面上 record:* 四个 block 全部失效——契约 publish 的 objectName/recordId 渲染器根本不读(#4340 后续) #4413。外加 lint 静态查不了的关系性错位(scope 声明的对象 ≠ recordId 状态实际来自的对象)。传感器:核实结论是「没有」
原设想是把
react-block-needs-record-context的 fire 频次当需求计数器。核实后该通路不存在(frameworkebb209c):validate/lint/compile三条命令都在本地调validateReferenceIntegrity,findings 只走console.log或--json(供本地 CI 消费),到此为止;auth-flows.ts的设备登录流、plugin/publish.ts的插件包发布、cloud/下只有 login/logout/whoami、environments/不传元数据;packages/cli/src/utils/telemetry-datasource.ts是 ADR-0057 §3.6 的客户侧事务——把 telemetry/event/audit 类对象路由到第二个本地 SQLite 文件,防止平台生成的数据撑爆业务库,与回传无关;commands/dev.ts:372记着 CLI 已经不再 POST/api/v1/dev/metadata-events——方向是在减少回传。所以唯一的需求信号是用户主动反馈(issue / 支持渠道)。建这条遥测通路要碰产品定位(是否收集客户构建期数据)、隐私声明与 opt-out 机制,分量远超一个 record block,不应由本议题驱动——若将来因别的原因建了,本节即失效,届时可把 fire 频次纳入信号。
翻转条件(任一成立即 reopen 并重启设计)
record:details的真实需求——它是唯一不可替代块,也是首要触发条件;<ListView filters>/<ObjectForm mode="view">/ 手写 JSX)被反复投诉不够用。record:path单独出现的需求不触发翻转:正确形状是不需要记录身份的 value-bound 展示块(<StageBar objectName field value>,picklist 选项+译名来自对象元数据、当前值来自作者已有标量),不是 prop-bound 记录块,更不是 RecordScope。若翻转,最低门槛(不打折)
RecordDetailView.tsx:317/319/531的useDataInvalidation/notifyDataChanged必须接上,否则页面上别处的<ObjectForm onSuccess>保存后 scope 数据不刷——"陈旧但看起来正确"比 kind:'react' 页面上 record:* 四个 block 全部失效——契约 publish 的 objectName/recordId 渲染器根本不读(#4340 后续) #4413 修掉的"渲染成空"更难发现。取数不是成本,接总线才是。objectName/recordId(RecordRelatedList子对象objectName除外),违者 error + hint;react-block-needs-record-context从"一律拒绝"改为"不在<RecordScope>祖先链内才拒绝"(JSX 祖先链静态可查)。buildComponentScope(react-page.tsx:64,从getPublicConfigs()推导)之外第一个手工成员——这是明确接受的偏离:做成公共 SDUI block 更糟(记录页上无意义,Studio 面板里徒增困惑)。REACT_BLOCKS重新收录 record 块(这次不带绑定 prop)、REACT_RECORD_BLOCK_ALTERNATIVESledger 改写、SKILL.md 与 validating-metadata §10b 同步。可以独立做的零暴露准备(不依赖翻转,objectui 内部事务)
把
RecordDetailView与PagePreview各自的"取数 + 喂 provider"收敛成一个内部 core。两个消费者已在漂移(PagePreview 手写了第二套取数),提取是纯卫生改动、不发布任何契约,却让将来的<RecordScope>(若翻转)从"新实现"降为"薄包装"。这一项与本决策无关,可随时单独进行。与此决策绑定的产品立场
在翻转之前,平台的立场是:要完整的记录明细体验,去
type:'record'页;react 页负责的是更大场景里的主从面板,父记录是普通 React state,用读自身 props 的块绑定。此立场已随 #4450 落到出厂产物里(skills/objectstack-ui/SKILL.md的 react 档一节、content/docs/deployment/validating-metadata.mdx§10b、以及 lint 报错的 hint),不依赖本 issue 存续。/cc
objectstack-ai/objectui(零暴露准备项 + 若翻转的实现侧)