Repository navigation
Commit 00918c8
docs(skills): objectstack-data teaches an object extension's fieldPatches — relabel a vendor field without redeclaring it in fields (#28795)
<!-- claude-projects-attribution: {"github_login":"marchtian"} -->
_Requested by **田騏** · [project
thread](https://claude.ai/code/project/chan_01VmuUhXU9SSUzqJYyXSmYSi?thread=cmsg_01VmuUhXU9SSUzqJYyXSmYSiHXKqxUqDPJKZyNHP7BoqTb)_
Fixes #28730
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:对外发布的 `objectstack-data` skill 的「Object Extension
Model」一节新增一段,教对象扩展的
`fieldPatches`:改厂商字段的显示文字(label、description、inlineHelpText、placeholder、按存储
`value` 定位的选项 label)用它,而不是在 `fields`
里把字段重新声明一遍(那会整个接管字段,厂商升级不再到达);租户自己改过的文字优先,两个扩展冲突时 `priority`
高者胜,指向目标对象没有的字段或选项值的补丁在安装时和 `os validate` 被拒,picklist 绑定字段的选项不可补丁;附
`crm_account.industry` → "Sector" 一例。另加一条 `@objectstack/skills` patch
changeset。
- **为什么改**:PR #28728 让 `fieldPatches` 真正生效后,skill 还只教 `fields` /
`priority`,照 skill 写代码的 AI 想把 "Industry" 显示成 "Sector" 只会在 `fields`
里重声明字段、把它接管过去;这是那张 PR 欠下的 `Skills-docs` 后续。
- **风险与回滚**:只改一个 SKILL.md 与一条 changeset;不动
spec、运行时、`content/docs/**`、ratchet 脚本、任何 ceiling。文件 token 数仍在上限内(6111 /
6123):新段落靠删同文件里的重复句付账——搜索一节第二段的「refused loudly」复述(并入第一段)、索引一节的
blockquote(`rules/indexing.md` 已有)、校验类型清单(`rules/validation.md`
已有)。风险在折叠处:读者要多开一个 rules 文件才看到被折叠的细节。回滚 = revert 本 PR。
- **先看**:① `skills/objectstack-data/SKILL.md` 「Object Extension
Model」新段(事实逐条对照 `packages/spec/src/data/field-customization.ts` 的
`BASE_FIELD_DISPLAY_WHITELIST` 与 `packages/objectql/src/registry.ts` 的
`patchedField` / `mergeObjectDefinitions`);② 同文件三处删减是否真是复述;③
`.changeset/28730-skill-field-patches.md`。
- **两分钟验证**:`node scripts/check-skills-token-ratchet.mjs` —— 预期含
`skills/objectstack-data/SKILL.md is 6111 tokens (ceiling 6123; headroom
12)`,末行 `57 authored bundle file(s) within their ceilings`。
- **需要你做的**:Tier H(`skills/**`)—— 授权账号 APPROVE 一次,席位落地;无其它动作。
## What changes
`skills/objectstack-data/SKILL.md`, section *Object Extension Model*:
one paragraph on `fieldPatches` plus the `crm_account.industry` example
from the `.changeset/28565-field-patch-applied.md` release note. Every
claim is read off the live code at `b48eeb16c4` (this branch's merge
base), not the card's summary:
| Claim in the paragraph | Source |
|:--|:--|
| Redeclaring the field in `fields` takes it over whole |
`packages/objectql/src/registry.ts:701-703` (`merged.fields = {
...base.fields, ...extension.fields }`);
`content/docs/data-modeling/object-extensions.mdx:96-100` |
| Display keys only: `label`, `description`, `inlineHelpText`,
`placeholder`; an option's `label` |
`packages/spec/src/data/field-customization.ts:75-80`
(`BASE_FIELD_DISPLAY_WHITELIST.field` / `.option`);
`packages/spec/src/data/object.zod.ts:4958-4967` (the slot's
`.describe()`) |
| An option is addressed by its stored `value` |
`packages/objectql/src/registry.ts:585-587`;
`packages/metadata-core/src/extension-field-patch-targets.ts:130-136` |
| Type, values and rules stay the owner's |
`field-customization.ts:65-68`; `object.zod.ts:4960-4962` |
| A key the tenant edited keeps the tenant's text | `registry.ts:576`,
`:592` (`tenantPatched` yield), `:731-734` |
| Between two extensions the higher `priority` wins |
`registry.ts:4202-4203` (ascending sort), `:735-736` (the higher one
written last) |
| A missing field or option value is refused at install and by `os
validate` | `extension-field-patch-targets.ts:95-103` (field),
`:126-137` (option);
`packages/cloud-connection/src/marketplace-install-local-plugin.ts:2136-2146`
(`400 VALIDATION_ERROR`);
`packages/cli/src/commands/validate.ts:732-745` |
| A `picklist`-bound field's options are never patchable |
`extension-field-patch-targets.ts:112-124` (`picklist-option`);
`registry.ts:581-582` |
`.changeset/28730-skill-field-patches.md`: `@objectstack/skills` patch —
the skill ships in that package's `dist` (`packages/skills/package.json`
`files[]`, synced from `skills/**` by its build).
**Token ratchet — paid by deleting restatement in the same file**
(standing ruling, maintainer 2026-10-27: 「A:先削重复,余额按实测提高」 — quoted for
the record; no ceiling moves here):
| Deleted | Why it was restatement |
|:--|:--|
| *Search Fields* L171-176: "Both spellings are refused loudly … Each
message carries its own prescription." and "Cross-object search paths
are rejected by design … the mirror field is the answer." | Repeats the
section's own L122-129 ("is **refused**, not silently dropped"; "This is
the one prescription — emit it every time"). The one fact only that
paragraph carried, the `searchable-field-unknown` lint code, is folded
into L125. |
| *Index Patterns* blockquote L360-364 (retired `type` / `partial`,
unique scope spellings) | Carried by `rules/indexing.md` L26-34 and
L63-77; the pointer sentence below it now names the retired keys and the
scope words. |
| *Validation Patterns* L331-337: the six-bullet type list with one-line
glosses | Carried by `rules/validation.md`'s type table (L16-22); the
names stay as one line. |
Readings (lines by `wc -l`; tokens in the ratchet's own convention,
`ceil(bytes/4)` minus the stamp line):
| Reading | Before (`origin/main` `b48eeb16c4`) | After (this head) |
|:--|:--|:--|
| `skills/objectstack-data/SKILL.md` | 472 lines · 6101 tokens (ceiling
6123) | 468 lines · 6111 tokens (headroom 12) |
| Package, all `skills/*/SKILL.md` | 4561 lines · 56328 tokens | 4557
lines · 56337 tokens |
## Tests
Docs-only: no package test suite reads `skills/**`. The gates that do
are in *Verification*. No ablation (no tested behaviour changed).
## Acceptance notes
- `rules/indexing.md` L31 carries the `os migrate meta --from 16`
prescription the deleted blockquote also quoted, so nothing an author
could act on left the skill — only its second copy.
- No eval added: the card's Wanted names one paragraph; the
`objectstack-data` evals do not exercise object extensions today, and an
eval fixture is outside the token ratchet (ruling record 6513306068,
letter B). Noted, not filed — an eval for the extension model is a
`carrier: #28730`-adjacent follow-up the seat may order.
## Verification
Head `7ba013288b`, the branch's only commit; the tree is clean after
every step below, so each reading is of this head. Prerequisites: `pnpm
install --frozen-lockfile`; `pnpm --filter @objectstack/spec --filter
@objectstack/formula build`; then a whole-repo `pnpm build` under
`scripts/pm/os-verify-lock.sh` (`Tasks: 117 successful, 117 total`,
`VERDICT command-exit 0`, held 13m57s) for the gates that read built
output.
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at head: 45 commands (34 derived for the
SKILL.md alone, 11 more once the changeset existed — both derivations
kept and run). Every command recorded with its exit code captured before
any pipe; `--ran` verdict: **45 derived, 45 run, 0 NOT-MEASURED, 0
UNRUN**, exit 0.
First pass, before the whole-repo build, four did not pass and were
traced to the checkout, not the diff: `check:doc-formula-expressions`,
`check:dual-build-cjs-loads`, `check:lean-entry-closure` exit 3
(PREREQUISITE NOT MET, built output missing) and `check:dts-closure`
exit 1 (`@objectstack/lint` declaration files missing — its dts build
needs `@objectstack/sdui-parser` built first). After `pnpm build`: exit
0 each. The other 41: exit 0 on their first run.
Readings worth quoting:
- `node scripts/check-skills-token-ratchet.mjs` —
`skills/objectstack-data/SKILL.md is 6111 tokens (ceiling 6123; headroom
12)`; last line `57 authored bundle file(s) within their ceilings; 10
generator-owned file(s) and 29 eval fixture(s) measured, not ratcheted`;
exit 0. Its `--self-test`: exit 0.
- `pnpm check:skill-frame-sync`, `check:skill-compatibility`,
`check:skill-identifier-liveness`, `check:pm-skill-id-lint`,
`check:role-word`, `check:doc-authoring`, `check:nul-bytes`,
`check:pm-governed-merges` — exit 0 each.
- `pnpm --filter @objectstack/spec run check:skill-docs` — exit 0.
Extra, not derived: `check:skill-refs` — `9 generated files in sync with
packages/spec`, exit 0.
- Changeset family: `check-adr-0087-registration --base origin/main`,
`check-changeset-no-major`, `check-empty-changeset`,
`check:changeset-gate-self-tests`, `check:pm-changeset-deadline-census`,
`check:published-files`, `check:closed-ceremony-text` — exit 0 each.
- Declared to CI, not run locally: `check:skill-examples` (not derived;
the paragraph adds no fenced TypeScript block) and `test:repo`. The
local-only families `check:dev-prereqs` / `check:skill-frame-freshness`
were not run: the diff touches neither `packages/spec` nor a frame file.
Dogfood battery: n/a — no `!` in the title and no `(narrowing)` arm. CI
check-runs: not read at report time; the PR is opened by the stroke that
carries this body, so the report comment records them as `in_progress`.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: objectstack-fleet[bot] <332303061+objectstack-fleet[bot]@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>1 parent 6ea8342 commit 00918c8
2 files changed
Lines changed: 32 additions & 24 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
122 | 122 | | |
123 | 123 | | |
124 | 124 | | |
125 | | - | |
| 125 | + | |
| 126 | + | |
126 | 127 | | |
127 | 128 | | |
128 | 129 | | |
| |||
168 | 169 | | |
169 | 170 | | |
170 | 171 | | |
171 | | - | |
172 | | - | |
173 | | - | |
174 | | - | |
175 | | - | |
176 | | - | |
177 | | - | |
178 | 172 | | |
179 | 173 | | |
180 | 174 | | |
| |||
328 | 322 | | |
329 | 323 | | |
330 | 324 | | |
331 | | - | |
332 | | - | |
333 | | - | |
334 | | - | |
335 | | - | |
336 | | - | |
337 | | - | |
| 325 | + | |
| 326 | + | |
338 | 327 | | |
339 | 328 | | |
340 | 329 | | |
| |||
357 | 346 | | |
358 | 347 | | |
359 | 348 | | |
360 | | - | |
361 | | - | |
362 | | - | |
363 | | - | |
364 | | - | |
365 | | - | |
366 | | - | |
367 | | - | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
368 | 353 | | |
369 | 354 | | |
370 | 355 | | |
| |||
373 | 358 | | |
374 | 359 | | |
375 | 360 | | |
376 | | - | |
| 361 | + | |
377 | 362 | | |
378 | 363 | | |
379 | 364 | | |
380 | 365 | | |
381 | 366 | | |
382 | 367 | | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
383 | 379 | | |
384 | 380 | | |
385 | 381 | | |
| |||
0 commit comments