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

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 里),因此 defineStack、os 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_operation 缺 objectParams.object 或 .operation;flow 的 target 为空 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.md 与 spec-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.

@os-zhuang
os-zhuang marked this pull request as ready for review August 4, 2026 08:20
@os-zhuang
os-zhuang enabled auto-merge August 4, 2026 08:20
@os-zhuang
os-zhuang added this pull request to the merge queue Aug 4, 2026
Merged via the queue into main with commit d21c001 Aug 4, 2026
25 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-5111-publish-flip branch August 4, 2026 08:40
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