codex@macbookpro
·
2026-04-01
T-S066.md
1# Task T-S066:风控状态持久化 — 重启后恢复限流/退避/熔断计数
2
3## 状态
4
5- 当前状态:`已完成`
6- 规模预估:`M`
7- 依赖任务:`T-S060`
8- 建议执行者:`Codex`
9
10## 直接给对话的提示词
11
12读 `/Users/george/code/baa-conductor/tasks/T-S066.md` 任务文档,完成开发任务。
13
14如需补背景,再读:
15
16- `/Users/george/code/baa-conductor/plans/AUTOMATION_ARBITRATION_REQUIREMENTS.md`
17- `/Users/george/code/baa-conductor/tasks/TASK_OVERVIEW.md`
18
19## 当前基线
20
21- 仓库:`/Users/george/code/baa-conductor`
22- 分支基线:`main`
23
24## 分支与 worktree(强制)
25
26- 分支名:`feat/persistent-rate-limit-state`
27- worktree 路径:`/Users/george/code/baa-conductor-persistent-rate-limit-state`
28
29开工步骤:
30
311. `cd /Users/george/code/baa-conductor`
322. `git worktree add ../baa-conductor-persistent-rate-limit-state -b feat/persistent-rate-limit-state main`
333. `cd ../baa-conductor-persistent-rate-limit-state`
34
35## 风险描述
36
37当前风控状态(限流计数、退避窗口、熔断标记)全部保存在进程内存中。conductor 重启后这些状态全部丢失,意味着:
38
39- 刚触发限流的对话重启后立即恢复发送
40- 正在退避的 renewal job 重启后立即重试
41- 已经熔断的通道重启后重新激活
42
43对于高频续命场景,这可能导致重启后短时间内大量请求涌向上游 AI 平台。
44
45## 目标
46
47将关键风控状态持久化到 `artifact.db` 或 `system_state`,使 conductor 重启后能恢复到上次的风控位置。
48
49## 范围
50
51- 识别需要持久化的风控状态(至少包括:对话级限流计数、退避窗口、熔断标记、`pause_reason`)
52- 选择存储方案(扩展 `local_conversations` 字段 / 独立 `rate_limit_state` 表 / `system_state` KV)
53- 在 conductor 启动时从持久化层恢复风控状态
54- 在风控状态变更时写入持久化层(不要求每次都同步写,可以定期批量)
55- 确保持久化写入不阻塞主流程
56
57## 路径约束
58
59- 持久化层必须复用现有 `artifact.db` 体系
60- 恢复逻辑不能拖慢 conductor 启动时间超过 1 秒
61- 不要求所有内存态都持久化,只持久化"重启后丢失会导致问题"的关键状态
62
63## 需要特别注意
64
65- `cooldownUntil` 已经持久化在 `local_conversations`,这部分不需要重复做
66- `renewal_jobs` 的 `next_attempt_at` 也已持久化,退避窗口不会丢失
67- 真正需要补的是:仲裁模块的执行锁状态、熔断计数器、对话级限流窗口
68- 持久化频率要权衡性能:每次变更都写太频繁,但纯靠定时写可能在崩溃时丢数据
69
70## 验收标准
71
72- conductor 重启后,正在熔断的通道不会立即恢复
73- conductor 重启后,限流窗口内的对话不会立即恢复发送
74- 持久化写入不影响正常请求延迟
75- 新增存储不破坏现有 schema 和 D1 同步
76
77## 执行记录
78
79> 以下内容由执行任务的 AI 填写,创建任务时留空。
80
81### 开始执行
82
83- 执行者:`Codex`
84- 开始时间:`2026-04-01 16:07:01 CST`
85- 状态变更:`待开始` → `进行中`
86
87### 完成摘要
88
89- 完成时间:`2026-04-01 16:52:07 CST`
90- 状态变更:`进行中` → `已完成`
91- 修改了哪些文件:
92 - `apps/conductor-daemon/src/browser-request-policy.ts`
93 - `apps/conductor-daemon/src/index.ts`
94 - `apps/conductor-daemon/src/index.test.js`
95 - `packages/artifact-db/src/types.ts`
96 - `packages/artifact-db/src/index.ts`
97 - `packages/artifact-db/src/schema.ts`
98 - `packages/artifact-db/src/store.ts`
99 - `packages/artifact-db/src/index.test.js`
100 - `packages/d1-client/src/sync-worker.ts`
101 - `packages/d1-client/src/d1-setup.sql`
102 - `packages/d1-client/src/index.test.js`
103 - `docs/api/control-interfaces.md`
104 - `docs/api/business-interfaces.md`
105 - `tasks/T-S066.md`
106 - `tasks/TASK_OVERVIEW.md`
107 - `plans/STATUS_SUMMARY.md`
108- 核心实现思路:
109 - 为 browser request 风控状态新增 `artifact.db` 持久化快照,保存平台级 dispatch window 和 target 级退避/熔断状态
110 - `BrowserRequestPolicyController` 改为启动时恢复、变更后异步 flush,避免热路径同步写阻塞
111 - `ConductorRuntime.start()` 增加恢复流程,重启时把遗留 `execution_state` 清成 `idle`,把 `running` renewal job 重新排回 `pending`
112 - 补 `artifact-db` / `d1-client` / `conductor-daemon` 测试,覆盖重启恢复和 D1 同步合同
113- 跑了哪些测试:
114 - `pnpm install`
115 - `pnpm -C packages/artifact-db test`
116 - `pnpm -C packages/d1-client test`
117 - `pnpm -C apps/conductor-daemon test`
118 - `pnpm build`
119
120### 执行过程中遇到的问题
121
122- 新 worktree 初始没有 `node_modules`,先执行了 `pnpm install`
123- 运行中的 renewal job 默认会带当前真实时间的 `next_attempt_at`,测试里显式改成 `null` 后才能稳定覆盖“重启回排”场景
124
125### 剩余风险
126
127- 持久化的是限流/退避/熔断窗口与恢复所需状态,不会恢复进程内 `in_flight` lease;如果 crash 发生在请求已发出但结果未落库的瞬间,只能通过重启回排延迟来降低重复发送风险
128- 现有远端 `baa-conductor-artifact` 已在 `2026-04-01` 应用更新后的 `d1-setup.sql`;后续如新建或重置 D1 环境,仍需先执行对应 schema 初始化或迁移,才能完整镜像新增列和 `browser_request_policy_state`