Repository navigation
Commit 125ce9f
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
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
277 | 277 | | |
278 | 278 | | |
279 | 279 | | |
280 | | - | |
281 | | - | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
282 | 283 | | |
283 | 284 | | |
284 | 285 | | |
| |||
306 | 307 | | |
307 | 308 | | |
308 | 309 | | |
309 | | - | |
310 | | - | |
311 | | - | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
312 | 314 | | |
313 | 315 | | |
314 | 316 | | |
| |||
0 commit comments