Repository navigation
Commit f3d0eab
docs(skills): automation capability table says a declared webhook or auto-launched flow is refused without its
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1X5YusjSEHT8KRnVbiKjJ22B)_
Fixes #25069
Clause-②: no
Metadata-protocol: none
## What changed
`skills/objectstack-automation/SKILL.md`, the 〈Prerequisite — declare
the capabilities your nodes need〉 table. Two rows described an absent
`requires` token as silent non-delivery; `defineStack` refuses both
cases at load time. The rows now name the pair each surface owes and the
refusal code, and the lead-in says the refusal is at `os validate` /
`build` / `dev` / `serve` (422) and that neither token implies the
other. One `@objectstack/skills` patch changeset
(`.changeset/25069-automation-webhooks-row.md`).
## Measured against `packages/spec/src/stack.zod.ts` on `origin/main`
`b2909fd4`
Row by row, what the code does — the text describes the code, not the
card:
| Row | Verdict | Evidence |
|:--|:--|:--|
| `webhooks` ("nothing delivered outbound") | **changed** |
`validateWebhookCapability` (`stack.zod.ts:4863`): `hasWebhooks =
requires.includes('webhooks')`, `hasRealtime =
requires.includes('realtime')`; `if (hasWebhooks && hasRealtime) return
errors;` otherwise one finding per entry of the top-level `webhooks[]`
(`isActive: false` included). `defineStack` (`stack.zod.ts:5342`) throws
`StackWebhookCapabilityRequiredError`, `code =
'STACK_WEBHOOK_CAPABILITY_REQUIRED'`, 422. An absent `requires` counts
as omitting both. Pinned by `stack-webhook-capability.test.ts` (three
arms on one code). |
| `triggers` ("flows register, never fire") | **changed** (same
staleness) | `validateTriggerCapability` (`stack.zod.ts:4772`):
`hasTriggers`, `hasAutomation`; `if (hasTriggers && hasAutomation)
return errors;` otherwise one finding per flow whose
`resolveFlowTriggerKind` is `record_change` / `schedule` /
`time_relative` / `api`, skipping `status: obsolete` / `invalid`.
`defineStack` (`stack.zod.ts:5335`) throws `code =
'STACK_TRIGGER_CAPABILITY_REQUIRED'`, 422. The card's
`stack.zod.ts:4526-4565` had moved to 4772-4812. |
| `automation` ("flows never execute") | **already correct for what it
still covers** | A flow with no auto-launch binding (an `autolaunched`
flow started explicitly, a `screen` flow) registers and never executes
without `automation`; the auto-launched case is the `triggers` +
`automation` row directly beneath it. Left as is: the token ceiling has
3 tokens of headroom after this change. |
| `job`, `queue`, `approvals`, `messaging` | **out of scope** | No
`defineStack` refusal reads these tokens (`grep -n "requires.includes"
stack.zod.ts` hits `hierarchy`, `triggers`/`automation`,
`webhooks`/`realtime` only); the card names only the webhook prose and
the `triggers` row. |
| Other webhook prose in the skill | **already correct** | Line 51
(`api` flow type), lines 340-355 (inbound webhook triggers) and the
`http` node row are about INBOUND webhooks and the `queue` consumer;
none claims outbound non-delivery. `references/*.md` carry no
outbound-webhook claim (`grep -rni webhook
skills/objectstack-automation/references/`: a schema pointer in
`_index.md` and the Slack-connector note in `examples-flows.md`).
`realtime` appeared nowhere in the skill before this change. |
## Readings (`skills/**`, Tier H)
- Changed file, lines: 438 → 432 (net −6). Tokens
(`check-skills-token-ratchet`): 5755 → 5777 against a 5780 ceiling
(headroom 25 → 3). The new row text is paid for by deleting the
`requires: [...]` example block under the table (its form,
`defineStack({ requires })`, moved into the lead-in sentence); no
re-wrap was counted as payment.
- Whole bundle, lines: all `SKILL.md` 4389 → 4383; all of `skills/**`
13355 → 13349. Bundle token total 155382 → 155404 (+22), every ceiling
green.
- Net line budget from dispatch: at most +2; actual −6.
## 维护者速读(草稿)
**改了什么。** `objectstack-automation` 技能的「声明能力」表里,`webhooks` 和 `triggers`
两行把缺 token 的后果写成「静默不投递 / 注册了但不触发」。现在改成代码的真实行为:声明了 webhook 却没在 `requires`
里同时写 `webhooks` 和 `realtime`,或声明了自动触发的 flow 却没同时写 `automation` 和
`triggers`,`defineStack` 在加载时直接拒收(`STACK_WEBHOOK_CAPABILITY_REQUIRED` /
`STACK_TRIGGER_CAPABILITY_REQUIRED`,422),`os validate` / `build` / `dev`
/ `serve` 都一样。
**为什么改。** 技能包随 npm 发到客户项目,AI 作者照它写 `requires` 时会漏掉 `realtime`,然后在 `os
validate` 上撞到技能没提过的拒收。文字和运行时不一致,就是这张卡立案的缺陷。
**风险与代价(含回滚)。** 纯文档改动,不动任何运行时;发布面是 `@objectstack/skills` 一个
patch。为了不超技能包的 token 上限,删掉了表下面那段 `requires: [...]`
示例(信息并入表头上面的句子),上限余量只剩 3 个 token,下一次改这份文件要先删才能加。回滚 = revert 这一个 commit。
**席位意见。**
**你要做的。** 作为 Tier H(`skills/**`)授权批准这份 PR;之后由席位落地。
## Acceptance notes
- `skills/**` is a governed surface (Tier H): this PR stays draft and
lands only on an authorized APPROVED review.
- Not a finding, noted only: the `automation` row still reads "flows
never execute", which is exact for an explicitly started flow and is
superseded for an auto-launched one by the row beneath it. Rewording it
costs tokens the file no longer has; a future PR that shrinks this file
could fold the two.
- Not a finding, noted only: the `requires` tokens and refusal codes are
cited in backticks, so `check:skill-identifier-liveness` (Leg 1, 456
citations over 53 files) binds them to the implementation; both codes
are in `error-code-ledger.zod.ts`.
- The card's parent #24997 is not addressed here; it landed the refusal
this text now describes.
## Tests and gates (head `284e1410`)
No package is touched, so no build closure (①) and no package
test/typecheck (②) is owed. Derived gate families (`dispatch-gates
--commands --repo objectstack-ai/objectstack`, 46 families once the
changeset exists), each exit code captured before any pipe:
- Green (exit 0): `check-skills-token-ratchet` (+ `--self-test`),
`check:skill-docs` (`✅ Skill docs in sync`), `check:skill-frame-sync`,
`check:skill-identifier-liveness` (`OK — Leg 1: 456 citation(s) over 53
published file(s)`), `check:skill-compatibility`, `check:doc-authoring`,
`check:pm-skill-id-lint`, `check:nul-bytes`, `check:role-word`,
`check:corpus-claim-drift`, `check:closed-ceremony-text`,
`check:published-files`, `check:objectui-changeset`,
`check:pm-changeset-deadline-census`, `check:changeset-gate-self-tests`,
`check-adr-0087-registration` / `check-changeset-no-major` /
`check-empty-changeset` (`--base origin/main` and `--self-test`),
`check-ci-filter-parity`, `check-closing-keyword-parity` (+ self-test),
`check-comment-mask-corpus`, `check-doc-route-spelling` (advisory +
self-test), `check-dts-emitted --self-test`, `assert-turbo-remote-cache
--self-test`, `prune-turbo-cache --self-test`, `release-rehearsal-clone
--self-test`, `release-pending-publish --self-test`,
`check:agent-test-spelling`, `check:cross-package-test-inputs`,
`check:driver-memory-census`, `check:gitlink-declared`,
`check:merge-driver`, `check:pm-governed-merges`,
`check:refd-timer-probe`, `check:watch-hint-literal`, and
`check:doc-formula-expressions` (exit 0 after `turbo run build
--filter=@objectstack/formula --filter=@objectstack/lint` under the
verify lock; its first run exited 3, PREREQUISITE NOT MET, before that
build).
- NOT MEASURED locally (exit 3, PREREQUISITE NOT MET — each sweeps every
workspace package's built `dist/`, which this diff does not touch and
which needs a full `pnpm build`): `check:dts-closure`,
`check:dual-build-cjs-loads`, `check:lean-entry-closure`,
`check:sourcemap-no-sources-content`. CI's `Lint & Repo Gates` runs them
on a fresh build.
- `dispatch-gates --ran`: 46 of 46 derived families accounted for.
---
_Generated by [Claude
Code](https://claude.ai/code/session_014FZ3TJucS1L7BdMe5DAzXC)_
Co-authored-by: objectstack-dev <noreply@anthropic.com>requires pair (#25689)1 parent 992a7e1 commit f3d0eab
2 files changed
Lines changed: 15 additions & 11 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
317 | 317 | | |
318 | 318 | | |
319 | 319 | | |
320 | | - | |
321 | | - | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
322 | 323 | | |
323 | 324 | | |
324 | 325 | | |
325 | 326 | | |
326 | | - | |
| 327 | + | |
327 | 328 | | |
328 | 329 | | |
329 | 330 | | |
330 | 331 | | |
331 | | - | |
332 | | - | |
333 | | - | |
334 | | - | |
335 | | - | |
336 | | - | |
337 | | - | |
338 | | - | |
| 332 | + | |
339 | 333 | | |
340 | 334 | | |
341 | 335 | | |
| |||
0 commit comments