Skip to content

声明式端点的两个机器可读面会说谎:runtime-authored api 行在 /meta/api 与 /openapi.json 里在场,匹配器却永远看不见(真实 boot 实测) #5224

Closed

Description

@os-zhuang

发现于 #5112(#5040 E8 收官验收)的真实 boot 探针,不在该单文件面内,按 Prime Directive #10 单独立项。

事实(showcase 真实 boot,objectstack dev --fresh,47 plugins)

通过 Studio 的元数据写入口写一条 api 条目 —— 注意这是匿名且未计量的形状(ADR-0121 D6 明令禁止的那一种):

PUT /api/v1/meta/api/e8_backdoor
{"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}
→ 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 {"error":"Not found"}
GET /api/v1/apps/showcase/backdoor            (已鉴权) → 404 {"error":"Not found"}

GET /api/v1/meta/api → 三条,含
  - e8_backdoor GET /api/v1/apps/showcase/backdoor authRequired=False

GET /api/v1/openapi.json → paths 含 /api/v1/apps/showcase/backdoor:
  {"get":{"operationId":"e8_backdoor","responses":{"200":{"description":"Success"}},"security":[]}}

路由 404,而两个机器可读面都在宣告它存在 —— 且 OpenAPI 用 security: [] 明确把它描述成「不需要凭据」的公开端点。

为什么会这样(不是 E7b 的门在挡)

两边读的是两个不同的库:

所以这条路由死掉不是因为 #5189/#5203 的装载期门把它拒了 —— 那道门压根没被走到(dev 日志里没有 [EndpointMatcher] ... EXCLUDED 那行)。E7b 的门依然正确且必要;这里是它下面还有一层看不见。

影响的两个方向

  1. 面在说谎(本条的主症):/openapi.json 是 SDK / codegen / AI 客户端直接生成代码的契约面(Route & surface ownership 第 4 条、ADR-0076 D12)。一个被宣告为匿名可达、实际 404 的端点,会传播进所有基于它构建的东西。
  2. 反方向同样成立:一条合法的、本应服务的端点如果是通过 Studio / 运行时写入(而非 stack artifact)落库的,匹配器同样看不见 —— 作者被告知 "Saved",面上也能看到,唯独请求 404。当前净行为是 fail-closed(安全),但「声明了却不生效」正是 声明式 apis:(ApiEndpoint)入站面全链路零执行:元数据装载成功、路由从未挂载、matchEndpoint 全仓无实现 #4936 这条线一直在还的债。

建议的判断轴(不预设结论)

三条的长期代价不同,请维护者裁决 —— 中间那条最省,但它把「面不说谎」变成了「面自己去问匹配器」,是唯一不引入第二真相源的形状。

复现

pnpm dev:showcase -- --fresh -p 39720 --seed-admin
# 登录取 token,然后照上面三条 curl

关联:#5040(执行器立项)、#5112(E8 验收,发现于此)、#5189/#5203(E7b 兜底门)、ADR-0076 §1/§4、ADR-0121 D6。

Activity

  1. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    Contributor

    分诊补记(cli 车道 PM,session_01VkPSGsX9o17MsGv3Lbxu2w,PM 循环第 1 轮):本轮暂缓,挂 pm:blocked。

    Blocked-by: #5206

    16:04Z 登记要求的「派前与 B 包属主对表」已做,结论:

    1. B 包(执行器 program,17.x 立项:建设声明式 ApiEndpoint 执行器(挂载 + matchEndpoint + authRequired/cacheTtl/inputMapping/outputMapping 逐键接线) #5040)已于 08-04 15:28Z 收官关闭,E 系列(挂载 / matchEndpoint / 逐键接线 / E7b 门)已建成进 v17,无在飞车道属主需协调。
    2. 但 api 不在 metadata 类型注册表里 —— Studio 直写路径完全不校验端点,publishPackageDrafts 也没有 E7 门 #5206(engine 车道,pm:dispatched 在飞)与本单同一领地:「api 不在 metadata 类型注册表 —— Studio 直写路径完全不校验端点,publishPackageDrafts 没有 E7 门」,其 spec 拆单 [spec] api 补进 DEFAULT_METADATA_TYPE_REGISTRY 与 BUILTIN_METADATA_TYPE_SCHEMAS(#5206 第 1 步,拆单) #5271 的 PR 仍在落地链上。api 不在 metadata 类型注册表里 —— Studio 直写路径完全不校验端点,publishPackageDrafts 也没有 E7 门 #5206 落地后,本单复现用的写入口(匿名未计量 api 条目 PUT 成功)大概率被 E7 门 / 注册表校验拒收 —— 本单前提的「写入成功」半边会实质改变,而「匹配器与两个面读不同库」的核心断链是否仍可达、以何种形状可达,须在其后重核。
    3. 同时 saveMetaItem 的 direct-active 写入是 api 的第三条门外通路 —— 命名空间门(ADR-0121 D1/D2)与去重门在这条路上无人跑 #5311(saveMetaItem direct-active 第三条门外通路)与本单相邻,重核时一并对照。

    解锁条件:#5206 关闭(其 PR 合入 main)后,重核本单前提(重跑 body 里的三条 curl 探针),再按当时事实决定派发形状 —— 届时三个方向(收敛取数源 / 面问匹配器 / 写入口拒绝)里「写入口拒绝」可能已被 #5206 部分兑现。

    另:与本单文件面相交的 #5155(dispatcher 实例字段串租户)本轮已先行派发 —— 其 dev 已被明确告知⛔不动 matchEndpoint 取数逻辑,本单裁决面不受污染。


    Generated by Claude Code

  2. self-assigned this
    on Aug 5, 2026
  3. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    Contributor

    解锁裁定 + 认领(cli 车道 PM,session_016FNvXhtSdnEGEfLEsMmvxh,2026-08-05 13:2xZ):摘 pm:blocked,与 #5206 解耦派发。

    解耦理由(留否决窗口):① #5206 认领已 24h 无分支无 PR,stale-claim 问询(12:0xZ)1h+ 无回应,v17 窗口不应无限等一个停滞认领;② 两单文件面不相交(#5206 落 spec kernel 注册表 + metadata-protocol,本单落 runtime/rest 的取数与宣告面),原阻塞理由是「复现面的写入半边会变」而非文件冲突 —— 该风险由派发词内的前提重核(重跑 body 三条 curl 探针)吸收:探针若显示写入口已被拒,核心断链(匹配器与两面读不同库)换合法写入路径复测即可,缺陷本体不消失。#5206 自身的认领不动,问询静默窗照走。

    方向裁定(两轴,留否决窗口):取中间条 —— 两个面只宣告匹配器实际会服务的集合(/meta/api 与 /openapi.json 的 enrichment 改为经匹配器索引取数)。判据:issue 自述它是「唯一不引入第二真相源的形状」;恢复的是已成文不变量(Route & surface ownership §4、ADR-0076 D12:契约面不得宣告不会被服务的端点),且不封死另两条路 —— 收敛取数源(方向一)是更大的架构统一,留作 engine/维护者的 appetite 决策另行立项;写入口拒绝(方向三)是 #5206 的领地不侵入。防 AI 轴:codegen/AI 客户端直接消费 /openapi.json,「security: [] 的 404 端点」会传播进所有生成物 —— 面必须说真话。维护者若属意方向一为 v17 形状,请否决,届时转 needs-user-decision。

    认领:PM 循环第 7 轮(cli 车道,v17 优先项)
    会话:session_016FNvXhtSdnEGEfLEsMmvxh
    分支:claude/issue-5224-surfaces-match-matcher
    Worktree:objectstack-issue-5224
    域:domain:cli
    文件面:packages/rest/src/**(/meta/:type 与 openapi enrichment 的取数)+ packages/runtime/src/**(仅读取匹配器索引的接缝,⛔ 不动 matchEndpoint 取数逻辑本身)+ 对应测试。与在队列 #5464(rest-server 错误路径)相邻同包 —— 须待 #5464 MERGED 后切树;与 #5448/#5462 不同文件。


    Generated by Claude Code

  4. baozhoutao commented on Aug 5, 2026

    @baozhoutao
    Contributor

    验收(cli 车道 PM,session_016FNvXhtSdnEGEfLEsMmvxh):ACCEPT → PR #5487。v17 契约窗口项闭环。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions