Skip to content

api 注册表条目声明 allowRuntimeCreate: true,但运行时创建的端点匹配器永远看不见 —— 声明的能力运行时不兑现(真实 boot 实测) #5488

Description

@baozhoutao

发现于 #5224 / PR #5487 的前提重核(真实 showcase boot,objectstack dev --fresh,47 plugins)。不在该单文件面内,按 Prime Directive #10 单独立项。这就是 #5224 body 里列的方向一(收敛取数源),PM 在 #5224 的解锁裁定里明确留作「更大的架构统一,另行立项」。

事实

DEFAULT_METADATA_TYPE_REGISTRYapi 的条目声明:

packages/spec/src/kernel/metadata-plugin.zod.ts:760
{ type: 'api', label: 'API Endpoint', ..., allowRuntimeCreate: true, ... }

allowRuntimeCreate: true = 平台声明允许在运行时(Studio / 元数据写入口)创建一条 api。实测确实允许:

PUT /api/v1/meta/api/e8_backdoor  {...}  → HTTP/1.1 200 OK
   {"success":true,"version":"sha256:9ad721f4...","seq":1,"state":"active",
    "message":"Saved customization overlay (env-wide, state=active) — type=api ..."}

但这条端点永远不会被服务:

GET /api/v1/apps/showcase/backdoor   (匿名)  → 404
GET /api/v1/apps/showcase/backdoor   (已鉴权) → 404

而且不是被门拒的 —— 整轮 dev 日志里没有 [EndpointMatcher] ... EXCLUDED 那一行(#5189/#5203 的 E7b 装载期门压根没被走到)。

原因(与 #5224 同一条断链,另一个方向)

服务判据的持有者是 IMetadataService.matchEndpointEndpointMatcherMetadataManager.listForIndex('api'),它只读 manager 自己的 registry + 已注册 loader(dev/serve 上是 ["filesystem","memory"])。运行时写入落的是 sys_metadata,不在这两者之中,所以匹配器的索引里根本不存在这一条。

#5224 修的是「面不许谎报」(PR #5487 已让两个面只宣告匹配器会服务的集合)。本单是反方向:注册表声明了「可以运行时创建」这一能力,而运行时不兑现它。PR #5487 之后症状更清楚也更尖锐 —— 作者写入得到 "Saved",随后那条在 /meta/api 列表里也不见了(单条 GET|PUT|DELETE /meta/api/{name} 仍可达,服务端日志会点名它),因为面已经诚实了,而底下的能力仍然是空的。

三种可能的收口(不预设结论,判据不同)

  1. 收敛取数源:让 matchEndpointgetMetaItems 读同一个库(一条路由一个所有者的元数据版本)。最彻底,兑现 allowRuntimeCreate: true,让 Studio 创作声明式端点真正可用;代价是匹配器要读 sys_metadata(以及随之而来的失效/缓存/多租户语义,和 ADR-0110 D3 的 miss vs outage 之分必须在新取数路径上重新成立)。
  2. allowRuntimeCreate: false:承认 17.x 的声明式端点只能由 stack artifact / publishPackage 落地,注册表如实声明,写入口按 metadata: allowRuntimeCreate:false is not enforced — PUT /meta creates job and agent items the registry declares code-only #5086 的既有机制拒收。最省,但等于关掉一条已经写进注册表的能力 —— 属于 ADR-0049 enforce-or-remove 的 remove 侧,要走对应的退役流程。
  3. 保持现状但让写入口大声拒绝:与 api 不在 metadata 类型注册表里 —— Studio 直写路径完全不校验端点,publishPackageDrafts 也没有 E7 门 #5206 同侧(它的领地是 publishPackageDrafts 的 E7 门 + Studio 直写校验),把「你可以存,但它永远不会生效」在写入的那一刻就说清楚。

三条的长期代价不同,请维护者裁决。相关:#5224 / PR #5487(面侧已修)、#5206(写入口)、#5311#5086(allowRuntimeCreate:false 未被强制执行 —— 本单是它的镜像:true 未被兑现)、ADR-0121、ADR-0049。

复现

pnpm dev:showcase -- --fresh -p 39720 --seed-admin
# 登录取 token
curl -X PUT .../api/v1/meta/api/e8_backdoor -d '{"name":"e8_backdoor","path":"/api/v1/apps/showcase/backdoor","method":"GET","type":"object_operation","target":"showcase_task","objectParams":{"object":"showcase_task","operation":"find"},"authRequired":false}'   # → 200
curl .../api/v1/apps/showcase/backdoor    # → 404,且日志中无 EXCLUDED 行

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions