Repository navigation
Commit 7f4cbc9
docs(skills): an email-template override names a locale its base ships; a new locale carries no overrides (#28814)
<!-- claude-projects-attribution: {"github_login":"marchtian"} -->
_Requested by **田騏** · [project
thread](https://claude.ai/code/project/chan_01VmuUhXU9SSUzqJYyXSmYSi?thread=cmsg_01VmuUhXU9SSUzqJYyXSmYSiHXKqxUqDPJKZyNHP7BoqTb)_
Fixes #28778
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:两处文档各补一条规则——邮件模板按「名称 + 语言(locale)」算一个条目,所以 `BASE.custom` 里带
`overrides` 的覆盖只能指向基础包确实发过的语言;基础包没发的语言直接新增、不写 `overrides`。改的是发布技能包
`skills/objectstack-platform/SKILL.md` 的 ADR-0146 定制段,和
`content/docs/concepts/metadata-lifecycle.mdx` 的 ADR-0146 节。
- **为什么改**:PR #28777 落地后,写入闸门已经按语言判断(基础包只发 `en-US` 却声明覆盖 `fr-FR` ⇒ `403
NOT_OVERRIDABLE`),而技能和文档只说「同名 + `overrides` 即覆盖」,对语言只字未提,照着写的 AI 作者会被拒。
- **风险与回滚**:极低,纯文档;无代码、无 schema、无行为变化。技能文件有 token 棘轮(上限 6012,改前余量
0):新句子靠把「尚未放行的八个类型」改为指向 `OVERRIDABLE_METADATA_TYPES`、删四句开场白付账,改后
6005,未动任何规则、未抬上限。回滚即 revert。
- **先看**:① `skills/objectstack-platform/SKILL.md` 第 131 行的定制段(新句子 +
类型列表的收缩);② `content/docs/concepts/metadata-lifecycle.mdx` 第 117–119
行与新增的「A new locale is not an override」条目;③
`.changeset/28778-email-template-override-locale.md`(`@objectstack/skills`
patch)。
- **两分钟验证**:`node scripts/check-skills-token-ratchet.mjs`,预期输出含
`skills/objectstack-platform/SKILL.md is 6005 tokens (ceiling 6012;
headroom 7)` 且结尾 `✓ … 57 authored bundle file(s) within their ceilings`。
- **需要你做的**:`skills/**` 为 Tier H 受管面——由授权审批人在本 PR 上给出 APPROVED
review,之后席位落地;PR 保持 draft、不请审、不指派。
## What changes
**The rule, taken from the gate PR #28777 landed, not from the card.**
An email template's identity is `(name, locale)`:
`ITEM_KEY_DISCRIMINATORS`
(`packages/metadata-core/src/item-key-discriminators.ts:68-70`) holds
exactly one entry, `email_template: { field: 'locale', canonical:
'en-US' }`, and `itemDiscriminator` (`:96-100`) keys a body that
declares no locale as the canonical member. The override write gate
reads that table through `overrideWriteMemberOf`
(`packages/metadata-protocol/src/protocol-packaged-base-refusal.ts:280-282`)
and `overrideWriteIdentityOf` (`:299-302`, name joined with member), and
`judgeOverrideWrite` refuses `declared_package_ships_no_such_item` when
no closure package ships the base at that member (`:448-455`, the
sentence naming the locale: "ships no email_template named 'X' with
locale 'fr-FR'"), thrown as `403 NOT_OVERRIDABLE` (`:535-542`). A locale
the base does not ship, saved in the pair WITHOUT `overrides`, collides
with no base member and is admitted as the pair's own member (pinned:
`packages/qa/dogfood/test/email-template-override-unshipped-locale.dogfood.test.ts:125`;
CLI `packages/cli/src/utils/override-declarations.test.ts:161`).
- **`skills/objectstack-platform/SKILL.md`** (ADR-0146 customization
paragraph, now L131): one sentence after the honoured-types sentence —
*An email template is one item per (name, locale): an override names a
locale the base ships; a locale the base does not ship is added without
`overrides`.*
- **`content/docs/concepts/metadata-lifecycle.mdx`** (ADR-0146 section):
the "bears a base item's name" sentence now reads "— for an
`email_template`, one item per `(name, locale)`, the name **and** a
locale the base ships —", and a new bullet **A new locale is not an
override** says the pair's own locale carries no `overrides`, is served
under `hotcrm.custom`, and that declaring one there is refused (`403
NOT_OVERRIDABLE` at the save, publish and install doors, a row from `os
validate`).
- **`.changeset/28778-email-template-override-locale.md`**:
`@objectstack/skills` `patch` (the catalog ships in that package's
`dist`), `Clause-②: no`, `Metadata-protocol: none`.
**Paying for the sentence (token ratchet,
`skills/objectstack-platform/SKILL.md`, ceiling 6012, headroom on `main`
0 tokens / 3 bytes).** Nothing paid with a re-wrap; no rule dropped.
What moved:
1. Same paragraph: the eight not-yet-honoured types (`page, app,
dataset, doc, book, mapping, flow and action`) are no longer enumerated;
the clause reads "the rest of `OVERRIDABLE_METADATA_TYPES` wait for
their doors". The honoured five stay named; the docs page keeps the full
list.
2. "Undeclared keys are handled per surface, and the two postures are
worth keeping straight:" → "…, in two postures:".
3. "Every stack needs a `manifest` to identify itself in the ecosystem:"
→ "Every stack needs a `manifest`:".
4. The Runtime Boot Sequence intro line "Understanding how ObjectStack
starts helps debug and customize:" removed (the heading carries it).
5. The driver table intro "Pick based on your environment:" removed (the
table's "Best For" column carries it).
**Skills readings (both, as the published-catalog rule requires; lines
by `wc -l`, tokens by the ratchet's `ceil((bytes − stamp line) / 4)`):**
| Reading | Before (`origin/main` c064d3a) | After (7390bef) |
|:--|:--|:--|
| `skills/objectstack-platform/SKILL.md` | 462 lines · 6012 tokens
(ceiling 6012, headroom 0) | 459 lines · 6005 tokens (headroom 7) |
| Whole package (every `skills/*/SKILL.md`) | 4561 lines · 56274 tokens
| 4558 lines · 56267 tokens |
The ratchet's authored-bundle total (57 files) reads 181895 / 190761
after; only this file moved (−7).
## Tests
No code changes; no test added or moved. The gates below are the
verification.
## Acceptance notes
- **Labels:** the dispatch names none and `skip-changeset` does not
apply (`@objectstack/skills` publishes `skills/**`), so `pr_create`
carries no labels and no assignees.
- **Local-only families** (`check:dev-prereqs`,
`check:skill-frame-freshness`) are not derived for this diff (no spec
build or four-axis frame file touched) and were not run.
- Nothing out of scope was found; nothing filed.
## Verification
All readings at head `7390bef4d6` after `pnpm install --frozen-lockfile`
and a full `pnpm build --concurrency=2` under `os-verify-lock.sh`
(VERDICT `command-exit 0`, held 1011 s).
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derives 71 commands for this diff (3 paths,
30 changed lines). Every one was run locally with its exit code captured
before any pipe: **71 / 71 exit 0**, reconciled with `--ran`.
<details><summary>Families the diff touches, with their verdict
lines</summary>
- `node scripts/check-skills-token-ratchet.mjs` → exit 0 — `✓
check-skills-token-ratchet: skills/objectstack-platform/SKILL.md is 6005
tokens (ceiling 6012; headroom 7)` · `57 authored bundle file(s) within
their ceilings`.
- `pnpm check:skill-frame-sync`, `check:skill-identifier-liveness`,
`check:skill-top-level-keys`, `check:skill-compatibility` → exit 0 each.
- `pnpm --filter @objectstack/spec run check:skill-docs`,
`check:skill-examples`, `check:docs`, `check:variant-docs`,
`check:yaml-examples` → exit 0 each (after the build).
- `pnpm check:doc-anchors`, `check:doc-authoring`,
`check:overlay-whitelist-table`, `check:docs-single-h1`,
`check:doc-frontmatter`, `check:docs-spec-enumerations`,
`check:docs-transcript-drift`, `check:docs-redirects`,
`check:docs-audit-scope` → exit 0 each.
- `node scripts/check-empty-changeset.mjs --base origin/main`,
`check-changeset-no-major.mjs --base origin/main`,
`check-adr-0087-registration.mjs --base origin/main`, `pnpm
check:changeset-gate-self-tests`, `check:pm-changeset-deadline-census` →
exit 0 each.
- `pnpm check:nul-bytes`, `check:pm-skill-id-lint`, `check:role-word` →
exit 0 each.
- The remaining derived commands (whole-tree and checker self-tests) →
exit 0 each.
</details>
Not measured locally (CI's own): the type-check lanes, `Build Docs`,
`Build Core`, and the `main`-push batteries the derivation lists; the
PR's check-runs carry them.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 56bd596 commit 7f4cbc9
3 files changed
Lines changed: 25 additions & 11 deletions
File tree
- .changeset
- content/docs/concepts
- skills/objectstack-platform
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
115 | 115 | | |
116 | 116 | | |
117 | 117 | | |
118 | | - | |
| 118 | + | |
| 119 | + | |
119 | 120 | | |
120 | 121 | | |
121 | 122 | | |
| |||
127 | 128 | | |
128 | 129 | | |
129 | 130 | | |
130 | | - | |
131 | | - | |
132 | | - | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
133 | 134 | | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
134 | 140 | | |
135 | 141 | | |
136 | 142 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
58 | | - | |
59 | | - | |
| 58 | + | |
60 | 59 | | |
61 | 60 | | |
62 | 61 | | |
| |||
108 | 107 | | |
109 | 108 | | |
110 | 109 | | |
111 | | - | |
| 110 | + | |
112 | 111 | | |
113 | 112 | | |
114 | 113 | | |
| |||
131 | 130 | | |
132 | 131 | | |
133 | 132 | | |
134 | | - | |
| 133 | + | |
135 | 134 | | |
136 | 135 | | |
137 | 136 | | |
| |||
227 | 226 | | |
228 | 227 | | |
229 | 228 | | |
230 | | - | |
| 229 | + | |
231 | 230 | | |
232 | 231 | | |
233 | 232 | | |
| |||
291 | 290 | | |
292 | 291 | | |
293 | 292 | | |
294 | | - | |
295 | | - | |
296 | 293 | | |
297 | 294 | | |
298 | 295 | | |
| |||
0 commit comments