Files
qinglong/docs/adr/ADR-0402-bounded-latest-task-run-outcome-comparison.md
T

7.4 KiB
Raw Blame History

ADR-0402:有界的 Task 最近成功/失败 Run 对比

  • 状态:Accepted
  • 日期:2026-08-14
  • 关联 RFCQL-RFC-0001 D-310、Phase 2
  • 关联 ADRADR-0347、ADR-0400、ADR-0401

问题

ADR-0400/0401 已提供按两个显式 Run ID 对比的共享受信 Tool 和可选本机 MCP 入口,但“选择 最近一次成功与失败运行”仍可能被留给模型。模型如果循环调用 run.list、翻页并自行过滤, 搜索次数、历史范围和停止条件都不可证明;在低配路由设备上会形成不可控 SQLite I/O,在 Cluster 上也会放大数据库读取和模型上下文,同时给 Prompt 注入制造更大的输入面。

直接把 Task/status 过滤继续塞入通用 Run Reader 也不合理。GitNexus 显示 LocalSqliteRunReader 为 CRITICAL(14 个直接、29 个总影响、1 条产品启动流程), PostgresRunReader 为 HIGH(7 个直接、15 个总影响)。为了一个 AI 只读用例扩大这两个基础 Reader 的职责,会让本地恢复、API、Cluster recovery 和写事务继承树承担无关回归风险。

决策

  1. 增加 qinglong.task.runs.compare@1.0.0。输入精确为一个不超过 255 字符的 taskId 没有 limit、cursor、status、SQL、排序或 Project 参数;Project 只来自受信 composition。 Definition 固定为 read/lowrun.read、5 秒 deadline。
  2. Runtime Core 在 run/outcome-comparison/ 定义窄 TaskRunOutcomeWindowReader。repository 一次只返回按 (created_at_ms DESC, id DESC) 排列的最小五字段记录:Run/Project/Task identity、status 和 created time。Tool 固定请求 65 条,其中前 64 条是搜索窗口,第 65 条只证明还有更老记录; 协议永远不返回 cursor,模型不能扩大窗口。
  3. 前 64 条中第一个 succeeded 是 baseline,第一个 failed 是 candidate。两者都找到, 或存储明确返回不超过 64 条时,selection.complete=true;如果窗口已满且缺少任一结果, 输出 complete=false,不能把“窗口内未找到”伪装成历史上不存在。
  4. 选择后按 succeeded → failed 固定顺序执行最多两个既有 Project-scoped Run 点查,并复用 ADR-0400 的低敏 projection、changed fields 和时长差值算法。选择出的 Run 如果消失、变更 Task/outcome、跨 Project 或损坏,整个调用稳定 unavailable;不回退到继续搜索。
  5. 输出携带 consistency=bounded_task_window_then_ordered_point_reads。它明确表示一次有界选择查询后跟 两次独立点查,不声称数据库事务快照。baseline 永远代表 succeededcandidate 永远代表 failed,差值方向固定为 failed succeeded。
  6. SQLite 与 PostgreSQL 各自新增独立、二级目录内的窄 adapter,不修改现有通用 Run Reader 或 Repository 继承树。SQLite 真实 EXPLAIN QUERY PLAN 必须命中既有 ql3_local_runs_task_created_idxPostgreSQL adapter 使用同样的 Project/Task/order/LIMIT 65 查询。复用既有索引避免新增 migration、索引空间和每次 Run 写放大。
  7. 可选 ql3-mcp 复用既有逐调用 Owner credential → Tool Policy → durable allowed audit → credential confirm 链,审计理由固定为 tool_qinglong_task_runs_compare。默认 Edge/Standalone 仍不装载 MCPCluster 只获得显式 PostgreSQL adapter subpath,不开放 ambient MCP/HTTP endpoint,内部 Copilot 仍须走完整 Trusted Tool completion 链。

低配、集群与 package 布局

  • 默认低配设备没有新增进程、连接、timer、listener、watcher、cache、migration 或索引;启用 MCP 时每次调用固定为一个 65 行上限的最小列查询和最多两个串行点查。
  • Cluster adapter 复用调用方现有 queryable/Pool,不创建第二连接池;driver 错误收敛为稳定 repository operation error,畸形 bigint/status 收敛为 constraint error。
  • package 数保持 18。能力落入 Runtime Core 既有 run/outcome-comparison/tool-execution/builtin-run-compare/,持久化实现落入两端既有 run/outcome-comparison/;不为一两个文件创建微型 package,也不回到 package src 根平铺。
  • Runtime Core、Local SQLite、Cluster PostgreSQL 只提供显式 subpathpackage 根入口不扩大; Local MCP dependency firewall 只放行两个新 Runtime Core 精确 subpath。

被否决方案

  1. 让模型分页 run.list:查询次数、停止条件和上下文大小不可证明。
  2. 把 task/status/cursor 加入通用 Run list:会把 AI 用例扩散到 HTTP/API 和基础 Reader, 且仍允许模型无界翻页。
  3. 分别查询所有成功和失败历史:即使只返回一条,缺少固定窗口时存储扫描和语义仍无界。
  4. 为两种 outcome 新增索引:会增加所有设备的磁盘与 Run 写放大;固定 64 条窗口可复用 已有 Task 时间索引,当前收益不足以支付 migration 和低配常驻成本。
  5. 修改 LocalSqliteRunReader/PostgresRunReaderGitNexus 已证明 HIGH/CRITICAL blast radius,独立 reader 能用更小权限和故障域完成目标。
  6. 只返回两个 Run ID:仍迫使调用方再次自由组合字段和差值;本 Tool 应交付完整的有界 低敏对比结果。

当前验证

  1. Runtime Core 定向 10/10:覆盖成功/失败选择顺序、差值、固定 64+1 窗口、无 cursor、 incomplete 语义、跨 Project/乱序/畸形/消失/存储失败、Definition/binding 漂移、显式 subpath 和根入口零导出。
  2. Local SQLite 1/1fresh production migration 后写入多 Project/Task/状态 Run,经 MCP 的 单 authority 读取精确窗口,并用真实 EXPLAIN QUERY PLAN 证明命中既有 Task 时间索引。 PostgreSQL adapter 2/2:精确 SQL/参数/顺序/上限、bigint 映射、畸形状态和 driver 错误 收敛全部通过。
  3. Local MCP 47/47:新增 Tool discovery、固定 read-only annotations、双 permission、durable audit reason、credential confirm、真实 stdio + fresh SQLite 的选择和两次点查均通过。
  4. dependency firewall 53/53,完整 dependency audit 与 package boundary audit 零 finding package 保持 18 个,singleSourcePackages=[]shallowSourcePackages=[]
  5. 最终 18-package clean build/test 退出 0backend 1,208 项为 1,206 pass、2 条平台条件 skip、0 fail。Edge import 与 Cluster deployment 审计零 finding。Runtime Core 为 165/164 nested、Local SQLite 为 197/196 nested、Cluster PostgreSQL 为 168/167 nested,三者 package 根入口均未增长。
  6. 默认 Edge artifact 保持 2,589,812 bytes/315 files/56 modules,证明未装配能力被完全裁掉; RSS 增量 11,173,888 bytes,低于 16 MiB 门。Edge-MCP 为 7,237,187 bytes/795 files/ 220 modules/RSS 38,699,008 bytesStandalone-MCP 为 7,237,295 bytes/795 files/ 220 modules/RSS 38,600,704 bytes,均低于 16 MiB/1,536 files/48 MiB 门。
  7. PostgreSQL 18.4 arm64 HA 125/125 Gate 通过,timeline 1→2,报告 SHA-256 为 229c7cac328ee960f667f92868374264a10cb75090ef93d644da1326385d8774;容器、网络与卷零残留。

后续门禁

  1. Cluster 产品 composition 装配 Definition/binding,并以真实 PostgreSQL 完成加密结果和 StepRun/Trace completion
  2. 日志解释另建 Artifact range、redaction、prompt-injection 和字节预算协议;
  3. 固定物理 Edge MCP 单次选择/点查延迟与 RSS,并验证撤权竞态。