Repository navigation
Commit 135daaa
feat(spec): agent.guardrails is live, enforced by the cloud AI runtime; tool.outputSchema steers authors to action.ai.outputSchema (#21280)
Part of #20274
Clause-②: no
## What this does
This is this repo's half of the card's first slice: the ledger rows that
cloud's readers now answer.
- **`agent.guardrails` → `live`.** The verdict covers all three
children: `maxTokensPerInvocation`, `maxExecutionTimeSec` and
`blockedTopics`.
- Evidence (`cloud 235c5b29`):
`packages/service-ai/src/ai-service.ts#TurnGovernor`,
`packages/service-ai/src/agent-runtime.ts#AgentRuntime.resolveTurnGuardrails`
and `#matchBlockedTopic`.
- `evidenceScope` is `cross-repo` and `verifiedAt` is 2026-10-01.
- `producer`: cloud's built-in build agent
(`metadata-assistant-agent.ts`) and tenant-authored agents.
- The row's note names the reading it rests on: the `repo:cloud#1`
seat's comment 5940785002, of cloud `main` `235c5b29`. No seat in this
session read cloud.
- **The `agent.zod.ts` `guardrails` describe** drops `[EXPERIMENTAL —
not enforced]`. It now reads: "Safety guardrails for the agent (token
budget, time limit, blocked topics), enforced per user turn by the cloud
AI runtime; the open framework edition does not run agents."
- **`packages/spec/liveness/README.md`, line 78 and §`live-elsewhere`.**
These no longer say the gate refuses `live` on cloud-only evidence.
- The gate's boundary pin (`check-liveness.test.ts`, "stays green when
the missing path is attributed to ANOTHER repo") deliberately says the
opposite.
- The corrected text uses only words the ledger already carries: the
pin's rationale, `agent.json`'s `_note`, and `manifest.runtime`'s own
row note.
- No rule, no other row and no gate changes.
- **`tool.outputSchema` stays `experimental`**, and now says where
output validation lives.
- This rests on the cloud seat's comment 5943158888, of cloud `main`
`cb62c3ea`. `action-tools.ts#compileOutputContract` validates
`action.ai.outputSchema` directly. `AIToolDefinition.outputSchema` is
only a copy of it. No authored `tool` record ever becomes a tool
definition.
- The row's evidence and note are rewritten. The old description-folding
sentences are gone, and `verifiedAt` is 2026-10-02, attributed to that
reading.
- The describe, its TSDoc and `content/docs/ai/tools.mdx` now point an
author to `ai.outputSchema` on the action.
- **Regenerated:** `content/docs/references/ai/agent.mdx`,
`content/docs/references/ai/tool.mdx` and
`liveness/state-counts/agent.md`. For `agent`, live goes from 20 to 21
and experimental from 4 to 3. `state-counts/tool.md` is unchanged,
because no status moved.
- **Changeset:** `.changeset/20274-agent-guardrails-live.md`,
`@objectstack/spec` patch.
## What remains on the card
- `agent.memory` and `agent.lifecycle` stay `experimental`. Their
readers are tracked on objectstack-ai/cloud#2568 and
objectstack-ai/cloud#2569.
- `agent.structuredOutput` stays `experimental` here. The cloud seat
reports in 5943158888 that its enforcement landed. It also raises a
contract question for the maintainer: authoring accepts formats the
runtime refuses. The PM files that question separately.
## Author-facing change (measured; a warning, not a refusal)
I ran `lintLivenessPropertiesFromLedgerDir` over one stack: one agent
that sets `guardrails` and one tool that sets `outputSchema`.
- **Before** (the ledger at `30c530e5`): 2 findings, both
`[liveness-experimental-property]`. One is on `guardrails` and one is on
`outputSchema`.
- **After** (this branch's ledger): 1 finding, on `outputSchema` only.
For `agent.guardrails` the reading goes from 1 finding to 0.
The accept set does not change.
## Verification, at `d0a0f125`, re-run on `58fdaac4`
- **Patch round 1, at `58fdaac4`** (dev report `5943917260` on #20274),
each with exit 0:
- spec `build`, `check:liveness` and `check:generated`;
- the 12 liveness script test files (347 passed);
- `check:nul-bytes`, `check:doc-authoring`, `check:issue-citations` and
`check:cross-package-test-inputs`;
- the changeset gates;
- `dispatch-gates --ran`: 104 families, 103 run, 1 NOT-MEASURED
(`check:dual-build-cjs-loads`; CI's `Build Core` concluded `success`).
- **At `d0a0f125`:**
- `pnpm --filter @objectstack/spec check:liveness` → exit 0.
- Verdict: "✓ every governed-type property, at every depth the ledger
drills, is classified ...".
- Totals: "987 live · 4 experimental · 1 live-elsewhere · 109 dead · 10
planned = 1111 classified".
- `pnpm --filter @objectstack/spec check:generated` → exit 0: "✓ All 15
generated artifacts are up to date". Earlier, `--fix` proved exactly
`gen:docs` and `gen:liveness-counts` stale and regenerated only those.
- `pnpm --filter @objectstack/spec test` → exit 0: 597 test files
passed; 17474 tests passed, 1 todo.
- `pnpm --filter @objectstack/spec typecheck` → exit 0.
- `@objectstack/lint` vitest over the 4 test files that import
`lint-liveness-properties` → exit 0, 495 passed.
- `pnpm check:doc-authoring` → exit 0.
- `pnpm check:nul-bytes` → exit 0: "no raw ASCII control bytes".
- `node scripts/pm/dispatch-gates.mjs --commands`: 10 paths against
merge base `b91e40bc`, yielding 103 commands. Each was run and its exit
code recorded. `--ran` reports: "✓ dispatch-gates --ran: 103 derived
famil(ies) accounted for — 102 run, 1 NOT-MEASURED (1 DERIVED from a
recorded exit 3)".
- **NOT MEASURED:** `pnpm check:dual-build-cjs-loads`. Reason:
PREREQUISITE NOT MET, because it reads every package's `dist/` and needs
a whole-repo build. Declared to CI.
## Deviations
- The PM's R1 refinement fell. Its premise, that the gate refuses `live`
on cloud-only evidence, is falsified by the boundary pin. The PM's
answer 5942977582 rules `live`, as triage wrote.
- The guardrails row gains a `producer` field, following the README's
producer discipline. Its content is quoted from 5940785002.
- `tool.outputSchema` changed by the PM's scope addition after
5943158888 (the "stay experimental and steer" option).
- The PM's message gives the author-lint reading as "2 findings, then
0". Measured per key, `agent.guardrails` goes from 1 to 0. The 2 counts
both keys in the probe stack.
## Acceptance notes
- **Filed as #21288:** `skills/objectstack-ai/SKILL.md:309-311` still
says guardrails are "declared only — no runtime reads them", which has
been false since cloud `235c5b29`. Lines `:279-281` still describe
`outputSchema` keys as folded into the description. This is published
skill text (Tier H), so the PM holds it for its own card, outside this
PR.
- **Fixed in patch round 1 (`58fdaac4`):** the two gate-script comments
that repeated the README's corrected sentence,
`packages/spec/scripts/liveness/elsewhere.mts` (header) and
`readme-table.mts` (the status-column docblock). They are comments only,
with no code change.
- **The `action.ai` reader's known gap (objectstack-ai/cloud#2572) is
fixed** on cloud `main` `1e0ea49a` (reading `5943779795` on #20274). A
schema whose untyped subschema carries a type-scoped keyword is now
refused before the action runs.
- The authoring side still accepts that shape, for both
`action.ai.outputSchema` and `agent.structuredOutput.schema`: filed as
#21289.
- The `action.json` row is not touched here.
- **Filed as #21288, position 3:**
`content/docs/protocol/objectui/actions.mdx:494` says `ai.outputSchema`
enables "structured tool chaining". No reading names a chaining
consumer, and the line is outside this PR's file surface.
- `origin/main` (`b91e40bc`) was merged in with
`scripts/pm/os-regen-merge.sh`. Nothing overlapped. The spec was rebuilt
and every gate above was re-run on the merged head.
Size: 12 files, +54 / −26.
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 1371dc9 commit 135daaa
12 files changed
Lines changed: 54 additions & 26 deletions
File tree
- .changeset
- content/docs
- ai
- references/ai
- packages/spec
- liveness
- state-counts
- scripts/liveness
- src/ai
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
145 | 145 | | |
146 | 146 | | |
147 | 147 | | |
148 | | - | |
| 148 | + | |
149 | 149 | | |
150 | 150 | | |
151 | 151 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
59 | 59 | | |
60 | 60 | | |
61 | 61 | | |
62 | | - | |
| 62 | + | |
63 | 63 | | |
64 | 64 | | |
65 | 65 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | | - | |
| 37 | + | |
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
78 | | - | |
| 78 | + | |
79 | 79 | | |
80 | 80 | | |
81 | 81 | | |
| |||
280 | 280 | | |
281 | 281 | | |
282 | 282 | | |
283 | | - | |
284 | | - | |
285 | | - | |
286 | | - | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
287 | 294 | | |
288 | 295 | | |
289 | 296 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
95 | 95 | | |
96 | 96 | | |
97 | 97 | | |
98 | | - | |
99 | | - | |
100 | | - | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
101 | 104 | | |
102 | 105 | | |
103 | 106 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
15 | | - | |
| 15 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
46 | | - | |
| 46 | + | |
47 | 47 | | |
48 | | - | |
49 | | - | |
| 48 | + | |
| 49 | + | |
50 | 50 | | |
51 | 51 | | |
52 | 52 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
12 | | - | |
13 | | - | |
14 | | - | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
304 | 304 | | |
305 | 305 | | |
306 | 306 | | |
307 | | - | |
308 | | - | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
309 | 311 | | |
310 | 312 | | |
311 | 313 | | |
| |||
0 commit comments