Files
yuanshuai c91a64fddb
CI / Python 3.12 (push) Waiting to run
CI / Python 3.9 (push) Waiting to run
chore(repo): initialize team collaboration repository
2026-07-27 20:40:12 +08:00

2.0 KiB
Raw Permalink Blame History

ADR-0002:以事件溯源作为 Run 的唯一真相

  • 日期:2026-07-27
  • 状态:已接受

背景

产品要交付的三件事——统一时间线审计自动复现——都需要回答同一个问题: "当时到底按什么顺序发生了什么"。

同时,观测是双通道的:Agent 报一套,带外控制器报一套,两者时钟不同步, 主机断电时 Agent 那一路会直接消失。

决定

run_events 是 append-only 的唯一真相。runs / run_steps / recovery_actions 是可以从事件重放重建的读模型

序号 seq 由控制平面单点分配(不是时间戳排序),Agent 事件与带外事件进同一条序列。

仓储层不提供 update_run_state() 类 API。改状态的唯一入口是 events/recorder.py::record(),它写事件并同步更新投影。

理由

  • 主机断电时,Agent 的最后几条日志可能永远到不了。带外控制器的观测 (掉电时刻、画面指纹)是那段时间唯一的证据。两路事件必须在同一条时间线上 才能交叉校验——"Agent 最后一条日志 seq=812,带外报掉电 seq=813"这种判断 只有单点序号能给。
  • 审计要求记录"操作者、审批者、命令模板版本、输入参数、结果、撤销动作" (方案 §6.6)。这些天然是事件,硬塞进当前状态表会做成一堆冗余字段。
  • 自动复现(§8.4)需要"失败前后的最小步骤区间"。有完整事件流才能裁剪。

代价

  • 写路径变长,每次状态变化多一次插入。
  • run_events 会很大:100 循环 × 每轮 ~30 事件 = 3000 条/Run。 缓解:事件按 run_id 分区友好,日志正文不进事件表(只存对象存储 URI)。
  • 开发者容易忍不住直接 UPDATE。缓解:仓储层不给这个 APIcode review 卡这一条。

什么时候推翻

不推翻。真要优化,是加快照(每 N 个事件存一次状态快照加速重放), 不是放弃事件溯源。