Files
qinglong/docs/adr/ADR-0368-bounded-project-run-discovery-http-api.md

6.2 KiB
Raw Permalink Blame History

ADR-0368:有界、Project-scoped 的 Run Discovery HTTP API

  • 状态:Proposed
  • 日期:2026-08-11
  • 关联:QL-RFC-0001 D-45、D-46、D-49、D-52、D-269、D-278、D-279、D-280ADR-0052、ADR-0349、ADR-0367

背景

Local 与 Cluster 已有同构的 GET /api/v3/projects/{projectId}/runs/{runId},但调用方必须预先知道 runId。这使 HTTP API 无法从“最近运行”进入诊断闭环。MCP 已证明 Project-scoped keyset pagination、双方言 repository 和低敏字段白名单可用;HTTP 不应复制另一套排序、投影或存储协议。

该切片不得因增加第二条 route 再拆 package。Local 继续使用现有可选 @qinglong/local-api 单进程组合根;Cluster 继续使用现有 @qinglong/cluster-control route registry、admission pipeline 与 PostgreSQL Pool。

决策

  1. Local 与 Cluster 同时增加 GET /api/v3/projects/{projectId}/runsoperation/permission 固定为 run.list/run.read。每页都必须经过 route/query validation → Authentication → Project Policy → durable security audit → credential fenceLocal)→ bounded repository read。
  2. query 只允许 limitafter_created_at_msafter_run_idlimit 默认 32、最大 64;两个 cursor 参数必须同时出现,时间必须是 canonical 非负 safe integerRun ID 必须满足现有 128 字符资源标识约束。重复、空值、未知、部分 cursor 或非 canonical decoded 数字在 Authentication 前失败关闭。Local loopback transport 额外拒绝 raw percent encodingCluster transport 先按 Node URL 语义解码,再对 decoded query 做 exact semantic validation,因此不宣称保留或拒绝原始编码形式。
  3. Runtime Core 在现有 src/run/projection/ 增加纯 bounded-run-list-projection subpath,统一输入、limit + 1 storage fetch、排序复验、Project 遮蔽、低敏投影、hasMorenext。MCP qinglong.run.list 改为薄协议 adapter 并保持公开 Tool schema/错误不变;Local/Cluster HTTP 不依赖 MCP 或 Tool Registry/SemVer。
  4. 返回固定 {runs, hasMore, next?}。Run item 只包含 id、taskId/revision、status/version/eventSequence、priority、execution origin/owner 和四个生命周期时间;不包含 Project、request/ref/trigger/attempt、executor、错误、Artifact、日志或 Secret 邻接字段。
  5. 双方言复用现有 (project_id, created_at_ms, id) 索引与 ProjectRunListReader;不新增 migration、table、connection、transaction authority 或缓存。排序固定 created_at_ms DESC, id DESC,cursor 为上一页最后一个已返回项。
  6. Local HTTP response 上限从只容纳 point read 的 4 KiB 调整为覆盖 64 条最坏字段长度低敏记录的固定 64 KiB;静态最坏 JSON envelope 为 61,516 bytes。Edge 并发仍为 4、Standalone 仍为 32,请求/URL/header/drain 上限不变。默认 headless Local artifact/image 仍不安装 local-api
  7. workspace 保持 18 package。新增代码只能进入 Runtime Core run/projection、Local API 既有 run/admission/transport/application-runtime 与 Cluster Control 既有 run/application-runtime 领域目录。不得以 route、projection、codec 或“一文件一目录”的形式制造新的 package/层级;单文件 capability 默认留在 owning domain,只有独立部署、authority、第三方运行闭包或被多生命周期复用的稳定安全叶子才允许形成 package 边界。

不采用方案

  • 只给 Local 增加列表:会让相同 /api/v3 在单机和集群具有不同的基础发现闭环。
  • HTTP 直接导入 MCP projection:会把 MCP SDK/Tool Registry/SemVer 闭包带入普通 API 制品。
  • offset pagination:深页成本随历史增长,且并发插入时容易重复或遗漏。
  • 把 cursor 编成 opaque token:首版没有签名/密钥 authority,编码并不增加可信度,反而扩大解析面。
  • 返回数据库 Run row 或错误摘要run.read 不是调试、Artifact、日志或 Secret 权限。
  • 新增 run-query package/service:没有新的部署或权限边界,只增加 manifest、importer、SBOM 和低配安装成本。

完成门

  • shared projection 覆盖默认/最大页、cursor、空页、排序、跨 Project/畸形 row、repository failure 与 module closure
  • Local 覆盖 canonical query、认证前拒绝、run.list audit、credential fence、真实 SQLite HTTP E2E、过载与 drain
  • Cluster 覆盖 reviewed route/operation allowlist、query、Policy/audit 顺序、真实 PostgreSQL repository contract
  • Runtime Core、MCP、Local API、Cluster Control/PostgreSQL 定向与完整 package/backend 通过;
  • package/source/dependency boundary、默认 Local image、Local/Cluster artifact 与 PostgreSQL HA 不回归。

实现证据(2026-08-11

  • Runtime Core 466/466、Local MCP 38/38、Local API 19/19、Cluster Control 189 pass/2 条件 skip18-package 完整门退出 0backend 1,156 pass/2 条件 skip。
  • workspace 仍为 18 package/1,018 source,其中 1,000 个位于 package 内部 domain/capability 目录,18 个 src/ 根文件全部是受审 public/binary entry;无 single-source、shallow-source 或 package-boundary finding。
  • dependency 回归 52/52,完整 dependency audit findings=[]MCP 只新增 @qinglong/runtime-core/bounded-run-list-projection 这一条纯读 subpath allowlist,默认 Local image 继续不安装 local-api
  • 14 个 Local Profile artifact 全部 compatible。Edge/Standalone API 分别为 5,085,520/5,085,664 bytes、518 files、57 loaded modulesRSS 增量 12,681,216/13,041,664 bytes,低于 6 MiB/640 files/24 MiBEdge/Standalone 并发仍为 4/32。
  • 最紧的 Edge/Standalone Application+AI 分别为 6,281,356/6,281,488 bytes,距 6 MiB 上限仅 10,100/9,968 bytes;预算未放宽,后续闭包增长必须先裁剪,不能通过新增 wrapper/package 转移成本。
  • PostgreSQL 18.4 arm64 HA Docker contract 112 gates 全部通过,timeline 1→2report SHA-256 为 a25e7226286f063d9b2e85a2a25c20834021627aa192e069f3bb4d40572c0447;结束后临时容器、卷、网络均为零。

固定物理路由器上的 API Profile RSS/延迟报告仍未取得,因此 ADR 保持 Proposed;该缺口不影响本轮自动化实现完成结论。