codex@macbookpro
·
2026-03-30
T-S058.md
1# Task T-S058:消息同步任务生成续命任务
2
3## 状态
4
5- 当前状态:`已完成`
6- 规模预估:`M`
7- 依赖任务:`T-S055`、`T-S056`、`T-S057`
8- 建议执行者:`Codex` 或 `Claude`
9
10## 直接给对话的提示词
11
12读 `/Users/george/code/baa-conductor/tasks/T-S058.md` 任务文档,完成开发任务。
13
14如需补背景,再读:
15
16- `/Users/george/code/baa-conductor/plans/discuss/DISCUSS-TIMED-JOBS-RENEWAL-REQUIREMENTS.md`
17- `/Users/george/code/baa-conductor/tasks/T-S055.md`
18- `/Users/george/code/baa-conductor/tasks/T-S056.md`
19- `/Users/george/code/baa-conductor/tasks/T-S057.md`
20
21## 当前基线
22
23- 仓库:`/Users/george/code/baa-conductor`
24- 分支基线:`main`
25- 提交:`071abbf`
26
27## 分支与 worktree(强制)
28
29- 分支名:`feat/renewal-message-projector`
30- worktree 路径:`/Users/george/code/baa-conductor-renewal-message-projector`
31
32开工步骤:
33
341. `cd /Users/george/code/baa-conductor`
352. `git worktree add ../baa-conductor-renewal-message-projector -b feat/renewal-message-projector main`
363. `cd ../baa-conductor-renewal-message-projector`
374. 在这个 worktree 目录里开发,不要回到主仓库目录
38
39完成后提交与推送:
40
411. 在 worktree 里提交所有变更(包括更新后的任务文档)
422. `git push -u origin feat/renewal-message-projector`
43
44合并步骤(由合并者执行):
45
461. `cd /Users/george/code/baa-conductor`
472. `git fetch origin`
483. `git merge origin/feat/renewal-message-projector`
494. `git push`
505. `git worktree remove ../baa-conductor-renewal-message-projector`(如果 worktree 还在)
51
52合并冲突处理:
53
541. 如果 `git merge` 报冲突,先 `git diff` 查看冲突文件
552. 手动解决冲突后 `git add` 冲突文件
563. `git merge --continue` 完成合并
574. 不要用 `git merge --abort` 然后 force 覆盖
58
59命名规则:
60
61- 功能任务分支名以 `feat/` 开头
62- 缺陷任务分支名以 `bug/` 开头
63
64## 目标
65
66实现“消息同步任务”:定时扫描旧消息,按照对话自动化状态和可用路由规则,生成续命任务。
67
68## 背景
69
70当前共识已经排除了“在 ingest 末尾直接发续命”的做法。首版需要一个独立的 projector,把消息事实和续命执行解耦开。
71
72## 涉及仓库
73
74- `/Users/george/code/baa-conductor`
75
76## 范围
77
78- 实现消息扫描与游标推进
79- 实现 `shouldRenew()` 和 payload 构建
80- 将满足条件的消息幂等投影到 `renewal_jobs`
81- 不实现实际发送
82
83## 路径约束
84
85- 不要把 projector 做成“消息到达即同步”的直接 hook
86- 必须通过 timed-jobs 框架运行
87- 必须遵守小批量和 settle delay 约束
88
89## 推荐实现边界
90
91建议优先做:
92
93- `apps/conductor-daemon/src/timed-jobs/`
94- `apps/conductor-daemon/src/renewal/`
95- 必要时最小改动 `apps/conductor-daemon/src/instructions/ingest.ts` 以补齐消息元数据
96
97## 允许修改的目录
98
99- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/timed-jobs/`
100- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/renewal/`
101- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/instructions/`
102- `/Users/george/code/baa-conductor/packages/artifact-db/`
103
104## 尽量不要修改
105
106- `/Users/george/code/baa-conductor/plugins/`
107- `/Users/george/code/baa-conductor/apps/conductor-daemon/src/local-api.ts`
108
109## 必须完成
110
111### 1. 消息扫描
112
113- 只扫描“旧消息”
114- 每轮最多处理约 `10` 条
115- 支持可配置 settle delay
116- 支持游标或等价机制,避免重复全表扫描
117
118### 2. 续命判断
119
120- 以对话状态 `manual / auto / paused` 为判断核心
121- 检查冷却时间
122- 检查重复消息
123- 检查当前目标路由是否可用
124
125### 3. 任务生成
126
127- 生成 `renewal_jobs`
128- 幂等,不为同一条消息重复生成任务
129- 写 projector 外部日志
130- 不执行发送
131
132## 需要特别注意
133
134- `paused` 和 `manual` 不应生成新任务
135- payload 构建不要写死成未来无法扩展的格式
136- 尽量把规则收敛成独立函数,避免散落在 runner 代码里
137- 所有开发必须在 worktree 中进行,不要在主仓库目录修改代码
138
139## 验收标准
140
141- auto 对话的新旧消息能生成 `pending` 续命任务
142- manual / paused 对话不会生成续命任务
143- 同一消息重复扫描不会生成重复任务
144- projector 执行过程会写外部日志
145
146## 推荐验证命令
147
148- `cd /Users/george/code/baa-conductor-renewal-message-projector && pnpm build`
149- `cd /Users/george/code/baa-conductor-renewal-message-projector && pnpm -C apps/conductor-daemon test`
150
151## 执行记录
152
153> 以下内容由执行任务的 AI 填写,创建任务时留空。
154
155### 开始执行
156
157- 执行者:`Codex`
158- 开始时间:`2026-03-30 16:00:12 CST`
159- 状态变更:`待开始` → `进行中`
160
161### 完成摘要
162
163- 完成时间:`2026-03-30 16:31:47 CST`
164- 状态变更:`进行中` → `已完成`
165- 修改了哪些文件:
166 - `apps/conductor-daemon/src/renewal/projector.ts`
167 - `apps/conductor-daemon/src/index.ts`
168 - `apps/conductor-daemon/src/timed-jobs/runtime.ts`
169 - `apps/conductor-daemon/src/index.test.js`
170 - `packages/artifact-db/src/schema.ts`
171 - `packages/artifact-db/src/store.ts`
172 - `packages/artifact-db/src/types.ts`
173 - `packages/artifact-db/src/index.ts`
174 - `packages/artifact-db/src/index.test.js`
175 - `tasks/T-S058.md`
176- 核心实现思路:
177 - 在 `artifact-db` 增加按 `(observed_at, id)` 游标顺序扫描消息的 store 原语和索引,支持按 settle cutoff 增量扫描旧消息,避免重复全表扫描
178 - 新增 `renewal/projector.ts`,把消息到续命任务的投影逻辑收敛到独立 runner,包含 cursor 持久化、`shouldRenew()` 判断、结构化 payload / target snapshot 构建,以及 projector 过程日志
179 - projector 基于 `local_conversations` 和 `conversation_links` 判断 `manual / auto / paused`、冷却期、重复任务和目标路由可用性,仅为满足条件的消息生成幂等 `pending` `renewal_jobs`
180 - 在 `ConductorRuntime` 启动时注册 `renewal.projector` 到 timed-jobs 框架,并把 shared timed-jobs log 目录暴露给 runner 以回写 `renewal_jobs.log_path`
181 - 用测试覆盖 cursor 扫描、manual / paused / cooldown / route unavailable 跳过、幂等投影、runtime 接线和重启后 cursor 持久化
182- 跑了哪些测试:
183 - `cd /Users/george/code/baa-conductor-renewal-message-projector && pnpm install`
184 - `cd /Users/george/code/baa-conductor-renewal-message-projector && pnpm -C packages/artifact-db test`
185 - `cd /Users/george/code/baa-conductor-renewal-message-projector && pnpm -C apps/conductor-daemon test`
186 - `cd /Users/george/code/baa-conductor-renewal-message-projector && pnpm build`
187
188### 执行过程中遇到的问题
189
190- 新 worktree 初始没有安装依赖,第一次跑测试直接失败于 `pnpm exec tsc` 找不到;补跑一次 `pnpm install` 后恢复正常构建和测试流程
191
192### 剩余风险
193
194- 当前 projector 主要依赖 `messages.conversation_id -> active conversation_links` 解析本地对话;如果未来 final-message 再次出现缺失 remote conversation 且无法从其他信号补齐的情况,这类消息会被记录为 skip,不会生成续命任务
195- 当前冷却期判断复用 `local_conversations.cooldown_until` 字段,但还没有单独的策略配置或自动写入逻辑;如果后续希望把“生成任务后自动推进冷却窗口”做成正式策略,需要在后续任务里补控制面配置