Skip to content

Commit 125ce9f

Browse files
docs(skills): objectstack-ai says guardrails is enforced per turn and output validation lives on action.ai.outputSchema (#21302)
Fixes #21288 Clause-②: no ## What this does Two sentences in the published `objectstack-ai` skill said the opposite of what the cloud AI runtime now does. Both are rewritten to state only what the readings on the parent card prove. The skill text cites no card number (it cites ADRs, as the rest of the file does); the readings are cited here. 1. **`ToolSchema` paragraph, the `outputSchema` clause** (lines 279–281 at `4e6dc233`). It said the key's top-level keys are folded into the tool description shown to the model and outputs are not validated. It now says nothing reads the key on a tool record, and steers the author to `ai.outputSchema` on the **action**, which the AI runtime ☁️ enforces by withholding a result that does not conform. - Reading: comment 5943158888 on #20274, of cloud `main` `cb62c3ea`. `packages/service-ai/src/tools/action-tools.ts#compileOutputContract` reads `action.ai.outputSchema` directly; `AIToolDefinition.outputSchema` is only a copy of it and nothing reads it back; no reader turns an authored `tool` record into a tool definition. - Wording aligned with PR #21280's describe and its `content/docs/ai/tools.mdx` row (nothing reads it on a tool record; declare it as `ai.outputSchema` on the action, where the cloud AI runtime validates the action result), not copied. The ☁️ marker is the file's own edition-boundary convention for a cloud surface. 2. **Common Pitfalls 1** (lines 309–311 at `4e6dc233`). It said `guardrails` / `memory` / `structuredOutput` are declared only, no runtime reads them, and real limits come from the quota service. It now says `guardrails` is enforced per user turn by the AI runtime ☁️ (token and time limits; blocked tool names and categories refused) but is a limit, not an approval, and that `memory` is declared only, no runtime reads it. The pitfall's heading and its second half (what an enforced gate is) are unchanged. - Reading: comment 5940785002 on #20274, of cloud `main` `235c5b29`. `packages/service-ai/src/ai-service.ts#TurnGovernor` checks `maxExecutionTimeSec` and `maxTokensPerInvocation` per user turn, before every model round, with each refusal audited; `packages/service-ai/src/agent-runtime.ts#matchBlockedTopic` matches `blockedTopics` exactly on the tool name, on `action_T` or on the tool category, removes the match from the offer and refuses it at call time. - `structuredOutput` is removed from the declared-only enumeration and nothing is written in its place. Its new semantics wait on #21277 (decision box); triage's sequencing leaves that clause out of this PR rather than rewriting it twice. The premise the PM set for dropping the word held: the sentence is rewritten anyway, a version that kept the word in the declared-only list fits the same four lines, so the deletion cost no line and introduced no new claim. - `memory` stays described as declared-only. The skill never named `lifecycle`, so there is nothing to keep unenforced there. ## Line budget (the `skills/**` discipline) | reading | before (`4e6dc233`) | after (`8f4222b5`) | |:--|--:|--:| | `skills/objectstack-ai/SKILL.md` lines | 416 | 418 (net +2; budget was net ≤ +2) | | the same file in the ratchet's unit, `ceil(utf8 bytes / 4)` | 5444 | 5486 (ceiling 6806, headroom 1320) | | whole catalog, every `skills/*/SKILL.md`, lines | 4395 | 4397 | | whole catalog, every `skills/*/SKILL.md`, `ceil(bytes / 4)` | 52087 | 52129 | Each position pays +1 line; no neighbouring line is re-wrapped (the diff is 7 insertions, 5 deletions, inside the two clauses only). The dispatch gave the file as 337 lines; at `4e6dc233` it is 416 (`git show 4e6dc23:skills/objectstack-ai/SKILL.md | wc -l`). ## Verification (at `8f4222b5`, worktree `objectstack-issue-21288`) - `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 24 commands from the merge base `4e6dc233` (1 path, +7/−5). Each ran with its exit code captured before any pipe; `--ran` answered: "✓ dispatch-gates --ran: 24 derived famil(ies) accounted for — 24 run, 0 NOT-MEASURED". - `node scripts/check-skills-token-ratchet.mjs` exit 0: "✓ check-skills-token-ratchet: skills/objectstack-ai/SKILL.md is 5486 tokens (ceiling 6806; headroom 1320)". - Exit 0 each: `pnpm --filter @objectstack/spec run check:skill-docs`, `pnpm check:skill-identifier-liveness`, `pnpm check:skill-frame-sync`, `pnpm check:skill-compatibility`, `pnpm check:corpus-claim-drift`, `pnpm check:doc-authoring`, `pnpm check:role-word`, `pnpm check:nul-bytes`, `pnpm check:pm-governed-merges`, `pnpm check:gitlink-declared`, `pnpm check:agent-test-spelling`, `pnpm check:cross-package-test-inputs`, `pnpm check:driver-memory-census`, `pnpm check:refd-timer-probe`, `pnpm check:watch-hint-literal`, and the direct `node scripts/check-*.mjs` rows (ci-filter-parity, closing-keyword-parity and its self-test, comment-mask-corpus, doc-route-spelling advisory and self-test). - `pnpm --filter @objectstack/lint run check:doc-formula-expressions`: first run exit 3, PREREQUISITE NOT MET (`@objectstack/formula` and `@objectstack/lint` not built), nothing measured; after `pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint` under the shared verify lock, exit 0. - Beyond the derivation, because it type-checks the `os:check` blocks in `skills/**`: `pnpm --filter @objectstack/spec run check:skill-examples` exit 0, "✅ 259 prose examples type-check across 3 surface(s)" (needed `@objectstack/spec`, `@objectstack/client` and `@objectstack/client-react` built first, all under the lock). - NOT MEASURED locally, CI's own: the whole-root scans (`pnpm lint`), the type-check lanes and Test Core; the `--ran` footer names them as outside the derived total. ## Changeset `skip-changeset`. `skills/**` is in no published package's `files[]`: a scan of every `package.json` in the tree for a `files[]` entry naming `skills` or `content/docs` finds zero; the positive control `@objectstack/spec` lists `dist`, `json-schema`, `liveness`, `prompts`, `llms.txt`, `README.md`, `src/**/*.zod.ts`, `CHANGELOG.md`, `api-surface`, `spec-changes.json`. The catalog ships to customer projects through `npx skills add`, not through npm. ## Governance Tier H: `skills/**` is a governed surface (Prime Directive #14). This PR stays draft and lands only after an authorized APPROVED review; no seat readies, queues or arms auto-merge on it. The sibling docs line of the same card is a separate, ordinary PR on `claude/issue-21288-actions-mdx-outputschema`, which carries no closing keyword. ## Acceptance notes - On `main` at `4e6dc233` the same folded-into-the-description claim still stands in `packages/spec/src/ai/tool.zod.ts:195` (the describe), `packages/spec/liveness/tool.json:49` (the row note), `content/docs/ai/tools.mdx:148` and the generated `content/docs/references/ai/tool.mdx:37` / `agent.mdx:62`. PR #21280 (open, draft) rewrites all of them and regenerates the reference pages. Carrier: that PR; noted, not filed. - `structuredOutput` now has no sentence in this skill. When #21277 is ruled, the skill owes one sentence on what the runtime enforces and refuses; that is the follow-up triage already sequenced. ## 维护者速读(草稿) - **改了什么**:`skills/objectstack-ai/SKILL.md` 两句。① `ToolSchema` 段里 `outputSchema` 的括注:不再说「顶层键被折进工具描述、输出不校验」,改为「tool 记录上没人读它;把 schema 写在 action 的 `ai.outputSchema`,AI 运行时 ☁️ 会扣住不合规的返回值」。② 常见陷阱第 1 条:不再把 `guardrails` 列为「只声明、运行时不读」,改为「每个用户回合由 AI 运行时 ☁️ 强制(token/时间上限;封禁的工具名与类别被拒),但它是限额不是审批」;`memory` 仍写为只声明。 - **为什么改**:这两句自 cloud `235c5b29` / `cb62c3ea` 起已是假话,会把 AI 作者引离一个已经生效的控制,或让它以为 tool 上的 `outputSchema` 有人读。写给 AI 的 skill 说错一句等于产品缺陷。每句新话只说 #20274 上 cloud 读数(5940785002、5943158888)证明了的事,不多说一字。 - **风险与代价(含回滚)**:纯文案,无 schema、解析、导出或行为变化;文件净 +2 行(预算 ≤ +2),token 5444→5486(上限 6806)。`structuredOutput` 一词从「只声明」枚举中删去但未写任何新语义,等 #21277 裁决后再补一句。回滚即 revert 本 PR 的一个 commit。 - **席位意见**: - **你要做的**:这是 Tier H(`skills/**`)。需要你的 APPROVED review;批后由席位落地,不需要你动手合并。 --- _Generated by [Claude Code](https://claude.ai/code/session_01FNKm1SmPpuJASnbjxWGtsJ)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 30af17e commit 125ce9f

1 file changed

Lines changed: 7 additions & 5 deletions

File tree

‎skills/objectstack-ai/SKILL.md‎

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,9 @@ no framework executor loads a metadata-authored tool.
277277
`ToolSchema` is **strict** — an unknown key (a typo, or a retired one) is a parse
278278
error, not a silent strip. Required `name` / `label` / `description` and a JSON
279279
Schema `parameters` object; optional `objectName` and `outputSchema` (⚠️
280-
experimental — its top-level keys are folded into the tool description shown to
281-
the model, and outputs are **not** validated). Retired in protocol 17:
280+
experimental — nothing reads it on a tool record; declare the schema as
281+
`ai.outputSchema` on the **action** instead, which the AI runtime ☁️ enforces
282+
by withholding a result that does not conform). Retired in protocol 17:
282283
`category`, `permissions`, `active`, `builtIn` — all authorable and inert —
283284
joining `requiresConfirmation`; each rejection carries its replacement.
284285

@@ -306,9 +307,10 @@ there is **no top-level `temperature` / `maxTokens`** on an agent
306307

307308
## Common Pitfalls
308309

309-
1. **Mistaking `guardrails` for a gate.** `guardrails` / `memory` /
310-
`structuredOutput` are declared only — no runtime reads them, and real limits
311-
come from the quota service. For a gate that is **enforced**, use
310+
1. **Mistaking `guardrails` for a gate.** `guardrails` is enforced per user turn
311+
by the AI runtime ☁️ — token and time limits, blocked tool names and categories
312+
refused — but it is a limit, not an approval; `memory` is declared only — no
313+
runtime reads it. For a gate that is **enforced**, use
312314
`enableActionApproval: true` (approval queue ☁️), `ai.requiresConfirmation` on
313315
the **action**, or `approval: 'always'` on an MCP tool binding. AI metadata
314316
edits are already gated: they land as drafts a human must publish (ADR-0033).

0 commit comments

Comments
 (0)