Commit f74725ab5d0d11ddcb6efe8b84f58a9feec45dea

Authored by yibo
1 parent ab4631c2

fix(company): 任务收敛到终态时清掉残留的 blocked_reason

settleTaskFromRun 只写 status/finished_at,不清 blocked_reason —— 任务卡住时
noteTaskBlockedReason 写过的那句「节点 xxx 卡住(...)」会一直挂在 tasks 行上,
哪怕后来 run 真的恢复跑完转 completed。界面上因此出现「已完成」绿色状态旁边
还留着一句刺眼的红字,容易被读成还在报错。

真实复现:T-mt2r6fz0-125b 手动推过熔断点后 org run 收敛到 completed,
任务列表却仍显示 org-coder 卡住的旧归因文本。手动清了这条任务的残留数据,
代码层面在 settleTaskFromRun 的 UPDATE 里一并置 NULL——task 进终态时
「为什么卡着」这句话本来就该失效,不管进的是 completed/failed/cancelled 哪一种。

扩展了 goal-task-acceptance.test.js 里"预算耗尽→恢复→跑完"那条既有用例,
断言 blocked_reason 在完成后确实被清空。全量单测 998/998 通过。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
server/services/work-graph-db.js
... ... @@ -2024,7 +2024,7 @@ function settleTaskFromRun(taskId, runId, status) {
2024 2024 const now = new Date().toISOString();
2025 2025 return getDb()
2026 2026 .prepare(`
2027   - UPDATE tasks SET status = @status, finished_at = @now, updated_at = @now
  2027 + UPDATE tasks SET status = @status, blocked_reason = NULL, finished_at = @now, updated_at = @now
2028 2028 WHERE id = @id
2029 2029 AND current_run_id = @runId
2030 2030 AND status NOT IN (${TASK_TERMINAL_STATUS.map((s) => `'${s}'`).join(', ')})
... ...
server/tests/unit/goal-task-acceptance.test.js
... ... @@ -304,6 +304,9 @@ describe(&#39;27-P3C 批 1 验收(§八 4 / 5 / 6 / 10 / 11 / 12b)&#39;, () =&gt; {
304 304 expect(sse.transitionRun(body.runId, 'running', 'blocked', {}, { summary: '用例模拟预算耗尽' })).toBeTruthy();
305 305 // task 行要看得见「卡住了」—— 这是界面上唯一的信号
306 306 expect(wdb.getTask(body.taskId).status).toBe('blocked');
  307 + // 界面上那句「卡在哪」的小字(真实链路里由 describeRunBlock + noteTaskBlockedReason 写)
  308 + expect(wdb.noteTaskBlockedReason(body.taskId, body.runId, '节点 xxx 卡住(budget_exhausted)')).toBe(1);
  309 + expect(wdb.getTask(body.taskId).blocked_reason).toBeTruthy();
307 310 // 但 goal 不许收敛:挂起等人加预算 ≠ 需求失败。判 failed 会写 OKR、唤醒上级、
308 311 // 并把 goal 锁进终态,人加完预算跑完也再改不回 done(缺陷 2:误报 + 白烧一轮 LLM)
309 312 expect(wdb.getGoal(body.goalId).status).toBe('active');
... ... @@ -323,6 +326,11 @@ describe(&#39;27-P3C 批 1 验收(§八 4 / 5 / 6 / 10 / 11 / 12b)&#39;, () =&gt; {
323 326 const task = wdb.getTask(body.taskId);
324 327 expect(task.status).toBe('completed'); // 修之前这里永远钉死在 blocked
325 328 expect(task.finished_at).toBeTruthy();
  329 + // 33 号文档同批修的另一个真实 bug:settleTaskFromRun 只写 status,不清 blocked_reason,
  330 + // 于是任务列表在「已完成」绿色状态旁边,还会一直挂着上一次卡住时留下的那句红字
  331 + // ——真实回归任务 T-mt2r6fz0-125b 复现过(org-coder 恢复跑完后,界面仍显示
  332 + // 「节点 org-coder 卡住(missing_required_input)」)。
  333 + expect(task.blocked_reason).toBeNull();
326 334 expect(wdb.getGoal(body.goalId).status).toBe('done');
327 335 expect(okrCalls).toEqual([{ nodeId: 'O-002.1', status: 'done' }]);
328 336  
... ...