Skip to content

[Decision] 用户页「分配岗位」「授予权限集」两个选择器改读注册表:加规范字段(A/A')、去掉用户页入口(B1),还是给授权的名称字段配注册表选择控件(B2) #22865

Closed

Description

@objectstack-fleet

Ruled: 6115690641 · letter B2 (Q3b B) · 2026-10-12T00:38Z

Filing gate ②:只有维护者能做的决定(产品取舍:用户页上「先打开用户,再给他分配」这个入口留不留、怎么留)。立卡:epic PM session_01Rerax7QTjKMPCUZxQUtPFR(marchtian),席位 epic:#15194。

锚点: 自然锚点是 objectstack-ai/objectui#7611(C9),但它的第二部分正在开发中,不能挂 needs-user-decision 退出活动队列,所以单开本卡。

查重: 两个仓库所有带 needs-user-decision 的卡(含已关),标题搜 picker / 选择器 / registry / spec 18,命中 0。测量报告另查了开着的 PR、分支名和卡,也没有在做这件事的。

动手的读者: 裁后由本席派 objectui#7611 的第三部分落实。它落地后,objectstack#15204 的 6b-2 才能合入、阶段 8 才能落地。

维护者速读

Setup 用户详情页上有两个「添加」按钮:分配岗位、授予权限集。按 ADR-0131,岗位和权限集只有一个来源,就是注册表;它们的数据库行在阶段 8 退役。这两个按钮弹出的选择框却还在读数据库行。

  • 已经出现的空窗: 在 main(未发版)上新建一个库,「分配岗位」选择框一个声明的岗位都列不出来。实测 0 条,注册表里有 16 个。
  • 即将出现的空窗: 6b-2 落地后,「授予权限集」也会变成这样。
  • 为什么卡住: 两个空窗都被发版条件 (c) 挡在所有版本之外,但阶段 8 必须等这两个选择框先改好才能落地。
  • 不受影响的部分: 按名称写入已经通了。实测在没有数据行的情况下,按岗位名分配返回 201;坑只在「列出可选项」这一步。

四条路:

  • A 规范加字段: 给相关列表的「添加」选择框加一个「从注册表选」的规范字段。objectui 只能从已发布的规范拿到新字段,所以要先发 v18 预发布版,而发版条件 (c) 又挡着发版,形成循环。
  • A' 同 A,但 objectui 先用、规范后发: 不用发版。但违反 objectui 的规则(「不许自造规范里没有的字段」),找不到允许的先例。
  • B1 去掉用户页的两个「添加」: 改为在岗位或权限集的目录页里分配持有人(C9 第一部分已经做好)。1 个 PR,约 100 行。代价是「先打开用户、再给他分配」这个用法没了。
  • B2 给授权记录的名称字段配一个「从注册表选」的控件: 用现有的 widget 字段,和今天已合入的 objectstack#22794 / objectui#12136 同一做法。用户页的「新建」表单里就能从注册表选岗位或权限集。2 个 PR(objectui 约 450 行,objectstack 约 400 行),不改规范、不用发版。

本席推荐 B2(测量开发也推荐 B2),回退 B1。选 A、A'、B1 还是 B2?

背景(实测:objectstack origin/main 55382dc02a,objectui origin/main 158c75d908;测量报告 objectui#7611 6111055760)

  • 选择框读的是数据行: sys-user.page.ts 两个 add.picker.object 分别是 sys_position、sys_permission_set。规范 RecordRelatedListProps.add.picker 只认 object 一种来源。
  • 新库实测(showcase,--fresh,管理员令牌):
    • GET /api/v1/data/sys_position 返回 0 行,GET /api/v1/meta/position 返回 16 项;
    • GET /api/v1/data/sys_permission_set 返回 17 行,与注册表 17 项同名。这一侧今天还对得上,6b-2 删除种子程序后就对不上了(阶段 8 测量 6110720794 的 E2)。
  • 按名称写入已就绪: POST /api/v1/data/sys_user_position,contributor(没有数据行)返回 201;everyone 返回 403;不存在的名字返回 400。
  • objectui 已有同类控件: RecipientPickerField 已能从注册表列出岗位、按名称保存。ObjectRefField 对对象做同样的事。今天合入的 ref-multi:permission 只用于元数据表单,记录页用不上。
  • 用这个入口的地方: 全仓手写的 add 选择框共 5 处,其中 3 处指向目录对象:sys-user.page.ts 两处,sys-position.page.ts 一处(该页在阶段 8 退役)。示例应用 0 处,objectui 源码 0 处。
  • 发版事实:
    • npm 上 @objectstack/spec 只有 latest: 17.7.0 和 rc: 17.0.0-rc.6,没有 18.x;
    • .changeset/pre.json 是 pre 模式、next 标签;
    • objectstack 发版时自带的控制台用本仓规范构建(scripts/build-console.sh 注入 OBJECTSTACK_SPEC_DIST),但 objectui 自己的源码、类型和测试只认已发布的规范。

Governing text

  • ADR-0131 D7(docs/adr/0131-…md:510-511):「Pickers (assign a user to a position, choose a recipient) list the registry. Catalogs are tens of items; nothing about them needs a server-side merge.」同节:「no surface merges sources」。
  • ADR-0131 D4(:356):「a picker lists the registry, an assignment names one of its entries.」
  • objectui#7611 正文: 「Pickers list the registry. There is no merged two-source list.」
  • [Decision] ADR-0131 剩余部分(C2 余下阶段 + C3):继续分段、合并成一次切换,还是改成「registry 支撑的对象」 #22601 → B: 不做过渡件。所以不能把数据行留着专门喂选择框。
  • objectstack AGENTS.md Prime Directive Add missing Field.phone() helper and factory methods for Action/Dashboard/Report #15: 「A version release is performed by the maintainer, by hand — no AI seat publishes, tags, cuts a Release, or triggers a release workflow」。
  • objectui AGENTS.md #0 / #0.1: 「All schemas/JSON structures/types MUST follow @objectstack/spec. Don't invent schema properties」,以及「declare it on the node type that reads it, by reference to the spec row」。
  • FieldSchema.widget(packages/spec/src/data/field.zod.ts:1942):「Form widget override — names a registered field component … Degrades to the type renderer when unregistered.」
  • 发版条件 (c)(6102862135,后续状态见 6110521846):C9 加阶段 7,再加 objectui 的 spec-18 pin。

前提(每条带复核命令)

  • 两个选择框读数据行:git grep -n "object: 'sys_position'\|object: 'sys_permission_set'" origin/main -- packages/platform-objects/src/pages/sys-user.page.ts,应各命中一次。
  • main 上没有任何代码写 sys_position 行:git grep -nE "(insert|create|upsert)\w*\(\s*['\"]sys_position['\"]" origin/main -- 'packages/**/*.ts' 'examples/**/*.ts' | grep -v test,应 0 命中。
  • widget 是自由字符串:git grep -n "widget: z.string().optional()" origin/main -- packages/spec/src/data/field.zod.ts,应命中 1 次。
  • 没有 v18 规范:npm view @objectstack/spec dist-tags,应只有 latest、rc。

选项 × 真实代价

选项 做什么 客户能感知的后果 工作量
A 规范加字段 add.picker 增加一个注册表来源(类型限定为元数据类型枚举);objectui 的相关列表据此从注册表列出;用户页两处改用它 用户页「添加」照旧,列的是注册表 4 个 PR(规范约 200 行、objectui pin 18 约 100 行、渲染约 400 行、objectstack 改页面约 400 行),外加一次 v18 预发布(你手动);Clause-②: yes(放宽);在发版条件 (c) 下是死循环
A' 先用后发 同 A,但 objectui 在已装规范还是 17 时先手写这个字段 同 A 3 个 PR,不用发版;违反 objectui 规则 #0/#0.1,在 pin 移动前 objectui 自己的严格校验和手写类型会打架
B1 去掉用户页入口 删掉用户页两个「添加」;分配改在目录页做(C9 第一部分已有持有人分配);Setup 导航指向目录页 用户页只能看、不能直接加;要先打开岗位或权限集再加人 1 个 objectstack PR,约 100–125 行;Clause-②: no
B2 名称字段配注册表控件 objectui 新增一个字段控件,从注册表列出一种类型、存名称;objectstack 在两张授权表的名称字段上声明它,并删掉用户页的两个 add 用户页点「新建」,表单里从注册表选;授权数据页的新建表单也同样能选 2 个 PR(objectui 约 450 行,objectstack 约 400 行,含 pin 移动),不改规范、不用发版;objectstack Clause-②: no

(排除项:给 objectui 写死「这两个对象名改读注册表」违反 objectui #0.1;让数据门把注册表伪装成对象违反 D3/D7;保留数据行喂选择框是过渡件,违反 #22601 → B。)

业务含义直译

  • A: 平台多了一种通用能力,以后任何页面的「添加」都能从注册表选。代价是先要发一个 v18 预发布版。
  • B1: 像很多后台那样,「谁有这个角色」只在角色页上管理。
  • B2: 像下拉框选角色:在用户页点「新建」,在表单里从下拉框选岗位或权限集。

四轴(从业务看)

  • 项目长远合理性(领起,权重 ≥50%):
  • 实际业务拉动: 用户页这两个入口是 Setup 管理员日常给人授权的路径,是真实场景;示例应用和 objectui 里没有别的使用者。A 的通用能力目前只有这 2 处需要。
  • 防 AI 犯错(出错时谁看到什么):
    • A 最好,类型是枚举,写错会在发布时被拒。
    • B2 的 widget 写错会静默退化成文本框,但服务端对不存在的名字一律返回 400,所以写不进错行。
    • B1 没有新东西可写错。
    • 这一轴上 A 胜,与其他三轴冲突,取舍交你。
  • 创业阶段不扩散: B1 最小,B2 次之(一个新控件),A 最大(规范新面加一次发版)。

os-decision-facets

  • ① 项目长远合理性:B2 复用已合入的做法,不新增规范、保留 D7 点名的选择器;A 最声明式,但为 2 处使用新增规范面并且要先解发版循环;B1 拿掉了选择器。
  • ② 实际业务拉动:用户页分配是真实日常路径;通用「从注册表添加」除这 2 处外无其他使用者。
  • ③ 防 AI 犯错:A 最强(枚举,发布时拒);B2 写错控件名静默退化,但服务端 400 兜底,写不进错行;B1 无新增可错之处。
  • ④ 创业阶段不扩散:B1 < B2 < A。

Prior rulings read: picker, registry, widget, release cut, spec-18 in docs/adr/ and on the thread → ADR-0131 D4/D7; #22601 → B; release-cut condition (c) of 6102862135 and 6104671088 (F1 added the spec-18 pin); seat answer 6110777865 (E2); objectstack#22794 / objectui#12136 (the widget precedent).

推荐

推荐 B2,回退 B1。

  • 只看①选 B2;②③④不翻转(③上 A 更强,但 B2 有服务端 400 兜底)。
  • 置信缺口: 未在浏览器里实测两点。一是这两张授权表的用户页相关列表是否提供「新建」;二是去掉 add 后,行上的「移除」是否还在(今天的通用移除依赖 add)。B2 和 B1 都受影响。派发时开发先实测;如果「移除」没了,作为第一件事报回,不自行加功能。
  • 如果你想把「从注册表添加」做成平台通用能力,选 A,但要同时决定 v18 预发布的时机。

附带问题 Q2(不需要你现在答): 发版条件 (c) 里「objectui 的 spec-18 pin」这半句,照字面会自己卡死自己:objectui 要 pin 18,得先发 18,而 (c) 不许发。它的起因 F1(岗位页误报「不符合规范」)是在 objectui 自己的控制台(npm 规范 17.7.0)上测的,而 objectstack 发版用的控制台注入的是本仓规范。本席先派人在注入后的控制台上实测 F1:

  • 不复现:本席提议把这半句从 (c) 中划掉,报你确认;
  • 复现:要不要提前发一个 18.0.0-next.0 预发布版,是你的发版决定,届时单独报你。

B1 和 B2 都不依赖 Q2。

裁后执行

  • 裁 B2:
    1. objectui PR:注册表字段控件。
    2. objectstack PR:移动 .objectui-sha,在两张授权表的名称字段上声明控件,删掉用户页两处 add。若 objectstack#22863 尚未合入,等它合入再落。
    3. 两个 PR 都可以在 6b-2 之前落地,之后 6b-2 合入、阶段 8 落地不再等选择器。
  • 裁 B1: 1 个 objectstack PR(删两处 add,Setup 导航改指目录页),在 6b-2 之前落地。
  • 裁 A: 先派规范 PR,同时报你 v18 预发布。在你发版之前,6b-2 可以带着空窗合入((c) 挡在所有版本外),阶段 8 等发版。
  • 裁 A': 3 个 PR,需要你同时批准 objectui 规则 #0/#0.1 的例外。
  • 不论裁哪一项,你只需回一个字母。附加条件随执行落地。

Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    补充子问题 Q3b(与本卡同一类:objectui 读取它已装规范里还没有的字段)· epic PM session_01Rerax7QTjKMPCUZxQUtPFR · 2026-10-11T16:49Z

    C9 盘点(objectui#7611 6111307114)又查到一处同类问题,按「一次裁清」并入本卡。你可以一起回,例如「B2,Q3b-B」;只回一个字母,就按本席推荐处理 Q3b。

    问题: 审批流里「审批人是某个岗位」的显示和编辑。

    • 规范在 objectstack main 上已改为按名称、从注册表取岗位(objectstack#22710 已合入);objectui 已装的规范 17.7.0 里还是「读 sys_position 数据行」。
    • objectstack 发版用的控制台注入的是本仓规范。所以今天在这个控制台上,待审批的岗位审批人会显示成截断的机器名,流程设计器里「岗位」一栏只能手打文字。这是从代码读出的,未在浏览器实测。

    选项:

    • A 等 objectui 升级到规范 18 再做: 不写代码,但缺陷一直留到 v18 发布,而发布又被发版条件 (c) 挡着。
    • B 结构化地读注册表绑定(推荐): objectui 的读取端按服务端实际发布的 { source: 'registry', type } 从注册表列出岗位,只存名字。只改读取,不改任何编写面,所以 objectui validate 和严格校验都不变;规范升到 18 之后再去掉放宽的类型。1 个 PR,约 0.4–0.5k 行。
    • C 手写一张「岗位走注册表」的对照表: 最小,但成了规范之外的第二份来源,会和规范漂移,对接 v17 服务端时也不对。

    四轴:

    • B 修掉了今天主干控制台上的缺陷,读的正是服务端发布的契约,不造字段。
    • 防 AI 犯错: B 用选择框取代手打文字,也没有别名。
    • 不扩散: 1 个 PR,不改规范、不发版。
    • 和 A' 的区别: A' 是在编写面上新增字段,objectui 自己的严格校验会和它打架;B 只读不写。

    本席推荐 B。

    同类、不需要你裁的一项(3a:审批时「决策输出」里的岗位选择)已经派出。


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 11, 2026

    @objectstack-fleet
    ContributorAuthor

    决裁详解(按决裁格式六项重写,取代正文的推荐段与工作量列)· epic PM session_01Rerax7QTjKMPCUZxQUtPFR · 2026-10-11T17:09Z

    呈报前重跑的检索:

    主问题

    一句话问题。 Setup 用户页上「分配岗位」「授予权限集」两个选择框,列的是即将删除的数据行,而不是岗位和权限集真正所在的注册表。

    • 新建的库上,「分配岗位」今天已经一个声明的岗位都列不出来(实测 0/16)。
    • 6b-2 之后,「授予权限集」也会变成这样。
    • 阶段 8 删掉这两类数据行之前,两个选择框必须改成读注册表。

    选项 × 真实代价 × 工作量:

    选项 做什么 客户能感知的后果 工作量(车道 · PR 数 · 实测先例)
    A 规范加注册表来源 相关列表「添加」的选择框,在规范里加一个「从注册表选」的来源,沿用审批人已有的 record/registry 写法;objectui 渲染;用户页两处改用它 用户页照旧点「添加」,弹窗列出注册表 spec 车道 + objectui + objectstack · 4 个 PR + 1 次发版。先例:规范改动 #22710(6 文件 +188/−59);控制台 pin 移动 #22794(23 文件 +372/−84);objectui 渲染端与 objectui 升到规范 18 均无先例。发版需你手动发 v18 预发布(无先例),并且要先裁「next 预发布算不算 (c) 所说的发版」
    A' 同 A,objectui 先用后发 同 A,不发版 同 A 3 个 PR,无先例;需你批准 objectui 规则 #0/#0.1 的例外
    B1 去掉用户页入口 删掉用户页两处「添加」;改在岗位或权限集目录页分配持有人(C9 第一部分已建好);Setup 导航改指目录页 用户页只能看授权,不能直接加;要去岗位或权限集页面加人 objectstack 1 个 PR · 无先例。实测:sys-user.page.ts:206、:254 两个 add 块各约 15 行,导航项约 25 行(阶段 8 测量),合计约 100–125 行
    B2 名称字段配注册表选择控件 objectui 新增一个字段控件,从注册表列出一种类型、只存名称;objectstack 在两张授权表的名称字段上声明它,删掉两处 add,改走「新建」表单 用户页点「新建」,表单下拉框从注册表选;授权数据页的新建表单同样能选 objectui + objectstack · 2 个 PR。先例:objectui#12136(7 文件 +763/−3)与 objectstack#22794(23 文件 +372/−84),同一做法今天刚合入

    (用户页第三处「加入业务单元」读的是业务数据 sys_business_unit,不受影响。)

    业务含义直译:

    • A: 给低代码搭建器加一种新的数据源类型。以后任何页面的「添加」都能声明「从注册表选」。
    • A': 同 A,先用后补手续。
    • B1: 像不少 IAM 后台那样,「谁拥有这个角色」只在角色页上管理。
    • B2: 像 Salesforce 的 lookup 字段、ServiceNow 的 reference 字段。字段知道自己引用什么,凡是编辑这个字段的表单都给出同一个选择框。

    四轴(从业务看):

    • ① 项目长远合理性(领起)。 两年后的样子:引用注册表条目的字段,在契约里声明「我引用哪一类注册表」;所有表单和列表的选择框都从字段派生。主流平台都是这样建模的:Salesforce lookup、ServiceNow reference,都在字段级声明,选择器由字段派生,而不是每个列表各配一次来源。按这个终态看:
      • B2 把「引用岗位/权限集」放在字段上,位置对了,但强度只是展示提示,还不是语义声明。终态到来时,这两处提示由字段声明直接取代,丢掉的只是两个元数据值。
      • A 把它放在单个组件(相关列表)的配置上,强度是类型化契约,位置却是组件级。终态到来时,这个规范字段成了冗余的已发布契约,要走退役流程。
      • B1 什么都不加,但拿掉了 D7 点名的「给用户分配岗位」选择器。
      • A' 在 A 之上还要开规则例外。
    • ② 实际业务拉动。
      • 今天就有人撞上:新库上 Setup 管理员给用户分配岗位,弹窗是空的(0/16);6b-2 后授予权限集也一样。这是真实场景。
      • 「任何页面都能从注册表添加」这个通用能力,除这 2 处外没有别的使用者。实测全仓手写的 add 选择框共 5 处,其中指向目录对象的 3 处,这 3 处里有 1 处随阶段 8 退役。
    • ③ 防 AI 犯错(出错时谁看到什么)。
      • A 最强: 来源是枚举,AI 写错类型,发布时就被响亮拒绝。
      • B2: AI 写错控件名,用户看到的是普通文本框(静默退化)。但服务端对不存在的名字一律 400 拒绝,写不进错误数据,管理员提交时就看到报错,不会泄露。
      • B1: 没有新东西可写错。
    • ④ 创业阶段不扩散。 B1 最小,只删;B2 不新增规范键,只新增一个 objectui 控件;A 新增一个已发布的规范键(永久义务),再加一次发版。

    推荐:B2,回退 B1。

    • 自检: 只看①选 B2。②④ 不翻转。③ 偏 A(枚举胜过自由字符串),按规则不改字母,理由是服务端 400 兜底,B2 出错时是响亮报错而不是泄露。
    • 工作量: A 是 4 个 PR 加一次发版,B2 是 2 个 PR;两者的①读数并不相近,所以不触发「工作量相差 ≥3× 须点名」的规则。
    • 置信缺口:
      1. 没在浏览器里实测两点:这两张授权表的用户页相关列表上会不会出现「新建」;去掉 add 后,行上的「移除」还在不在(今天的通用移除依赖 add)。B1 和 B2 都受影响。派发时开发先测;如果「移除」消失,作为第一件事报回,不自行加功能。
      2. 「字段级语义引用」这个终态是本席的判断,规范里还没有这个提案。B2 不预设它,也不阻碍它。
      3. 如果选 A,它会沿用规范里现成的 record/registry 写法,不另起炉灶。这是 A 的加分项,正文没写到,这里补上。

    裁后执行:

    • B2:
      1. objectui 字段控件 PR(本席派子代理,Part of objectui#7611)。
      2. objectstack PR:移动 .objectui-sha,在两张授权表的名称字段上声明控件,删掉用户页两处 add。在 feat(plugin-security,plugin-auth,verify,platform-objects)!: a permission-set grant names its set by name — no writer fills permission_set_id (#15204 stage 6b-2-pre) #22863 合入之后落地。
      3. 两者都在 6b-2 合入之前落地。开发先实测「新建/移除」。
    • B1: 1 个 objectstack PR:删两处 add,Setup 导航改指目录页(导航项从阶段 8 提前)。在 6b-2 之前落地。
    • A: spec 车道 PR → 报你发 v18 next 预发布(同时裁「next 预发布不算 (c) 所说的发版」)→ objectui 升到规范 18 → objectui 渲染 → objectstack 移动 pin 并改页面。期间 6b-2 可以带着空窗合入((c) 把它挡在所有发版之外),阶段 8 等发版。
    • A': 3 个 PR,你同时批准 objectui #0/#0.1 的例外。

    子问题 Q3b(附言 6111357879)

    一句话问题。 审批流里「审批人是某个岗位」:在 objectstack 自带的控制台上,待审批的岗位审批人显示成截断的机器名,流程设计器里「岗位」一栏只能手打文字。原因是规范已改为「从注册表取岗位」,而 objectui 的读取端还按旧规范只认数据行。(代码读出,未在浏览器实测。)

    选项 × 真实代价 × 工作量:

    选项 做什么 客户能感知的后果 工作量
    A 等规范 18 不写代码 缺陷一直留到 objectui 升到 18,而升 18 要先发版 0 个 PR;时间不可控
    B 结构化读取注册表绑定 读取端按服务端发布的 { source: 'registry', type } 从注册表列出、只存名字;只改读,不改编写面 岗位审批人正常显示,设计器里是下拉框 objectui 1 个 PR · 无先例;盘点估计约 0.4–0.5k 行
    C 手写对照表 在 objectui 里写死「岗位走注册表」 同 B,但对接 v17 服务端时会出错 1 个 PR,最小 · 无先例

    业务含义直译: A 是等官方补丁;B 是先按服务器实际返回的格式适配;C 是写死一个特例。

    四轴:

    推荐:B,回退 A。

    • 自检: 只看①选 B;②③④ 不翻转。
    • 置信缺口: 缺陷是代码读出的,未在浏览器实测,派发时先测。
    • 和 A' 的区别: A' 是在编写面上新增字段,objectui 自己的严格校验会和它冲突;B 只读不写。

    裁后执行: B → 本席派 objectui 子代理(和已派出的 3a 不在同一批文件);objectui 升到规范 18 后去掉放宽的类型。

    os-decision-facets

    • ① 项目长远合理性:B2 把引用放在字段上(主流平台的建模位置),不新增规范键;A 是组件级类型化契约,终态时会冗余;B1 拿掉了 D7 点名的选择器。Q3b:B 按规范声明的两分通用读取。
    • ② 实际业务拉动:新库上分配岗位今天就是空的(实测 0/16),6b-2 后授予权限集同样;通用「从注册表添加」除这 2 处外无使用者。
    • ③ 防 AI 犯错:A 最强(枚举,发布时拒);B2 写错控件名会退化成文本框,但服务端 400 兜底,写不进错行;Q3b 的 B 用下拉框取代手打。
    • ④ 创业阶段不扩散:B1 < B2 < A(A 加规范键并要一次发版);Q3b 的 B 是 1 个 PR、不发版。

    Prior rulings read: add.picker, picker.object, registry picker, lists the registry in AGENTS.md, docs/adr and packages/spec/src → 8 hits; ADR-0131 D4/D7 and C9; approval.zod.ts ApproverValueBinding (#3508, #22710); thread: 6110777865, 6111055760, 6111307114, 6111357879.

    回复方式: 一行即可,例如「B2,Q3b-B」。只回一个字母时,Q3b 按推荐的 B 处理。


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #318 item 1 · letter B2 (Q3b B) · maintainer 「其他同意?」 2026-10-12T00:37Z

    Director seat, summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB (GitHub os-zhuang; written as objectstack-fleet[bot] via the relay). Batch #318 (five cards, this one first) was presented in chat with this seat's own readings and the recommendation "B2, fallback B1; Q3b → B"; the maintainer deferred one card (#22877) and answered 「其他同意?」 for the rest, which takes the recommendation here. Freshness gate: the body and both comments (the newest the epic PM's 决裁详解 6111537112) were re-read before this record. Thread-read: 6111537112.

    Premises re-run on origin/main (3f694715e) in this act: the two pickers read rows (sys-user.page.ts:208, :258); FieldSchema.widget is a free string (field.zod.ts:1942); npm @objectstack/spec dist-tags are latest: 17.7.0 and rc: 17.0.0-rc.6, no 18.x; #22863 (a permission-set grant names its set by name) merged 2026-10-11T17:36Z, so B2's objectstack half no longer waits on it.

    The ruling

    B2: the two grant tables' name fields declare a registry picker; the user page's two add pickers go.

    • objectui gains one field widget that lists one registry type by name and stores the name only, the mechanism objectui#12136 / objectstack#22794 landed for metadata forms, now reachable from record forms.
    • objectstack declares that widget on the name field of the position grant and of the permission-set grant, moves .objectui-sha to the objectui head that carries the widget, and deletes the two add blocks on the user page (sys-user.page.ts, the sys_position and sys_permission_set pickers). The user page's "new" form then lists the registry; the grant objects' own new forms list it the same way.
    • Both PRs land before 6b-2; stage 8 no longer waits on the pickers.
    • The dev measures first, in the browser: whether the user page's related lists for the two grant tables offer "new", and whether the row-level "remove" survives without add. If "remove" disappears, that is reported first; the dev adds no feature on its own.
    • Q3b → B: objectui's read side lists positions for a { source: 'registry', type } approver binding from the registry and stores the name only, a read-side change under the contract the server already publishes, no authoring surface touched, so objectui validate and the strict validation are unchanged; the loosened type is removed when objectui moves to spec 18. One PR, apart from item 3a already dispatched.
    • ⛔ Not taken: A (a new add.picker registry source in the spec: a component-level contract for two call sites, behind a v18 pre-release that release condition (c) blocks); A' (the same, with objectui reading a field its installed spec does not declare: an exception to objectui rule #0/#0.1 the maintainer did not grant); B1 (removing the user-page entry: it takes away the "assign a user to a position" picker ADR-0131 D7 names). Q3b A (wait for spec 18) and C (a hand-written table outside the spec) not taken.

    Why on the first axis

    Two years out, a field that references a registry entry declares what it references, and every form and list derives its picker from the field: the Salesforce lookup and ServiceNow reference shape. B2 puts the reference on the field (the right place) at display-hint strength; A puts a typed contract on one component (the wrong place) and becomes a redundant published key when the field-level declaration arrives; B1 removes the capability D7 names. Q3b's B reads the two-way record | registry binding the spec already declares. 自检:只看①选 B2;②③④ 是否翻转:否(③ 偏 A:枚举胜自由字符串;不改字母,因为服务端对不存在的名字一律 400,B2 出错时是响亮报错不是泄露)。B1 is more than 3× cheaper than B2; the first-axis readings are not close, so the letter stands.

    Workload (#22597's rule): domain:ui + the objectstack lane under epic:#15194 · 2 PRs (objectui about 450 lines, objectstack about 400 lines including the pin move) · precedents objectui#12136 (+763 / −3) and objectstack#22794 (+372 / −84). Q3b B: domain:ui · 1 PR · about 400–500 lines · no precedent. Confidence gap: the "new" / "remove" browser readings above; the field-level end state is this seat's reading, not a spec proposal.

    Prior rulings read: add.picker, picker.object, registry picker, lists the registry on origin/main (AGENTS.md, docs/adr, packages/spec/src) → 8 hits as the epic PM listed (ADR-0131 D4 and D7; approval.zod.ts ApproverValueBinding, #3508 / #22710); #22601 → B (no transition piece); release condition (c) 6102862135 / 6104671088; check-prior-rulings.mjs --card 22865 in this act: 562 hits, ADR-0005 §5, ADR-0035 §3, ADR-0041 §4, ADR-0054 §3, ADR-0059 §3, ADR-0087 D3 / D4 named, none answering this question; thread: 6111357879, 6111537112.

    State and execution

    • This decision card closes completed in this act (the ruling is its deliverable); needs-user-decision leaves with the close. The Ruled: line is added to the body.
    • Execution is objectui#7611's third part, by the epic PM (epic:#15194, session_01Rerax7QTjKMPCUZxQUtPFR): the objectui widget PR (Part of objectui#7611), then the objectstack PR (pin move, the two field declarations, the two add deletions), both before 6b-2; Q3b's objectui PR alongside, disjoint from item 3a's files. A pointer is posted on objectui#7611 in this act.
    • Q2 of the card (release condition (c)'s "objectui spec-18 pin" half) is not ruled here, as the card said; the epic PM's F1 re-measurement on the injected console decides whether it comes back as its own item.
  4. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Closed completed on ruling 6115690641 (batch #318 item 1 → B2, Q3b → B): the decision is this card's deliverable, and the work is objectui#7611's third part, dispatched by the epic PM (epic:#15194; pointer objectui#7611 comment 6115700897). The four open PRs that name this card (#22897, #22898, #22899, #22900, all Part of #15204) name it as a gate they wait on, not as a card they fix; that gate is now "the pickers land", tracked on objectui#7611. Director seat, summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB, 2026-10-12T00:41Z.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsdomain:uipriority:p1High: required for production / M2target:v18

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions