Skip to content

docs(skills): name the pluralLabel exception to "an extension can add but never remove" - #30722

Merged
os-zhuang merged 1 commit into
mainfrom
claude/project-thread-ki6fr1
Nov 6, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/project-thread-ki6fr1

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Elon · project thread

domain:skills#1 · os-elon-musk · session_016WV4cx4foyi3wUWBrRHCmF

Fixes #30466

Clause-②: no
Metadata-protocol: none

维护者速读

What changes

  • skills/objectstack-data/SKILL.md § Object Extension Model keeps "an extension can add but never remove" and names the one exception: a new label without pluralLabel clears the base plural unless a tenant authored it, so an author sets both.
  • The rule is read off origin/main, packages/objectql/src/registry.ts mergeObjectDefinitions: if (extension.pluralLabel === undefined && extension.label !== merged.label && !yields('pluralLabel')) delete merged.pluralLabel;, inside the extension.label !== undefined && !yields('label') branch. So the plural survives when the extension repeats the running label, when the tenant authored the plural (the ADR-0029 D9.2a yield), or when the tenant authored the label (the label itself yields).
  • Token payment, same file: the Lifecycle Hooks pointer line drops its parenthetical second link to references/data-hooks.md. That file is already linked from the catalog list (L46) and from the backfill paragraph (L160), so the parenthetical restated a link.
  • .changeset/30466-extension-plurallabel-exception.md: '@objectstack/skills': patch.

Tests

Docs-only. No behaviour changes, so no test or ablation applies.

Acceptance notes

  • Out of scope by the order, for the seat to raise for Tier H: ADR-0029 D9.2, docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md L472–473, "mergeObjectDefinitions merges fields additively (...) and has no expression for removal at all." Since PR fix(objectql,rest)!: serve an object an extension renames without the base's plural (#30391) #30459 it has one, for pluralLabel. No decision moves (the sentence argues about fields in an overlay); whether it gets an amendment note is the maintainer's.

Verification

Skills readings (lines and tokens):

  • skills/objectstack-data/SKILL.md: 464 → 465 lines; 6116 → 6122 tokens (ceiling 6123, headroom 7 → 1). Net +6 after the same-file deletion, inside the existing headroom. The ceiling row is not touched.
  • Whole package, all SKILL.md: 4534 → 4535 lines. Bundle total (whole shipped tree, ratchet reading): 226234 → 226240 tokens.

Gates, head a069bdb668 (dispatch-gates --commands, 44 derived families, plus pnpm lint):

  • 40 families exit 0, and pnpm lint exit 0. --ran reconciliation: "44 derived famil(ies) accounted for — 40 run, 4 NOT-MEASURED".
  • check:doc-formula-expressions first exited 3 (prerequisite); after turbo run build --filter=@objectstack/formula --filter=@objectstack/lint it exits 0.
  • NOT MEASURED: check:dts-closure, check:dual-build-cjs-loads, check:lean-entry-closure, check:sourcemap-no-sources-content. Reason: exit 3, they need a whole-tree build. They read package dist/ output, which this docs-only diff does not change; CI measures them.
COMMAND :: exit CODE record
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-doc-route-spelling.mjs --advisory :: exit 0
node scripts/check-doc-route-spelling.mjs --self-test :: exit 0
node scripts/check-dts-emitted.mjs --self-test :: exit 0
node scripts/check-empty-changeset.mjs --base origin/main :: exit 0
node scripts/check-empty-changeset.mjs --self-test :: exit 0
node scripts/check-skills-token-ratchet.mjs :: exit 0
node scripts/check-skills-token-ratchet.mjs --self-test :: exit 0
node scripts/ci/assert-turbo-remote-cache.mjs --self-test :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
node scripts/ci/prune-turbo-cache.mjs --self-test :: exit 0
node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0
node scripts/release-pending-publish.mjs --self-test :: exit 0
pnpm --filter @objectstack/spec run check:skill-docs :: exit 0
pnpm check:agent-test-spelling :: exit 0
pnpm check:changeset-gate-self-tests :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:closed-ceremony-text :: exit 0
pnpm check:corpus-claim-drift :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:doc-authoring :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:dts-closure :: exit 3
pnpm check:dual-build-cjs-loads :: exit 3
pnpm check:gitlink-declared :: exit 0
pnpm check:lean-entry-closure :: exit 3
pnpm check:merge-driver :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:pm-governed-merges :: exit 0
pnpm check:pm-skill-id-lint :: exit 0
pnpm check:published-files :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:role-word :: exit 0
pnpm check:skill-compatibility :: exit 0
pnpm check:skill-frame-sync :: exit 0
pnpm check:skill-identifier-liveness :: exit 0
pnpm check:sourcemap-no-sources-content :: exit 3
pnpm check:watch-hint-literal :: exit 0
pnpm --filter @objectstack/lint run check:doc-formula-expressions :: exit 0
pnpm lint :: exit 0

Generated by Claude Code

… but never remove"

An object extension that sets a new `label` and no `pluralLabel` clears
the base's `pluralLabel` from the served object. The Object Extension
Model sentence now names that exception. The token cost is paid in the
same file by dropping the Lifecycle Hooks pointer's duplicate link to
references/data-hooks.md.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WV4cx4foyi3wUWBrRHCmF
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface labels Nov 5, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · os-elon-musk · session_016WV4d1mkgEris4MHHLjtnk

Contract-review-claim: session_016WV4d1mkgEris4MHHLjtnk · head a069bdb · 2026-11-05T23:28Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · os-elon-musk · session_016WV4d1mkgEris4MHHLjtnk

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: a069bdb668fd1e49f78e3fa9a4d0e3ea58c3fe25
Local-runs: probe — node scripts/check-skills-token-ratchet.mjs run read-only in a throwaway git worktree under the scratchpad at the head and at origin/main (badf24d), to confirm the 6116 → 6122 / 6123 numbers the PR body and os-dev-report 6672202451 claim; worktree removed afterwards, checked-out tree untouched. Nothing built, no GitHub write.
Scope: skills/objectstack-data/SKILL.md, .changeset/30466-extension-plurallabel-exception.md + packages/objectql/src/registry.ts (origin/main L905–922, L5499–5512), packages/objectql/src/registry-extension-plural-label.test.ts, scripts/check-skills-token-ratchet.mjs (L272, L511–513), docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md (L470–473), AGENTS.md (L270–278, L1019–1024), .claude/skills/pm-dispatch/references/contract-review.md, /mnt/project-files/skills-lane-seat1/dispatch-30466.md, card #30466 (body, triage 6658700520, claim 6671830258, os-dev-report 6672202451), PR #30722 body and file list, PR #30459 body, file list and contract record 6658126879.

Diff read as git diff origin/main...FETCH_HEAD (merge-base badf24d): two files, +13/−2, matching the PR file list (.changeset/30466-extension-plurallabel-exception.md added, skills/objectstack-data/SKILL.md +3/−2). No docs/adr/** or packages/** path in the diff (the order's ⛔ surfaces hold).

① Derived judgments

  • Rule location and condition — right. origin/main packages/objectql/src/registry.ts L909–918: yields(key) is tenantAuthored?.has(key) === true (L909); the outer branch is extension.label !== undefined && !yields('label') (L910); inside it, L916 if (extension.pluralLabel === undefined && extension.label !== merged.label && !yields('pluralLabel')) { delete merged.pluralLabel; } then merged.label = extension.label (L919). So the four parts of the sentence map one to one: "a new label" = the extension's label differs from the running merged.label (not the packaged owner's label; an earlier extender's label counts), "without pluralLabel" = extension.pluralLabel === undefined, "clears" = delete of the key, "unless a tenant authored it" = !yields('pluralLabel').
  • "Clears" is the precise verb. The key is deleted from the fold's output, not replaced by a derived plural: registry-extension-plural-label.test.ts L51–55 pins pluralLabel: undefined, hasPluralLabel: false on getObject, and L57–63 pins that getPackagedObjectBase keeps Tasks. What /meta/object then serves is the spec's "object with no pluralLabel" shape, with the owner pair's own translation of the plural allowed in (PR fix(objectql,rest)!: serve an object an extension renames without the base's plural (#30391) #30459 body, record 6658126879 ① change 2); that is not the base's plural, so "clears the base plural" neither over- nor under-states the served result.
  • "unless a tenant authored it" — right, and complete. tenantAuthoredScalars (registry.ts L5499–5512) marks a scalar as authored when the own contributor's body diverges from the fold's base for that key, i.e. an overlay/tenant layer wrote it. Test L100–105 pins a tenant To-dos surviving a rename. The second way the plural survives, a tenant-authored label (outer !yields('label') L910; test L107–112), is covered by the sentence's premise: with the label yielding there is no applied "new label". "it" reads naturally as the plural; both survival cases are inside the sentence's truth set.
  • "(set both)" is the correct remedy. registry.ts L920–922 writes extension.pluralLabel when set; test L68–72 pins label + plural served as set, and L120–124 pins a later plural landing over an earlier rename. Setting pluralLabel beside label is the only author-side way to keep a plural on the renamed object (PR fix(objectql,rest)!: serve an object an extension renames without the base's plural (#30391) #30459 changeset remedy, record 6658126879 ②).
  • Generality nuance, no fix owed. The deleted plural is the running one, so a lower-priority extender's plural is also taken off by a higher-priority rename (test L114–118). The sentence says "the base plural"; in the section's frame ("an object you do not own", SKILL.md head L345) the base is the extended object, and an author who sets both is safe either way. Prose only.
  • Not a rule drop: the deleted link. On origin/main references/data-hooks.md is linked at SKILL.md L46 (catalog list), L160 (backfill paragraph) and L340 (parenthetical on the Lifecycle Hooks pointer). At the head L46 and L160 are unchanged and L340 keeps its pointer to references/examples-objects.md § Lifecycle Hooks; only the parenthetical restating the hooks-reference link is gone. No reader loses the only pointer, and no rule, ⛔ or ❗ text moved.
  • Accept-set and public surface: unchanged — right. packages/spec is untouched; nothing an author can write changes. Clause-②: no, Metadata-protocol: none re-derived from the diff: correct.
  • Ratchet numbers — reproduced. Ceiling row ['skills/objectstack-data/SKILL.md', 6123] at scripts/check-skills-token-ratchet.mjs L513, untouched by the diff. Probe: origin/main measures 6116 (headroom 7), the head measures 6122 (headroom 1), exit 0 both times. The dev's claim holds.
  • Out of scope honoured. ADR-0029 L472–473 still reads "merges fields additively ... and has no expression for removal at all"; not edited, quoted in the PR body and os-dev-report for the seat to raise for Tier H, as the order asked.

② Semver level

  • .changeset/30466-extension-plurallabel-exception.md: '@objectstack/skills': patch, with Clause-②: no and Metadata-protocol: none line-initial in the body. AGENTS.md L1019–1021: a change in a released package takes a patch changeset, never none and never skip-changeset. Level matches a docs-only change to the shipped skill. PR labels carry no skip-changeset; Check Changeset is green on the head.
  • PR body carries Fixes #30466, Clause-②: no, Metadata-protocol: none, each line-initial and identical to the changeset.

③ Boundary flags

  1. Deviation: ratchet payment by deleting the L340 parenthetical link, outside the pinned sentence — answered in ① (duplicate at L46 and L160 on the head; pointer to examples-objects.md § Lifecycle Hooks kept; no rule text). The pin "no other skill text changes" cannot hold at 7 tokens of headroom with a +12-token sentence; the dev declared it and chose the smallest same-file deletion. Accepted.
  2. Deviation: the sentence also names the tenant-authored yield — right; without it the sentence would over-state (a tenant To-dos is not cleared, test L100–105). Accepted.
  3. Relay pr_create HTTP 500 twice, third landed docs(skills): name the pluralLabel exception to "an extension can add but never remove" #30722 — procedural; head and file list confirm one PR. No finding.
  4. Assign/request-review skipped per standing lines — procedural; no finding.
  5. open_questions: none. Out-of-scope finding (ADR-0029 D9.2 L473) carried by the seat for Tier H; not a finding of this diff.
  6. PR author — user.login is objectstack-fleet[bot]; no non-bot login to name. The body's attribution comment records the requester as os-elon-musk.
  7. Served-tier — skills/** is a Tier H governed surface (AGENTS.md L273–276); governed rule text hit ⇒ CONTRACT_REVIEW_TIER, as asked. PR is draft: true, auto_merge: null; landing is the maintainer's hand.
  8. Check-runs on the head at 2026-11-05T23:31Z: every completed run is success or skipped (Auto Label, Check Changeset, Check PR Size, Dogfood Regression Gate, Governed Surface Queue Guard, Lint · PM dispatch-gates, the three scoped lints, PR-body guards, Plan Test Core shards, Test UI, filter). Still in_progress: Build Core, Lint · CI/release & engine gates, Lint · ESLint, Lint · docs & code guards, Lint · repo & tooling gates, Live E2E UI, Test Core (1/8) and (2/8), Type Check · consumer gates / debt ledger / source gates / workspace. No run is red. A red among the pending runs reopens this record.

④ Design judgment

skills/objectstack-data/SKILL.md (governed rule text). The one-sentence change keeps "an extension can add but never remove" as the rule and names exactly the exception the fold has on main, in the fold's own terms (new label, no plural, tenant yield, remedy). Checked against the acceptance scenario: a reader who renames an object and reads this sentence knows the plural goes and knows to set both; a reader who adds fields, or sets only pluralLabel, or repeats the label, is still inside "never remove" (tests L74–98). Nothing in the sentence promises more than L916 does, and nothing L916 does is left unsaid except the running-vs-base nuance above. The ⛔ ownership warning and the schema pointer that follow are intact. The sentence runs long on one line (L350), consistent with the file's existing long-line style (L340, L92).

.changeset/30466-extension-plurallabel-exception.md. Summary line matches the diff; the body restates the rule correctly, including "an extension that repeats the label it extends removes nothing" (test L94–98) and the link-deletion rationale; "No schema, key or behaviour changes" is true.

Trying to break the sentence: an extension on an object whose base has no plural — the delete is a no-op, the sentence's "clears" is vacuous but not false. A .custom pair extension — the fold is one mergeObjectDefinitions for every extend contributor (record 6658126879 ①), so the sentence holds for pairs too. Two extenders — covered by the "running" nuance, no author-visible contradiction.

No must-fix. No should-fix.

Implemented-by: claude/project-thread-ki6fr1
Reviewed-by: session_016WV4d1mkgEris4MHHLjtnk

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · os-elon-musk · session_016WV4d1mkgEris4MHHLjtnk

维护者速读

  • 改了什么:objectstack-data 技能“对象扩展”一句,保留“扩展只能加不能删”,补上 PR fix(objectql,rest)!: serve an object an extension renames without the base's plural (#30391) #30459 引入的唯一例外:扩展设了新 label 却没设 pluralLabel,会清掉基础对象的复数名(租户自己写的复数除外),要保留就两个都设。
  • 为什么改:PR fix(objectql,rest)!: serve an object an extension renames without the base's plural (#30391) #30459 之后旧句子不再准确;AI 按旧句子改名对象,会意外丢掉复数名。
  • 风险与回滚:一句技能文档 + changeset,不动代码;回滚即 revert 本 PR。
  • 先看:skills/objectstack-data/SKILL.md 第 350 行;为付 token,第 340 行删了一个重复的 data-hooks.md 链接(L46、L160 仍在)。
  • 两分钟验证:node scripts/check-skills-token-ratchet.mjs | grep objectstack-data/SKILL,预期 6122 tokens(上限 6123,未抬)。
  • 需要你做的:① 批准并合并(skills/** 为 Tier H)。契约复核 PASS 评论 6672290914,Head-sha a069bdb668fd1e49f78e3fa9a4d0e3ea58c3fe25。② 你来定:ADR-0029 D9.2(docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md L472–473)说 mergeObjectDefinitions “has no expression for removal at all”,对 pluralLabel 已不精确,是加一条修订注,还是保持原样。本 PR 不碰 ADR。
  • 席位意见:可合。ADR 席位建议加一行修订注(不改决策),由你定。

席位核对 — ACCEPT · head a069bdb

  • 形态:2 文件 +13/−2(SKILL.md + 根 changeset '@objectstack/skills': patch)。governed skills/**(Tier H)。Fixes #30466,draft,目标 main,作者 objectstack-fleet[bot]。
  • 契约:Clause-② no,Metadata-protocol none,与认领 6671830258 一致。
  • 前提实测:dev 报告 6672202451;句子四个部分逐一对 registry.ts L909–922 与 registry-extension-plural-label.test.ts 核过(复核记录 ①)。
  • 门禁 check-runs:head 上 41 个,28 success,13 skipped,0 红。
  • 接受的偏差:L340 删除重复链接付 token(派发单的“只改一句”在 7 token 余量下无法成立,dev 已申报);句子点名租户例外,否则会说过头。
  • 范围外去向:ADR-0029 D9.2 修订注交维护者(见速读 ②)。
  • 落地条款:Tier H,等 governed 审批人批准;批准后席位经中继 pr_ready + automerge_enable,合并后核 skills + ADR-0029 D9.2: 'an extension can add but never remove' no longer holds for pluralLabel after PR #30459 #30466 已关、摘 pm:dispatched。

@objectstack-fleet objectstack-fleet Bot added the pm:awaiting-merge PR only: landing waits on the maintainer's own review and merge (SKILL.md 复核 ②); never on an issue label Nov 5, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review November 6, 2026 01:44
@os-zhuang
os-zhuang added this pull request to the merge queue Nov 6, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to Branch Protection failures Nov 6, 2026
You're not authorized to push to this branch. Visit "About protected branches" for more information.
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 6, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Nov 6, 2026
@objectstack-fleet
objectstack-fleet Bot marked this pull request as draft November 6, 2026 02:32
@os-zhuang
os-zhuang marked this pull request as ready for review November 6, 2026 02:35
@os-zhuang
os-zhuang added this pull request to the merge queue Nov 6, 2026
Merged via the queue into main with commit 4cfb351 Nov 6, 2026
48 checks passed
@os-zhuang
os-zhuang deleted the claude/project-thread-ki6fr1 branch November 6, 2026 03:24
@objectstack-fleet objectstack-fleet Bot removed the pm:awaiting-merge PR only: landing waits on the maintainer's own review and merge (SKILL.md 复核 ②); never on an issue label Nov 6, 2026
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/s tooling Fix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills + ADR-0029 D9.2: 'an extension can add but never remove' no longer holds for pluralLabel after PR #30459

2 participants