Skip to content

spec: a shared picklist (global value set) metadata kind — option lists reused across objects and packages are TypeScript constants today #18164

Description

@os-elon-musk

Epic: session_016tKoy8NJa35Yih1FdzrVmn (director seat, summon #32), taken over on the maintainer's order 「你负责接手,并派发处理所有所有相关的」 · 2026-10-03T09:43Z · checklist 5967887779
Epic territory: objectstack-ai/hotcrm#2000 (hotcrm src/**: _picklists.ts, new *.picklist.ts, the select fields and consumers that import the lists, locale bundles); objectstack-ai/objectui#10202 when it unlocks (Studio picklist page, object designer field editor)
Ruled: 5904864936 · letter Q1 A · Q2 A — #19518 (the spec layer) is dispatchable now; the kind is named picklist (*.picklist.ts, Field.select({ picklist }), picklists.<name>, picklistExtensions); #19519 and objectui#10202 keep their Blocked-by order · 2026-09-30T05:42Z

Path: 本地跑起来、看到 — records-forms (清单项待写, authored with #19518) | P2

Parent of a cross-layer feature point (ruling batch #209 item 1 · A · maintainer 「18164 同意」): sub-issues in Blocked-by: order — #19518 (spec) → #19519 (runtime) → objectui#10202 (Studio). This card is a coordination node and is never dispatched itself; the road order (behind the open product P0/P1 items) decides when #19518 is taken.

Gap

There is no metadata kind for an option list that several objects share. Checked on @objectstack/spec 17.4.0's dist/index.d.ts and dist/data/index.d.ts: no globalPicklist, valueSet, picklists or equivalent key. An app that wants industry, lead_source, salutation, opportunity_stage or territory to mean the same thing on several objects keeps them as exported TypeScript arrays and spreads them into each Field.select({ options: [...] }).

Evidence (hotcrm, origin/main c716a2c)

  • src/objects/_picklists.ts — ~3,001 authored tokens; imported by 17 files: seven objects (account, contact, lead, opportunity, task, event, event_attendee, plus contract and quote), two views, a flow, an action, a dashboard, an import mapping and a locale bundle.
  • Under the ADR-0130 package split (Epic: split HotCRM into ADR-0130 packages — sales is the app, service / revenue / marketing are modules, a directory is a package hotcrm#1904) those consumers sit in three packages (sales, revenue, and the app's own dashboards and translations), so the file becomes cross-package source that every module must import from the app package — the shape a metadata kind would replace with a reference by name.
  • The same lists are what a customer overlay most often wants to extend (a customer-specific industry or lead-source value), and today that is a source edit in the app, not an overlay (ADR-0005 has nothing to overlay).

Ask

A picklists (or valueSets) stack collection: { name, label, options: SelectOption[] }, owned by a package like any other metadata, referenced from a select field by name (Field.select({ picklist: 'crm_industry' })), translatable through the locale packs the way field options are, and extensible by an org overlay (ADR-0005) so a customer can add a value without forking the object. Salesforce Global Value Sets and Dataverse global option sets are the reference shape.

Dedupe words: global picklist, value set, shared select options, _picklists.ts, picklist metadata kind.


Generated by Claude Code

Activity

  1. hotlong commented on Sep 17, 2026

    @hotlong
    Contributor

    Ruling: batch #147 item 2 · letter 停放 (parked; the design discussed with the maintainer is recorded here so the restart starts from it) · maintainer 「18164 停放」 2026-09-17T14:09Z

    Director seat, summon #24, session_01Wj1HUjzyeiBQ8atRf1ZhaL. Presented in detail; the maintainer first said 「这是非常具体的业务需求,主流平台应该都支持吧,这个应该要开发。你可以和我讨论具体的方案」, the seat laid out a design, and the maintainer then ruled 「18164 停放」 under 「创业期现在不追求功能多,追求稳定」. Under the corrected need standard (5715688324) the need is real (Salesforce Global Value Sets, Dataverse global option sets); the park is a sequencing decision, ⛔ not a judgement that the need is absent.

    Ruling — 停放

    • needs-user-decision → pm:on-hold. Restart-when (body's leading line): a customer requirement needs a shared option list extended per organization without forking the app, or the maintainer schedules it after the current stability work (package split, can, spec narrowings) lands.
    • Meanwhile the reference app keeps its TypeScript constants (src/sales/objects/_picklists.ts, spread at each use site) — a working, non-silent shape.

    Design recorded for the restart (discussed on the direct channel; ⛔ not ruled in detail — the three open points are the maintainer's)

    1. New metadata kind picklist (name to confirm: picklist vs valueSet): { name, label, description?, options: SelectOption[] } — SelectOption is today's field option shape, ⛔ no new option shape; package-owned, file pattern *.picklist.ts, registered before object in load order.
    2. Field reference Field.select({ picklist: 'industry' }), mutually exclusive with options; both or neither on a select type is refused.
    3. Server-resolved: field metadata served to clients carries the resolved options, so objectui's renderers, validation and filters are unchanged in phase 1; write validation uses the resolved set.
    4. Extension and overlay are additive only: package-level picklistExtensions: [{ extend, options }] (the objectExtensions idiom); per-organization overlay of the same shape in sys_metadata with allowOrgOverride: true and an overlay schema that accepts new values only — removal/rename stays with the owning package (open point: allow the org overlay at all, or package-level extension only).
    5. Translation: TranslationData.picklists.<name>.{ label?, options: { value: label } }; a field referencing a picklist inherits it; field-level options translation remains for inline options.
    6. Verification (ADR-0136 D2.4): two records-forms checklist items + one dogfood case (one picklist, two objects, org A adds a value, A writes it, B is refused, locale switch relabels); hotcrm migrates its shared lists as the acceptance.
    7. Phases: 1 = spec + engine + CLI compile + translation + hotcrm migration (Studio untouched); 2 = Studio picklist page and 「use picklist」 in the object designer. Not in v1: cascading picklists (per-option visibleWhen and dependsOn exist), unrestricted mode, per-record-type value restriction. Open point three: one-page ADR first vs. straight to a card.

    Generated by Claude Code

  2. os-steve commented on Sep 21, 2026

    @os-steve
    Collaborator

    回决策箱(维护者指令,skills 席 2 代执行)— 2026-09-21T03:45Z

    出处三件(SKILL.md :149 代执行他人指令,评论带出处三件)— 谁的指令:维护者,在本席(domain:skills seat 2,session_017ETYWqMQD4qMtZzAGovWNi,席位帖 #19287)会话内的真实用户轮次。在哪说:本席会话聊天,2026-09-21,在本席呈交「停放排查」四组清单(全板 165 张停放卡:pm:blocked 64 + pm:on-hold 101;其中 38 张的停放条件已消失——正文与评论里 Blocked-by: / Restart-when: 指向的卡或 PR 全部已关或已合)之后。原话(逐字,⛔ 未翻译、未润色):「还有哪些应该解除停放的你一起排查一下」;对四组清单:「同意」。

    本卡属第三组「条件已消失的决策卡 ⇒ 回决策箱」:本席于 2026-09-21T03:00Z 机器复核,本卡停放所指向的目标已全部关闭/合并;卡的本体是一道待维护者裁的题,停放条件消失后它不该继续 hold,而该回到 needs-user-decision 收件箱排批。

    动作:停放状态标签一笔换为 needs-user-decision;⛔ 本席不代裁、不派发。所属车道席位或总监席在下次决策批前按 SKILL.md 〈决策箱勤务〉补全四棱卡面块与「维护者速读」(存量卡低频子轮回填);H62 在补全前对本卡报行属正常。


    Generated by Claude Code

  3. os-project-manager commented on Sep 21, 2026

    @os-project-manager
    Collaborator

    Ruling: batch #209 item 1 · letter A · maintainer 「18164 同意」 2026-09-21T05:05Z

    Director seat, summon #25 (session_012GcsUbuqFGBibkEDMRC1eE). Returned to the decision box at 5755100805 under the maintainer's 「还有哪些应该解除停放的你一起排查一下」/「同意」; presented in detail with the recommendation A (facet ①: every mature platform models a shared option list as first-class metadata — Salesforce Global Value Sets, Dataverse global option sets — and it retires the 「cross-package TypeScript constants」 special case; ② pull measured in the reference app: _picklists.ts ≈ 3,001 tokens, 17 consumers, three packages; ③ a named picklist makes an AI author's wrong reference a loud refusal where today's copied option lists drift silently; ④ a new declared kind is a permanent obligation, so the direction is set now and the schedule stays behind the open product P0/P1). The maintainer agreed. The 2026-09-17 park (batch #147 item 2, 5715762696) was a sequencing decision; its recorded design is the design of record and is carried into the sub-issues unchanged.

    Ruled: A. The feature enters the road map and the queue at its road position — step ②「本地跑起来、看到」, records — as one cross-layer feature point: this card is the parent, three sub-issues carry the layers in Blocked-by: order, spec first:

    1. picklist metadata kind — spec: picklist collection, Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 — spec (domain:spec, pm:queue, p2): the picklist kind, Field.select({ picklist }) mutually exclusive with options, the server-resolved served shape, the translation face, the additive package-level picklistExtensions shape; with it the feature-map line in docs/NORTH-STAR.md 「路上的功能点」 and the two records-forms checklist items (its own small Tier H docs PR).
    2. picklist metadata kind — runtime: resolve picklist → options when serving field metadata, validate writes against the resolved set, apply package-level extensions (phase 1 of objectstack#18164) #19519 — runtime (domain:engine, pm:blocked → released when picklist metadata kind — spec: picklist collection, Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 lands): load order, additive merge, resolve-at-serve, write validation against the resolved set; hotcrm's migration of its shared lists is filed as a hotcrm card by the epic PM when this lands.
    3. objectui#10202 — Studio (domain:ui, pm:blocked → released when picklist metadata kind — runtime: resolve picklist → options when serving field metadata, validate writes against the resolved set, apply package-level extensions (phase 1 of objectstack#18164) #19519 is installable by pin): picklist page and 「use picklist」 in the object designer (phase 2; phase 1 needs no frontend change because options are served resolved).

    Phase 2's per-organization overlay (ADR-0005, additive only) is deferred to its own sub-issue when a customer requirement measures it; the three sub-issues say so. ⛔ None of the three is dispatched before the open product P0/P1 checklist items — the road order decides, and the domain:spec seat takes #19518 when it reaches it. When work starts, an epic PM session takes this parent (pm:epic + session ID on the body per 〈Epic 子树车道〉); until then the parent carries pm:queue as a coordination node and is never dispatched itself.

    四棱行:① A(成熟平台皆有,收掉跨包常量特例) · ② 自家实测、外部未测 · ③ A 响亮(命名引用写错即拒) · ④ 定方向不抢期(排在 P0/P1 之后)
    Prior rulings read: picklist, global value set, valueSet → 2 hits (this card's batch #147 park; #18163 sibling); ADR-0005 (overlay), ADR-0136 D2.4 (verification); thread: none

    Execution, same stroke: needs-user-decision → pm:queue on this card; body's leading Restart-when: line replaced by the Path: line; the three sub-issues filed, labelled and linked as GitHub sub-issues of this card; area:records is added to the parent and the sub-issues once the area:* labels exist (created by ensure-pm-labels.sh after PR #19488 lands).


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    os-decision-facets

    决策请求:「共享选项列表」这项功能,现在就开工 spec 层吗?它的元数据类型叫 picklist 还是 valueSet? · 2026-09-30T03:31Z

    domain:spec seat 5(session_01Sfe5YjBLwB9J3y8fvm2xq1)。本卡是父卡,一直以 pm:queue 充当协调节点;它的 spec 子卡是 #19518。本评论把两个一直没落卡的问题放进决策箱,本卡同时转入 needs-user-decision。
    ⚠️ 本席此前只在聊天里问过这两题,违反了「卡先于弹窗」。

    一句话问题

    Governing text

    前提(每条带复查方法)

    1. 未关闭的产品 P0/P1 数量。 本席 2026-09-30T03:31Z 用 REST 按标签列出:P0 2 张,P1 非 tooling 15 张;09-22 4 号席读数为 P0 4 张、P1 28 张。spec 车道里的 P1 是 1 张 epic([epic] hotcrm ADR-0130 拆包的上游依赖集 —— 一条代码门禁(#18202) + 一次发版,其余五张是作者体验 #18215)和 4 张 pm:blocked,没有能接的。复查:GET /repos/objectstack-ai/objectstack/issues?labels=priority:p1&state=open。
    2. picklist metadata kind — spec: picklist collection, Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 仍是 pm:queue,未被认领。 复查:读 picklist metadata kind — spec: picklist collection, Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 的标签与 assignee。
    3. 仓内已有「picklist」的叫法。
      • content/docs/ui/translations.mdx:7、:68 把下拉选项称为「picklist options」。
      • content/docs/protocol/objectql/types.mdx:584 写「Dropdown/picklist」。
      • 参考应用用 _picklists.ts,裁决记为 17 个使用点、3 个包。
      • packages/spec/src 里没有叫 valueSet 的类型或字段。
      • 复查:git grep -n -i picklist origin/main -- content/docs。

    Q1 选项与代价

    选项 做什么 客户看到的后果
    A 按本车道已放开的规则,现在开工 #19518(只做 spec 层) 共享选项列表更早可用;#19519 运行时层与 objectui#10202 Studio 层仍在各自车道排队
    B 维持 09-21 裁决,等全部产品 P0/P1 关闭 本车道不做这项;参考应用继续靠复制 TypeScript 常量(能用,不静默)

    业务直译:A = 先把「选项集」这个概念在协议里定下来,后面两层可以接着排;B = 这项功能整体晚一些。

    Q2 选项与代价

    选项 做什么 客户看到的后果
    A 叫 picklist:文件 *.picklist.ts,引用 Field.select({ picklist: 'industry' }),翻译 picklists.<name> 与仓内文档和参考应用的现有叫法一致
    B 叫 valueSet:文件 *.valueSet.ts,引用 Field.select({ valueSet: 'industry' }) 与 Salesforce 的 Global Value Set 叫法一致;仓内现有文档里「picklist options」的说法要另外统一

    业务直译:A = 用客户和文档里已经在用的词;B = 用一个更抽象、今后也能套在非下拉字段上的词。

    四轴(业务立场)

    • 长远合理性: 两年后的样子:共享选项列表是一等元数据,多个对象引用同一份。主流平台(本席未实测):Salesforce 叫 Global Value Set,字段类型叫 Picklist;Dataverse 叫全局 choice(旧称 option set);ServiceNow 叫 choice list。名字一旦发布就是永久接口,选与现有文档一致的名字,特例最少。
    • 实际业务拉动: 参考应用有 17 个使用点在复制同一批选项常量(裁决实测);外部客户需求未测。
    • 防 AI 犯错: 两个名字都能做到写错引用时响亮拒绝;差别在于 AI 生成代码时更可能写出哪个词。仓内文档已用「picklist」,AI 照文档写更不容易拼错。
    • 创业阶段不扩散: Q1 的 A 只开 spec 这一层,不连带开工运行时和 Studio。

    推荐

    • Q1:A,只开 spec 层。只看①选 A;②③④ 是否翻转:否。回退:B。置信缺口:「P0/P1 优先」放开后是否也覆盖一张卡上明写的时序,本席看不到你的本意,所以上交。
    • Q2:A(picklist)。只看①选 A;②③④ 是否翻转:否。回退:B。置信缺口:主流平台的叫法并不统一,本席没有实测客户更熟哪个词。

    裁后执行(维护者只裁方向)

    四棱

    ① 项目长远合理性:共享选项列表收掉「跨包复制 TypeScript 常量」这个特例;名字选与现有文档一致的一个。
    ② 实际业务拉动:参考应用 17 个使用点(裁决实测);外部需求未测。
    ③ 防 AI 犯错:命名引用写错即被拒,响亮;与文档一致的名字更少拼错。
    ④ 创业阶段不扩散:只开 spec 一层;新类型是永久义务,所以名字一次定准。
    Prior rulings read: picklist, valueSet, global value set → 本卡 3 条裁决与指令评论(5715762696、5755100805、5755653853)以及 #19518 正文;ADR: ADR-0005(覆盖层,第 2 阶段才涉及);thread: 本卡 4 条评论。
    推荐:Q1 A,Q2 A。只看①选 A / A;②③④ 是否翻转:否。置信缺口:见上。


    Generated by Claude Code

  5. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    Ruling: batch #251 item 3 · letter Q1 A · Q2 A · maintainer 「同意」 2026-09-30T05:39Z

    Director seat (objectstack#12708, summon #30 续 2, session_01AsCNgFBs8HCjwhyHQsFbx3). Provenance: maintainer, live PM chat with the director seat, 2026-09-30, replying 「同意」 to batch #251 as presented (this card as item 3, with #20281 and #18386); 「同意」 is to the director's recommendation in chat, which adopted the seat's decision request 5903510250 (Q1 A, Q2 A) after this seat's own reading: open P0 2 / P1 19 at 04:3xZ and none takeable in the domain:spec lane; #19518 pm:queue, p2, unclaimed; "picklist" in content/docs 9 hits and in the reference app's _picklists.ts, valueSet 0 hits in packages/spec/src; the design of record 5715762696 item 1 already spells picklist with the name left to confirm; ruling 5755653853 (batch #209 item 1, A).

    Ruled: Q1 A. #19518 (the spec layer) is dispatchable now: the maintainer's 2026-09-23 release of the P0/P1-first rule in the domain:spec lane covers the sequencing sentence of ruling 5755653853 for this layer. #19519 (runtime) and objectui#10202 (Studio) keep their Blocked-by: order and are released as that ruling states, not by this one.

    Ruled: Q2 A — the kind is named picklist. File pattern *.picklist.ts; the field reference Field.select({ picklist: 'industry' }), mutually exclusive with options; translation TranslationData.picklists.<name>; the package-level extension picklistExtensions — the design of record with its one open name closed. ⛔ Not valueSet: the repository, the reference app and the docs already say picklist, and a published name is permanent.

    Readings recorded with the ruling:

    • Long-run: a first-class shared option list, named as this ecosystem already speaks (Salesforce's field type is Picklist; its set is a Global Value Set; Dataverse says global choice; ServiceNow choice list — the names differ, the documented word here is one).
    • Pull: 17 use sites in the reference app (measured on the earlier ruling); external demand unmeasured.
    • AI-safety: a wrong reference is refused loudly under either name; the documented word is the one an AI writes correctly.
    • Startup scope: the spec layer only.

    Execution parameters (ruled in the same stroke):

    State: needs-user-decision → pm:queue on this parent (the coordination node; priority:p2, domain:spec, area:records stay); #19518 stays pm:queue and is takeable now; the Ruled line goes on the body in the same stroke; a pointer goes on #19518.

  6. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    Contributor

    Epic checklist: #18164 (shared picklist) · epic PM taken over · 2026-10-03T09:42Z

    Director seat, summon #32, session_016tKoy8NJa35Yih1FdzrVmn, now this card's epic PM. This is on the maintainer's order in the live director chat, verbatim 「你负责接手,并派发处理所有所有相关的」, after the maintainer asked why the card had stalled. ⛔ Not a new ruling: every step below executes ruling 5755653853 (batch #209 item 1) and ruling 5904864936 (batch #251 item 3).

    Why it looked stalled. Ruling 5755653853 said an epic PM takes this parent when work starts. None did. The spec and runtime seats landed their sub-issues and closed them, and two steps had no owner:

    • hotcrm's migration, which the ruling assigned to the epic PM "when this lands", was never filed;
    • objectui#10202 stayed held behind objectui's 17.6.0 upgrade and the lane's road order.
    Step Card State
    ① spec: picklist kind, Field.select({ picklist }), translation face, NORTH-STAR line, two checklist items #19518 ✅ landed 2026-09-30, closed
    ② runtime: serve resolved options, additive picklistExtensions, write validation #19519 ✅ PR #21047 → 88b484e00, shipped in 17.6.0
    ③ acceptance: hotcrm's shared lists become picklist metadata, plus the live-boot checklist run objectstack-ai/hotcrm#2000 🟡 filed in this act; claimed and dispatched next
    ④ Studio: picklist page, "use picklist" in the object designer, and dropping options when picklist is set before a PUT (the producer obligation in objectui#10202 5925784898) objectstack-ai/objectui#10202 ⏸ pm:on-hold. Restart-when: objectui resolves a 17.6.0. Blocked behind objectui#11438 (ruled A′ on batch #272; PR objectui#11531, the trunk). The road-order clause ("after the open product P0/P1 items") is lifted by the maintainer's order above.
    deferred: per-organization overlay (records-forms.picklist-org-append) not filed on a measured customer requirement, ADR-0005 additive only, as both rulings state

    The parent closes when ③ and ④ land. Each dispatch and each landing appends one audit line here.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 3, 2026

    @objectstack-fleet
    Contributor

    Epic audit · #18164 · 2026-10-03T09:54Z · session_016tKoy8NJa35Yih1FdzrVmn. This updates checklist 5967887779.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    Contributor

    Epic audit · #18164 · 2026-10-06T00:10Z · director seat, summon #34, session_0195diSK6vuqxgiJ38VWBHb6. This updates checklist 5967887779 by one line; ⛔ not a takeover of the epic.

  9. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    Contributor

    Cross-seat note from the repo:hotcrm seat, session_012zh91QzFgePbkmuHnugLN3, 2026-10-08T03:08Z. ⛔ Not a claim on this card; its body and labels are untouched.

    objectstack-ai/hotcrm#2000, the hotcrm acceptance step of this epic, left this subtree and is now in the repo:hotcrm lane's pm:queue. pm:epic was removed from it.


    Generated by Claude Code

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:recordsBusiness objects, records, the views that show data, usable forms, searchdomain:specpm:epicpriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions