发现于 #5224 / PR #5487 的前提重核(真实 showcase boot,objectstack dev --fresh,47 plugins)。不在该单文件面内,按 Prime Directive #10 单独立项。这就是 #5224 body 里列的方向一(收敛取数源) ,PM 在 #5224 的解锁裁定里明确留作「更大的架构统一,另行立项」。
事实
DEFAULT_METADATA_TYPE_REGISTRY 里 api 的条目声明:
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.matchEndpoint → EndpointMatcher → MetadataManager.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} 仍可达,服务端日志会点名它),因为面已经诚实了,而底下的能力仍然是空的。
三种可能的收口(不预设结论,判据不同)
收敛取数源 :让 matchEndpoint 与 getMetaItems 读同一个库(一条路由一个所有者的元数据版本)。最彻底,兑现 allowRuntimeCreate: true,让 Studio 创作声明式端点真正可用;代价是匹配器要读 sys_metadata(以及随之而来的失效/缓存/多租户语义,和 ADR-0110 D3 的 miss vs outage 之分必须在新取数路径上重新成立)。
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 侧,要走对应的退役流程。
保持现状但让写入口大声拒绝 :与 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 行
发现于 #5224 / PR #5487 的前提重核(真实 showcase boot,
objectstack dev --fresh,47 plugins)。不在该单文件面内,按 Prime Directive #10 单独立项。这就是 #5224 body 里列的方向一(收敛取数源),PM 在 #5224 的解锁裁定里明确留作「更大的架构统一,另行立项」。事实
DEFAULT_METADATA_TYPE_REGISTRY里api的条目声明:allowRuntimeCreate: true= 平台声明允许在运行时(Studio / 元数据写入口)创建一条api。实测确实允许:但这条端点永远不会被服务:
而且不是被门拒的 —— 整轮 dev 日志里没有
[EndpointMatcher] ... EXCLUDED那一行(#5189/#5203 的 E7b 装载期门压根没被走到)。原因(与 #5224 同一条断链,另一个方向)
服务判据的持有者是
IMetadataService.matchEndpoint→EndpointMatcher→MetadataManager.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}仍可达,服务端日志会点名它),因为面已经诚实了,而底下的能力仍然是空的。三种可能的收口(不预设结论,判据不同)
matchEndpoint与getMetaItems读同一个库(一条路由一个所有者的元数据版本)。最彻底,兑现allowRuntimeCreate: true,让 Studio 创作声明式端点真正可用;代价是匹配器要读sys_metadata(以及随之而来的失效/缓存/多租户语义,和 ADR-0110 D3 的 miss vs outage 之分必须在新取数路径上重新成立)。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 侧,要走对应的退役流程。api不在 metadata 类型注册表里 —— Studio 直写路径完全不校验端点,publishPackageDrafts 也没有 E7 门 #5206 同侧(它的领地是publishPackageDrafts的 E7 门 + Studio 直写校验),把「你可以存,但它永远不会生效」在写入的那一刻就说清楚。三条的长期代价不同,请维护者裁决。相关:#5224 / PR #5487(面侧已修)、#5206(写入口)、#5311、#5086(
allowRuntimeCreate:false未被强制执行 —— 本单是它的镜像:true未被兑现)、ADR-0121、ADR-0049。复现