Skip to content

Commit f3d0eab

Browse files
docs(skills): automation capability table says a declared webhook or auto-launched flow is refused without its requires pair (#25689)
<!-- 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>
1 parent 992a7e1 commit f3d0eab

2 files changed

Lines changed: 15 additions & 11 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 objectstack-automation capability table says a declared webhook or auto-launched flow is refused without its `requires` pair, not silently undelivered
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
The 〈Prerequisite — declare the capabilities your nodes need〉 table in `objectstack-automation/SKILL.md` said that without `webhooks` in `requires` "nothing [is] delivered outbound", and that without `triggers` "flows register, never fire". Neither is what `defineStack` does: a declared webhook while `requires` omits `webhooks`, `realtime` or both is refused with `STACK_WEBHOOK_CAPABILITY_REQUIRED` (422), and an auto-launched flow while `requires` omits `triggers`, `automation` or both is refused with `STACK_TRIGGER_CAPABILITY_REQUIRED` (422) — at `os validate`, `os build`, `os dev` and `os serve` alike. The two rows now name the pair each surface owes and the refusal code; the lead-in says the refusal is at load time and that neither token implies the other. The `requires: [...]` example block under the table is folded into the lead-in to keep the skill within its token ceiling.

‎skills/objectstack-automation/SKILL.md‎

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -317,25 +317,19 @@ binding lives entirely in the flow's **`start` node `config`**.
317317

318318
### Prerequisite — declare the capabilities your nodes need
319319

320-
Metadata registers without its token; the surface just never runs — two of them
321-
silently:
320+
Metadata registers without its `defineStack({ requires })` token; the surface
321+
just never runs. Two pairs are instead **refused** at `os validate` / `build` /
322+
`dev` / `serve` (422); neither token implies the other:
322323

323324
| `requires` token | Turns on | Absent ⇒ |
324325
|:--|:--|:--|
325326
| `automation` | the flow engine + node executors | flows never execute |
326-
| `triggers` | `record-*` / schedule / `api` start bindings | flows register, never fire |
327+
| `triggers` + `automation` | `record-*` / schedule / `api` start bindings | auto-launched flow refused: `STACK_TRIGGER_CAPABILITY_REQUIRED` |
327328
| `job` | cron cadence + the `timeRelative` sweep | scheduled flows never launch |
328329
| `queue` | the inbound-webhook consumer | inbound POST answers **503** |
329330
| `approvals` | `approval` / `approval_revise` (`plugin-approvals`) | no executor for the node type |
330331
| `messaging` | `notify` delivery to inbox (`sys_inbox_message`) | **silent:** success with `skipped: true` |
331-
| `webhooks` | `defineStack({ webhooks })` outbound registrations | nothing delivered outbound |
332-
333-
```typescript
334-
defineStack({
335-
// …
336-
requires: ['automation', 'triggers', 'job', 'queue', 'approvals', 'messaging'],
337-
});
338-
```
332+
| `webhooks` + `realtime` | `defineStack({ webhooks })` outbound dispatch | declared webhook refused: `STACK_WEBHOOK_CAPABILITY_REQUIRED` |
339333

340334
### Inbound webhook (`api`) triggers (ADR-0041 Tier 1)
341335

0 commit comments

Comments
 (0)