Skip to content

E3(#5040 执行器):挂载 seam —— IHttpServer.setFallbackHandler 的 Hono 实现 + dispatcher 端点派发步 + 路由台账登记 #5090

Description

@os-zhuang

Part of #5040(E 系列第 3 单)。Blocked-by: #5080(需 IHttpServer.setFallbackHandler? 契约成员先落)。维护者已放行提前开发(2026-08-04,见 #5080 认领评论;E7 翻转仍守 v17 分期)。

范围(以 #5040 设计 §1 方案 C、§3 与总表 E3 行为准)

  1. plugin-hono-server:实现 setFallbackHandler —— 仅在全部显式路由未命中后调用;handler 收到的 req.body 可读(与 use() 中间件「body 不填充」契约区分,adapter.ts:362 一带);实测覆盖设计 §7-1 标注的 Hono 兜底行为风险;
  2. dispatcher-plugin:注册兜底 → dispatch() 端点匹配步(调 matchEndpoint,17.x 挂载前缀 /apps/<ns>/…);未命中维持现状 404 形状(不改变既有 404 语义,收口另议);
  3. route-ledger.ts:新增挂载面登记行,注记与实际一致(取 GET /openapi.json 有两个属主:rest-server 真serve,http-dispatcher 的 generateOpenApi 分支全仓无实现(ADR-0076 D1 影子重复) #5078 教训)。

约束

  • 结构性不可达(publish 仍拒),零现网行为变更;含集成测试(fallback 触发顺序 / body 可读 / 未命中穿透);
  • 执行器车道程序卡(session_01EYGdmvWP1ieZSLqvAW6uyd 按序派发),其它车道请勿认领。

关联:ADR-0121、#5080(E1)、#4910-Q1(server: seam 先例)、#5040 设计 §1/§3/§7-1。

Activity

  1. self-assigned this
    on Aug 4, 2026
  2. os-zhuang commented on Aug 4, 2026

    @os-zhuang
    ContributorAuthor

    认领 —— PM 会话 session_01EYGdmvWP1ieZSLqvAW6uyd(执行器车道),分支 claude/issue-5090-fallback-seam,R2 批与 #5089 并行派发。前置 #5080 已落 main(77be690)。

    文件面声明(#4604):packages/plugins/plugin-hono-server(setFallbackHandler 实现 + 测试)、packages/runtime 的 dispatcher-plugin 兜底注册与端点派发步(+ 测试)、route-ledger.ts 登记行、.changeset/*.md。不触碰 metadata 槽位实现方的匹配模块(那是 #5089 的面)—— 派发步以 typeof metaSvc.matchEndpoint === 'function' 探测,#5089 未落时探测缺席自然穿透,测试用实现契约的 stub,两单无落地顺序依赖。

    规格来源:main 上 packages/spec/src/contracts/http-server.ts 的 setFallbackHandler 契约文本即规格,逐字实现(仅全显式路由未命中后调用、映射到 app.notFound 而非路由、body 可读、重复安装即替换、handler 不写响应则保持适配器既有 404/405 语义)。


    Generated by Claude Code

  3. os-zhuang commented on Aug 4, 2026

    @os-zhuang
    ContributorAuthor

    实现完成 —— 草稿 PR #5120(分支 claude/issue-5090-fallback-seam,会话 session_01EYGdmvWP1ieZSLqvAW6uyd,已合入 origin/main 含刚落地的 #5089)。

    三个落面均已落地:setFallbackHandler 的 Hono 实现(映射 app.notFound,契约四条保证逐条有测试)、dispatcher 端点派发步(新模块 packages/runtime/src/api-endpoint-step.ts,挂载前缀按 ADR-0121 D1 只拼写一处)、路由台账 * /apps/** 行 + NON_DISPATCH_MOUNT_PREFIXES。未命中写空响应,404/405 逐字节不变;执行未接线(E4–E5),注记如实写明。

    设计 §7-1 的 Hono 兜底行为风险,三条实测结论(均已转成测试):

    1. 方法不匹配与路径不存在走同一个 notFound 出口 —— fallback 会看到 405 destined 请求,弃权后 405 必须完好;
    2. c.req.param() 在 notFound 上下文抛异常(hono 4.12,无 match result),不是返回空 —— 首版实现全部用例因此炸掉,已收口;
    3. app.notFound 后调用者覆盖 —— 这直接决定了实现形状:404/405 应答必须从 hono-plugin.ts 移入适配器与 fallback 组合,否则两个写入方的幸存者由插件启动顺序决定。

    顺带发现并已在改动路径上修掉两处契约不一致:适配器给路由处理器构造的 IHttpRequest 缺 remoteAddress(中间件 seam 有,同契约两种形状,E4 端点级限流要读);处理器同步抛出会逃到 Hono 自己的错误页(异步 reject 则不会),在 fallback 上会让「抛错」与「弃权」不可区分。

    范围外发现:#5122(观察类,finding)—— runtime 导出的 HttpServer 包装器不转发 IHttpServer 的任何可选成员,含 setFallbackHandler;仓内零组合点,故不影响本单,但它是 public API。

    给 E4/E5 的接线点:策略键与执行目标插在 runAppEndpointStep() 的「匹配命中 → 现答 501」之间(顺序按设计 §3);per-environment 的 metadata 解析随 E5 的 kernel swap 一起落(今天派发步不经该服务读任何数据)。


    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