Skip to content

docs: shared picklist — NORTH-STAR feature line, two planned records-forms items, coverage waiver; upgrade skill stops claiming a connector sync ran - #20938

Merged
os-zhuang merged 3 commits into
mainfrom
claude/issue-19518-picklist-docs
Sep 30, 2026
Merged

os-zhuang merged 3 commits into
mainfrom
claude/issue-19518-picklist-docs

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Part of #19518

The Tier H docs follow-up for the shared picklist: the section "Also with this card" on the card, plus one skills correction carried from #20281 under ruling 5916259513. The card stays open until this lands; the seat closes it by hand. Five files, no package source, nothing published from any package.

What changes

  1. docs/NORTH-STAR.md: one new line in step ② 「本地跑起来、看到」, records axis, with the card's text verbatim: records · 共享选项集:多个对象复用同一份选项,客户按组织追加值而不改应用源码 · records-forms · picklist-shared-across-objects, picklist-org-append. It sits after the last existing records row (search), so it ranks below every records capability that already exists. Moving it up is a priority call for the maintainer.
  2. docs/qa/platform-checklist/areas/records-forms.json: two new items, both status: "planned", since: null, P2, with no steps (README, "Implementation status"):
    • records-forms.picklist-shared-across-objects covers phase 1. One picklist on two objects: both are served the same resolved options, a package picklistExtensions value reaches both, the write door refuses a value outside the set, and a locale switch relabels the options. It carries three drafted acceptance clauses taken from the design of record and from the acceptance sentence of 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, so the runtime PR has a concrete target when it promotes the item.
    • records-forms.picklist-org-append covers phase 2. Organization A appends a value without editing the app source, A can write it, and organization B is refused. It carries no acceptance clauses, because the overlay's schema and write door are not designed. A knownGaps entry records that the overlay is not declared: the picklist registry row has allowOrgOverride: false, and ruling 5904864936 defers the overlay to its own sub-issue.
  3. docs/qa/platform-checklist/coverage.json: picklist gets a waiver. It was UNCLASSIFIED. The waiver states the measured reason: packages/spec/liveness/picklist.json grades every key planned, and check-stack-collection-maps holds picklists and picklistExtensions as PENDING rows for 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. It names both planned ids and states what retires the waiver.
  4. skills/objectstack-upgrade/references/examples-upgrade.md: the worked R1 walks a protocol-16 connectors[].fieldMappings[].transform source. Since feat(spec)!: connector-attached sync leaves the connector — syncConfig / fieldMappings retired, mapping gains the connectorSource pull binding (#20281 stage 1) #20903 (0efbdc3), the chain removes the whole of fieldMappings after transform (connector-sync-keys-removed, toMajor 18, part of the default os migrate meta --from 16 terminus), and the author meets that key's tombstone. Three sentences said otherwise, and each now says what is true:
    • "the parse error is the prescription" pointed at a transform tombstone. It now names the fieldMappings tombstone.
    • "the connector has been landing raw values for as long as it has been running" is now "no connector sync ever ran, so no value ever passed through this mapping".
    • The report template's "connector sync run against staging, 200 rows" is now "nothing ever read the key, so no data changes".
    • The report template's chain line now reads 16 → 18, the chain the default run replays.
  5. scripts/check-platform-checklist.mjs: four sentences (three comments and the self-test success line) said the live ledger carries zero planned items. They now say that no coverage.json entry maps a planned item.

How behaviour that does not exist yet is represented

The checklist's own rules settle the status. planned is for a capability the definition requires and the platform does not implement or verify yet. A planned item never runs and is never coverage. Both items are planned: no runtime reads a picklist yet.

The coverage rule also settles the waiver. A kind whose only items are planned is UNMAPPED, and the gate's instruction is "Add an item that RUNS, or waive the kind with a reason". An entry cannot hold both, so the planned ids are named in the waiver's prose. One consequence: checklist-select capability:picklist matches nothing until the waiver flips to items.

Two content choices are the rules' to leave open. The dev report asks about both:

Skill readings (skills/**)

reading before (aaad682) after (cab0e1b)
examples-upgrade.md lines 119 119
examples-upgrade.md bytes / tokens (ceil(bytes/4), ceiling 1197) 4788 / 1197 4751 / 1188
package: all 10 SKILL.md, lines 4394 4394
token ratchet, authored total 143461 143452

The additions are paid for by deleted content. Nothing was re-wrapped to buy lines. The ceiling stays 1197, with headroom 9. Lowering it is a separate edit to the ratchet script.

Local verification, at cab0e1b

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derives 43 families from the five paths. All 43 ran; --ran answers "43 derived famil(ies) accounted for — 43 run, 0 NOT-MEASURED", exit 0.
    • 42 families exit 0. check:platform-checklist exits 1 on the pre-existing anchor below.
    • check:pm-dispatch-gates exits 0 (1976 self-test cases).
    • check:doc-formula-expressions first exited 3 (PREREQUISITE NOT MET: no lint or formula dist). After a locked build of those two packages it exits 0.
  • pnpm check:platform-checklist exits 1, the same as on origin/main:
    • before, 2 problems: coverage.json · picklist: UNCLASSIFIED and areas/identity-auth.json: ABSENT SYMBOL … auth-plugin.ts#twoFactor;
    • after, 1 problem: the same twoFactor anchor, which this diff does not touch;
    • the 5 anchors this diff adds resolve.
  • pnpm gen:checklist-status lists records-forms as 40 active and 2 planned (264 active and 2 planned overall).
  • node scripts/check-skills-token-ratchet.mjs exits 0: "examples-upgrade.md is 1188 tokens (ceiling 1197; headroom 9)".
  • node scripts/pm/check-governed-merges.mjs --branch HEAD exits 3, GOVERNED, landing tier H. Two of five paths hit the register (skills/**, docs/NORTH-STAR.md). The diff is +119 / -17.
  • No changeset: the diff releases nothing, because skills/ ships through npx skills add and appears in no package's files[]. skip-changeset is applied.

Acceptance notes

维护者速读(草稿)

终稿以席位在本 PR 上的「维护者速读(终稿)」评论为准;下面与终稿一致。

改了什么:

  • 北极星「路上的功能点」第②步 records 组末尾,加一行「共享选项集」,文字照卡片原文。
  • 平台测试清单加两个 planned 项(已计划,还不能跑):
    • 第一期:一份选项集两个对象共用、包扩展加值、越界值被拒、切语言换标签;
    • 第二期:组织自己追加值、本组织能写、别的组织被拒。
  • coverage.json 给 picklist 记一条带理由的豁免。
  • upgrade 技能示例改正三句话,报告模板里的迁移链改成 16 → 18。第一句原本把处方指向一个已不存在的 transform 墓碑;第二、三句说连接器同步跑过、落过数据,实际从来没有引擎跑过。
  • 清单门禁脚本里有四处说「清单里没有 planned 项」(注释和自测提示语),改成与现状相符。

为什么改:

风险与代价(含回滚):

  • 只改了文档、一份对外技能参考文件,以及一个门禁脚本的注释和自测提示语;不动任何包,不发版。技能文件仍是 119 行,token 从 1197 降到 1188。
  • 回滚就是 revert 三个提交。回滚后,清单门禁会重新报 picklist UNCLASSIFIED。
  • 两个版本都过了档位审查(8e7420019e 和 cab0e1b557),CI 全绿。

席位意见:

  • 建议合并。
  • 下面三处您合并时可以顺手改:
    ① 「客户按组织追加值」(第二期)现在就写进路线图和清单,作为 planned 需求。席位意见是保留:文字是卡片原文,planned 不算覆盖,也不宣称已经做到。但裁决 5904864936 说的是等有实测的客户需求再立子卡。您若不想现在就把它放上路,删掉那一行的后半句和第二个清单项即可。
    ② 「切语言换标签」放在第一期的项里(卡片原来归在第二期)。它在第一期就会交付,放在第二期要等很久才能验证。席位同意这样放。
    ③ 新行放在 records 组最后,排序最低。这张表的顺序就是优先级,您想提前就挪一下位置。

你要做的:

  • 合并本 PR。这是 Tier H,需要您亲手合并;或者给出授权的 APPROVED,由席位落地。

Generated by Claude Code

…ed records-forms items, coverage waiver

The feature-map line for the shared picklist joins step 2's records rows and
names two new records-forms items, both `planned`: the spec layer landed but no
runtime reads a picklist yet, so neither item has anything to drive. The
picklist kind is waived in coverage.json with the measured reason and the
condition that retires the waiver.

Claude-Session: https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1
Co-authored-by: Claude <noreply@anthropic.com>
The worked R1 in the upgrade skill's examples walks a protocol-16
`connectors[].fieldMappings[].transform` source. Since the connector sync
keys retired, the chain removes all of `fieldMappings` after the `transform`
key, and the tombstone the author meets is that key's. The example said the
connector had been landing raw values and its report template verified the
decision with a "connector sync run"; no engine ever ran a connector-attached
sync, so both now say what is true. The file shrinks by 37 bytes (1197 to
1188 tokens) at the same 119 lines.

Claude-Session: https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 8e7420019e7983018da0b8f77979740a58a5e8dc
Local-runs: none

① Derived judgments

Shape of the diff. Four files, +111 / −9, net against merge base aaad682dbc (identical against origin/main at 1571aedce5): docs/NORTH-STAR.md (+1), docs/qa/platform-checklist/areas/records-forms.json (+98), docs/qa/platform-checklist/coverage.json (+3), skills/objectstack-upgrade/references/examples-upgrade.md (+9 / −9). No package source, no accept-set change, no public surface change. What the diff does imply: the checklist ledger carries its first two planned items (0 → 2; gen:checklist-status and checklist-select now have a planned population), and coverage.json carries its second waiver beside realtime_subscription. Both JSON files parse at the head; ids are unique.

A. docs/NORTH-STAR.md row — right. Follows line 13's own format 轴 · 功能点(业务语言) · 清单区 · 项 id; the text is the card's "Also with this card" sentence verbatim with the two ids filled in; the unprefixed ids resolve under the preceding 清单区 records-forms and both exist at the head; no number is added (本页不带任何数字). It sits last among the step ② records rows — the row order is the priority order (「改它即改优先级」), so the placement is the maintainer's; the PR body says so. The row's second half (客户按组织追加值) names the per-organization overlay that ruling 5904864936 defers to a sub-issue on a measured customer requirement; the card dictated the text and the PR escalates the half to the maintainer — see ③.

B. records-forms.picklist-shared-across-objects — right. Obeys every planned rule of the README and scripts/check-platform-checklist.mjs (statusFieldProblems): since: null, status: "planned", no steps key, personas present, revision 1 equals the last history revision, P2, mixed. Its three drafted acceptance clauses are allowed on a planned item and are still validated (each has clause, oracle: api, verify, evidence). The five anchors resolve on main as line-start declarations: packages/spec/src/data/picklist.zod.ts#PicklistSchema (line 64), #PicklistExtensionSchema (114), #PicklistServedFieldSchema (156), packages/spec/src/system/i18n-resolver.ts#translateObject (2767), and — on the sibling item — packages/spec/src/kernel/metadata-plugin.zod.ts#DEFAULT_METADATA_TYPE_REGISTRY (714). Anchors are shrink-never, so adding five reds nothing. Content against the sources it cites: clause 1 (both objects served the same resolved options beside the picklist name) is design-of-record item 3 plus the served schema; clause 2 (the extension's value persists on A, an out-of-set value is refused on B, the refusal names the picklist) is #19519's acceptance sentence and its Scope item 3 word for word; clause 3 (locale relabel via picklists.NAME.options.VALUE, values unchanged) is the fallback translateObject performs at i18n-resolver.ts 2802-2812; the four negatives restate design item 3 and #19519 items 1-2 (loud unknown-name refusal, additive-only, duplicate refused not last-wins). "Stock showcase has none of these" is true: examples/app-showcase carries only the coverage.ts waivers for picklist / picklistExtensions. The item claims no behaviour the tree lacks — it says the runtime layer has not landed. One phrase is over-broad: "nothing outside packages/spec reads a picklist yet". packages/cli/src/utils/i18n-extract.ts (walkPicklists, landed with #20823) walks picklists and picklistExtensions to emit translation keys, and packages/lint reads the field ledger's picklist row. The operative claim — no code resolves a picklist onto a field or judges a write against one — is true on main; the phrase is the liveness ledger's own wording (packages/spec/liveness/picklist.json), inherited. True in the ledger's sense (no runtime reader of the key's behaviour); narrow it at the next edit.

C. records-forms.picklist-org-append — right. planned, no acceptance (allowed: "no oracle to consult yet"), two personas, since: null. The knownGaps entry is true on main: the registry row at metadata-plugin.zod.ts 825 carries allowOrgOverride: false; ADR-0005 line 47 makes allowOrgOverride the authoritative whitelist (the one opt-in); ruling 5904864936 defers the overlay "to its own sub-issue on a measured customer requirement". Sources are right: design item 4 (the overlay left as the maintainer's open point), item 6 (the verification sentence: org A adds, A writes, B refused), #19518 Scope 5 (⛔ not declared here), and ADR-0005 cited bare as a .md must be. The three negatives restate design item 4. It claims nothing the tree has: it says NOT DECLARED.

D. coverage.json picklist waiver — right, and the form the rule demands. The gate accepts EITHER non-empty items OR a non-empty waived string, never both (script 2957-2961). Listing the two planned ids under items is legal but leaves the kind UNMAPPED and red (coverageEntryProblems: "Add an item that RUNS, or waive the kind with a reason"); the waiver is the rule's sanctioned debt marker, and it names both planned ids in prose and states what retires it (#19519 lands, the phase-1 item runs, passes, is promoted, and the same edit flips the entry to items). The reason is measured and true: packages/spec/liveness/picklist.json grades every property planned; scripts/check-stack-collection-maps.mjs holds picklists / picklistExtensions as PENDING rows inside the METADATA_ARRAY_KEYS site (line 624) and the ARTIFACT_FIELD_TO_TYPE site (line 690), both naming #19519; SWEEP.md asks every waiver to be re-audited each sweep. Same over-broad "nothing outside packages/spec reads a picklist" phrase as B, same verdict. The entry mirrors the realtime_subscription waiver's shape and dating.

E. examples-upgrade.md — each rewritten sentence against the tree after #20903 (0efbdc3421).

  1. "The chain deletes the key (field-mapping-transform-removed), then all of fieldMappings (connector-sync-keys-removed), whose tombstone is the prescription: nothing ever ran any connector field mapping." — field-mapping-transform-removed is toMajor: 17 and strips transform (conversions/registry.ts 4663); connector-sync-keys-removed is toMajor: 18 and strips syncConfig + fieldMappings whole (10190-10206). The default terminus of os migrate meta --from 16 is max(PROTOCOL_MAJOR 17, MIGRATION_MAJORS) = 18 (cli migrate/meta.ts 88; MIGRATIONS_BY_MAJOR has an 18 entry), so the default run performs both, in that order. The tombstone a 16-era source meets is FIELD_MAPPINGS_RETIRED (connector.zod.ts 240-247): "no engine ever moved a value through a connector field mapping" — the sentence's bold clause is the tombstone's. No transform tombstone is reachable any more: ConnectorFieldMapping left whole at 18 and the shared FieldMapping tombstone at shared/mapping.zod.ts 93 has no extender — so the old "the schema tombstones it" was false and the rewrite is true on main now. One over-breadth: "then all of fieldMappings" is unconditional, and holds at the default terminus; with --to 17 (SKILL.md's "stop at a specific major") the 18 step does not run and the source then fails the chain's own schema-valid check on the fieldMappings tombstone. The walkthrough's unchanged report template still reads "Protocol 16 → 17 upgrade", "Chain: 16 → 17" and "replay-from-17 applies 0 mechanical changes": for the worked example as now written those name a chain that excludes the step the rewrite adds — the CLI prints protocol 16 → 18 for the default run, and the replay applies 0 only once the 18-step edits are ported. Left inconsistent within the walkthrough, not false in the tree: the template is a shape, and the naming muddle (spec 17.x carrying protocol-18 steps; the tombstone itself says "removed in @objectstack/spec 17") is the tree's, which SKILL.md's own box at line 398 states. A one-clause fix; flagged in ③.
  2. "no connector sync ever ran, so no value ever passed through this mapping" — the D3 entry connector-sync-keys-retired and the tombstones say exactly this. True on main now.
  3. "nothing ever read the key, so no data changes" — the residue is transform; no runtime executed any of its five members (registry 4669-4673). True on main now.
    Unchanged sentences in the same walkthrough re-tested: table row 1 (import mapping transform string enum; REST runs none/constant/map/split/join, passes lookup to reference resolution, rejects javascript 400) holds at packages/rest/src/import-mapping.ts 21, 44, 107-110; row 2 ("the L2 ETL layer retired at 17, unexecuted") holds — semantic 17.etl-pipeline-layer-retired and retired def 17.automation__ETLDestination; "The prescription names one live target" holds — the fieldMappings tombstone names mapping.fieldMapping; the SKILL.md pointer at line 269 names this section's unchanged heading; evals/protocol-major-upgrade.json eval 3 (unchanged) claims no sync run and stays true. Readings verified from git objects: bytes 4788 → 4751, lines 119 → 119, tokens ceil(bytes/4) 1197 → 1188 under the ratchet ceiling 1197 (check-skills-token-ratchet.mjs 584), all ten SKILL.md files 4394 → 4394 lines; the authored-total delta of −9 is the one changed skills file. The two reflowed paragraphs stay four lines each — no line bought by re-wrap. No tracker number entered the rewritten text.

F. The PR body as text the maintainer acts on. "#20903 (0efbdc3)", "toMajor 18, part of the default os migrate meta --from 16 terminus", "the author meets that key's tombstone": all true. "no code outside packages/spec reads a picklist" — the over-broad phrase of B, true in the ledger's sense. The check:platform-checklist red on main for areas/identity-auth.json line 1599's auth-plugin.ts#twoFactor is pre-existing (no line-start twoFactor declaration in that file) and untouched. "No ADR-0136 exists in this repository's registry": 0 files, 0 hits. The Acceptance note on the stale "zero planned items" prose in scripts/check-platform-checklist.mjs (lines 660, 1081, 1342) is accurate. 「改它即改优先级」 is quoted verbatim. The session-URL footer is present. 维护者速读(草稿): the five fixed sections are present and 席位意见 is left empty as os-dev.md line 287 requires; "token 从 1197 降到 1188", "回滚是 revert 两个提交" (2c41e486c8, 8e7420019e), "回滚后清单门禁会重新报 picklist UNCLASSIFIED" and "北极星优先级第 4 条" (line 115) are all true. Two things for the seat's final: 「你要做的」 lists two bullets where the rule says one action (pm-dispatch line 191); and 「那几句说连接器同步跑过、落过数据」 over-describes — only sentences 2 and 3 claimed a sync ran or landed data; sentence 1's fault was a prescription pointing at a transform tombstone that no longer exists.

② Semver level

The diff publishes nothing from any package: docs/NORTH-STAR.md and docs/qa/** are in no package's files[]; skills/** ships through npx skills add objectstack-ai/objectstack/skills (skills/README.md line 9) and no package.json files[] names skills; no .changeset/*.md is touched. skip-changeset is right (os-dev.md 298-299: the fast lane for surfaces that do not publish), and the Check Changeset run is skipped on that label. The absent Clause-②: line is right — the claim's Clause-②: yes belongs to #20823's spec layer, which landed as addbbf02ab; this diff widens and narrows nothing.

③ Boundary flags

Dev report 5919353754 (branch claude/issue-19518-picklist-docs, head 8e7420019e): no deviations key — the report template carries none and no refused write was reported, so none is owed. Its three open_questions and four out_of_scope_findings, each answered or escalated:

Reviewer flags, none blocking: (i) sentence 1 of the skill rewrite versus the template's "Chain: 16 → 17" (E.1) — one clause naming the chain's default terminus, or the template's chain, can ride this PR before the hand-off; every claim is true on main for the default run today; (ii) "nothing outside packages/spec reads a picklist" in the item history, the waiver and the PR body — narrow to "no runtime reader" at the next edit (the CLI's walkPicklists is a reader); (iii) the 速读 final: one action under 「你要做的」, and the sentence-1 description corrected (F).

Check-runs on 8e7420019e7983018da0b8f77979740a58a5e8dc, read last, 39 runs deduped by name keeping the newest started_at → 31 names: 21 success, 10 skipped, 0 failure, 0 still running. Success: Check Documentation Links, Dogfood Regression Gate (roster), Governed Surface Queue Guard, Lint & Repo Gates, No other open PR may claim the same issue, No other open PR may claim the same single-writer path, Part-of PR must not also close its card, Test Core (roster and 1/6 to 6/6), The card this PR closes must claim this branch, Type Check · consumer gates / debt ledger / source gates / workspace, TypeScript Type Check, filter. Skipped: Auto Label, Build Core, Build Docs, Check Changeset (on the skip-changeset label), Check PR Size, Console Pin Gate, the Dogfood Regression Gate matrix-shard template name, Dogfood Verify CLI, Packed-tarball smoke (opt-in), Temporal Conformance (live PG + MySQL). The conclusions are the gate verdicts: nothing red.

Implemented-by: claude/issue-19518-picklist-docs
Reviewed-by: session_01Sfe5YjBLwB9J3y8fvm2xq1

VERDICT: PASS

Adopted and posted by domain:spec seat 5 (session_01Sfe5YjBLwB9J3y8fvm2xq1) · 2026-09-30T21:16Z · rendered by the seat's at-tier review subagent on this head. The seat read its served tier family from the subagent transcript before posting.

  • The ACCEPT waits for one cut round, so the maintainer reads a PR with no known false sentence. The cuts are flags (i), (ii) and (iv):
    • (i) One clause, so the rewritten sentence 1 holds for the walkthrough's own chain line, not only at the default terminus.
    • (ii) "Nothing outside packages/spec reads a picklist" is narrowed wherever the diff says it (records-forms.json history, coverage.json waiver), because the CLI's walkPicklists is a reader. The claim is about runtime.
    • (iv) The carrier is this PR. The three "zero planned items" sentences in scripts/check-platform-checklist.mjs (≈:1059, :2280, :2541) are false once this PR's two planned items land.
  • (iii) The seat writes the final 维护者速读 itself at ACCEPT, with one action under 「你要做的」. The draft in the body is corrected then.
  • Re-review: the delta gets an at-tier review at the new head, because it touches skills/**.
  • Tier H hand-off at that PASS, in one act: the final 速读 comment, needs-user-decision on this PR, and review requests to both authorized approvers. The PR stays draft, and the maintainer merges.

Generated by Claude Code

…ime reads a picklist", and the checklist gate stops saying the ledger has no planned items

- The upgrade walkthrough's report template names the chain the default run
  replays (16 -> 18), so it matches the rewritten sentence that the chain
  removes all of `fieldMappings`.
- The picklist item's history and the coverage waiver said nothing outside
  packages/spec reads a picklist; the CLI's i18n walk does. Both now say no
  runtime reads one.
- Four sentences in scripts/check-platform-checklist.mjs said the live ledger
  carries zero planned items. It now carries two, none mapped in coverage.json,
  so they now name that condition instead.

Claude-Session: https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: cab0e1b55757d85cde8cf64f1602ea1ee4e95372
Local-runs: none

① Derived judgments

Shape of the delta. One commit, cab0e1b557, appended linearly on 8e7420019e (no main merge, no rebase: cab0e1b557 → 8e7420019e → 2c41e486c8 → aaad682dbc, the merge base). git diff 8e7420019e cab0e1b557 touches four files, +10 / −10: one phrase in docs/qa/platform-checklist/areas/records-forms.json (:4234), the same phrase in docs/qa/platform-checklist/coverage.json (:229), four places in scripts/check-platform-checklist.mjs (:1059, :2280, :2541, :2622), and one line in skills/objectstack-upgrade/references/examples-upgrade.md (:47). Every hunk belongs to flag (i), (ii) or (iv) of the adoption 5919896214; nothing outside the three flags changed. The whole PR at the head: five files, +119 / −17 against the merge base aaad682dbc, and byte-identical against origin/main at f80e2a6dad on those five paths (git log aaad682dbc..origin/main over them is empty). No package source, no accept-set change, no public-surface change; the one new path, scripts/check-platform-checklist.mjs, changes three comments and one printed self-test string — no assertion, no verdict logic, no gate rule. The commit's trailer pair is the model-free form the pre-push hook requires.

Cut (i) — the template chain line 16 → 17 to 16 → 18 — right, and it makes the walkthrough consistent without making another sentence false. The default terminus of os migrate meta --from 16 is CHAIN_TERMINUS_MAJOR = Math.max(PROTOCOL_MAJOR, ...MIGRATION_MAJORS) (cli migrate/meta.ts :88, applied at :544 as flags.to ?? CHAIN_TERMINUS_MAJOR); PROTOCOL_VERSION is '17.0.0' (spec kernel/protocol-version.ts :18) and MIGRATIONS_BY_MAJOR carries exactly the keys 17 and 18 (spec migrations/registry.ts :18837-18840), so the default run replays 16 → 18 and performs field-mapping-transform-removed (toMajor 17, conversions/registry.ts :4663) then connector-sync-keys-removed (toMajor 18, :10191) — which is what the rewritten sentence 1 of § 2.3 says the chain does. SKILL.md's own box states the same default in words (:410-413: --to defaults to the highest major this build carries a step for, one PAST the installed major for most of a release line), so the template now agrees with the skill it belongs to. The walkthrough heading "Protocol 16 → 17 upgrade" stays true: it names the upgrade by the installed spec major, the way SKILL.md itself does (upgrade/protocol-17 at :110, "The v17-canonical shapes"), and the box is where the reader learns why the chain reaches one past it. "replay-from-17 applies 0 mechanical changes" stays true: SKILL.md :74 and :162 spell that acceptance as os migrate meta --from 17 with applied empty, and once the 18-step edits are ported from --out (the fieldMappings deletion among them) the 17 → 18 hop rewrites nothing. The prior record's residue — sentence 1 is unconditional while an explicit --to 17 (SKILL.md :128) would stop before the 18 step — no longer makes the walkthrough disagree with itself: every line of it now describes the default run. Readings from the git objects: 4751 bytes and 119 lines at both 8e7420019e and cab0e1b557 (a same-length edit), so the ratchet reading (1188 tokens under the 1197 ceiling, check-skills-token-ratchet.mjs :584) is unchanged. One thing that is the tree's, not this PR's: SKILL.md :407 spells the replay as --from the target major while :74 and :162 spell --from 17; with the terminus at 18 those two spellings compose different chains. SKILL.md is untouched by this PR and is Tier H; noted, no carrier owed here.

Cut (ii) — "nothing outside packages/spec reads a picklist" narrowed to "no runtime reads a picklist" in the item history (:4234) and the waiver (:229) — right, and true on main when this lands. Measured at the head over every package's non-test sources outside packages/spec (git grep -i picklist over packages/*/src and packages/*/*/src, tests and generated bundles excluded): the only readers of picklists / picklistExtensions / a field's picklist key are the CLI — packages/cli/src/utils/i18n-extract.ts (walkPicklists, :1607-1629, emits translation keys) and packages/cli/src/utils/i18n-coverage.ts (the picklist bucket) — which is tooling, not runtime. In the runtime packages the word occurs only in comments (objectql/src/engine.ts :5815, rest/src/rest-server.ts :10496, metadata-core/src/object-schema-fls.ts :14, plugins/plugin-audit/src/audit-writers.ts :463 and :573, drivers/driver-sql/src/sql-driver.ts :11113), in drivers/driver-sql/src/builtin-column-collision.ts :107, which classifies the field KEY picklist as a presentation key that emits no DDL and never reads a picklist, and in a generated form label (platform-objects en.metadata-forms.generated.ts :926). core, metadata, metadata-protocol, runtime, services/*, adapters/*, client*: zero hits. No runtime package resolves a picklist onto a field or judges a write against one — the operative claim of both sentences — and the sources each cites still hold on origin/main: packages/spec/liveness/picklist.json grades all ten properties status: "planned", and scripts/check-stack-collection-maps.mjs :624-626 carries picklists / picklistExtensions as rows PENDING #19519. The sentence turns false exactly when #19519 lands, which is what the waiver's own WHAT-RETIRES clause says. The inherited over-broad phrase still lives in the liveness ledger's notes ("No code outside packages/spec reads a picklist yet", packages/spec/liveness/picklist.json) — outside this PR's surface; it is #19519's re-verify edit's to change.

Cut (iv) — the four scripts/check-platform-checklist.mjs sentences — right, each true on this head. What the gate and the ledger do at cab0e1b557, measured over the git objects: the areas carry 268 items — 264 active, 2 retired, 2 planned (both in records-forms.json); coverage.json maps no planned id under any kind's items — the picklist entry is a bare waived string, and the walk at :2965 calls coverageEntryProblems(entry.items, statusOf) only over an entry's items, so the coverage half of the planned rule is reached by no live data. Hence (:1059) "no coverage.json entry maps a planned item today, so nothing but these fixtures can tell a working ratchet rule from a deleted one" — true; (:2280) "no coverage.json entry maps a planned item, which means the real data cannot tell 'this rule works' from 'this rule was deleted'" — true; (:2622) "Its schema half is exercised by the tree the moment anyone authors a planned item; its COVERAGE half is not, and will not be while no coverage.json entry maps a planned item" — true, and the schema half now IS exercised by the tree, which the sentence allows for; (:2541) the success string lost "rather than on a ledger that carries none of it" and now says "driven on fixtures —", which is true whatever the ledger carries. The old phrases are pinned nowhere: git grep at the head for "rather than on a ledger that carries none of it", "carries ZERO planned items", "planned count is the 0 this gate prints" and "zero planned items" each returns nothing, and no *.test.* names the script (package.json :119 runs its --self-test inside check:platform-checklist, which Lint & Repo Gates ran green). Two residues in the same string and battery, both over-broad by exactly the two planned items and both non-blocking: the success line's "while the ${plannedStatus.liveItems} live items are judged exactly as before" — liveItems (:2300-2305) counts every item, planned ones included, and the two planned items are judged under the relaxation, not as before (the dev disclosed this in the cut-round report; the fix is one phrase, "the non-planned live items", or a count that subtracts them); and the untouched F13 label at :2333, "this battery did not widen a requirement onto the ${liveItems} live items", which the personas requirement F8 imposes on the two planned items. Cosmetic: the :2622 edit leaves a short line ending "a planned item. A" before the wrapped continuation.

The prior record's judgments, re-read at the new head. A (the NORTH-STAR row): the delta does not touch docs/NORTH-STAR.md, and main has not touched it since the merge base — stands verbatim. B and C (the two items): only the one history phrase of B changed; ids, statuses, since: null, no steps, personas, the acceptance clauses, the negatives, the sources, the five symbol anchors and the knownGaps entry are byte-identical, and the registry row (metadata-plugin.zod.ts :825, allowOrgOverride: false) still holds on origin/main — stand. D (the waiver): one phrase changed, the form (a bare waived string, no items) unchanged — stands. E (the skill file): only the chain line changed; bytes, lines and the token reading are identical, so E's readings and its sentence-by-sentence verdicts stand, with the E.1 residue closed above. ② is untouched by the delta.

The PR body at the new head — every sentence false, stale or contradicted (the seat writes the edits at ACCEPT).

  1. Paragraph 1, "Four files, no package source, nothing published from any package." — "Four files" is false: five. The rest is true.
  2. "## What changes" — carries no item for scripts/check-platform-checklist.mjs, and item 4's list of edits omits the template chain line (its "Three sentences said otherwise" is true as far as it goes). Omissions, not false sentences.
  3. "## How behaviour that does not exist yet is represented", "Both items are planned: no code outside packages/spec reads a picklist yet." — over-broad (the CLI's walkPicklists reads them), and it now contradicts the diff's own wording ("no runtime reads a picklist yet").
  4. "## Skill readings" — the column head "after (8e74200)" names the old head; every value in it (119 lines, 4751 bytes, 1188 tokens, 4394 SKILL.md lines, 143452) is unchanged at cab0e1b557. Stale label, true values.
  5. "## Local verification, at 8e74200" — the heading and three sentences describe the old head only: "derives 25 families from the four paths. All 25 ran; --ran answers '25 derived famil(ies) accounted for — 25 run, 0 NOT-MEASURED'"; "24 families exit 0"; "Two of four paths hit the register"; "The diff is +111 / -9". At cab0e1b557 the paths are five, the diff is +119 / −17 (measured), and the cut-round report's own numbers are 43 families, 43 run, 42 exit 0, two of five paths. The remaining bullets (check:platform-checklist exits 1 on the pre-existing twoFactor anchor alone; 40 active and 2 planned in records-forms, 264 active and 2 planned overall — the retired pair is not counted as active; the ratchet at 1188; no changeset) are still true.
  6. "## Acceptance notes", bullet 1 — false at the new head in three ways: the --self-test success line no longer says "driven on fixtures rather than on a ledger that carries none of it" (0 hits at cab0e1b557); the stale prose was four places, not the line plus two comments; and "Carrier: none" is now "this PR (cab0e1b557)".
  7. 速读 改了什么, bullet 3, "upgrade 技能的示例里删掉三处不实的话。那几句说连接器同步跑过、落过数据…" — over-describes sentence 1 (its fault was a prescription pointing at a transform tombstone that no longer exists; only sentences 2 and 3 claimed a sync ran or landed data) and omits the chain-line edit, so the file now carries four changed hunks, not three.
  8. 速读 风险与代价, bullet 1, "只改文档和一份对外技能参考文件,不动任何包。" — the first clause is false at the new head: a root gate script, scripts/check-platform-checklist.mjs, is also edited (three comments and one printed line). "不动任何包" stays true.
  9. 速读 风险与代价, bullet 2, "回滚是 revert 两个提交。" — false: three (2c41e486c8, 8e7420019e, cab0e1b557). "回滚后清单门禁会重新报 picklist UNCLASSIFIED" stays true.
  10. 速读 你要做的 — two bullets where the rule says one action (pm-dispatch SKILL.md :191). Not false; flag (iii), the seat's at ACCEPT.
    Still true and re-checked: "Since feat(spec)!: connector-attached sync leaves the connector — syncConfig / fieldMappings retired, mapping gains the connectorSource pull binding (#20281 stage 1) #20903 (0efbdc3)" is feat(spec)!: connector-attached sync leaves the connector — syncConfig / fieldMappings retired, mapping gains the connectorSource pull binding (#20281 stage 1) #20903's merge commit; "toMajor 18, part of the default os migrate meta --from 16 terminus"; "The Path: lines on picklist metadata kind — spec: picklist collection, Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518 and 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 still read 清单项待写" (both bodies, verified); "No ADR-0136 exists in this repository's registry" (0 files, 0 hits at the head); eval 3 of protocol-major-upgrade.json is not in the file list; the session-URL footer is present.

② Semver level

Unchanged by the delta and re-checked at the head: the five paths are docs/NORTH-STAR.md, docs/qa/**, scripts/** and skills/** — the root package.json is private: true with no files[], skills/** ships through npx skills add and appears in no package's files[], and no .changeset/*.md is touched. The diff publishes nothing from any package, so skip-changeset is right (Check Changeset is skipped on the label) and the absent Clause-②: line is right — this diff widens and narrows nothing; the claim's Clause-②: yes belongs to the spec layer that landed as addbbf02ab.

③ Boundary flags

Cut-round report 5920221459 (branch claude/issue-19518-picklist-docs, head cab0e1b557): no deviations key — the template carries none, and the one declared non-action is right: "(iii) The PR body was NOT edited" follows .claude/agents/os-dev.md :59 (the dev writes the body once at pr_create, never PATCHes; the seat writes later edits), and the adoption 5919896214 already reserves the final 速读 to the seat at ACCEPT. Its one open_questions entry and one out_of_scope_findings entry:

  • OQ-1 — the body edits E1 to E8, applied by the seat at ACCEPT together with the final 速读 (dev: A). A, answered. E1 to E8 are each right and each maps onto a sentence named above (E1 → 1, E2 → 2, E3 → 3, E4 → 5, E5 → 6, E6 → 7, E7 → 10, E8 → 9). Two the list does not carry: E9 — 速读 风险与代价 bullet 1 (item 8 above) must also name the gate script (e.g. 「只改文档、一份对外技能参考文件和一个门禁脚本的注释与自测提示语,不动任何包」); E10 — the "Skill readings" column head (item 4) should name cab0e1b557 or say the values are unchanged there. B (a dev PATCH) is not needed.
  • OOS-1 — the stale "zero planned items" prose, carrier now this PR, closed in cab0e1b557. Verified: four places corrected, none pinned elsewhere, the gate's self-test green in CI. Answered. The two residual over-breadths named under cut (iv) (the success line's "N live items … exactly as before" and the F13 label, both by the two planned items) are the same class in miniature; non-blocking, one phrase each, the seat's call whether they ride a later edit.

The prior record's flags at 8e7420019e: (i) closed by the chain line; (ii) closed in both places the diff says it (the PR body's copy is item 3 above, the seat's at ACCEPT); (iv) closed, with a fourth sentence the adoption had not counted (:2622) corrected too; (iii) still open by design — the seat's final 速读 at ACCEPT, one action under 「你要做的」 and the sentence-1 description corrected. Prior Q1 (the organization-append half on the road) stays escalated to the maintainer, unchanged by the delta; prior Q2, Q3, OOS-2, OOS-3 and OOS-4 stand as answered.

Check-runs on cab0e1b55757d85cde8cf64f1602ea1ee4e95372, read last: 31 runs, 31 names after deduping by name on the newest started_at (no name repeats): 23 success, 8 skipped, 0 failure, 0 still running (the Lint & Repo Gates run the cut-round report saw in progress completed 21:46:58Z, success). Success: Auto Label, Check Documentation Links, Check PR Size, Dogfood Regression Gate (roster), Governed Surface Queue Guard, Lint & Repo Gates, No other open PR may claim the same issue, No other open PR may claim the same single-writer path, Part-of PR must not also close its card, Test Core (roster and 1/6 to 6/6), The card this PR closes must claim this branch, Type Check · consumer gates / debt ledger / source gates / workspace, TypeScript Type Check, filter. Skipped: Build Core, Build Docs, Check Changeset (on the skip-changeset label), Console Pin Gate, the Dogfood Regression Gate matrix-shard template name, Dogfood Verify CLI, Packed-tarball smoke (opt-in), Temporal Conformance (live PG + MySQL) — the same skipped set as at the prior head. Of the seven required contexts, five are success and two (Build Core, Temporal Conformance) are path-filtered skips, as before. The conclusions are the gate verdicts: nothing red.

Implemented-by: claude/issue-19518-picklist-docs
Reviewed-by: session_01Sfe5YjBLwB9J3y8fvm2xq1

VERDICT: PASS

Adopted and posted by domain:spec seat 5 (session_01Sfe5YjBLwB9J3y8fvm2xq1) · 2026-09-30T21:56Z · rendered by the seat's at-tier review subagent on this head. The seat read its served tier family from the subagent transcript before posting. ACCEPT at cab0e1b557. The Tier H hand-off happens in this same act:

  • PR body: the seat applies OQ-1 A (E1–E8) plus E9 and E10, and the ten stale sentences this record names are corrected. The body's 速读 draft now matches the final version.
  • Final 维护者速读: posted as its own comment on this PR, in five sections with the seat's opinion filled and one action under 「你要做的」.
  • Labels and reviewers: needs-user-decision goes on this PR, needs:contract-review comes off the PR and picklist metadata kind — spec: picklist collection, Field.select({ picklist }), server-resolved options, translation face (phase 1 of objectstack#18164) #19518, and review is requested from both authorized approvers. The PR stays draft, and the maintainer merges.
  • Two residues stay (the self-test line's "N live items judged exactly as before" and the F13 label, each over-broad by the two planned items). Neither makes a claim about a delivery. They are recorded for the next edit to that gate script.

Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

维护者速读(终稿)· 2026-09-30T21:57Z

domain:spec seat 5(session_01Sfe5YjBLwB9J3y8fvm2xq1)。PR #20938 在 cab0e1b557,两轮档位审查都通过,CI 全绿。

改了什么:

  • 北极星「路上的功能点」第②步 records 组末尾,加一行「共享选项集」,文字照卡片原文。
  • 平台测试清单加两个 planned 项(已计划,还不能跑):
    • 第一期:一份选项集两个对象共用、包扩展加值、越界值被拒、切语言换标签;
    • 第二期:组织自己追加值、本组织能写、别的组织被拒。
  • coverage.json 给 picklist 记一条带理由的豁免。
  • upgrade 技能示例改正三句话,报告模板里的迁移链改成 16 → 18。第一句原本把处方指向一个已不存在的 transform 墓碑;第二、三句说连接器同步跑过、落过数据,实际从来没有引擎跑过。
  • 清单门禁脚本里有四处说「清单里没有 planned 项」(注释和自测提示语),改成与现状相符。

为什么改:

风险与代价(含回滚):

  • 只改了文档、一份对外技能参考文件,以及一个门禁脚本的注释和自测提示语;不动任何包,不发版。技能文件仍是 119 行,token 从 1197 降到 1188。
  • 回滚就是 revert 三个提交。回滚后,清单门禁会重新报 picklist UNCLASSIFIED。
  • 两个版本都过了档位审查(8e7420019e 和 cab0e1b557),CI 全绿。

席位意见:

  • 建议合并。
  • 下面三处您合并时可以顺手改:
    ① 「客户按组织追加值」(第二期)现在就写进路线图和清单,作为 planned 需求。席位意见是保留:文字是卡片原文,planned 不算覆盖,也不宣称已经做到。但裁决 5904864936 说的是等有实测的客户需求再立子卡。您若不想现在就把它放上路,删掉那一行的后半句和第二个清单项即可。
    ② 「切语言换标签」放在第一期的项里(卡片原来归在第二期)。它在第一期就会交付,放在第二期要等很久才能验证。席位同意这样放。
    ③ 新行放在 records 组最后,排序最低。这张表的顺序就是优先级,您想提前就挪一下位置。

你要做的:

  • 合并本 PR。这是 Tier H,需要您亲手合并;或者给出授权的 APPROVED,由席位落地。

Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 30, 2026 22:51
@os-zhuang
os-zhuang enabled auto-merge September 30, 2026 22:51
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 30, 2026
@os-justin
os-justin removed the request for review from hotlong September 30, 2026 22:53
Merged via the queue into main with commit c1602ba Sep 30, 2026
50 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-19518-picklist-docs branch September 30, 2026 23:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants