Skip to content

rest 的 9 条 direct-mount 路由对 RestServer 不可枚举 —— 因此进不了 /openapi.json,也进不了任何运行时自省 #5822

Description

@baozhoutao

观察类发现,来自 #5588(PR #5821)的实现过程,按 Prime Directive #10 单独立单。今天没有用户会撞到:它只影响文档覆盖面,不影响任何路由的可用性。

事实

packages/rest 有两个 registrar 绕过 RouteManager、直接注册到 IHttpServer:

  • packages/rest/src/package-routes.ts —— POST /api/v1/packages/publish、GET /api/v1/packages、GET /api/v1/packages/:id、DELETE /api/v1/packages/:id
  • packages/rest/src/external-datasource-routes.ts —— datasources/:name/external/* 5 条

台账 packages/rest/src/rest-route-ledger.ts 里它们是 source: 'direct-mount' 的 9 行,其中 8 行 disposition: 'sdk'(packages.list / packages.get / packages.uninstall / datasources.external.* 都是 SDK 表达得出来的真实能力)。

由 rest-api-plugin.ts 分别在 packageService / external-datasource 服务存在时调用,RestServer 自身不持有任何记录:RestServer.getRoutes()(= routeManager.getAll())看不到它们。

后果

#5588 裁定 C 之后,GET {apiPath}/openapi.json 的 built-in 段由 routeManager.getAll() 产出(PR #5821)。这 9 条因此不在文档里 —— 这是 #5821 刻意选的边界并写进了 PR 正文:本服务器不持有「本次 boot 它们是否挂载」的事实,凭空补上就是 #5588 修的那类幽灵。所以现状是 honest but incomplete,不是 bug:

  • 拿 /openapi.json 生成客户端的 consumer 拿不到 packages.* 与 datasources.external.* 这 9 条(其中 8 条 SDK 有对应方法),要自己照台账手写;
  • 除 openapi 之外,任何基于 getRoutes() 的自省(调试、路由清单、未来的门禁)同样看不见它们;rest-route-ledger.conformance.test.ts 之所以能守住它们,是因为它另起一套枚举方式(用 mock server 捕获注册调用),而不是问服务器。

可能的处置(留给分诊,不预设)

  1. 让两个 registrar 返回自己挂载的路由描述,由 rest-api-plugin.ts 交给 RestServer 登记为「已挂载」—— 事实来自实际调用点,不新增第二真相源;
  2. 或者把它们迁到 RouteManager 注册(需确认当初绕开是否有原因 —— package-routes.ts 的注释只解释了为什么不用 POST /packages,没解释为什么绕开 RouteManager);
  3. 或者维持现状,把「文档不含 direct-mount」明确为契约。

处置口径上 (1) 与 (2) 都会顺带让 rest-route-ledger.conformance.test.ts 的两套枚举收敛成一套。


Generated by Claude Code

Activity

  1. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    Contributor

    发现分诊:持有(维持 finding) + 补 domain:cli。

    域标签理由:落点在 packages/rest(package-routes.ts / external-datasource-routes.ts / rest-server.ts / rest-route-ledger.ts),packages/rest 在 SKILL 域表 cli 行。与产生它的 #5588 同车道,处置时不必跨座位。

    过时前提检查(origin/main@846ed1f,实读,成立):

    • rest-route-ledger.ts 的 direct-mount 命中 13 处 ✅(正文说的 9 条路由 + 相关注记),台账仍如实记着这批路由;
    • rest-server.ts:8457-8458 getRoutes() { return this.routeManager.getAll(); } ✅ —— 即 RestServer 确实只能看见 RouteManager 里的东西,direct-mount 的 9 条对它不可枚举,前提原样成立。

    判持有(而非晋级)的理由 —— 两条,第二条是硬的:

    1. 正文自评为 "honest but incomplete,不是 bug",分诊同意:9 条路由全部可用,受影响的只有文档覆盖面与自省面;今天没有用户会撞到。这是观察类的教科书形状。
    2. ⛔ 它的前提正在被在飞的 发布出去的 /api/v1/openapi.json 描述的 built-in 路由一条都不存在 —— 10 个 operation 真实 boot 全部 404(证伪 #5456 的「当前未漂移」) #5588 / PR fix(rest): /openapi.json 的 built-in 路由段改由 rest 按自身路由事实产出(#5588,裁定 C 第一棒) #5821 改写 —— 本单描述的现状(「built-in 段由 routeManager.getAll() 产出,因此这 9 条不在文档里」)正是 fix(rest): /openapi.json 的 built-in 路由段改由 rest 按自身路由事实产出(#5588,裁定 C 第一棒) #5821 刚刚选定的边界,而该 PR 还没落地。现在晋级派发,dev 会在一个尚未稳定的边界上做决策;更糟的是三个处置选项里,(1)(2) 都要改 fix(rest): /openapi.json 的 built-in 路由段改由 rest 按自身路由事实产出(#5588,裁定 C 第一棒) #5821 正在动的那条枚举路径,是直接的同文件撞车。

    ⛔ 重启条件(明确、可机械判定):#5588 / PR #5821 合入 main 之后。那一刻 /openapi.json 的 built-in 段成为既成事实,三个选项的成本才是可比的,由 cli 座位判级。

    判级时的提示(供届时参考,不构成裁决):三个选项不是平权的 —— (3)「维持现状并把『文档不含 direct-mount』明确为契约」需要回答一个不便宜的问题:8/9 条的 disposition 是 sdk,即 SDK 已经表达得出来的真实能力,把它们永久排除在生成的客户端之外,是把「服务器不持有该事实」这个实现约束升格成对外契约。(1) 看起来最省(事实来自实际调用点,不新增第二真相源,且顺带让 rest-route-ledger.conformance.test.ts 现在那套「用 mock server 捕获注册调用」的第二套枚举与主枚举收敛成一套)。(2) 之前需先答正文点出的那个未解问题:当初为什么绕开 RouteManager —— package-routes.ts 的注释只解释了为什么不用 POST /packages,没解释绕开的理由;⚠️ 没查清这条就改成 RouteManager 注册,是在拆一个可能有原因的绕行。

    查重:三仓 open issue / PR 各搜一遍(direct-mount / getRoutes / openapi.json 覆盖面 / rest-route-ledger)。#5588(在飞,PR #5821)是产生本单的现场、其 PR 正文已把本边界写明,非重复;#5563(rest 线全仓翻转)是相邻但不同现场。无影子单,不关重复。

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    Contributor

    发现分诊(存量裁决轮,维护者 2026-08-06 委托,session_01LeEfA7CFwbJb7JJmXm2KM3):晋级 finding → pm:queue。分诊席的机械重启条件(PR #5821 合入)已于 07:05Z 触发——/openapi.json 的 built-in 段成为既成事实,而 9 条 direct-mount 路由(含 8 条 disposition=sdk 真实能力)对 RestServer 仍不可枚举(rest-api-plugin.ts:319-344 直挂 IHttpServer,getRoutes 只回 routeManager)。默认方向按席位提示选项 1(registrar 返回挂载描述、事实来自实际调用点,顺带收敛 conformance 测试第二套枚举);选项 2 须先答清当初为何绕开 RouteManager。


    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

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions