Skip to content

test(spec,client,runtime): both producers of /ai/agents are enveloped now — relocate the declaration and pin it (#4053) - #4238

Merged
os-zhuang merged 3 commits into
mainfrom
claude/ai-agents-sdk-envelope-a2xk1w
Jul 31, 2026
Merged

test(spec,client,runtime): both producers of /ai/agents are enveloped now — relocate the declaration and pin it (#4053)#4238
os-zhuang merged 3 commits into
mainfrom
claude/ai-agents-sdk-envelope-a2xk1w

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Closes the remainder of #4053. Companion: objectui#3080.

Where #4053 actually stands

The issue asked for three steps plus one relocation. Checking each rather than assuming:

step status
cloud buildAgentRoutes emits { success: true, data } ✅ cloud#929
framework runtime/src/domains/ai.ts fallback, same shape #4124
framework SDK — "correct it or delete it outright" needed no change, and that is the finding
AiAgentsResponseSchema describes data, not the body this PR

The SDK row is the one worth stating plainly, because "no diff" reads like an oversight. unwrapResponse returns body.data when a body carries a boolean success and a data key, so body?.agents reads .agents off { agents } whichever producer answered. That is true only because the conversion relocated the payload; the flatten would have made this exact line read undefined. The line now says so, instead of leaving the next reader to re-derive it.

The declaration follows the wire

AiAgentsResponseSchema was declared as the whole GET /api/v1/ai/agents body. Since the conversion it is what travels under data — so it says that now, along with why this was #3843's relocation (a declared payload moving unchanged) rather than #3983's flatten (an ad-hoc { links } wrapper being reshaped). That reasoning existed only in the two producers that implement it and in a closed PR body; it belongs on the thing both of them import.

One pin, in the package both producers share

packages/spec/src/api/ai-agents-envelope.test.ts asserts both halves of the contract — envelopeViolations clean and data parsing as the declared payload — with the drifts pinned as negatives: the flattened conversion, the pre-#4053 bare body, an agents key mirrored beside data (the #4038/#4049 shim), and a row missing capabilities.

Note which check catches the flatten:

const body = { success: true, data: [ASK, BUILD] };
expect(envelopeViolations(body)).toEqual([]);                       // ← envelope is FINE
expect(AiAgentsResponseSchema.safeParse(body.data).success).toBe(false);

The envelope is conformant; it is the payload that stops matching its declaration. A suite leading with envelopeViolations alone passes that body — which is exactly how it would ship.

It lives in spec because nothing else can hold it. Each producer pins its own body in its own repo and neither can pin the other's, and scripts/check-route-envelope.mjs reaches neither: dispatcher domains return { status, body } for a central sender (#4049), and cloud is outside the framework guard entirely. What both producers do share is this package.

Records that had gone stale

Four comments across runtime and client still described cloud as unenveloped and the migration as in flight, and the client suite's header said "cloud's has not yet [converted]".

On this route that is not cosmetic. The entire reason #4053 exists is that a wrong belief about the shape produces no error, no 403 and no log — just a hidden AI surface, which is also what a seat-less caller (ADR-0068) and a Community Edition deployment correctly see. A reader who believes the servers are still bare is one step from "clean this up".

The client suite keeps reading the unenveloped body, retitled to say why: an SDK outlives the server it is pointed at, so a current client talking to a pre-conversion deployment is ordinary, not hypothetical.

Verification

Re-run after merging main (see below), so these are the numbers for the merged tree rather than the branch point:

gate result
@objectstack/spec 7149 passed (276 files; 7 of them new here)
@objectstack/client 205 passed
@objectstack/runtime 956 passed
check:route-envelope (+ self-test) 0 ratcheted, both surfaces
check:role-word · check:nul-bytes clean
tsc --noEmit — spec, client clean

runtime's tsc --noEmit reports two pre-existing TS6133 unused-symbol errors in domains/mcp.ts and domains/meta.ts — neither file is in this diff, and runtime has no type-check script, so this is not the gate that package ships behind. Recorded rather than quietly skipped.

Why main is merged in

#4222 landed while this was open and edits packages/runtime/src/domains/ai.ts — the same file, changing the sibling mounted-but-unimplemented refusal from 404 to 501 and re-pinning check-route-envelope.mjs. Git reported no conflict, but "no conflict" is not "still correct" when another PR rewrites the same function, so main is merged here and the gates above were re-run against the result. #4222 explicitly left GET /ai/agents's empty-list 200 alone; the two changes sit side by side. (check:route-envelope now audits 16 dispatcher domains rather than 15 — #4222's new domains/unavailable.ts.)

Carries an empty changeset — the sanctioned "this PR releases nothing" declaration. There is no behavior change: comments, one doc-block relocation, and a test file.

… now — relocate the declaration and pin it (#4053)

#4053 asked for three steps plus one relocation. The three landed: the
framework's degraded fallback (#4124), cloud's `service-ai` (cloud#929),
and the SDK read — which needed no change, and that is the finding rather
than an omission. What was left is the relocation the issue named, and a
set of records that all still say the conversion is half done.

## The declaration follows the wire

`AiAgentsResponseSchema` was declared as the whole `GET /api/v1/ai/agents`
body. Since the conversion it is what travels under `data`, so it now says
so — the same move `SettingsNamespacePayload` made in #3843, and the reason
this was a RELOCATION rather than #3983's flatten is recorded on the
declaration instead of only at the two producers that implement it.

## One pin, in the package both producers share

`packages/spec/src/api/ai-agents-envelope.test.ts` asserts BOTH halves of the
contract — `envelopeViolations` clean AND `data` parsing as the declared
payload — with the drifts pinned as negatives: the flattened conversion, the
pre-#4053 bare body, an `agents` key mirrored beside `data`, and a row with no
`capabilities`.

Note which check catches the flatten. The envelope is *fine*; it is the payload
that stops matching its declaration. A suite leading with `envelopeViolations`
alone passes that body, which is exactly how it would ship.

This lives in spec because nothing else can hold it. Each producer pins its own
body in its own repo and neither can pin the other's;
`scripts/check-route-envelope.mjs` reaches neither — dispatcher domains return
`{ status, body }` for a central sender (#4049), and cloud is outside the
framework guard entirely. What both producers do share is this package.

## Records that had gone stale

Four comments still described cloud as unenveloped and the migration as in
flight. On this route that is not cosmetic: the whole reason #4053 exists is
that a wrong belief about the shape produces no error, no 403 and no log — just
a hidden AI surface, which is also what a seat-less caller and a Community
Edition deployment correctly see. A reader who believes the servers are bare is
one step from "clean this up".

Verified: spec 7174 passed (277 files, 7 new), client 205, runtime 956;
`check:route-envelope` 0 ratcheted on both surfaces, self-test included;
`check:role-word`, `check:nul-bytes` clean; spec and client tsc clean.
No behavior change, so no changeset.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BZaiYNM5igzGk6JiibjShb
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 30, 2026 8:17pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/client, @objectstack/runtime, @objectstack/spec.

116 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via packages/client, @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/client, packages/runtime, @objectstack/spec)
  • content/docs/api/data-flow.mdx (via @objectstack/client)
  • content/docs/api/environment-routing.mdx (via @objectstack/client, @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/client, @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime, packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/runtime, packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/client, @objectstack/runtime, @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/client)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/client, packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/client, @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/runtime, @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/client, @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/client)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/client, @objectstack/runtime, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/client, @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

The Check Changeset gate takes an empty-frontmatter changeset as the
sanctioned "releases nothing" declaration, on par with the skip-changeset
label. The diff is comments, a doc-block relocation and one new test file.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BZaiYNM5igzGk6JiibjShb
@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling labels Jul 30, 2026
Picks up #4222, which rewrote the sibling refusal in `domains/ai.ts`
(mounted-but-unimplemented now answers 501, not 404) and re-pinned
`check-route-envelope.mjs`. It deliberately left `GET /ai/agents`'s
empty-list 200 alone, so this PR's comment block on that branch merges
without conflict — verifying it against the merged tree rather than
assuming.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BZaiYNM5igzGk6JiibjShb
@os-zhuang
os-zhuang marked this pull request as ready for review July 31, 2026 00:39
@os-zhuang
os-zhuang merged commit 469b3d4 into main Jul 31, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/ai-agents-sdk-envelope-a2xk1w branch July 31, 2026 00:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants