Skip to content

docs(skills): split the four over-500-line SKILL.md into routing + references, TOC the seven long reference files, trim data's description - #19738

Merged
hotlong merged 4 commits into
mainfrom
claude/issue-19715-published-skills-split-500
Sep 23, 2026
Merged

hotlong merged 4 commits into
mainfrom
claude/issue-19715-published-skills-split-500

Conversation

@huangyiirene

@huangyiirene huangyiirene commented Sep 22, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #19715
Clause-②: no

维护者速读(草稿)

改了什么 — 四个超过 500 行的已发布 SKILL.md(platform 1223 → 487 · automation 961 → 448 · data 854 → 469 · upgrade 600 → 488)按标题边界切分:每个被移走的段落与代码块逐字节落到该技能自己的 references/ 下(新增 9 个参考文件),原位只留一行指针;七个超过 300 行的参考文件顶部各加 5 行目录(锚到已有标题);objectstack-data 的 description 压到 689 字符,触发短语与排除句原样保留、只删括号枚举。零删内容:20 个移动块中 17 个字节相同,3 个仅改了 10 处相对链接路径(逐条列在下文)。

为什么改 — 决策批次 #213 第 1 项,维护者裁决「1 2 4 同意」:超长 SKILL.md 会被 head 预读截断,示例与运维尾段读起来像第二个技能;切成「路由 + 规则」后入口文件只装规则、决策表与指针,长示例按需跟指针再读。

风险与代价(含回滚) — ① 直接读 SKILL.md 单文件时,105 个 eval 断言词里有 18 个(从 103 降到 85)现在只经指针可达;整棵技能树(SKILL.md + rules + references)的读数 105/105 前后不变,方法与局限见下文。② 为了到 500 行,platform 的第二部分(插件开发)与 automation 的「状态机与审批」整段下沉,其中含少量决策表——它们仍在树里,入口页保留指向 rules/*.md 的路由行。③ 三个门禁脚本的数据行跟着文本走(token 天花板行、role-word 基线两行搬家、scaffold 政策的载体路径),没有新增门禁。④ 令牌总量 +2058(指针行 + 目录行),四个入口行已按落地值下锁,七个目录文件中 4 行按裁决上调、3 行有余量按落地值下锁。回滚:整个 PR 一次 revert 即可,没有生成物或状态迁移。

席位意见 — 建议批准并合并,但先看一眼「Sections that left SKILL.md」。 裁决的八条形状逐条核过:零删内容(20 个移动块 17 个字节相同、3 个只改了 8 处相对链接;席位另做了四个技能的整行多重集比对,除链接与 description 外没有任何一行离开树)、四个入口文件全部 ≤ 500、data 的 description 689 字且触发短语与排除句原文保留、七个长参考文件各 5 行目录且锚点全部可达、净 +77 ≤ +80、无新门禁、changeset 按 #19721 惯例。evals 读数按机械法前后树列 105 / 105 不变;入口页单读 103 → 85,离开的 18 个词都在指针可达处 —— 这是切分的代价,不是丢失。token 棘轮四行入口下锁、九个新文件零余量钉住、四行目录文件按裁决引文上调。第 0 轮 CI 红是本 PR 的:packages/rest 的仓级测试钉住 automation 入口页必须写出状态内省路由,切分把唯一拼写搬走了;第 1 轮把拼写放回指针行(净 0 行,不改测试),席位在补丁头上重跑该测试 8 / 8 绿。留给你的一个判断:为了到 500 行,platform 的插件开发与运维两大部分、automation 的状态机与审批、data 的 seeds / 字段组 / lint 整段下沉,其中含少量决策表 —— 它们仍在树里、入口页留有路由行;如认为某段必须留在入口页,点名即可,dev 按行预算换一段下沉。复核记录:PR 评论 5786766593(PASS,在席按服务档渲染);ACCEPT 在卡 #19715。CI 读数:32 latest-per-name check runs — 25 success, 7 skipped, 0 in progress, 0 other。

你要做的 — 这是 Tier H(skills/**)受管面:确认「哪些规则段可以离开入口页」符合你的意图(见「Sections that left SKILL.md」),然后手工合并;如认为某段必须留在入口页,请点名,我按行预算再换一段下沉。


What this does

The four published SKILL.md files over 500 lines are split at heading boundaries into routing + rules. Every moved paragraph and code block lands verbatim under that skill's references/ (nine new files) with a one-line pointer left where it was; the seven reference files over 300 lines gain a 5-line table of contents anchored to their existing headings; objectstack-data's description shrinks to 689 characters with the same trigger phrases and exclusion sentence. The token ratchet re-locks the four entry rows at their landed counts, pins the nine new files at theirs, and raises the four TOC'd rows that carried no headroom by exactly the added tokens under the ruling. skills/README.md and content/docs/ai/skills-reference.mdx are regenerated from the trimmed frontmatter by gen:skill-docs.

Premise re-measured on origin/main 106d4c8dd before editing: the four line counts (1223 · 961 · 854 · 600) hold; the seven files carried no TOC; data's description measured 1003 characters by a YAML folded-scalar parse (the card's 1,023 was a different counting; either way it sat against the 1,024 cap). premise_still_valid: true.

Readings after (head 011dfd603)

File Before After
skills/objectstack-platform/SKILL.md 1223 487
skills/objectstack-automation/SKILL.md 961 448
skills/objectstack-data/SKILL.md 854 469
skills/objectstack-upgrade/SKILL.md 600 488
data description (YAML folded, trailing newline excluded) 1003 chars 689 chars
net lines across skills/** (tracked +77 / −1781, new files +1781) — +77 (budget ≤ +80)

Diff proof — every moved block (source lines at 106d4c8dd → destination), verified byte-for-byte against the base blob

# Source (lines, count) Heading(s) Destination (lines) Bytes
1 platform SKILL.md 39–68 (30) ### Minimal Example references/bootstrap.md 3–32 verbatim
2 platform 116–157 (42) ### Map Format (Key → Name) · ### Barrel Import Pattern references/bootstrap.md 34–75 verbatim
3 platform 272–280 (9) ### Scaffolding Command references/bootstrap.md 77–85 verbatim
4 platform 498–527 (30) ### Plugin Loading Order Matters · ### Programmatic Bootstrap (Without CLI) references/bootstrap.md 87–116 verbatim
5 platform 531–542 (12) ## Multi-App Composition references/bootstrap.md 118–129 verbatim
6 platform 585–644 (60) ## Complete Working Example references/bootstrap.md 131–190 verbatim
7 platform 649–1007 (359) # Part 2 — Plugin Development & Kernel Extension (whole) references/plugin-development.md 1–359 6 link paths re-pathed, else verbatim
8 platform 1012–1213 (202) # Part 3 — Operations: CLI, Testing, Deployment (whole) references/operations.md 1–202 verbatim
9 automation 143–209 (67) ### Flow Example — Auto-Escalate Overdue Cases references/examples-flows.md 3–69 verbatim
10 automation 378–760 (383) ## State Machines & Approvals (whole) references/state-machines-and-approvals.md 1–383 verbatim
11 automation 851–916 (66) ### Time-relative triggers — scheduled per-record date sweep references/examples-flows.md 71–136 verbatim
12 data 184–230 (47) ## Field Groups (MVP) references/examples-objects.md 3–49 verbatim
13 data 300–359 (60) ## Quick-Start Template references/examples-objects.md 51–110 1 link path re-pathed
14 data 499–525 (27) ### Lifecycle Hooks references/examples-objects.md 112–138 1 link path re-pathed
15 data 565–622 (58) ## Metadata Protection (\protection`)` references/examples-objects.md 140–197 verbatim
16 data 626–767 (142) ## Seed Data & Fixtures (\defineSeed()`)` (whole) references/seeds.md 1–142 verbatim
17 data 771–823 (53) ## Linting & Generation Quality references/lint-rules.md 1–53 verbatim
18 upgrade 269–301 (33) ### 2.3 A worked R1 — the retired field-mapping \transform`` references/examples-upgrade.md 3–35 verbatim
19 upgrade 449–496 (48) ### 3.4 The report — the human half references/examples-upgrade.md 37–84 verbatim
20 upgrade 540–573 (34) ## The v17-canonical shapes, compiled references/examples-upgrade.md 86–119 verbatim

Method: for each row the base bytes (git show 106d4c8dd:path, the listed lines) were hashed against the destination's listed lines — 17 rows identical, 3 rows differ only on the link-path lines below. The upgrade a-tag anchors (decide-alone-or-ask, reverse-check) stayed in SKILL.md because they sit just outside the moved ranges. The four new multi-block files carry a one-line H1; the five single-block files begin with the moved heading itself.

The only non-verbatim bytes — 10 link-path retargets (a relative link crossing a move boundary would otherwise dangle):

  • platform SKILL.md (staying text): #verify-your-work, #ports--networking, #part-3--operations-cli-testing-deployment → ./references/operations.md#… (3)
  • references/plugin-development.md (moved text, lines 656/657/658/738/760/791 at base): ./rules/plugin-lifecycle.md → ../rules/… (2), ./rules/service-registry.md → ../rules/… (2), ./references/plugin-hooks.md → ./plugin-hooks.md (2), ../objectstack-data/SKILL.md → ../../objectstack-data/SKILL.md (1)
  • data SKILL.md (staying text): #field-groups-mvp → ./references/examples-objects.md#field-groups-mvp (1)
  • references/examples-objects.md (moved text, base lines 359 and 523): ./rules/indexing.md → ../rules/indexing.md (1), ./references/data-hooks.md → ./data-hooks.md (1)

Every intra-file anchor in the 15 touched markdown files resolves (github-slugger, the repo's slug authority; 100 anchors, 0 unresolved) and all 104 relative links under skills/** resolve to existing files (the two ./crm_index.md / ./crm_user_guide.md spellings in objectstack-ui/rules/pages.md are illustrative example text on the base, untouched).

Sections that left SKILL.md, and why the route had to widen

The card's route (platform's ops tail + the two 60-line complete examples) reaches 894 lines on platform — the fenced code in the four files totals 462 / 310 / 223 / 162 lines against the 723 / 461 / 354 / 100 that had to go, so examples alone cannot reach 500 on three of the four. The cut therefore also moves whole self-contained parts: platform Part 2 (plugin development, which already has its own rules/*.md and references/plugin-hooks.md — the entry keeps a routing line to them), automation's State Machines & Approvals, data's Seed Data & Fixtures, Field Groups and Linting. Decision tables that now live behind a pointer: platform's ObjectKernel vs LiteKernel, Plugin Loading Order, Well-Known Plugin Names, MetadataPlugin boundary, Feature Flags, the ops tables; automation's Approver Types, Node Config, Branching, Best Practices and the state-machine rule; data's seed tables and the lint-rule table. Every pointer names the destination and the moved headings (heading names only — no paraphrase). If the maintainer wants a named section back in the entry, it costs its line count against the 500 ceiling; say which and I swap.

Evals reading (card item 5) — method, before / after, limit

There is no executable runner in this repo: the fixtures skills/*/evals/*.json are read by scripts/check-skills-token-ratchet.mjs for pricing only (no script consumes must_contain). The reading is therefore the mechanical one the dispatch names: for every eval of the four skills, each must_contain term's presence (substring, case as written) in that skill's SKILL.md alone and in the skill tree (SKILL.md + rules/** + references/**), on 106d4c8dd and on this head. Script: eval-reading.mjs (in the scratchpad, not committed).

Skill SKILL.md alone, before SKILL.md alone, after Tree, before Tree, after
objectstack-platform 24/24 18/24 24/24 24/24
objectstack-automation 26/26 20/26 26/26 26/26
objectstack-data 35/37 31/37 37/37 37/37
objectstack-upgrade 18/18 16/18 18/18 18/18
total 103/105 85/105 105/105 105/105

The tree column — the reading of record for a skill whose entry routes to references — is unchanged for all 105 terms. The 18 terms that left SKILL.md alone, each with the pointer on the eval prompt's path (the two data terms already absent on the base, schemaMode and type: 'secret', live in rules/datasources.md and rules/security.md and are untouched):

Eval Term Now in Pointer in SKILL.md
platform #2 (audit plugin) registerService, ctx.hook(, metadata:reloaded, init(, destroy references/plugin-development.md (+ rules/plugin-lifecycle.md, references/plugin-hooks.md) the Part 2 pointer, which also names rules/plugin-lifecycle.md · rules/service-registry.md · references/plugin-hooks.md
platform #6 (production deploy) OS_TRUSTED_ORIGINS references/operations.md the Part 3 pointer (names Ports & networking · Deployment targets)
automation #1 (nightly sweep) defineFlow, type: 'schedule' references/examples-flows.md the Flow Example pointer; the Flow Types table row schedule stays in the entry
automation #3 (approval + revise) type: 'approval', type: 'back', maxRevisions references/state-machines-and-approvals.md the State Machines & Approvals pointer (names Send-back for revision · Node Config); approval_revise and revise stay in the entry
automation #5 (function step) timeoutMs references/examples-flows.md the Flow Example pointer
data #4 (seeds) env:, daysFromNow references/seeds.md the Seed Data pointer (names Dynamic values (CEL)); defineSeed, externalId, upsert stay in the entry
data #2 (invoice lines) deleteBehavior, inlineEdit rules/relationships.md, rules/field-types.md, references/lint-rules.md the Relationship Patterns table's link to rules/relationships.md (unchanged)
upgrade #2 (conditionalRequired) requiredWhen references/examples-upgrade.md the v17-canonical shapes pointer
upgrade #3 (transform residue) never executed references/examples-upgrade.md the worked R1 pointer

Limit of the method: substring presence is not a graded run — it cannot say whether an agent given the prompt would follow the pointer. It is the reading the card can have today; no runner was built (item 6). No assertion was tuned.

Token ratchet (scripts/check-skills-token-ratchet.mjs, convention ceil(utf8 bytes / 4))

Bundle total 152,338 → 154,396 (+2,058: the 20 pointer lines, seven 5-line TOCs, four new-file titles, minus the description trim); ratcheted ceiling sum 157,621 → 154,915 (the four entry re-locks bank their shrink). Gate and --self-test green on this head (54 authored files within ceilings, 65 self-test cases).

Row Ceiling before → after Kind
objectstack-platform/SKILL.md 12984 → 5833 re-lock at landed count
objectstack-automation/SKILL.md 12768 → 5762 re-lock
objectstack-data/SKILL.md 10009 → 6128 re-lock
objectstack-upgrade/SKILL.md 8333 → 6193 re-lock
objectstack-data/rules/field-types.md 3032 → 3158 raise +126 (TOC; zero headroom) — ruling cited in the row
objectstack-ui/rules/dashboards.md 6090 → 6252 raise +162 (TOC; zero headroom)
objectstack-ui/rules/list-views.md 3011 → 3141 raise +130 (TOC +132, 2 absorbed)
objectstack-ui/rules/pages.md 5501 → 5692 raise +191 (TOC; zero headroom)
objectstack-data/references/data-hooks.md 12611 → 10066 re-lock (TOC +182 landed inside 2,727 headroom)
objectstack-data/rules/relationships.md 3778 → 3676 re-lock (TOC +154 inside 256 headroom)
objectstack-data/rules/validation.md 3109 → 2756 re-lock (TOC +155 inside 508 headroom)
9 new rows examples-flows 1436 · state-machines-and-approvals 5569 · examples-objects 1779 · lint-rules 970 · seeds 1299 · bootstrap 1351 · operations 3125 · plugin-development 3137 · examples-upgrade 1197 pinned AT landed count, zero headroom

The dispatch's assumption that all seven TOC'd rows sat at zero headroom was false for four of them; those four are re-locked (a lowering, always legitimate) rather than raised.

Other gate data that followed the moved text (no new gate, ratchet or check script)

  • scripts/role-word-baseline.json: the automation entry's one role occurrence (the Approver Types row) and the upgrade entry's one (role: in the v17 agent shape) moved with their sections; the two ledger rows moved with them. 44 files / 123 occurrences before and after — a relocation, not an expansion; check:role-word green.
  • scripts/sync-scaffold-emission-policy.mjs: the published-restatement row that locates the Complete Working Example's package.json fence by heading now points at references/bootstrap.md, where the fence lives; check:scaffold-emission-policy green (2 carriers).
  • Generator-owned files: check:skill-refs stays green without regeneration — build-skill-references.ts owns only _index.md, *.zod.ts and subfolders under references/, so the new top-level hand-written files are inputs it tolerates; _index.md lists Zod schemas only. gen:skill-docs regenerated skills/README.md and content/docs/ai/skills-reference.mdx (the one file outside skills/** and the gate scripts).
  • check-skill-identifier-liveness leg-2 bindings (## Seed Data on platform, ### Access depth … on data) stayed in their entries.

Gates (captured exit before any pipe; union derived by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands on 011dfd603, 70 families, --ran reconciles 70/70 with exit codes)

All 70 derived families exit 0 on 011dfd603, plus pnpm --filter @objectstack/spec check:generated (15 artifacts up to date after the origin/main merge). The ones that read a build were run after pnpm --filter '@objectstack/lint...' build and pnpm --filter '@objectstack/client-react...' build under the shared verify lock: check:skill-examples — "258 prose examples type-check across 3 surface(s)" (the moved os:check blocks included); check:docs; check:docs-transcript-drift; the two @objectstack/lint doc checks. Highlights: check:skills-token-ratchet + self-test ✓ · check:skill-docs ✓ · check:skill-refs ✓ · check:skill-identifier-liveness ✓ · check:skill-top-level-keys ✓ · check:skill-compatibility ✓ · check:skill-frame-sync ✓ · check:doc-authoring ✓ · check:role-word ✓ · check:scaffold-emission-policy ✓ · check:nul-bytes ✓ · check:pm-dispatch-gates (1905 cases) ✓ · bare-root-worklist --self-test ✓ (the skills/*/references/** liveness/precision pin holds over the enlarged population). pnpm lint (repo-wide eslint) is CI's run: the diff touches no .ts/.js source, only markdown, one JSON ledger and two .mjs gate scripts whose own self-tests ran green.

Branch merged origin/main 170fd836a (three spec commits, no overlap with this diff) before opening; packages/spec was rebuilt after the merge.

Changeset

skip-changeset, per the last merged skills/** PR (#19721: documentation · skip-changeset, Clause-②: no) and measured: no workspace package's files[] ships skills/ (positive control: packages/cli ships bin). Clause-②: no. Tier H — draft, the maintainer merges by hand.

Acceptance notes

  • Two data eval terms were already reachable only through rules/ on the base (schemaMode, type: 'secret') — noted, not a card.
  • objectstack-ui/rules/pages.md lines 356/448 carry ./crm_index.md-style example links that resolve to nothing; they are illustrative package-docs text inside the Docs section, untouched here — noted, not a card.

Generated by Claude Code


Generated by Claude Code

…ferences, zero deletion

The four published SKILL.md files over 500 lines (platform 1223, automation
961, data 854, upgrade 600) now keep frontmatter, when-to-use, rules, decision
tables and pointers; every moved paragraph and code block lands verbatim under
that skill's references/ with a one-line pointer left where it was. The seven
reference files over 300 lines gain a 5-line table of contents anchored to
their existing headings. objectstack-data's description shrinks to 689
characters with the same trigger phrases and exclusion sentence. The token
ratchet re-locks the four entry rows at their landed counts, pins the nine new
reference files at theirs, and raises the four TOC'd rows that carried no
headroom by exactly the added tokens under the maintainer's ruling on
decision batch #213 item 1. skills/README.md and the skills-reference page are
regenerated from the trimmed frontmatter.

Claude-Session: https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc
Co-authored-by: Claude <noreply@anthropic.com>
… scaffold-emission-policy carrier path

The role-word ledger keeps its 123 occurrences: the one in the automation
entry and the one in the upgrade entry now sit in the reference files their
sections moved to verbatim. The scaffold emission policy's published
restatement row points at references/bootstrap.md, where the Complete Working
Example's package.json fence now lives, so the fence stays enforced.

Claude-Session: https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc
Co-authored-by: Claude <noreply@anthropic.com>
…te-introspection route

packages/rest's repo-level test pins skills/objectstack-automation/SKILL.md as
a site that teaches /api/v1/meta/object/:name/state/:field, the path the REST
ledger row for meta.getLegalNextStates declares; the split had moved the only
spelling into references/state-machines-and-approvals.md. The pointer line
for that block now carries the one spelling (net 0 lines, the reference is
untouched), and the entry's token-ratchet row is re-locked at its new landed
count.

Claude-Session: https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc
Co-authored-by: Claude <noreply@anthropic.com>

Copy link
Copy Markdown
Collaborator Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: ef0b6182918202c0c6147c04836e64f16a27fe21

① Derived judgments

Rendered in-seat by the skills seat 1 session at the served tier the maintainer named on this date (the fable tier word at get_session → external_metadata.last_served_model, re-read this hour; ruling record 5771798588). The contract is the maintainer's 「1 2 4 同意」 on decision batch #213 item 1, filed by the director seat as the 直派 card's ruled shape (8 items, ⛔ not open for re-design): the four over-500-line published SKILL.md split at heading boundaries into routing + rules with every moved block VERBATIM under that skill's references/ and a one-line pointer left in place; each of the four ≤ 500 lines; objectstack-data's description ≤ 700 characters with the trigger phrases and the exclusion sentence kept; a 5–8 line TOC on the seven reference files over 300 lines; the #19714 evals read before and after; ⛔ no new gate; net ≤ +80 lines across skills/**; Tier H.

  • (a) Zero content deletion — proved by this seat two ways on a review worktree at the head. Block by block: the 20 moved blocks (source line ranges at the base → destination ranges, as the PR body tables them) compared line for line — 17 byte-identical, 3 differing only on 8 relative-link retargets (./rules/… → ../rules/…, ./references/x.md → ./x.md, ../objectstack-data/… → ../../objectstack-data/…) that a moved file needs to keep its links live. Multiset: every line of the four base SKILL.md files is present in the after tree (SKILL.md + the nine new references/*.md) except the retargeted link lines and the rewritten description lines — nothing else left the tree; automation and upgrade lose no line at all.
  • (b) The four readings, re-measured. SKILL.md lines: platform 1223 → 487, automation 961 → 448 (448 after round 1 as well), data 854 → 469, upgrade 600 → 488; the six skills under the line untouched. Net across skills/**: +77 (tracked +77 / −1781 against the base, the nine new files +1781; the round-1 pointer edit is +1 / −1) (budget ≤ +80). data's description: 1003 → 689 characters by the YAML folded-scalar parse (the card's 1,023 was a different count; either way at the 1,024 cap) — the trigger phrase 「Use when the user is creating or modifying *.object.ts files or src/data/*.ts seed modules …」 and the exclusion sentence 「Do not use for querying data (see objectstack-query) or for plugin / kernel hooks (see objectstack-platform)」 kept verbatim; the parenthetical enumerations (defineDatasource, defineSeed(), the retention / rotation / protection list, the CEL contexts) dropped. TOCs: 5 lines on each of the seven files, every anchor resolving to an existing heading under the slug rule (this seat re-derived the slugs; 87 anchors, 0 unresolved).
  • (c) The evals reading, re-run by this seat with the dev's script on the base tree and the head. No executable runner exists (the fixtures are read only by the token ratchet for pricing), so the reading is mechanical: each must_contain term's presence in SKILL.md alone and in the skill tree. Tree column 105 / 105 before and after — unchanged for every term. SKILL.md-alone 103 / 105 → 85 / 105 (round 0 and round 1 alike — the route spelling is no eval term): the terms that left the entry file each sit behind the pointer on the prompt's path (the PR body tables the 18). Limit stated: substring presence is not a graded run.
  • (d) The token ratchet — read row by row. The four entry rows re-locked at the landed counts; nine new rows pinned at their landed counts with zero headroom (bootstrap 1351, plugin-development 3137, operations 3125, examples-flows 1436, state-machines-and-approvals 5569, examples-objects 1779, seeds 1299, lint-rules 970, examples-upgrade 1197); four TOC'd rows that carried no headroom RAISED by exactly the TOC's tokens with the ruling cited in the row (field-types +126, dashboards +162, list-views +130, pages +191); three TOC'd rows with headroom re-locked downward (data-hooks, relationships, validation) — the dispatch's H3 was wrong about those three. Bundle total 152338 → 154396 (+2058 tokens of pointers, TOCs and H1s); the ceiling sum falls 157621 → 154915. Gate data rows outside skills/** followed the text (the ratchet rows; two role-word baseline rows relocated with an unchanged total; the scaffold-emission-policy carrier path) — ⛔ no new gate; skills/README.md and content/docs/ai/skills-reference.mdx regenerated by gen:skill-docs.
  • (e) The dispatch's route widened by measurement, and the maintainer decides the residue. Zone 3's cut (the ops tail + two complete examples) reaches only 894 lines on platform, so whole self-contained parts moved (platform Part 2 — plugin development; automation's State Machines & Approvals; data's Seed Data, Field Groups, Linting) and some decision tables now sit behind pointers — listed in the PR body under 「Sections that left SKILL.md」 for the maintainer's word; item 2's 「keeps the rules and decision tables」 could not hold in full at ≤ 500 and the PR says so rather than hiding it.
  • (f) Round 1 — CI red on the first head, this PR's, fixed. Test Core (2/6) failed on 011dfd6: packages/rest/src/meta-state-route-doc-spelling.test.ts pins skills/objectstack-automation/SKILL.md as a TEACHING_SITE of the ledger's canonical route /api/v1/meta/object/:name/state/:field, and the split had moved the only spelling into the reference. Round 1 (ef0b61829, one single-parent commit on the same branch, ordinary push): the pointer line for the moved block now ends with the route spelling GET /api/v1/meta/object/:name/state/:field?from=:state — net 0 lines (448 / 500), the reference untouched and still carrying the Introspection bullet, ⛔ no test edit, ⛔ no assertion tuned; the dev measured the test's MENTION / CANONICAL construction on the edited line before running it (one hit, canonical); the automation SKILL.md ratchet row re-locked 5762 → 5785 with the pinning test named in the row's comment (a re-lock of a row this same PR lowered by 7,006). The seat re-ran pnpm --filter @objectstack/rest run test:repo on the patched head: 1 file, 8 / 8 tests green, both formerly red assertions among them; the entry file carries the spelling once, the reference once. The seat grepped every test that reads a published SKILL.md (rest, formula ×2, lint ×2, create-objectstack): only this one was red; shards 1 and 3–6 green on the first head.
  • (g) Gates — re-run by this seat on the review worktree after pnpm install --frozen-lockfile --offline. check-skills-token-ratchet 0 (54 authored files within their ceilings) and its self-test 0 (65); check:skill-refs (spec) 0 — 9 generated files in sync; check:skill-docs 0; check:skill-identifier-liveness 0 (456 citations over 53 files); check:skill-top-level-keys 0; check:skill-compatibility 0; check:skill-frame-sync 0; check:doc-authoring 0; check:role-word 0 (123 occurrences, no new); check:scaffold-emission-policy 0; check:nul-bytes 0; bare-root-worklist --self-test 0; re-run by the seat on the patched head: the token ratchet 0 (objectstack-automation/SKILL.md 5785 / 5785, headroom 0) and its self-test 0, check:skill-docs 0, check:skill-refs 0, check:role-word 0, check:scaffold-emission-policy 0, check:nul-bytes 0; the evals reading unchanged; check-governed-merges.mjs --pr 19738 exit 3 — GOVERNED, Tier H (skills/** ×21, 3754 changed lines under the human-merge threshold). The dev's derivation: 70 families, --ran 70 / 70 / 0 NOT-MEASURED after the declared builds through the verify lock; the spec check:skill-examples (258 prose examples) green after the build. CI at the round-1 head at the seat's read: 30 latest-per-name check runs — 12 success, 7 skipped, 11 in progress, 0 other (the round-0 head had shards 1 and 3–6 green and shard 2 red; the 四件套 waits for this head to finish).

② Semver level

None — no release. No workspace package's files[] ships skills/ (the dev measured 70 manifests; packages/cli ships bin as the lit control); skip-changeset per the last merged skills/**-only PR #19721, written through label-write.mjs with read-back.

③ Boundary flags

  • Tier H (skills/** on the register — the published catalog): draft stays draft; the 四件套 by this seat on green; the maintainer merges by hand after reading 「Sections that left SKILL.md」 — the one judgment this PR leaves to them.
  • Report 5779508012 (round 0) and 5786717884 (round 1) on the card parse; mcp_calls 0; round 0: three pushes, one POST /pulls, one label write, one report; round 1: one push, one report; no body PATCH by the dev.
  • Dispatch bookkeeping: the seat's H3 named the seven TOC'd rows as raises — four raised, three re-locked (headroom existed); the seat's evals H2 method held; the round-0 CI red was caught by the seat's check-run read, not by the dev's local farm (the rest package test runs only in the shard).
  • Out of scope, noted by the dev, ⛔ not touched: two data eval terms (schemaMode, type: 'secret') were reachable only through rules/ on the base already; objectstack-ui/rules/pages.md :356 / :448 carry illustrative package-docs links that resolve to nothing — example text.

Implemented-by: claude/issue-19715-published-skills-split-500
Reviewed-by: session_01Wnstp2kTth7sGXfr8fXypc

VERDICT: PASS


Generated by Claude Code

@hotlong
hotlong marked this pull request as ready for review September 23, 2026 02:40
@hotlong
hotlong added this pull request to the merge queue Sep 23, 2026
Merged via the queue into main with commit 595621d Sep 23, 2026
45 checks passed
@hotlong
hotlong deleted the claude/issue-19715-published-skills-split-500 branch September 23, 2026 03:15
github-merge-queue Bot pushed a commit that referenced this pull request Sep 30, 2026
… a connector credentialRef and drops the Slack webhook-url example (#20778)

Fixes #20657

Clause-②: no

The skills half of the #20590 family (the parent is completed; the spec,
runtime and guide faces landed in #20654 / #20655 / #20672).
`skills/objectstack-automation` now tells an author what a flow
definition serves and where an outbound credential goes, and its long
example no longer teaches a secret-bearing Slack webhook url.

## What changed

**`skills/objectstack-automation/SKILL.md`**
- The `http` row of the node table now says: `url` and `headers` are
served as written with the definition to every member who can read flows
— only `signingSecret` and a start node's `secret` are withheld — so
never a credential there; routed by shape — a header credential → a
declarative connector (`bearer` / `basic` / `api-key`) with
`auth.credentialRef`; a query-string key → `api-key` with `paramName`; a
path-secret webhook url → a token-authenticated connector such as
`slack` — called via `connector_action`. The same row carries the
`timeoutMs` lesson that used to live only in the example's `http` node
(the executor arms a timer only when `timeoutMs` is set —
`packages/services/service-automation/src/builtin/http-nodes.ts:281`).
- The `script` note's dispatch sentence routes Slack to
`connector_action` on the `slack` connector instead of "or `http`
webhook".
- The CRM Blueprint's lead sentence carries the metadata-first rule —
"Default approach for metadata apps — model the business lifecycle in
Flow/Approval metadata first, reserve custom code for edge-case
integrations — in this CRM-style structure:" — because that rule had no
other home in the skill.
- Removed as token payment (content with a home elsewhere or redundant
in place, never a re-wrap): the `http_request` alias clause on the
`http` row — the clause was accurate: the ADR-0087 conversion
`flow-node-http-callout-rename`
(`packages/spec/src/conversions/registry.ts:58`) still rewrites
`http_request` / `http_call` / `webhook` to `http` on build/validate
even though the node-type enum
(`packages/spec/src/automation/flow.zod.ts:41`) names only `http`; the
skill teaches the canonical `http` and the alias needs no author action,
so the deletion stands; the `FlowNodeAction` seed-set aside; the
engine-internal `resolveTriggerBinding` name; the trigger-intro clause
that duplicated the Trigger Types table's ObjectQL-hook column; the "It
is not a way past a guardrail" one-liner that duplicated the paragraph
under the routing table; the three-line `previous` / `record` blockquote
reduced to a one-line pointer at objectstack-formula §5
(`skills/objectstack-formula/SKILL.md:283-296` carries it); the word
"verbatim" in the three moved-to pointers; and word trims in four
sentences.

**`skills/objectstack-automation/references/examples-flows.md`**
- The `notify_manager` node is a `connector_action` on the `slack`
connector (`chat.postMessage`, `input: { channel, text }`) — the shape
`examples/app-showcase/src/automation/flows/index.ts:329-339` dispatches
and `packages/connectors/connector-slack/src/slack-connector.ts:100-114`
declares. A three-line comment says why it is not an `http` node with a
webhook url. The block keeps its `os:check` marker and type-checks
(readings below).
- Removed as token payment: the four-line schedule comment is two lines
of the same facts, and the `filter` comment that duplicated the
blockquote at the top of the file.

Wording matches the landed sources: the `HttpConfigSchema.headers`
describe (`packages/spec/src/automation/io-node-config.zod.ts:363-370`,
the #20654 describe the dispatch could not locate; its sibling for
`connectorConfig.input` is `flow.zod.ts:628-634`), the `http` node
descriptor describes
(`packages/services/service-automation/src/builtin/http-nodes.ts:111-133`)
and the flows guide callout (`content/docs/automation/flows.mdx:274`,
whose "Only `signingSecret` (and a start node's `secret`) is withheld"
and "`bearer`, `basic` or `api-key`" the row now matches; the redaction
paths are `packages/metadata-protocol/src/metadata-redaction.ts:427` /
`:477` / `:521`). Per the wording guard on the card, no sentence routes
a path-secret webhook url to `auth.credentialRef`.

Not touched, by the card's serial constraint: SKILL.md's `api` trigger
row and the inbound-webhook `secret` row are #20569's; #20569 remains
open.

## `skills/**` readings

Tokens are `scripts/check-skills-token-ratchet.mjs` readings (ceil of
utf8 bytes / 4); lines are `wc -l`. Before = `c9c182ed`, after =
`6b3450a0` (the `skills/**` bytes are identical at `7d4fcc50`).

| File | Lines before → after | Tokens before → after (ceiling) |
|---|---|---|
| `skills/objectstack-automation/SKILL.md` | 448 → 439 | 5785 → 5777
(5785, headroom 8) |
| `skills/objectstack-automation/references/examples-flows.md` | 136 →
135 | 1436 → 1426 (1436, headroom 10) |
| Whole package — every `skills/**/SKILL.md` | 4404 → 4395 | ratcheted
authored total 143347 → 143329 |
| Whole package — every `SKILL.md` plus the touched reference file |
4540 → 4530 (net −10 against the PM's +4 budget) | bundle total 153900 →
153882 |

No ceiling row moved. `evals/flows-triggers-approvals.json` is untouched
(1255 / 1255).

## Verification (all on head `6b3450a0`; exit codes captured before any
pipe)

Head `6b3450a0` is `7d4fcc50` (the review-round commit) merged with
`origin/main` `91e8fa19`; the merge touched nothing under `skills/**`,
recorded no regen deferral, and the diff against `origin/main` is
exactly the two files above. The merge is the derivation tool's own
prescription: at `7d4fcc50` it reported a STALE TREE (`origin/main` had
moved to `eead9dcf` with `.github/workflows/release.yml` and
`scripts/release-pending-publish.mjs` changed, both inputs of derived
families).

- `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--commands` (no paths) derived the same 25 commands at `b6041881`,
`7d4fcc50` and `6b3450a0`; all 25 ran on `6b3450a0` with exit 0,
recorded as `cmd :: exit N`, and `dispatch-gates --ran` answers "25
derived families accounted for — 25 run, 0 NOT-MEASURED" with no
stale-tree warning: `check-ci-filter-parity`,
`check-closing-keyword-parity` (+ `--self-test`),
`check-comment-mask-corpus`, `check-doc-route-spelling --advisory` (+
`--self-test`), `check-skills-token-ratchet` (+ `--self-test`), lint
`check:doc-formula-expressions`, spec `check:skill-docs`, spec
`check:skill-refs`, root `check:agent-test-spelling`,
`check:corpus-claim-drift`, `check:cross-package-test-inputs`,
`check:doc-authoring`, `check:driver-memory-census`,
`check:gitlink-declared`, `check:nul-bytes`, `check:pm-governed-merges`,
`check:refd-timer-probe`, `check:role-word`,
`check:skill-compatibility`, `check:skill-frame-sync`,
`check:skill-identifier-liveness`, `check:watch-hint-literal`. The same
25 also ran on `7d4fcc50`, all exit 0.
- Implicated beyond the derived list: spec `check:skill-examples` (the
edited example carries an `os:check` marker): exit 0 on `6b3450a0` —
"259 prose examples type-check across 3 surface(s) — every marked block
parsed, so tsc ran the SEMANTIC pass on all of them" (skills + docs
surface: 225 blocks), after `turbo run build --filter=@objectstack/spec
--filter=@objectstack/formula --filter=@objectstack/lint
--filter=@objectstack/client --filter=@objectstack/client-react` under
the verify lock.
- Ablation of the edited block, both legs through
`scripts/ablation-replace.mjs`, run at `b6041881` on the
`examples-flows.md` blob `6e725a55` — the same blob at `6b3450a0`, so
the reading stands (anchor hit 1 → 0 on disk, blob hash changed,
restored to the `HEAD` blob with `git diff HEAD` empty; no build step
involved because the checker reads the markdown itself):
- `actionId:` → `actionIdX:` inside `connectorConfig`: exit 1 —
`examples-flows.md:56:9 error TS2561: Object literal may only specify
known properties, but 'actionIdX' does not exist in type '{ connectorId:
string; actionId: string; input?: ... }'` (the `input` type is a Record
of string to unknown, spelled in words here because the platform eats
angle-bracket fragments). The block's `connectorConfig` shape is
measured.
- `type: 'connector_action'` → `type: 'connector_actionX'`: exit 0,
still 259 green. The node `type` string is not constrained by the
type-check (plugin-registered node types such as `approval` mean it
admits any string), so that half of the example rests on the showcase
app and the spec enum, not on this gate. Reported as observed.
- A control-character grep (the C0 range and DEL) over both touched
files: no match. No HTML comment and no angle-bracket fragment is added
by this diff.
- `check:skill-docs` / `check:skill-refs` are green without
regeneration: the frontmatter is unchanged, so no generated artifact
moved.

## Changeset

`skip-changeset`, measured: `git grep -n -w skills -- '*/package.json'`
→ 0 hits at `6b3450a0` (positive control: `git grep -n '"files"' --
'packages/*/package.json'` hits `packages/adapters/hono`,
`packages/apps/account`, `packages/apps/setup`), so nothing under
`skills/**` ships in any released package's `files[]`. Precedent: the
last skills-only PR that touched these files (#19738) carried the same
label.

## Acceptance notes

- `SKILL.md` `:216` (a reference outside a filter — message body, `http`
url, write payload — renders an empty string) is a
template-interpolation statement, not a credential statement; left as
is, the `http` row carries the steer.
- The eval `evals/flows-triggers-approvals.json:47` expects an `http`
node to set `timeoutMs`; that lesson now lives on the `http` row (it
left the example when the node became a `connector_action`).
- `content/docs/automation/flows.mdx:274`, which the services seat's
wording guard said carried an over-reach, already routes by shape on
`main` at `c9c182ed`; nothing to correct, and this PR does not touch it.
- Noted, not filed: `check:doc-formula-expressions` and
`check:skill-examples` each refuse (exit 3) on a fresh worktree until
their producer packages are built; both say so loudly and name the
build. Working as designed.

## 维护者速读(草稿)

**改了什么**:`objectstack-automation` 技能的 `http` 节点行现在说明:flow 定义(含 `http`
节点的 `url` 与 `headers`)会原样提供给所有能读 flow 的成员——只有 `signingSecret` 与 start
节点的 `secret` 会被隐去——因此凭据不能写在那里;并按凭据所在位置给出去向:请求头凭据 → 声明式 connector 的
`auth.credentialRef`(`bearer` / `basic` / `api-key`),查询串密钥 → `api-key` 的
`paramName`,路径即密钥的 webhook → 带 token 的 connector(如 `slack`),再用
`connector_action` 调用。长示例里的 Slack incoming-webhook url 换成了 `slack`
connector 的 `chat.postMessage`,与 showcase
示例应用的写法一致。「元数据优先、自定义代码只留给边缘集成」这条规则并入了 CRM 蓝图的首句(它在技能里没有别的落脚点)。为守住 token
上限,删掉的都是别处已有归属或原地重复的内容(如 `previous` / `record` 的说明缩成指向
objectstack-formula §5 的一行)。

**为什么改**:这是 #20590 家族的技能面。AI 作者直接从这份技能复制,原示例教的是把秘密写进 url;spec
描述、运行时描述与文档已在别的 PR 落地同一措辞,技能面是最后一块。

**风险与代价(含回滚)**:纯文档改动,不动运行时、不发布任何包(`skip-changeset` 已实测)。示例块经
`check:skill-examples` 类型检查通过,并用消融证明 `connectorConfig` 的形状确实在检。SKILL.md
剩余 token 余量为 8,下一张改此文件的卡(#20569)仍需自付 token。回滚即 revert 本 PR,无迁移。

**席位意见**:(留空)

**你要做的**:`skills/**` 是 Tier H 受管面——需要维护者的 APPROVED review 后由席位落地;本 PR 保持
draft,不进队列、不开 auto-merge。

---
_Generated by [Claude
Code](https://claude.ai/code/session_01KTZmMfzVzjNvyaLyQ8mHvg)_

---------

Co-authored-by: os-warren <warren@objectstack.ai>
Co-authored-by: Claude <noreply@anthropic.com>
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 needs-user-decision size/xl skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants