Skip to content

Commit 89803c5

Browse files
docs(skills): the platform skill teaches the package customizations read's contributions (#30071)
<!-- claude-projects-attribution: {"github_login":"huangyiirene"} --> _Requested by **Irene** · [project thread](https://claude.ai/code/project/chan_01TJXtQ1tVD26ecLDZxFS67x?thread=cmsg_01TJXtQ1tVD26ecLDZxFS67xEzujNK3mUgKv682JDmvunN)_ Fixes #29411 Clause-②: no Metadata-protocol: none The Fable mandate was waived by the maintainer; this PR was developed on Opus. ## 维护者速读 - 改了什么:objectstack-platform 技能的「定制已安装包」一节,在 `GET /packages/<id>/customizations` 段后新增一段,教读取结果的 `contributions` 成员:每个其他包加到基础包上的条目一条,带 `packageId`;`field` / `flow` 条目给出所在的基础包 `object`,`nav` 条目给出基础包的 `app`、目标 `group`(有则给)和条目 id(`name`);`counts.contributions` 数的是条目而非包。另加一个 `'@objectstack/skills': patch` changeset。 - 为什么改:spec 的 `GetPackageCustomizationsResponseSchema` 早已声明 `contributions`(#28722 已在 main 上产出 `nav` 条目),技能只说该读取列出 overrides、extensions 和 switched-off,AI 读不到第四个列表。 - 风险与回滚:纯技能文本 + changeset。token 天花板就地付账:删了同文件三处复述(每处的规则在文件内另有归宿),6004 → 6000 / 6011,上限行未动,无 re-wrap。回滚即 revert。 - 先看:`skills/objectstack-platform/SKILL.md` 新段(L132)与三处删除;对照 `packages/spec/src/api/package-lifecycle.zod.ts` 的 `contributions` 与 `counts.contributions`。 - 两分钟验证:`node scripts/check-skills-token-ratchet.mjs`,预期 platform SKILL.md 6000/6011。 - 需要你做的:Tier H 受管面(`skills/**`),需要 `GOVERNED_APPROVERS` 的批准;PR 保持 draft。 ## What changes `skills/objectstack-platform/SKILL.md`, "Customizing an installed package (ADR-0146)". A new paragraph after the one that introduces `GET /packages/hotcrm/customizations` (that paragraph is byte-identical): ``` That read's `contributions` lists what other packages add to the base, one entry per item with its `packageId`: a `field` or `flow` names the base's `object` it is on, a `nav` item the base's `app`, its `group` if any, and its id as `name`; `counts.contributions` counts items, not packages. ``` Each fact is read off `main` at `c23501b2`: - `GetPackageCustomizationsResponseSchema.contributions` (`packages/spec/src/api/package-lifecycle.zod.ts`): a discriminated union on `kind`; the `field` / `flow` arm carries `object`, `name`, `packageId`; the `nav` arm carries `app`, optional `group`, `name` (the nav item's id), `packageId`. `packageId` is never the base nor its pair. - `counts.contributions`: "`contributions.length`: items, not packages." - **`nav` is served on main.** `readBaseContributions` in `packages/runtime/src/domains/packages.ts` pushes `{ kind: 'nav', app, group?, name: id, packageId }` from `registry.getAppNavContributions(app)` for each app the base owns (#28722 closed; `packages-customizations.test.ts` pins it). So the paragraph teaches it plainly, with no "not yet served" mark. - Not taught, on purpose: "a disabled package's items are not listed". The runtime applies `isPackageDisabled` only to the `nav` loop (a disabled package's flow is simply not registered; fields are not filtered), so a general sentence would overstate it, and the card did not ask for it. `.changeset/29411-platform-skill-package-contributions.md`: `'@objectstack/skills': patch`, with `Clause-②: no` and `Metadata-protocol: none`. `@objectstack/skills` ships this catalog, so the change publishes and takes a changeset, never `skip-changeset`. ### Token ratchet, paid in place (no ceiling row moved, no re-wrap) | file | tokens before / after / ceiling | bytes before / after | lines before / after | |:--|:--|:--|:--| | `skills/objectstack-platform/SKILL.md` | 6004 / 6000 / 6011 (headroom 7 → 11) | 24036 / 24019 | 429 / 426 | The new paragraph is paid for by three deletions in the same file, each a restatement whose rule keeps a home there. The lines around each cut are byte-identical; nothing was rewrapped. 1. **"Exact shape: `ObjectStackDefinitionSchema` in `node_modules/@objectstack/spec/src/stack.zod.ts`; each collection's item schema sits in its domain folder (…)."** (3 lines and the blank line, 201 bytes). Home: the References section ("Always `Read` the source for exact field shapes") and `references/_index.md`, which lists `stack.zod.ts` and every domain schema file. `check:skill-top-level-keys` reads the enumeration paragraph above it by its own anchor, not this line. 2. **"Raise it there; do not compensate for it here."** (the tail of the "fix is upstream" bullet). Home: the "A platform defect means waiting for the platform fix" bullet two items below ("No defensive coding, no shape tolerance …", "Record the block against the platform issue"). 3. **"Pick `demoStaff` whenever the demo needs an account to exist."** (the last sentence of Demo accounts). Home: the section's opening, which says a seed cannot create an account and to "Declare the people in `demoStaff`", and the sentence before it, which says `devLogins` creates nothing. ## Why The skill told an author that the customizations read lists overrides, extensions and switched-off items, and stopped there. The schema has served a fourth list, `contributions`, plus its count, since #28722; an AI reading only the skill would not know other packages' fields, flows and nav items come back on the same read, or would read `counts.contributions` as a package count. ## Verification Head `21e8aa1a` (one commit on `c23501b2`). <details><summary>Local gates on 21e8aa1: 45 derived, 45 run with exit 0, 0 NOT MEASURED (`dispatch-gates --ran`)</summary> - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 45 commands for the two changed files. All 45 ran after `pnpm install --frozen-lockfile` and a full `pnpm build` (exit 0), each with a 900 s timeout and its exit code captured before any pipe. - All 45 exited 0, among them `check-skills-token-ratchet.mjs` (and `--self-test`), `check-changeset-no-major.mjs`, `check-empty-changeset.mjs`, `check:changeset-gate-self-tests`, `check-comment-mask-corpus.mjs`, `check:skill-docs`, `check:skill-top-level-keys`, `check:skill-identifier-liveness`, `check:skill-frame-sync`, `check:skill-compatibility`, `check:role-word`, `check:dts-closure`, `check:dual-build-cjs-loads` and `check:lean-entry-closure`. - `--ran` printed: `45 derived famil(ies) accounted for — 45 run, 0 NOT-MEASURED`. - `node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD`: exit 0 (one commit, no card relation, model-free trailer pair). - Writes: one `git push` (the branch, 21e8aa1); one relay `pr_create`; no GitHub MCP write. </details> - Evals: no case in `skills/objectstack-platform/evals/config-plugins-ops.json` covers the customizations read, so none is run or added for the new paragraph. Two cases (L116, L134) cover the Demo accounts section that cut 3 touches; their expected outputs rest on the sentences that stay (`demoStaff` creates the accounts, `devLogins` creates nothing), so they read the same. ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (No schema touched.) - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `pnpm lint` is CI's repo-wide run. - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. - [x] 6. `packages/spec` not touched. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English (the 维护者速读 block is the repo's own Chinese reading aid). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01J8VVAjMvCpqNhHkd2m3T5A Co-authored-by: Claude <noreply@anthropic.com>
1 parent 8fa370c commit 89803c5

2 files changed

Lines changed: 14 additions & 7 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/skills': patch
3+
---
4+
5+
docs(skills): the platform skill teaches the `contributions` member of the package customizations read
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
`skills/objectstack-platform/SKILL.md` now names `contributions` beside the overrides, extensions and switched-off items that `GET /packages/<id>/customizations` lists: one entry per item another package adds to the base, stamped with its `packageId`; a `field` or `flow` entry names the base's `object` it is on, a `nav` entry names the base's `app`, its `group` when it targets one, and the item id as `name`; `counts.contributions` counts items, not packages. The text is paid for by deleting three restatements in the same file, so the token ceiling is unchanged.

‎skills/objectstack-platform/SKILL.md‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,6 @@ Undeclared keys are handled per surface, in two postures:
6868
Treat these as errors-in-waiting: a key that only warns today is expected
6969
to be refused later.
7070

71-
Exact shape: `ObjectStackDefinitionSchema` in
72-
`node_modules/@objectstack/spec/src/stack.zod.ts`; each collection's item
73-
schema sits in its domain folder (`data/object.zod.ts`, `ui/view.zod.ts`, …).
74-
7571
→ Moved verbatim to [references/bootstrap.md](./references/bootstrap.md) § Map Format (Key → Name) · § Barrel Import Pattern.
7672

7773
### Strict Validation
@@ -133,6 +129,8 @@ to a new protocol major — never to silence a mismatch.
133129

134130
The pair comes from `POST /api/v1/packages/hotcrm/ensure-customization`: `namespace` = the base's + `_custom`, `dependencies: { hotcrm: '^<major>' }`; `GET /packages/hotcrm/customizations` lists its overrides, extensions and switched-off items, and uninstalling the base is refused (`409`) while the pair exists. Only the pair declares: the save, publish and install doors, `os validate` and `os build` refuse `overrides` from any other package, and a dependent's item under a base item's name — its one fix is a new name. A permission set, position or capability is never overridden: copy it under a new name ("new similar", landing in the pair). An object is extended (`__c` fields, **objectstack-data**); a flow is overridden or copied (**objectstack-automation**).
135131

132+
That read's `contributions` lists what other packages add to the base, one entry per item with its `packageId`: a `field` or `flow` names the base's `object` it is on, a `nav` item the base's `app`, its `group` if any, and its id as `name`; `counts.contributions` counts items, not packages.
133+
136134
---
137135

138136
## The App / Platform Boundary
@@ -144,7 +142,7 @@ what the platform owns.
144142

145143
- **Business features belong in the app; capability belongs in the platform.**
146144
A missing default, a wrong diagnostic, a shape the spec refuses — the fix is
147-
upstream. Raise it there; do not compensate for it here.
145+
upstream.
148146
- **Could this be written by something that has only the metadata, and no
149147
knowledge of this company?** *No* — it encodes this company's own judgement (a
150148
discount ceiling, who a case is assigned to, how won/lost is booked) ⇒ the
@@ -403,8 +401,7 @@ boot writes `manager_id` itself once every account exists and keeps one set
403401
by hand, so no seed hook writes it; a display name, an address no entry
404402
has, the entry itself or a loop is refused at load; `os build` drops the
405403
key and a non-dev boot creates nothing. `devLogins` creates and grants nothing — it only prints an
406-
existing account on the boot banner. Pick `demoStaff` whenever the demo
407-
needs an account to exist.
404+
existing account on the boot banner.
408405

409406
---
410407

0 commit comments

Comments
 (0)