Skip to content

docs(skills): an email-template override names a locale its base ships; a new locale carries no overrides - #28814

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-28778-email-template-locale
Nov 2, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/issue-28778-email-template-locale

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by 田騏 · project thread

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 fix(metadata-protocol)!: the override write gate judges an email template by its locale, so a pair's override of a locale the base does not ship is refused (#28746) #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.

Families the diff touches, with their verdict lines
  • 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.

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

… ships; a new locale carries no overrides

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2g7RyXa8ErM6GAkHyc
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation tooling labels Nov 1, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 7390bef4d67963533b28c1979cf4a92bafdcac8b
Local-runs: none
Scope: skills/objectstack-platform/SKILL.md + content/docs/concepts/metadata-lifecycle.mdx (the docs half of the one rule), packages/metadata-core/src/item-key-discriminators.ts, packages/metadata-protocol/src/protocol-packaged-base-refusal.ts, packages/metadata-protocol/src/served-override.ts, packages/metadata-protocol/src/protocol-lock-state.ts, packages/metadata-protocol/src/protocol-environment-rows.ts, packages/spec/src/kernel/customization-package.ts (+ kernel/index.ts), packages/cli/src/utils/override-declarations.ts and its test, packages/qa/dogfood/test/email-template-override-unshipped-locale.dogfood.test.ts, packages/cloud-connection/src/marketplace-install-local-plugin.ts, docs/adr/0146 (D2, D8, D9, Rollout), scripts/check-skills-token-ratchet.mjs, skills/objectstack-platform/evals/config-plugins-ops.json — all read on main at merge base c064d3a (= origin/main 70bf434 for every file named). Remainder of the diff (.changeset/28778-email-template-override-locale.md; the docs page as a page): the lane seat's ACCEPT at TIER_DEFAULT.

Inputs: card #28778 (body, claim 6563766275, dev report 6564145197), PR #28814 (body, file list, net diff origin/main...head, 3 files / +22 −8), and the 44 check-runs on the head, none pending at the write: 32 success, 12 skipped (the UI lanes, Dogfood Verify CLI, Temporal Conformance, the two opt-in harnesses and the schedule gate — none derived for this diff), 0 failure. No dispatch order and no seat conclusion was read as evidence.

① Derived judgments

  • Accept-set. One governed path, skills/objectstack-platform/SKILL.md (skills/**, Tier H, published as @objectstack/skills — packages/skills/package.json ships dist, the synced catalog). The other two paths are the docs site page (no package) and the changeset. Right: no packages/spec, no schema, no runtime, no exported identifier moves; the only public surface that changes is the catalog text the next @objectstack/skills patch carries.
  • Clause-②: no · Metadata-protocol: none on the PR body and the changeset. Right on both: nothing under packages/spec/src, no protocol method, no door, no code.
  • Token ratchet, audited by the script's own hand formula (ceil((wc -c − 20) / 4), the 20-byte stamp line version: "18.2.0"): origin/main 24065 bytes → 24045 priced → 6012 tokens (ceiling 6012, headroom 0); head 24040 → 24020 → 6005 (headroom 7). The dev's two readings are exact. The ceiling row (['skills/objectstack-platform/SKILL.md', 6012]) is untouched; lowering is a "may" in the script's discipline, not a finding. Paid by deletion in the same file, no re-wrap counted: one enumeration folded into a constant's name and four intro clauses — ② and ④ judge whether any taught fact went with them (none did).
  • Landing. Tier H: the PR is draft, carries no reviewer or assignee, and this record is a review of record, ⛔ not an approval — the APPROVED review of an account in GOVERNED_APPROVERS is still what lifts it. Right.
  • Labels. documentation, size/s, tooling, all from the labeler; the dispatch named none and skip-changeset would be wrong (the path publishes). Right.
  • Gates (the check-runs ARE the verdicts). Every derived family the diff reaches is green on the head: Lint · docs & code guards, Lint · repo & tooling gates, Lint · PM dispatch-gates, Lint · ESLint, Check Changeset, Check Documentation Links, Build Docs, Build Core, Governed Surface Queue Guard, PR-body guards, Spec property liveness, the three Type Check lanes, Dogfood Regression Gate, Test Core (1/8), (2/8) and (3/8), Test UI, Live E2E UI. Nothing pending, nothing red.

② Semver level

@objectstack/skills: patch — right. The catalog package ships skills/** byte-for-byte in dist; a teaching sentence with no frontmatter, name, compatibility or eval change is a patch of that package and of nothing else. content/docs/** publishes no package; the changeset names nothing for it, correctly. The changeset body carries Clause-②: no and Metadata-protocol: none, matching the PR body (Check Changeset green). Clause-② line: no is right — the diff touches no spec surface, declares no narrowing, so the review owed is this rules-face record and not a declaration-face one.

③ Boundary flags

Dev report 6564145197 — four deviations, a ten-row facts table, open_questions: [], out_of_scope_findings: [].

  1. Local-only families (check:dev-prereqs, check:skill-frame-freshness) not run — accepted: the diff touches neither a spec build nor a four-axis frame file; the derivation does not name them and the head's check-runs carry every derived family.
  2. pr_create carried no labels — accepted: the intersection was empty, the labeler's three labels are the right ones, nothing to add.
  3. The attribution HTML comment as the PR body's first line — accepted: the harness form, the one sanctioned exception; no other tag-shaped fragment in the diff or the changeset.
  4. pnpm build held the shared verify lock 1011 s — noted; nothing to answer, nothing to file.

Facts table — every file:line re-read in the live tree and found as stated: item-key-discriminators.ts:68-70 (one entry, email_template: { field: 'locale', canonical: 'en-US' }) and :96-100 (a body with no locale keys as en-US); protocol-packaged-base-refusal.ts:280-282 (overrideWriteMemberOf off the table, never a type literal), :299-302 (overrideWriteIdentityOf, name NUL member), :448-455 (declared_package_ships_no_such_item, the sentence naming ITEM_KEY_DISCRIMINATORS[type].field and the member, prescribing "Remove overrides to keep it as the pair's own item"), :538-545 (NOT_OVERRIDABLE, status 403); dogfood :89, :97, :117, :125 as described; CLI test :125, :151, :161, :173 as described; the skill's L134 on main and the docs' L117 as described; the ratchet row present (at :581 on main, the dev wrote :584 — a line-number slip, the row is the one named).

open_questions: none raised; none escalated from the dev. One flag this review raises itself, answered under ④ (the flow drift), with its owner named: card #28577 (N-30), open.

④ Design judgment

skills/objectstack-platform/SKILL.md — the new sentence against the gate it teaches: holds. The 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" — is the gate landed by 5bb7834 (#28777), read end to end: identity is (name, locale) with en-US the canonical member (item-key-discriminators.ts:68-70, :96-100); the write gate takes the member off the body (overrideWriteMemberOf, :280-282), the save door computes shippers AT that member (overrideWriteVerdict, :575-589: shippedArtifactsOf(type, name, undefined, member) filtered to the same member, writable shippers dropped) and judgeOverrideWrite refuses a declaration whose base ships no such member (:448-455), thrown as 403 NOT_OVERRIDABLE (:538-545). The other half of the sentence — the unshipped locale WITHOUT overrides is simply the pair's own member — is the same function: shippers is empty at fr-FR, so the undeclared branch answers NOT_CONCERNED (:459) and the save, publish and read serve it (dogfood :125-132; CLI :155-165). All three doors the docs bullet names compare on the member-joined identity: save/publish through overrideWriteVerdict; the install door through overrideWriteItemsOf (:528, overrideWriteIdentityOf) on both the delivered items and the held ones (marketplace-install-local-plugin.ts:3380, :3427-3433, :3453-3459); os validate through the same walk (override-declarations.ts:109-128), with the sentence verbatim from the gate.

Against the card's eval scenario (the Reach line): holds. The author who customizes a vendor email template through BASE.custom now meets, in the one paragraph that defines the override, that the item's identity is (name, locale), that overrides is for a locale the base ships, and that a new locale is an addition without overrides — the declared-fr-FR write the scenario describes is no longer what the skill teaches. Tried to break it: (a) the paragraph's later "An undeclared pair row or a dependent's row is an orphan in the layered read's overlay, effective = the base's" — read after the identity sentence, "undeclared pair row" is a row at a (name, locale) the base ships; an unshipped locale has no base document to be effective, and the docs bullet says so outright ("the pair's own member, served under hotcrm.custom"). Not a contradiction. (b) A body that declares no locale is keyed en-US (:99) — so an override that omits the key targets the canonical member; the skill does not say it, the spec default and the docs page do, and it sends no author to a refusal. Not a finding at skill depth. (c) Eval #10 in evals/config-plugins-ops.json (the view override) stays true as written; the card asked for no eval and the sentence is a one-fact rule, so none is owed here.

Every phrase cut, checked for a lost fact or a wrong identifier: none lost, none wrong.

  • page, app, dataset, doc, book, mapping, flow and action wait for their doors → the rest of OVERRIDABLE_METADATA_TYPES wait for their doors: the constant exists and is public (customization-package.ts:366-370, exported through kernel/index.ts:46, so @objectstack/spec/kernel as the docs page says); its overridable rows are exactly thirteen (:319-339) = the five the skill still names + the eight it stopped enumerating. The actionable fact — nothing beyond the five is honoured today — survives, and the docs page keeps the full enumeration one bullet above the new one.
  • "and the two postures are worth keeping straight" → "in two postures"; "to identify itself in the ecosystem" cut; "Understanding how ObjectStack starts helps debug and customize:" cut; "Pick based on your environment:" cut. Each carried no rule, no identifier, no number; no gate, eval or reference quotes any of them (grep over main outside the file: nothing).

Should-fix — the flow drift the hunk re-states (not this card's rule; owner named). On main the clause "today only for a view, dashboard, report, email_template or translation (the rest … wait for their doors)" is stale for flow: 3ee6af4 (#28693, N-11, 2026-11-01 17:10 UTC) and 8f294e0 (#28770) delivered its D9 conditions — CONDITIONS_DELIVERED = {'flow'} (protocol-packaged-base-refusal.ts:231), isOpenOverrideType admits it (:242-246), declinesStoredRow serves the pair's declared flow override over the shipped name (protocol-lock-state.ts:142-148), and the CLI test admits a declared flow override (override-declarations.test.ts:101-103). The sentence was true when #28586 (8de519f, 10:04 UTC) wrote it; this PR folds the enumeration into the constant's name and so re-states "flow waits", and the docs page's enumeration two lines above the new bullet names flow among the waiters too. Fix in this PR: "…, email_template, translation or flow" in both pages (+6 bytes → 24026 priced → 6007 ≤ 6012, inside the headroom the PR earned), or leave it to card #28577 (N-30, open), whose Wanted already covers "the flow override and its pinning (N-11)" in these pages. Should-fix, not a FAIL: the drift predates the PR, no fact the PR adds depends on it, the eval scenario is untouched by it, and the card that owns it is cut.

content/docs/concepts/metadata-lifecycle.mdx (widened in, the docs half of the rule): holds. "the name and a locale the base ships" and the bullet "A new locale is not an override" say exactly what the gate does, with the three doors, the os validate row and the sentence naming the locale — each verified above. Same should-fix as the skill for the flow enumeration in the neighbouring bullet.

Must-fix: none.

Implemented-by: claude/issue-28778-email-template-locale
Reviewed-by: session_017ihL2g7RyXa8ErM6GAkHyc

VERDICT: PASS

Read-only review of head 7390bef against origin/main 70bf434; written 2026-11-01T21:40Z.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: dd9e43d1e5650d6c761501d7ea4646bd5cd21ed7
Local-runs: none
Scope: skills/objectstack-platform/SKILL.md + content/docs/concepts/metadata-lifecycle.mdx (the docs half of the one rule), packages/metadata-protocol/src/protocol-packaged-base-refusal.ts, packages/metadata-protocol/src/protocol-lock-state.ts, packages/spec/src/kernel/customization-package.ts, scripts/check-skills-token-ratchet.mjs — re-read on current origin/main c5ac1b6 for this round; everything round one read (record 6564277480 on head 7390bef) stands unchanged, since git log c064d3a246..origin/main on the three touched files is empty. Remainder (.changeset/28778-email-template-override-locale.md; the docs page as a page): the lane seat's ACCEPT at TIER_DEFAULT.

Delta round over record 6564277480 (PASS, one should-fix). Inputs: card #28778 (body; claim 6563766275; reports 6564145197 and 6564445482), PR #28814 (body, file list, git diff 7390bef4d6..dd9e43d1e5 and the net diff origin/main...dd9e43d1e5, 3 files / +25 −11), and the 44 check-runs on the new head, none pending at the write: 32 success, 12 skipped (the UI lanes, Dogfood Verify CLI, Temporal Conformance, the two opt-in harnesses and the schedule gate — none derived for this diff), 0 failure.

① Derived judgments

  • The delta is the should-fix and nothing else. Two files, one clause each: the skill's honoured list reads "a view, dashboard, report, email_template, translation or flow"; the docs bullet names the same six and its waiters enumeration drops flow ("page, app, dataset, doc, book, mapping and action"). No other line moved; the changeset is unchanged (still @objectstack/skills: patch, Clause-②: no, Metadata-protocol: none — still right, the accept-set is unchanged).
  • Token ratchet, audited by hand (ceil((wc -c − 20) / 4)): head 24046 bytes → 24026 priced → 6007 tokens against ceiling 6012 (headroom 5); main still 24045 → 6012 (headroom 0). The dev's reading is exact; the ceiling row is untouched. Paid out of the headroom round one earned by deletion in the same file; no re-wrap, no raise.
  • Gates. Every derived family green on the new head — Lint · docs & code guards, Lint · repo & tooling gates, Lint · PM dispatch-gates, Lint · ESLint, Check Changeset, Check Documentation Links, Build Docs, Build Core, Governed Surface Queue Guard, PR-body guards, Spec property liveness, the three Type Check lanes, Dogfood Regression Gate, Test Core (1/8)–(3/8), Test UI, Live E2E UI. Nothing pending, nothing red.
  • Landing unchanged: Tier H, draft, no reviewer or assignee; this record is a review of record, ⛔ not an approval.

② Semver level

Unchanged from round one and still right: @objectstack/skills: patch for a catalog-text change with no frontmatter, eval or schema movement; content/docs/** publishes no package; Clause-②: no — no spec surface, no narrowing.

③ Boundary flags

Delta report 6564445482 — two deviations, four facts, open_questions: [], one out-of-scope observation.

  1. The PR body still carries round-one readings (6005 tokens / headroom 7; the honoured-five wording under "What changes") — accepted as declared; the tree is what this record judges, and the seat amends the body in its ACCEPT with the delta's readings (459 lines · 6007 tokens; package 4558 lines · 56269 tokens, consistent with the byte audit above).
  2. Local-only families still not derived or run — accepted, unchanged reasoning from round one.

Facts: protocol-packaged-base-refusal.ts:231 (CONDITIONS_DELIVERED = new Set(['flow'])), :242-246 (isOpenOverrideType), :227-229 (action's door not cut), protocol-lock-state.ts:142-148 (declinesStoredRow serves the pair's declared override of a shipped flow name) — each re-read on current origin/main c5ac1b6 (the dev read 663b7c0; main has since taken 2081a5e and c5ac1b6, neither touching these files or the three in the diff) and found as stated. The out-of-scope observation (the stale header docblock of served-override.ts:44-46) is comment text owned by #28577 and is not judged here.

④ Design judgment

skills/objectstack-platform/SKILL.md — flow named rightly: holds. On current main a declared .custom override of a shipped flow name is admitted at the write gate (CONDITIONS_DELIVERED :231, isOpenOverrideType :242-246) and served over the code package's name by the read (declinesStoredRow :142-148, the one row isServedOverrideRowOf admits for the shipping package), as ADR-0146 D9 items 1–4 require and 3ee6af4 (#28693) / 8f294e0 (#28770) delivered. So "today only for a view, dashboard, report, email_template, translation or flow" is the honoured set as the tree serves it, and "the rest of OVERRIDABLE_METADATA_TYPES wait for their doors" is exactly the seven remaining overridable rows of OVERRIDE_TYPE_CLASSIFICATION (customization-package.ts:319-339: page, app, dataset, doc, book, mapping, action) — action rightly stays a waiter (its door is not cut, :227-229; declared_type_not_yet_available). Tried to break it: an author who now declares a flow override from BASE.custom meets the admitting gate and the serving read, not a refusal; an author declaring an action override still meets "not yet available", which the clause still teaches by omission from the six. The round-one sentence on the email-template locale is untouched and still holds against the gate as read in record 6564277480. The card's eval scenario (the Reach line) is unaffected by the delta.

content/docs/concepts/metadata-lifecycle.mdx — the same clause: holds. The six honoured types and the seven-type waiters enumeration match the skill and the constant; the "A new locale is not an override" bullet is unchanged.

Must-fix: none. Should-fix: none — round one's is applied in full.

Implemented-by: claude/issue-28778-email-template-locale
Reviewed-by: session_017ihL2g7RyXa8ErM6GAkHyc

VERDICT: PASS

Read-only delta review of head dd9e43d against origin/main c5ac1b6; written 2026-11-01T21:58Z.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc

维护者速读(席位终稿 · head dd9e43d1e5650d6c761501d7ea4646bd5cd21ed7)

  • 改了什么:objectstack-platform skill 和 metadata-lifecycle.mdx 的 ADR-0146 段落写明:邮件模板按 (名称, locale) 各算一项,覆盖只能写基础包已有的 locale;基础包没有的 locale 直接新增,不写 overrides。顺手把已放行覆盖的类型改准:flow 已放行,所以现在是 view、dashboard、report、email_template、translation、flow。
  • 为什么改:fix(metadata-protocol)!: the override write gate judges an email template by its locale, so a pair's override of a locale the base does not ship is refused (#28746) #28777 上线后,给基础包没有的 locale 写 overrides 会被拒(declared_package_ships_no_such_item,403 NOT_OVERRIDABLE),但 skill 和文档都没提 locale。
  • 风险与回滚:只改 skill 和文档文字,外加一个 @objectstack/skills patch changeset。为腾 token 预算删了几处铺垫句,复审确认没有丢规则。回滚 = revert。
  • 先看:skills/objectstack-platform/SKILL.md 的 ADR-0146 段;content/docs/concepts/metadata-lifecycle.mdx 的 ADR-0146 节。
  • 两分钟验证:check-skills-token-ratchet objectstack-platform 6007/6012,通过;dogfood email-template-override-unshipped-locale 钉住了这条规则。
  • 需要你做的:批准本 PR(skills/** 对外发布,以你的批准为裁决)。契约复审 PASS:6564484664(Head-sha: dd9e43d1e5650d6c761501d7ea4646bd5cd21ed7)。

席位意见:ACCEPT.

席位核对

  • 形态: 3 files: skills/objectstack-platform/SKILL.md (462 → 459 lines, 6012 → 6007 tokens vs ceiling 6012), content/docs/concepts/metadata-lifecycle.mdx, .changeset/28778-email-template-override-locale.md (@objectstack/skills: patch). Clause-②: no, Metadata-protocol: none.
  • 执行档: the dev ran at the tier dispatch-gates --tier mandates for skills/**. The reviewer was a separate agent.
  • 复审: CONTRACT_REVIEW_TIER PASS 6564277480 (head 7390bef4d6, 0 must-fix, 1 should-fix: flow is honoured on main) → patch round (delta report 6564445482) → delta PASS 6564484664 on dd9e43d1e5650d6c761501d7ea4646bd5cd21ed7, 0 must-fix, 0 should-fix. Every fact was checked against the live gate.
  • 门禁: dev's dispatch-gates --commands 71/71 exit 0, --ran 0 NOT-MEASURED, both rounds. Check-runs on dd9e43d1: 44, 0 failure, 0 pending.
  • PR 正文更正: the body's readings are from round one (6005 tokens, five honoured types). The head reads 459 lines · 6007 tokens (package 4558 lines · 56269 tokens), and six honoured types including flow. This record is the correction (the relay does not patch PR bodies).
  • 接受的偏差: no labels sent with pr_create; local-only check:dev-prereqs / check:skill-frame-freshness not run (not derived). PR footer is the 🤖 form; no PR assignee — as on docs(pm-dispatch): one patrol routine per seat, not per project #28739.
  • 范围外去向: served-override.ts L44–46 header comment still says flow waits. It is a comment only, owned by skills/docs: the ADR-0126 §1.3 promise pages and the skills teach what ADR-0146 D2 delivers — customizations in <base>.custom, __c fields, flow override and "new similar", no package-less overlay #28577. Skills-docs: none further.
  • 落地条款: Tier H, skills/** governed. The PR stays draft with needs-user-decision until an authorised approver acts.

@os-zhuang
os-zhuang marked this pull request as ready for review November 2, 2026 00:01
@os-zhuang
os-zhuang enabled auto-merge November 2, 2026 00:01
@os-zhuang
os-zhuang added this pull request to the merge queue Nov 2, 2026
Merged via the queue into main with commit 7f4cbc9 Nov 2, 2026
53 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-28778-email-template-locale branch November 2, 2026 00:20
marchtian pushed a commit that referenced this pull request Nov 2, 2026
The two passages this card extends now come from main; the conflict on
them is resolved to this branch's text, which is main's plus this card's
sentences (delta against origin/main re-read: this card's changes only).

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ihL2g7RyXa8ErM6GAkHyc
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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

skills(objectstack-platform) + docs: an email-template override names a locale its base ships; a new locale carries no overrides (#28746 follow-up)

2 participants