6.9 KiB
ADR-0157:有界 Tool Execution Trace 与 Audit Evidence
- 状态:Accepted
- 日期:2026-07-26
- 关联:ADR-0049、ADR-0074、ADR-0133、ADR-0154、ADR-0155、ADR-0156; RFC D-03/D-29/D-131/D-148/D-149
背景
ADR-0155 已定义 Tool execution admission 必须绑定耐久 StepRun、Trace 和 Audit evidence;ADR-0156 已完成 StepRun aggregate 与双方言 Run fence,但仍缺少可以在崩溃、 响应丢失和多副本重放后验证的 Trace/Audit 事实。
仅在 OpenTelemetry exporter、RunEvent payload 或普通日志中记录 trace/span id 不足以 形成启动门禁:
- exporter 可以关闭、采样、延迟或失败;
- RunEvent 不能证明独立 Trace 与审计事实的完整内容和摘要;
security_audit_events在 PostgreSQL runtime 角色下是 insert-only,不能为了重放而 扩大为全表可读;- 低配路由器不能为了这项能力引入常驻 collector、额外 workspace package 或新的第三方 依赖。
决策
1. 使用 profile-neutral、digest-bound evidence bundle
@qinglong/runtime-core/tool-execution-evidence 是 runtime-core 的显式 subpath,不新增
workspace package。它定义:
qinglong/tool-execution-trace-anchor@v1;qinglong/tool-execution-audit-receipt@v1;qinglong/tool-execution-evidence-bundle@v1;- 32 位小写十六进制 Trace ID、16 位 Span ID,与 W3C Trace Context 的 identity 形状兼容;
- Project、Run、StepRun、invocation plan、binding、adapter、redaction contract 和 audit contract 的完整摘要绑定;
- 固定
tool.invoke.start、allowed、非空 Policy fence 的 SecurityAuditRecord; - domain-separated SHA-256 trace、audit record 与 receipt digest。
Bundle 的 canonical JSON 总量上限为 16 KiB,单页最多 128 条。输入、Secret、handler、 异常对象、execute seam 和 Tool 结果都不得进入该 bundle。
2. 两个 durable identity 与 exact replay
repository 同时以 (trace_id, span_id) 和 audit event_id 作为唯一 identity。第一次
prepare 原子写入,完全相同的重放返回 existing;任一 identity 复用到不同内容必须
返回 semantic conflict。按 Run 查询使用
(created_at_ms, trace_id, span_id) 稳定 keyset pagination。
读取时必须重新执行领域规范化,并把 canonical JSON 与每个镜像列逐一比对。数据库内 JSON、digest、identity 或时间镜像发生漂移时失败关闭,不能返回部分可信 evidence。
3. SQLite 使用共享 operation authority
SQLite 0053-tool-execution-evidence 新增:
ToolExecutionTraceAnchors;ToolExecutionAuditReceipts。
0054-capability-v27 将 local-control-core 推进到 v27,并声明
tool_execution_evidence:1。repository 复用 LocalSqliteOperationAuthority 与
BEGIN IMMEDIATE,只允许绑定同 Project、同 Run、状态为 ready 或
waiting_approval 的 Tool StepRun。SecurityAuditEvent、Trace anchor 和 receipt
在同一事务中提交或回滚。
数据库 CHECK 完整绑定 JSON 与镜像列;foreign key 将 receipt 绑定到既有审计事件、Trace 和同 Run StepRun。
4. PostgreSQL 保持 Audit insert-only
PostgreSQL pg-0029-tool-execution-evidence 将 control-core 推进到 v28,并新增:
ql3.tool_execution_trace_anchors;ql3.tool_execution_audit_receipts。
只有 ql3_runtime 取得两张 evidence 表的 SELECT/INSERT,禁止 UPDATE/DELETE;其他
产品角色保持零权限。ql3_runtime 对 security_audit_events 继续只有 INSERT,没有
SELECT。
因此 PostgreSQL repository 不 JOIN 审计表读取:它在同一个 SERIALIZABLE 事务中先写
immutable SecurityAuditEvent,再写 Trace 和保存完整 audit_json 的 receipt;receipt
以 foreign key 证明审计行存在。运行时没有修改或删除审计行的权限,重放通过 receipt
内的完整规范化 audit 与 digest 校验,不需要扩大低敏审计表的读取面。
事务使用固定 statement/lock/idle timeout、最多三次 serialization/deadlock/并发唯一 冲突收敛,并以共享锁固定同 Project ready Tool StepRun,避免状态检查与提交之间漂移。
5. evidence 仍不是副作用启动授权
双方言显式 tool-execution-evidence subpath 只提供存储能力,root、通用 runtime、
admin、worker ingress 不重新导出 repository。它没有连接真实 Tool adapter,也不会
启动进程、HTTP、MCP、Worker 或任意外部副作用。
production execution 继续不可达,直到一个后续 start-barrier authority 能在同一 可判定事务中绑定或精确证明:
- immutable plan/dispatch;
- ready Tool StepRun;
- Trace anchor;
- allowed Audit receipt;
- handler binding 与 adapter-specific recovery evidence。
低配与集群资源影响
- 不新增 workspace package、依赖、timer、watcher、socket、线程或常驻进程;
- 没有 exporter/collector 才能运行的前置条件;
- 每次 Tool 启动只增加一条 Trace、一条 receipt 和既有一条 Audit;
- 所有读取都有唯一索引或有界 keyset page;
- Edge 与 Cluster 使用同一领域摘要和重放语义,数据库机制和权限模型按 profile 分别实现。
被否决方案
- 只依赖 OpenTelemetry:采样和 exporter 可用性不能成为耐久启动证据,拒绝。
- 把完整 evidence 塞进 RunEvent:失去独立 identity、retention 和 ACL,拒绝。
- 允许 runtime SELECT 全部 Audit:扩大低敏审计读取面,拒绝。
- Trace、Audit、receipt 分三个事务提交:产生可见半提交窗口,拒绝。
- 只保存 digest,不保存规范化 JSON:无法在恢复时重建并验证完整绑定,拒绝。
- 为 Trace/Audit 新拆 workspace package:没有独立部署或依赖生命周期,拒绝。
- prepare 时允许 running/terminal StepRun:无法证明 evidence 在副作用开始前 建立,拒绝。
验证
- runtime-core Tool evidence 定向测试:7/7,完整 runtime-core:304/304;
- local-sqlite 完整测试:106/106;
- cluster-postgres package:160 pass、1 条件 skip;
- PostgreSQL 18.4 arm64 新增 evidence 真实 integration:migration/runtime 独立角色 下 1/1;
- PostgreSQL 18.4 arm64 六角色完整 integration:40 pass、1 条件 skip;
- PostgreSQL 18.4 arm64 physical HA:physical streaming、
remote_apply、旧主隔离、 timeline 1→2 promotion、pg_rewind、同步复制恢复、两代双 control replica,gates.passed=true; - 所有单实例和 HA 临时 Docker 资源均由 gate 清理。
后续门禁
- 实现 opaque/encrypted invocation plan 与 redacted preview Artifact;
- 实现 plan/dispatch、StepRun、Trace、Audit 的双方言同事务 start barrier;
- 定义 built-in、isolated process、MCP、HTTP 和 Worker adapter 的启动后恢复证据;
- 增加 receipt retention/compaction,不得破坏未终结 Run 的恢复可验证性;
- 完成物理 Edge 故障与规模证据后,再评审 production adapter composition。