Skip to content

skills(objectstack-ui): state the one-app-per-package cap in App Navigation (GOVERNED — over the token ratchet by 59, needs a maintainer decision) - #17310

Draft
baozhoutao wants to merge 1 commit into
mainfrom
claude/issue-16565-one-app-rule-ui-skill
Draft

skills(objectstack-ui): state the one-app-per-package cap in App Navigation (GOVERNED — over the token ratchet by 59, needs a maintainer decision)#17310
baozhoutao wants to merge 1 commit into
mainfrom
claude/issue-16565-one-app-rule-ui-skill

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Item 2 of #16565. This PR does not close that card — item 1/3 ship in the companion PR #17309 and item 4 remains open. No closing keyword is used here.

GOVERNED SURFACE — do not merge, queue, arm auto-merge, or flip out of draft. skills/** is on the GOVERNED_SURFACES register. Landing this is a GOVERNED_APPROVERS act by hand. It is deliberately kept out of #17309's diff: a mixed diff is governed whole, judged on the file list and not on proportion.

⚠️ This PR is RED by design and cannot go green without a decision that is not mine to make. See The price, below. Nothing was trimmed and no ceiling was moved.

维护者速读(草稿)

改了什么 —— skills/objectstack-ui/SKILL.md 的 App Navigation 一节加三行:一个 type: 'app' 包只暴露一个 App,多受众是它内部用 requiredPermissions 门控的分组,并把 ADR-0019 写成指名到 app-as-consumer-unit 记录。只加这一处,不动别的。

为什么改 —— 这是 AI 作者真正会读的地方。发布包里的实测:一个 app 的规则出现 0 次(所有拼写),而 defineStack 出现 54 次、App.create 3 次 —— 零是读数,不是空语料。照这份技能写 *.app.ts 的 agent 没有任何理由不按受众开三个 app,直到 defineStack 在 load 期抛出;卡片记录的真实代价是「一个设计小节 + 一张卡 + 一次已派发的实现」全部重做。发布包里现有的 3 处 ADR-0019 全部指向 approvals 那份记录,所以顺着引用走的作者会落到错误的 ADR。

风险与代价(含回滚) —— ⭐ 代价是 59 个 token,而 skills/objectstack-ui/SKILL.md 的余量实测为 0(3815/3815)。 加完是 3874,超出 59。门禁自己的判定行:✗ ... is 3874 tokens; the ratchet ceiling is 3815 (over by 59) ... ⛔ MAINTAINER-ONLY。⛔ 我没有动上限常量,也没有为了腾空间删任何别的内容 —— 按门禁自己的规则,抬上限只能落在「正文引用了维护者裁决」的 PR 里,而我拿不出这样一条裁决;删内容则是替你做编辑判断。两者都留给你。回滚成本为零:单文件、三行、无代码、无生成物,关掉 PR 即可。

席位意见 —— (留空,待席位定稿)

你要做的 —— 三选一:① 认为这 59 token 值得,给出裁决并授权抬 ceiling(定稿时把裁决原话贴进本正文);② 认为不值得,关掉本 PR —— 规则仍由 #17309 在文档面陈述,只是 agent 读不到;③ 指定同文件内一处等量删减来支付,我据此改。⛔ 无论哪一个,#16565 都不因本 PR 关闭。

The measurement, re-derived

Taken on origin/main at b90aff81f2, over the whole published bundle. Every zero carries a same-corpus positive control from the same pass.

grep -ric over skills/          (BEFORE)
  'at most one app'                    0
  'exactly one app'                    0
  'only one app'                       0
  'one app per package'                0
  'single app'                         0
  'app-as-consumer-unit'               0
  positive control  defineStack       54
  positive control  App.create         3
  positive control  ADR-0019           3   <- and all 3 mean the APPROVALS record:
                                             objectstack-automation/SKILL.md x2,
                                             objectstack-platform/SKILL.md x1
  negative control  'zzz-nonsense-zzz'  0

So the rule is absent in every spelling from a bundle that names defineStack 54 times, and the number an author would follow resolves, in this bundle's own usage, to the wrong record.

The price — measured before writing, exactly as instructed

Headroom was read first, from the gate rather than assumed:

BEFORE   skills/objectstack-ui/SKILL.md   15260 bytes  ->  3815 tokens   ceiling 3815   headroom 0
AFTER                                     15494 bytes  ->  3874 tokens   ceiling 3815   over by 59
delta                                      +234 bytes       +59 tokens

15260 is exactly divisible by the gate's 4-bytes-per-token convention, so the headroom is not merely small — a single added byte overflows it.

Package total, for the whole-package reading this surface owes:

skills/objectstack-ui, all files      BEFORE 114289 bytes   AFTER 114523 bytes   (+234)
ratcheted authored catalog total      BEFORE 139932 / 157098   AFTER 139991 / 157098

The gate's own verdict line, run on this branch after the edit (node scripts/check-skills-token-ratchet.mjs, exit 1 — a finding, not a PREREQUISITE NOT MET 3):

✗ check-skills-token-ratchet: skills/objectstack-ui/SKILL.md is 3874 tokens; the ratchet
  ceiling is 3815 (over by 59). ... New text is paid for by deleting text IN THE SAME FILE
  — genuine deletion, never a re-wrap ... Loosening a ceiling to fit new text is not the fix:
  these ceilings are shrink-only. The other direction lands only in a PR whose body quotes a
  maintainer ruling authorizing it. ⛔ MAINTAINER-ONLY

I hold no such ruling, so the ceiling stays where it is and this PR stays red.

Why nothing was trimmed to pay for it. The obvious candidate is the section's opening sentence — "An App groups objects, dashboards, reports, and custom pages into a structured navigation tree" — which is arguably restated by the navigation-item-types table directly beneath it. That is an editorial judgement about someone else's prose, made only to buy budget, and it is offered here as an option rather than performed. rules/navigation.md is not an escape either: it is also at exactly 0 headroom (2273/2273). Checked for genuine redundancy between the two files — separator, componentRef, actionDef, requiresService, recordId each appear in SKILL.md and zero times in rules/navigation.md, so the section duplicates nothing and there is no free deletion to take.

Changeset: measured separately, and the answer is the label

Not a changeset — the skip-changeset label. Measured rather than assumed: no package manifest's files[] contains skills (checked across every tracked package.json), skills/ is not a workspace member, and the root manifest is private. pr-automation.yml spells this exact case out, including that an empty-frontmatter changeset is now rejected and that the label is what "names no package" is for. The label is applied on this PR.

Verification

Gate family derived from this diff, not recalled:

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack   ->  24 commands
24 run: 23 exit 0, 1 exit 1 (the token ratchet, intended and described above)

pnpm --filter @objectstack/lint run check:doc-formula-expressions first returned exit 3PREREQUISITE NOT MET, which is neither green nor red — and was driven to a real verdict (exit 0) after building @objectstack/formula and @objectstack/lint. pnpm check:pm-governed-merges, check:skill-frame-sync, check:skill-compatibility, check:skill-identifier-liveness, check:nul-bytes and check:doc-authoring all exit 0. Exit codes captured before any pipe.

🤖 Generated with Claude Code

https://claude.ai/code/session_012GKcPZbMoGq7WPzKLfRBTU


Generated by Claude Code

…gation

The App Navigation section tells an author to `register under
defineStack({ apps: [...] })` and stops there. Nothing in the published
bundle says the array holds one entry: measured across `skills/`, the
one-app rule appears 0 times in any spelling, while `defineStack` appears
54 times and `App.create` 3 — the zeros are readings, not an empty corpus.
An agent authoring `*.app.ts` from this skill therefore has no reason not
to write one app per audience, and finds out at `defineStack` load time,
after the design is written.

All three `ADR-0019` citations in the published bundle point at
`0019-approval-as-flow-node`, so this one names its record explicitly.

⚠️ This overruns the published-skills token ratchet by 59 tokens
(3874 against a ceiling of 3815, headroom measured at 0 before writing).
The ceiling is deliberately NOT touched and nothing else is trimmed to
pay for it — both are maintainer decisions. See the PR body.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012GKcPZbMoGq7WPzKLfRBTU
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/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants