Skip to content

feat(spec)!: 声明式 apis: 翻转 —— 硬拒收窄为逐端点门(#5040 E7) - #5188

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-5111-publish-flip
Aug 4, 2026
Merged

feat(spec)!: 声明式 apis: 翻转 —— 硬拒收窄为逐端点门(#5040 E7)#5188
os-zhuang merged 1 commit into
mainfrom
claude/issue-5111-publish-flip

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes #5111
Part of #5040(E7 —— 本程序唯一改变行为的一单)

这一单做了什么

#4936 对非空 apis:整面硬拒packages/spec/src/stack.zod.ts 上是一条 .max(0),理由是当时端点面全链路零执行(无挂载、无匹配器、每个键——包括 authRequired——解析通过而不生效)。E1–E6 把执行器建成之后,这条理由不复存在,继续拒绝就变成了反方向的谎:一条能跑的能力被挡在门外。

本 PR 把它收窄为逐端点门:过门的端点在 publish 之后真实挂载、真实服务流量。门挂在 ObjectStackDefinitionSchema 上(不是挂在 defineStack 里),因此 defineStackos validate、lint 评分、metadata 插件的 artifact 摄入、EnvironmentArtifactSchema.metadata 这五条路径没有一条能绕过它

五道门(每道自带处方,点名端点、点名键)

拒绝的形状 运行时对偶
命名空间(ADR-0121 D1/D2) path 不是 /api/v1/apps/{manifest.namespace}/{subpath};或声明了 apis: 却没有显式 manifest.namespace(Q1 = A,不做 deriveNamespaceFromPackageId 回落——对外 URL 契约不应因为改了 package id 而漂移) isAppEndpointPath(路由候选判据)
支持子集 type: 'script' / 'proxy';object_operationobjectParams.object.operation;flowtarget 为空 planEndpointTarget
映射 任何 transform;不可用的 source/target 路径(空串、空段 a..b、原型键);互撞的 target(同路径 / 一条写进另一条内部);外加 PM 裁决:inputMapping 写在 find/get/delete 上(不读 body,声明必然惰性,与非 GET 的 cacheTtl 同类同判) mappingDeclarationRejection
策略(ADR-0121 D6 + E4 四条) authRequired: false 而无已装配限流(判据 rateLimit?.enabled === true,不是键存在——enabled 的 schema 缺省是 false,写了窗口和配额却不写 enabled 会得到一个「匿名且完全不计量」的端点);已装配但不可用的预算(maxRequests/windowMs ≤ 0);负数 cacheTtl;非 GET 上的 cacheTtl endpointRateLimiterRegistry / cacheControlHeader
唯一性 同栈内两条声明认领同一 METHOD + 规整后 path(裁掉一个尾斜杠,与匹配器同规则),拒绝文案点名两条 endpointIndexKey

每一道门的判据都是照读运行时得出的,不是凭记忆复述:接受的集合 = 执行器服务的集合。运行时侧的 501 拒绝保留不动——绕过 publish 直写 metadata.register() 的条目仍需要那道兜底。

翻转的阳性断言(#4936 之后第一次)

新增测试里第一组就是正面用例:命名空间下的 object_operation 端点、flow 端点、装配了限流的匿名端点、body 型操作上的映射键——全部通过校验。回归钉子同时保留:空 apis: / 缺省 apis: 依然合法,没有 namespace 但也没有端点的 stack 依然可发布。

升级文档 = 安全承载件(维护者裁决:不加激活开关)

生成机制只从 ADR-0087 registry 取料,所以指令写在 registry 里:

  • packages/spec/src/migrations/registry.ts 新增 semantic 条目 declarative-apis-endpoints-live(surface / replacement / reason / acceptanceCriteria),外加 step17 rationale 的一段 ⚠️ 前置说明;
  • 二者经 gen:upgrade-guide / gen:spec-changes 落进 docs/protocol-upgrade-guide.mdspec-changes.json(本 PR 已重生成)。

内容明确指令升级者(通常是 AI 维护者):升级前审视每一处历史 apis: 配置;过门的端点在 v17 publish 后即为在线;特别注意显式 authRequired: false——schema 缺省是 true,漏写是安全的,只有显式 false 才打开匿名面,且 D6 要求它配一条已装配的限流。未触碰 content/docs/releases/

其它

  • 词表冻结:ApiEndpointSchema 零改动——门是校验逻辑,不是新键;
  • normalizeEndpointPath 上移到 @objectstack/spec/api,packages/metadata 的匹配器改为再导出。唯一性门与匹配器索引键从此不可能对「规范形式」产生分歧(否则可以发布一对匹配器只会留一条的重复声明);
  • changeset:@objectstack/spec major(与一期 feat(spec,core,runtime)!: 声明式 apis: 响亮拒绝 + ApiRegistry 整面退役 (#4936, #4939) #5065 同级,同属 v17 破坏面),正文含 FROM → TO 与升级前的安全审视说明。

验证(真实输出)

spec test          Test Files 305 passed (305) / Tests 7794 passed (7794)
spec typecheck     tsc --noEmit (clean)
spec check:generated  ✗ 3 stale → --fix → spec-changes / upgrade-guide / api-surface(仅本改动)
check:exported-any    ✅ 1843 types + 1594 schemas
check:dual-source     ✅ 0 accepted dual-source
metadata test      17 passed / 384 tests      runtime test  89 passed / 1312 tests
rest test          40 passed / 608 tests      cli test      69 passed / 612 tests
turbo typecheck    runtime + rest + cli:55 tasks successful
eslint             clean(六个改动文件)

🤖 Generated with Claude Code

https://claude.ai/code/session_01EYGdmvWP1ieZSLqvAW6uyd


Generated by Claude Code

…ates (#5111, #5040 E7)

THE FLIP. #4936 refused a non-empty `apis:` wholesale because the declarative
endpoint surface executed nothing — no route mounted, no matcher, every key
including `authRequired` parsed green and gated nothing. The #5040 E-series
built the executor, so that premise is gone; keeping the refusal would be the
lie in the other direction. This replaces the blanket `.max(0)` with a
per-endpoint gate on `ObjectStackDefinitionSchema`, and an endpoint that passes
it is MOUNTED and serves traffic on publish.

Gates, each rejecting with a prescription naming the endpoint and the key:

- namespace (ADR-0121 D1/D2): `path` must be
  `/api/v1/apps/<manifest.namespace>/<subpath>`; `manifest.namespace` must be
  declared explicitly (#5040 Q1 = A — no `deriveNamespaceFromPackageId`
  fallback for an outward URL contract);
- supported subset (mirrors `planEndpointTarget`): `script` / `proxy`, an
  `object_operation` missing `objectParams.object|operation`, a `flow` with an
  empty `target`;
- mapping (mirrors `mappingDeclarationRejection`): any `transform`, an unusable
  `source`/`target` path (empty, empty segment, prototype keys), colliding
  targets — plus `inputMapping` on `find`/`get`/`delete`, which never read a
  body (PM ruling: same category as `cacheTtl` on a non-GET);
- policy (ADR-0121 D6 + the E4 refusals): `authRequired: false` requires
  `rateLimit.enabled === true` (presence is NOT armed — `enabled` defaults to
  `false`), an armed budget must be usable, `cacheTtl` non-negative and GET-only;
- uniqueness: one claim per METHOD + normalized path inside a stack.

The gate lives on the schema, not in `defineStack`, so every publish/validate
seam runs it: `defineStack`, `os validate`, the lint scorer, the metadata
plugin's artifact ingestion and `EnvironmentArtifactSchema.metadata`.

`normalizeEndpointPath` moves to `@objectstack/spec/api` and the endpoint
matcher re-exports it, so the uniqueness gate and the matcher's index key can
never disagree about the canonical path form.

Upgrade documentation is the security deliverable (maintainer ruling: no
activation switch): a `declarative-apis-endpoints-live` semantic migration entry
plus a step-17 rationale paragraph instruct the upgrading (AI) maintainer to
review every historical `apis:` block before upgrading and to pay particular
attention to explicit `authRequired: false`. Both reach
`docs/protocol-upgrade-guide.md` and `spec-changes.json` through the ADR-0087
generators. Vocabulary frozen: no key added, removed or renamed.

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

vercel Bot commented Aug 4, 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 Aug 4, 2026 8:18am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Aug 4, 2026
@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/metadata, @objectstack/spec.

108 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 @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @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/spec)
  • content/docs/automation/approvals.mdx (via @objectstack/spec)
  • content/docs/automation/connectors.mdx (via @objectstack/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via 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 @objectstack/metadata, packages/spec)
  • content/docs/concepts/north-star.mdx (via @objectstack/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @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/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • 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/spec)
  • content/docs/kernel/cluster.mdx (via packages/metadata, @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/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via 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/metadata, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @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/metadata, @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/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/metadata-service.mdx (via @objectstack/metadata)
  • content/docs/protocol/kernel/plugin-spec.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/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/metadata, @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/metadata, @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.

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/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

E7(#5040 执行器):翻转 —— publish 硬拒收窄为「不支持子集 + 命名空间门」,声明式端点随 v17 放行执行

2 participants