baa-conductor

git clone 

baa-conductor / tasks
im_wower  ·  2026-03-29

T-S045.md

  1# Task T-S045:串联 artifact-db 写入与 D1 同步队列
  2
  3## 状态
  4
  5- 当前状态:`已完成`
  6- 规模预估:`S`
  7- 依赖任务:`T-S040`、`T-S042`
  8- 建议执行者:`Claude`(需要理解 artifact-db store 和 d1-client sync-queue 的交互,在写入路径中精确插入 enqueue 调用)
  9
 10## 直接给对话的提示词
 11
 12`/Users/george/code/baa-conductor/tasks/T-S045.md` 任务文档,完成开发任务。
 13
 14如需补背景,再读:
 15
 16- `/Users/george/code/baa-conductor/plans/ARTIFACT_STATIC_SERVICE.md`
 17- `/Users/george/code/baa-conductor/packages/artifact-db/src/store.ts`
 18- `/Users/george/code/baa-conductor/packages/d1-client/src/sync-queue.ts`
 19- `/Users/george/code/baa-conductor/packages/d1-client/src/sync-worker.ts`
 20
 21## 当前基线
 22
 23- 仓库:`/Users/george/code/baa-conductor`
 24- 分支基线:`main`
 25- 提交:`80ecf7b`
 26
 27## 分支与 worktree(强制)
 28
 29每个任务必须使用独立的分支和 worktree,禁止直接在 main 上修改,禁止多个任务共用同一个 worktree。
 30
 31- 分支名:`feat/artifact-d1-sync`
 32- worktree 路径:`/Users/george/code/baa-conductor-artifact-d1-sync`
 33
 34开工步骤:
 35
 361. `cd /Users/george/code/baa-conductor`
 372. `git worktree add ../baa-conductor-artifact-d1-sync -b feat/artifact-d1-sync main`
 383. `cd ../baa-conductor-artifact-d1-sync`
 394. 在这个 worktree 目录里开发,不要回到主仓库目录
 40
 41完成后提交与推送(由执行者完成,不要合并):
 42
 431. 在 worktree 里提交所有变更(包括更新后的任务文档)
 442. `git push -u origin feat/artifact-d1-sync`
 45
 46## 目标
 47
 48将 artifact-db 的 insertMessage / insertExecution / upsertSession 写入操作与 D1 同步队列串联,每次本地写入后自动 enqueue 一条同步记录。同时让 sync worker 定期清理已同步的记录。
 49
 50## 背景
 51
 52T-S042 实现了 D1 客户端和同步队列,但还没与 artifact-db 的写入路径串联。当前本地写入不会触发 D1 同步。`purgeSynced()` 方法已实现但未被自动调用,长期运行会积累已同步记录。
 53
 54## 涉及仓库
 55
 56- `/Users/george/code/baa-conductor`
 57
 58## 范围
 59
 60- artifact-db 写入时自动 enqueue 同步记录
 61- sync worker 定期清理已同步记录
 62- conductor 启动时注入 sync queue 到 artifact store
 63
 64## 允许修改的目录
 65
 66- `/Users/george/code/baa-conductor/packages/artifact-db/src/` (store.ts、types.ts)
 67- `/Users/george/code/baa-conductor/packages/d1-client/src/` (sync-worker.ts,如需加 purge 调度)
 68- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/index.ts` (注入 sync queue)
 69
 70## 尽量不要修改
 71
 72- `/Users/george/code/baa-conductor/packages/d1-client/src/client.ts` (D1 客户端已完成)
 73- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/local-api.ts`
 74- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/instructions/`
 75- `/Users/george/code/baa-conductor/plugins/`
 76
 77## 必须完成
 78
 79### 1. artifact-db 写入时自动 enqueue
 80
 81- ArtifactStore 接受可选的 SyncQueue 实例(通过构造函数或 setter 注入)
 82- `insertMessage()` 成功后,调用 `syncQueue.enqueue("messages", id, "insert", payload)`
 83- `insertExecution()` 成功后,调用 `syncQueue.enqueue("executions", instructionId, "insert", payload)`
 84- `upsertSession()` 成功后,调用 `syncQueue.enqueue("sessions", id, "insert", payload)`
 85- enqueue 失败只 log,不影响本地写入(与 artifact 写入的 best-effort 原则一致)
 86- SyncQueue 未注入时(D1 未配置),跳过 enqueue
 87
 88### 2. sync worker 定期清理已同步记录
 89
 90- sync worker 每次扫描完 pending 记录后,调用 `purgeSynced()` 清理已同步记录
 91- 保留最近 1000 条 synced 记录(或可配置),删除更早的
 92- 清理失败只 log,不影响 sync worker 运行
 93
 94### 3. conductor 启动时注入
 95
 96- ConductorRuntime 创建 D1SyncWorker 时,同时获取其 SyncQueue 实例
 97- 将 SyncQueue 注入到 ArtifactStore
 98- D1 未配置时,ArtifactStore 的 syncQueue 为 null,写入时跳过 enqueue
 99
100## 需要特别注意
101
102- enqueue 操作必须在本地 SQLite 事务提交成功之后执行,不能在事务内
103- enqueue 失败不能回滚已成功的本地写入
104- SyncQueue 的 `enqueue()` 写的是 sync_queue 表(d1-client 管理),不是 artifact.db 里的表——注意两个 SQLite 库的区分
105- 所有开发必须在 worktree 中进行,不要在主仓库目录修改代码
106
107## 验收标准
108
109- D1 环境变量设置后,insertMessage 触发 sync_queue 中出现 pending 记录
110- D1 环境变量未设置时,insertMessage 正常工作,无 enqueue 调用
111- sync worker 扫描后,synced 记录被自动清理(保留最近 N 条)
112- enqueue 失败时本地写入不受影响
113- 现有测试全部通过
114
115## 推荐验证命令
116
117- `cd /Users/george/code/baa-conductor-artifact-d1-sync && pnpm build`
118- `cd /Users/george/code/baa-conductor-artifact-d1-sync && pnpm test`
119
120## 执行记录
121
122> 以下内容由执行任务的 AI 填写,创建任务时留空。
123
124### 开始执行
125
126- 执行者:Claude
127- 开始时间:2026-03-29
128- 状态变更:`待开始` → `进行中`
129
130### 完成摘要
131
132- 完成时间:2026-03-29
133- 状态变更:`进行中` → `已完成`
134- 修改了哪些文件:
135  - `packages/artifact-db/src/types.ts` — 新增 `SyncEnqueuer` 接口
136  - `packages/artifact-db/src/index.ts` — 导出 `SyncEnqueuer` 类型
137  - `packages/artifact-db/src/store.ts` — ArtifactStore 增加 `syncQueue` 字段、`setSyncQueue()` setter,三个写入方法(insertMessage、insertExecution、upsertSession)在事务提交后 enqueue 同步记录
138  - `packages/d1-client/src/types.ts` — SyncWorkerConfig 增加 `purgeKeepCount` 选项
139  - `packages/d1-client/src/sync-queue.ts` — 新增 `purgeSyncedKeepRecent()` 按数量保留的清理方法
140  - `packages/d1-client/src/sync-worker.ts` — 新增 `getQueue()` 访问器,tick 后自动调用 `purgeCompleted()`
141  - `apps/conductor-daemon/src/index.ts` — ConductorRuntime 构造函数中将 D1SyncWorker 的 SyncQueue 注入 ArtifactStore
142- 核心实现思路:
143  - 在 artifact-db 中定义最小化 `SyncEnqueuer` 接口,避免对 d1-client 的直接依赖
144  - 通过 setter 注入(而非构造函数),因为 ArtifactStore 在 D1SyncWorker 之前创建
145  - enqueue 在 `executeWrite`(SQLite 事务)提交成功之后执行,失败时静默 catch,不影响本地写入
146  - payload 使用 snake_case 列名,与 D1 表结构一致,供 sync-worker 的 buildUpsertSql 直接使用
147  - sync worker 每次 tick 后调用 `purgeSyncedKeepRecent(1000)` 清理已同步记录
148- 跑了哪些测试:
149  - `pnpm build` — 全量构建通过
150  - `pnpm --filter @baa-conductor/artifact-db test` — 1 test passed
151  - `pnpm --filter @baa-conductor/d1-client test` — 11 tests passed
152  - `pnpm test` — conductor-daemon 有若干预存失败(main 分支同样失败,与本次改动无关)
153
154### 执行过程中遇到的问题
155
156- conductor-daemon 测试中有多个 `handleConductorHttpRequest` 相关的 `TypeError: Cannot read properties of undefined (reading 'localApiBase')` 失败,经确认 main 分支同样存在,与本次改动无关。
157
158### 剩余风险
159
160- `insertMessage` / `insertExecution` 内部调用 `buildDerivedSessionRecord` 会隐式 upsert session,但本次只在顶层三个方法末尾 enqueue 对应表(messages/executions/sessions),内部 session upsert 没有单独 enqueue。如果需要 D1 侧也同步 session 的每次更新,可以在 `writeSessionArtifacts` 之后也加 enqueue,但这会增加同步量。当前策略是:session 数据通过后续的 `upsertSession` 调用或下一次 message/execution 写入时自然同步。
161