Repository navigation
spec: a shared picklist (global value set) metadata kind — option lists reused across objects and packages are TypeScript constants today #18164
Description
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, pluscontractandquote), 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
hotlong commentedon Sep 17, 2026
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.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)
picklist(name to confirm:picklistvsvalueSet):{ name, label, description?, options: SelectOption[] }—SelectOptionis today's field option shape, ⛔ no new option shape; package-owned, file pattern*.picklist.ts, registered beforeobjectin load order.Field.select({ picklist: 'industry' }), mutually exclusive withoptions; both or neither on a select type is refused.options, so objectui's renderers, validation and filters are unchanged in phase 1; write validation uses the resolved set.picklistExtensions: [{ extend, options }](theobjectExtensionsidiom); per-organization overlay of the same shape insys_metadatawithallowOrgOverride: trueand 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).TranslationData.picklists.<name>.{ label?, options: { value: label } }; a field referencing a picklist inherits it; field-leveloptionstranslation remains for inline options.records-formschecklist 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.visibleWhenanddependsOnexist), unrestricted mode, per-record-type value restriction. Open point three: one-page ADR first vs. straight to a card.Generated by Claude Code
os-steve commentedon Sep 21, 2026
回决策箱(维护者指令,skills 席 2 代执行)— 2026-09-21T03:45Z
出处三件(
SKILL.md:149 代执行他人指令,评论带出处三件)— 谁的指令:维护者,在本席(domain:skillsseat 2,session_017ETYWqMQD4qMtZzAGovWNi,席位帖 #19287)会话内的真实用户轮次。在哪说:本席会话聊天,2026-09-21,在本席呈交「停放排查」四组清单(全板 165 张停放卡:pm:blocked64 +pm:on-hold101;其中 38 张的停放条件已消失——正文与评论里Blocked-by:/Restart-when:指向的卡或 PR 全部已关或已合)之后。原话(逐字,⛔ 未翻译、未润色):「还有哪些应该解除停放的你一起排查一下」;对四组清单:「同意」。本卡属第三组「条件已消失的决策卡 ⇒ 回决策箱」:本席于 2026-09-21T03:00Z 机器复核,本卡停放所指向的目标已全部关闭/合并;卡的本体是一道待维护者裁的题,停放条件消失后它不该继续 hold,而该回到
needs-user-decision收件箱排批。动作:停放状态标签一笔换为
needs-user-decision;⛔ 本席不代裁、不派发。所属车道席位或总监席在下次决策批前按SKILL.md〈决策箱勤务〉补全四棱卡面块与「维护者速读」(存量卡低频子轮回填);H62 在补全前对本卡报行属正常。Generated by Claude Code
picklistcollection,Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518picklist→ options when serving field metadata, validate writes against the resolved set, apply package-level extensions (phase 1 of objectstack#18164) #19519os-project-manager commentedon Sep 21, 2026
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:picklistcollection,Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 — spec (domain:spec,pm:queue, p2): thepicklistkind,Field.select({ picklist })mutually exclusive withoptions, the server-resolved served shape, the translation face, the additive package-levelpicklistExtensionsshape; with it the feature-map line indocs/NORTH-STAR.md「路上的功能点」 and the tworecords-formschecklist items (its own small Tier H docs PR).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:picklistcollection,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.domain:ui,pm:blocked→ released when picklist metadata kind — runtime: resolvepicklist→ 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:specseat 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 carriespm:queueas 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:queueon this card; body's leadingRestart-when:line replaced by thePath:line; the three sub-issues filed, labelled and linked as GitHub sub-issues of this card;area:recordsis added to the parent and the sub-issues once thearea:*labels exist (created byensure-pm-labels.shafter PR #19488 lands).Generated by Claude Code
objectstack-fleet commentedon Sep 30, 2026
os-decision-facets
决策请求:「共享选项列表」这项功能,现在就开工 spec 层吗?它的元数据类型叫
picklist还是valueSet? · 2026-09-30T03:31Zdomain:specseat 5(session_01Sfe5YjBLwB9J3y8fvm2xq1)。本卡是父卡,一直以pm:queue充当协调节点;它的 spec 子卡是 #19518。本评论把两个一直没落卡的问题放进决策箱,本卡同时转入needs-user-decision。一句话问题
picklistcollection,Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 现在能不能开工?picklist还是valueSet?Governing text
5755653853(batch Refactor protocol docs: business value over code examples #209 item 1,字母 A,维护者「18164 同意」,2026-09-21):「⛔ None of the three is dispatched before the open product P0/P1 checklist items — the road order decides」。picklistcollection,Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 正文 Scope 第 1 条:「name to confirm on the parent before the PR:picklistvsvalueSet」。5715762696(batch 🔗 Broken links detected in documentation #147 item 2)第 1 条同样写着「name to confirm」。前提(每条带复查方法)
pm:blocked,没有能接的。复查:GET /repos/objectstack-ai/objectstack/issues?labels=priority:p1&state=open。picklistcollection,Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 仍是pm:queue,未被认领。 复查:读 picklist metadata kind — spec:picklistcollection,Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 的标签与 assignee。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 = 先把「选项集」这个概念在协议里定下来,后面两层可以接着排;B = 这项功能整体晚一些。
Q2 选项与代价
picklist:文件*.picklist.ts,引用Field.select({ picklist: 'industry' }),翻译picklists.<name>valueSet:文件*.valueSet.ts,引用Field.select({ valueSet: 'industry' })业务直译:A = 用客户和文档里已经在用的词;B = 用一个更抽象、今后也能套在非下拉字段上的词。
四轴(业务立场)
推荐
picklist)。只看①选 A;②③④ 是否翻转:否。回退:B。置信缺口:主流平台的叫法并不统一,本席没有实测客户更熟哪个词。裁后执行(维护者只裁方向)
picklistcollection,Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 的 Scope 认领并派发 spec 层,带上裁定的名字,走完整认领、达档复核和落地;picklist metadata kind — runtime: resolvepicklist→ options when serving field metadata, validate writes against the resolved set, apply package-level extensions (phase 1 of objectstack#18164) #19519 与 objectui#10202 按原裁决在 picklist metadata kind — spec:picklistcollection,Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 落地后解锁。pm:queue,picklist metadata kind — spec:picklistcollection,Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 保持原样。Q2 的名字照样记下,开工时直接用。picklistcollection,Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 正文 Scope 第 1 条的「name to confirm」改为裁定的名字。四棱
① 项目长远合理性:共享选项列表收掉「跨包复制 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
1 remaining item
objectstack-fleet commentedon Sep 30, 2026
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 request5903510250(Q1 A, Q2 A) after this seat's own reading: open P0 2 / P1 19 at 04:3xZ and none takeable in thedomain:speclane; #19518pm:queue, p2, unclaimed; "picklist" incontent/docs9 hits and in the reference app's_picklists.ts,valueSet0 hits inpackages/spec/src; the design of record5715762696item 1 already spellspicklistwith the name left to confirm; ruling5755653853(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:speclane covers the sequencing sentence of ruling5755653853for this layer. #19519 (runtime) and objectui#10202 (Studio) keep theirBlocked-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 referenceField.select({ picklist: 'industry' }), mutually exclusive withoptions; translationTranslationData.picklists.<name>; the package-level extensionpicklistExtensions— the design of record with its one open name closed. ⛔ NotvalueSet: the repository, the reference app and the docs already say picklist, and a published name is permanent.Readings recorded with the ruling:
Execution parameters (ruled in the same stroke):
domain:specseat 5 claims picklist metadata kind — spec:picklistcollection,Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 under its Scope with the ruled name, corrects Scope item 1 ("name to confirm") on that body, and runs the full claim, at-tier review (Clause-②: yes: a new metadata kind) and landing. The NORTH-STAR feature-map line and the tworecords-formschecklist items ride their own small Tier H docs PR, as ruling5755653853states.State:
needs-user-decision→pm:queueon this parent (the coordination node;priority:p2,domain:spec,area:recordsstay); #19518 stayspm:queueand is takeable now; the Ruled line goes on the body in the same stroke; a pointer goes on #19518.objectstack-fleet commentedon Oct 3, 2026
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 ruling5755653853(batch #209 item 1) and ruling5904864936(batch #251 item 3).Why it looked stalled. Ruling
5755653853said 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:picklistkind,Field.select({ picklist }), translation face, NORTH-STAR line, two checklist itemspicklistExtensions, write validation88b484e00, shipped in 17.6.0picklistmetadata, plus the live-boot checklist runoptionswhenpicklistis set before a PUT (the producer obligation in objectui#102025925784898)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.records-forms.picklist-org-append)The parent closes when ③ and ④ land. Each dispatch and each landing appends one audit line here.
Generated by Claude Code
objectstack-fleet commentedon Oct 3, 2026
Epic audit · #18164 · 2026-10-03T09:54Z ·
session_016tKoy8NJa35Yih1FdzrVmn. This updates checklist5967887779.picklistmetadata —*.picklist.tsandField.select({ picklist })replace_picklists.ts(acceptance of objectstack#18164) hotcrm#2000: filed, then claimed (5967912141,pm:epic+pm:dispatched). An os-dev is dispatched (mode:subagent): the shared option lists become*.picklist.tswithField.select({ picklist }), followed bypnpm verifyand a live-boot run ofrecords-forms.picklist-shared-across-objects.5967926862) and claimed (5967957684). An os-dev is dispatched on a branch based on the 17.6.0 trunk (chore(deps): resolve @objectstack/* 17.6.0 in pnpm-lock.yaml and follow its mechanical contract moves; five owner-held reds reported by row (objectui#11438) objectui#11531). Its draft PR targetsmain, so CI runs on 17.6.0. It lands after the trunk, whose row 3 waits on 17.7.0 (the maintainer's 「先等,暂不处理」, recorded on deps: bump objectui's @objectstack/* to 17.6.0 — nineteen held cards' conditions are met on npm, and objectui's lockfile still resolves 17.5.0 objectui#11438). It does not wait on the road order any more.picklistkind is package-owned, with no runtime create (spec docblock). If the metadata API refuses picklist writes, Studio builds the read-only page and the designer reference only, and create/edit returns as an open question. ⛔ No work-around.Generated by Claude Code
objectstack-fleet commentedon Oct 6, 2026
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.session_016tKoy8NJa35Yih1FdzrVmnis unreachable, the branch has no commit of its own, the worktree is gone). The card is back inpm:queueunderdomain:uiwithpm:epicremoved, its scope cut to the protocol: the designer's 「use picklist」 picker, the save path dropping resolvedoptionswhenpicklistis set, and a READ-ONLY Studio picklist page. ⛔ No Studio create or edit:kernel/metadata-plugin.zod.ts:825declares the kind withallowRuntimeCreate: false.picklistmetadata —*.picklist.tsandField.select({ picklist })replace_picklists.ts(acceptance of objectstack#18164) hotcrm#2000: NOT read from this session (the repository is not attached). Its claim belongs to the same unreachable session; whether its dev finished is unknown here.pm:epic, body line namingsession_016tKoy8NJa35Yih1FdzrVmn) is left as it stands: step ③ may still be in flight under that session, and triage's zombie rule or the maintainer decides the reservation. The parent closes when ③ and ④ land, as the checklist says.feat(objectql): resolve picklist references at runtime — served optio…
feat(spec): offer onSuccess and outcomeMessages in Studio's action fo…
test(spec): the last system/ file group's test titles state each cite…
objectstack-fleet commentedon Oct 8, 2026
Cross-seat note from the
repo:hotcrmseat,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:hotcrmlane'spm:queue.pm:epicwas removed from it.Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
Epic close-out at 2026-10-11T22:28Z: completed. The shared
picklistkind shipped in all three layers that stayed in this subtree. The one remaining item is ruled out. Sessionsession_01EgxC4UNYnzhuvmG12fh5A8.Provenance: the maintainer gave the order in live PM chat in this session, verbatim 「该关的关,改开卡的开卡」 and 「按组织追加 picklist 值,不考虑」, and this session executed it.
Landed
picklistcollection,Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518.picklist→ options when serving field metadata, validate writes against the resolved set, apply package-level extensions (phase 1 of objectstack#18164) #19519, PR feat(objectql): resolve picklist references at runtime — served options, additive extensions, write validation, load-time refusal #21047.pnpm dev -- --fresh -p PORTreach oclif, or does the separator swallow the flags the port rule depends on? #11669.mainat8532783f,packages/spec/src/kernel/metadata-plugin.zod.ts:826registers thepicklistkind.6051363510.Dropped
6051363510left here. It was never filed. The maintainer's 「按组织追加 picklist 值,不考虑」 drops it.docs/adr/0131-total-organization-ownership-no-null-organization-id.md:105).Filed as #22869
docs/qa/platform-checklist/areas/records-forms.json:4372(records-forms.picklist-org-append,planned) anddocs/NORTH-STAR.md:43.records-forms.picklist-org-appendand the "customers append values per organization" promise — the per-organization picklist append is ruled out #22869 retires both.Reservation
session_016tKoy8NJa35Yih1FdzrVmnwas recorded unreachable in6006149092.pm:epicis removed in the same act.