baa-conductor

git clone 

baa-conductor / tasks
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- 如果远端 Cloudflare D1 仍停留在旧 schema,需要先应用更新后的 `d1-setup.sql` 或对应迁移,才能完整镜像新增列和 `browser_request_policy_state`