Files
DevFlow/docs/待审查.md

426 lines
62 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 待审查队列
> **职责分离**:
> - **主会话**(编码合并后 / 巡检)→ 【**写入**】"当前队列"区,登记待审查项(范围 + 维度 + commit)。
> - **审查 agent**(独立会话 / workflow)→ 【**读取**】"当前队列",执行审查,完成回填结论 + 移到"已审归档"。
>
> 这里**只放审查登记**,不放推进待办(推进待办见 [todo.md](./todo.md))。
> 主会话**不在这里做审查**,只登记 + 读 todo 推进。审查发现的【待修代码项】回流 todo 作推进待办。
## 审查规则(审查 agent 遵守)
- 只读审查,**不改代码**。
- **独立 grep/read 核验源码,不信文档 / 会话描述 / 设计声明的结论**(防上下文污染)。
- 每条 finding 须 `file:line` 源码佐证 + evidence。
- 严重度:high(破坏性 / 数据错 / 回归) / med(逻辑瑕疵 / 边界漏) / low(风格 / 可读)。
- 完成回填:总体 verdict(PASS / ISSUES / WATCH)+ high/med/low 清单 + 待修项回流 todo。
## 状态图例
🟡 待审 / 🔵 审查中 / ✅ 已审(结论) / 🔴 待修(有 high 问题)
---
## 当前队列
## 已审归档
### CR-260616-26 batch53 F-05 去重根治(audit.rs High risk 审批前缓存命中去重) — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo + vue-tsc 双 EXIT 0 **附 log 末尾证据** + grep/read 核验全件 + 边界核验)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪3
- **亲跑 `cargo check --workspace` + `npx vue-tsc --noEmit`** ✅ — 双 EXIT 0(cargo Finished 0.68s + vue-tsc log 空;5 warning 全既存 dead_code 非本批)。**无中间态误报**(附 log 末尾)。
- **逐件核验(全 PASS)**:find_cached_high_risk_result(audit.rs:400-458 反向扫 `msgs.iter().rev()` + tool_name 过滤 :423 + canonical_args_key 规范化比较 :430 + 旧 id 反查 tool_result :444-456)+ High 分支查缓存命中回传(:536-553 guard High → push tool_result 新 tool_call_id :544 + emit AiToolCallCompleted :545-549 + 审计 completed/auto_dedup :551 + continue :552 跳过 pending insert)+ 仅 High 去重(:534 Medium|High 共分支 + :536 内嵌 High guard,Med 走原审批 :555-573)+ pending 占位不命中(:452 占位串「需要用户审批等待确认」return None,与 push :564 全角逗号一致)+ args 规范化(sort_object_keys :462-492 sort_by 字典序 + 递归值/Array + to_string 紧凑稳定)+ 不同命令/参数不命中(timeout 重发可重试)+ tool_call_id 来源修正(stream_recv.rs:181 draft.id 来自 tc_delta.id 非 stream_recv UUID)+ 零越界(纯 audit.rs 3 函数 + High 分支,未碰 batch42/44/51)。
- **关键边界核验**:二次循环自吞(第一次重试命中缓存 push tool_result → 第二次重试 find_cached 反扫命中第一次 tool_call 又跳过审批)= **期望行为**(每次重试跳过审批断循环,非 bug)。
- **⚪ 观察项(全 low)**:OBS1(canonical_args_key to_string unwrap_or_default 理论序列化失败空串误等价,实际 JSON 不会失败)/ OBS2(空参数同名 High 工具误命中,当前工具集无)/ OBS3(去重命中 tool_result 下轮被命中 = 期望行为断循环)。
- **待修项回流 todo**: **无**(全件 PASS,3 OBS 全 low)。完整 agentic loop 通用去重(search_files 重复卡片 + 滑动窗口)③类待用户,本批仅 run_command 循环核心。
---
### CR-260616-25 batch52 UX-10 @实体引用全栈(@ popover + prompt 任务段注入) — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo + vue-tsc 双 EXIT 0 **附 log 末尾证据** + grep/read 核验全件)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪3
- **亲跑 `cargo check --workspace` + `npx vue-tsc --noEmit`** ✅ — 双真实 EXIT 0(cargo Finished 0.72s + vue-tsc log 空 0 error;5 warning 全既存 dead_code 非本批)。**无中间态误报**(附 log 末尾,呼应 CR-23-1 教训防 E0594 类瞬态漂移)。
- **逐件核验(全 PASS)**:@ popover 复用 `.ai-skill-popover`(AiChat.vue:563)+ 联想状态三件(mentionOpen/Index/Start :992/993/995 独立于 skill)+ detectMentionTrigger 邮箱排除(:927-953 prev 非空白 break)+ selectMention `[类型: 名]` 插入(:1057-1079)+ mentionItems 项目+任务各 slice(0,20)(:1009-1037)+ mentionGroups 分组(:1046-1049)+ mentionTotal 空/无匹配区分(:1040-1043)+ **键盘导航与技能联想互斥**(:902-920 watch inputText skill 块优先强制关 mention + selectSkill/selectMention 互清,skillOpen 与 mentionOpen 不可同时 true)+ Enter 不冲突(:1433-1456 popover 开 selectMention preventDefault 覆盖发送,关 fallthrough handleSend)+ prompt.rs:117-126 任务段(state.tasks.list_active take(20) + 注入 title/status/description 镜像项目段范式 :108-115)+ 签名零变化(build_system_prompt :102 4 调用方 commands.rs:69/161/391 + agentic.rs:478 零改)+ 降级合理(prompt 走后端 state repo :119 非前端 mentionEntities 透传,避碰 batch45/48/49/51 领地)+ 实体 id 未透传(仅 `[类型:名]` 文本,重名任务风险低已知降级)+ i18n 5 key 双语(aiChat.ts:76-80)。
- **⚪ 观察项(全 low)**:OBS1(mentionHint 死键定义无 .vue 消费,建议删或激活)/ OBS2(mentionQuery :1003-1006 slice 到串尾非光标前,光标中移时偏差,常规用法无影响)/ OBS3(desc 仅 popover 展示不进 prompt,prompt 任务段用 tk.description 摘要列间接影响 LLM,语义链路清晰)。
- **待修项回流 todo**: **无**(全件 PASS,3 OBS 全 low)。
---
### CR-260616-24 batch51 UX-09 编辑已发送消息并重新生成全栈(messages JSON status + ai_chat_edit IPC + AiChat 编辑 UI) — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo + vue-tsc 双 EXIT 0 + grep/read 核验全件 + **CR-23-1 独立核验**)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪4
- **亲跑 `cargo check --workspace` + `npx vue-tsc --noEmit`** ✅ — 双 EXIT 0(cargo Finished 0.84s,5 warning 全既存 dead_code 非本批)。
- **🔴 CR-23-1 独立核验:不成立** ✅ — `context.rs:478-495` 当前是 **for 循环**(L488 `for t in ...iter_mut()` + L490 `t.message.status=Some("truncated")` + L491 `count += 1;` 计数非 filter 闭包体),workspace cargo check 真实 EXIT 0(全量非分 crate)。原 CR-23 agent 报 E0594 是**中间态误报**(batch51 最终 for 循环规避双层引用,呼应 CR-21/18/16 瞬态漂移)。**主代理声明属实,CR-23-1 标无效**。
- **逐件核验(全 PASS)**:provider.rs:54-55 ChatMessage `status: Option<String>`(serde default+skip_serializing_if 向前兼容 None=active 无 V17 迁移)+ 5 构造函数补 None(:60/63/66/69/72)+ is_active()(:76-77)+ sanitize_messages step0 过滤 truncated(context.rs:287-296)+ replace_last_active_user_content(:501-512 rposition+token 重估)+ truncate_after_user_message(:478-495 for 循环)+ ai_chat_edit IPC(commands.rs:351-445 复用 ai_regenerate spawn 模式:generating 拦截:363+活跃一致:367+replace 末条 user:371-377+truncate 其后:379-382+save:418+spawn:428-442)+ 只末条 active user 可编辑(replace rposition + Err)+ title.rs:51 + lib.rs:108 + 前端 api/ai.ts:33 editMessage + useAiSend.ts:212-270(splice 截断+改 content+空气泡占位+IPC+失败回滚)+ useAiConversations.ts:72 filter truncated + AiChat.vue:329-337 编辑按钮 hover(isLastUser && !streaming)+ isLastUser/startEdit/cancelEdit(:1028-1059)+ handleSend 编辑分支(:1267-1285)+ ESC 取消(:1211-1215)+ 切换取消(:883-885)+ i18n 4 key 双语(aiChat.ts:100-103)。
- **⚪ 观察项**(全 low):OBS1(导出 batch46 含 truncated 软删历史,markdown/txt 视觉见旧回复段,完整审计语义取舍)/ OBS2(truncate_after_user_message/replace_last_active_user_content 无单测,token 计数同步易错建议补 case)/ OBS3(useAiSend editMessage convId 空回滚不彻底,极端场景后端未触发 IPC)/ OBS4(editMessage 无 generating 前端预检,DOM 隐藏+后端拦截双兜底无并发风险)。
- **待修项回流 todo**: **无**(CR-23-1 标无效,4 OBS 全 low 非阻断)。
---
### CR-260616-23 batch50 审查 med 修复聚合(CR-15-1 kill_on_drop + CR-08-O1 blocked 排除 + CR-10-A/B 停下报告) — ⚠ 已审(ISSUES)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo check EXIT 101(撞同攒批 CR-23-1)+ vue-tsc EXIT 0 + grep/read 核验四件)
- **总体结论**: ⚠ **ISSUES** — 🔴1 🟡0 ⚪1(三件声明项全 PASS,但同攒批工作区 context.rs:491 编译失败阻断整批)
- **亲跑 `cargo check --workspace`** ⚠ **EXIT 101**(df-ai 编译失败,CR-23-1,非三件范围)/ `npx vue-tsc --noEmit` ✅ EXIT 0。
- **三件声明项核验(全 PASS)**:
- **CR-15-1 kill_on_drop** ✅ `shell.rs:85` `.kill_on_drop(true)` match 块外统一调用,三类型(PowerShell:62/Cmd:68/Sh:74)全覆盖,注释:81-84 配合 tokio::time::timeout:96-101 防孤儿;正常完成路径 cmd.output() 已读完 output 自然 drop 无害 — 不破坏 cmd.output() 成立。
- **CR-08-O1 blocked 排除** ✅ `TaskDetail.vue:265-274` `WF_EXCLUDED_FROM={'blocked'}` :265 + wfAdvanceAction computed :269 `if has return null`,DOM :71 v-if 不渲染。**不动 ADVANCE_MAP**(:219-246 五态原推进项全保留),其他态不受影响。
- **CR-10-B 否决** ✅ **同意主代理「不成立,审查锚定漂移」**:独立 Read commands.rs:37-110,L94 save_conversation 锁外(L46-65 锁块 L65 关闭),L105 spawn 在 save 后,时序正确。L56/59 是 pop 失败防御性错误处理(复位 generating + 报错)非 save/emit 时序。**原 CR-10-B 把 pop-失败-错误分支误读为时序冲突,审查锚定漂移坐实**。
- **CR-10-A 降级 P2** ✅ 三入口(ai_regenerate:37/ai_chat_send:128/ai_chat_force_send:453)统一「锁内变更+锁外 spawn」,兜底充分(generating 占用 busy 拦截 + stop_flag 复位 + force_send:460-468 复位三件套 + ai_chat_stop:520-536 3s 兜底任务防 panic/异常退出卡死),接受现状合理。
- **🔴 CR-23-1(high,编译失败,同攒批非三件范围)**:`crates/df-ai/src/context.rs:491` E0594 `cannot assign to t.message.status, which is behind a & reference``truncate_after_user_message``self.messages[i+1..].iter_mut().filter(|t| {... t.message.status=...})` filter 闭包参数 t 是 `&&mut TrackedMessage`(双层引用)不能写字段。git stash HEAD EXIT 0 / pop 工作区 EXIT 101 → UX-09 新增代码引入。**阻断整个 df-ai crate 构建,下游 commands.rs/agentic.rs 全 fail**。修法:filter 改 for 循环 + 计数,或闭包内 `let t=&mut **t;` 解引用。
- **⚪ 观察项**:OBS1(agent 自报 cargo EXIT 0 与实际 EXIT 101 不符,可能跑 HEAD 或分 crate,结论可信度打折,建议后续 agent 自报附 log 末尾证据)/ OBS2(CR-23-1 非三件范围但同攒批,合并前必先修否则整批构建失败)。
- **待修项回流 todo**: **CR-23-1**(high,context.rs:491 编译失败,改 for 循环或解引用,阻断 df-ai 构建 — **紧急,主会话合并前必修**)。
---
### CR-260616-22 batch49 UX-17 对话置顶全栈(pinned 字段+迁移+IPC+排序+图钉按钮) — ✅ 已审(PASS-WATCH)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo check + cargo test df-storage + vue-tsc 三 EXIT 0 + grep/read 核验 14 件)
- **总体结论**: ⚠ **PASS-WATCH** — 🔴0 🟡1 ⚪3(CR-22-1 med 已置顶图钉非 hover 不可见)
- **亲跑 `cargo check --workspace` + `cargo test -p df-storage` + `npx vue-tsc --noEmit`** ✅ — 三 EXIT 0(cargo 9 warning 全既存 dead_code;df-storage 22 单元 + 11 集成 passed;vue-tsc 0 error)。
- **独立核验**(14 件):models.rs:163 `pub pinned: bool`(非 Option 必填,list 摘要手写 json! snake_case 对齐)/ crud.rs:1141-1148 INSERT 含 pinned(?8)+ :1153-1160 UPDATE 含 pinned(?7)params 对齐 / :1050 ai_conversation_from_row 读 pinned i32→bool / :1657-1672 set_pinned 仅 SET pinned 不动 updated_at(纯元数据)/ migrations.rs:285-296 V16 column_exists 守卫幂等 + ALTER ADD COLUMN pinned INTEGER NOT NULL DEFAULT 0(老库非 NULL)+ :53 注册 (16, migrate_v16)/ commands.rs:849-859 ai_conversation_set_pinned IPC / :746 list 摘要 json! 加 pinned / lib.rs:128 注册 / **conversation.rs:141 pinned: false(proactive-bug-fix 坐实:models.rs:163 非 Option 必填,insert 不补编译断 E0063;update :108 从库 get rec.pinned 回写不丢失)** / AiChat.vue 排序 :1054(groupedActive)+ :1069(archivedConvs)`Number(b.pinned?1:0)-Number(a.pinned?1:0)||Number(b.updated_at)-Number(a.updated_at)` pinned DESC→updated_at DESC + V8 stable / :53/120/162 三处图钉按钮 toggle / i18n zh:9-10/en:9-10 双语 / useAiConversations.ts:174-178 setPinnedConversation IPC+本地同步 / api/ai.ts:156-157 + types.ts:246。
- **🟡 CR-22-1(med,UX 缺陷)**:AiChat.vue:1872-1873 `.ai-conv-item-actions { display:none }` + :1878 `:hover``display:flex` → 所有操作按钮(含图钉)默认隐藏,:1903 `--pinned` 仅改 color 未覆盖 display → **已置顶对话非 hover 态图钉不可见**,「常驻强调色一眼识别」UX 意图落空。功能(toggle/排序)正常。修法:`.ai-conv-item-act--pinned``display:flex`。登记自相矛盾(hover 浮出 toggle 与常驻强调色无法同时满足),需产品定调。
- **⚪ 观察项**:OBS1(filteredConversations 搜索态未加 pinned 排序,置顶不前置,登记自认降级可接受)/ OBS2(V16 无独立测试靠 column_exists 探测,项目一贯模式)/ OBS3(update_full:1151 读库 rec.pinned 回写不丢失,未来绕过 get 路径风险当前无)。
- **待修项回流 todo**: **CR-22-1**(med,AiChat.vue:1872-1903 已置顶图钉非 hover 不可见,「常驻强调色」UX 未达成,补 display 规则或调 actions 可见性策略)。
---
### CR-260616-21 batch48 UX-18 对话导出前端(exportConversation 封装 + 3 处导出按钮 + Blob 下载) — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 vue-tsc + cargo check 双 EXIT 0 + grep/read 核验 12 件)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪3
- **亲跑 `npx vue-tsc --noEmit` + `cargo check --workspace`** ✅ — 双 EXIT 0。**vue-tsc EXIT 0 确认 batch48 完成后 `toggleExportMenu/exportingId/exportOpenId/exportConversation` 均已定义,CR-15/16 agent 早报的 12 TS2339 瞬态已消除**(cargo 5 warning 全既存 dead_code NodeExecutionRepo/ReleaseRepo 非本批,本批纯前端)。
- **独立核验**(12 件):api/ai.ts:165-167 exportConversation 封装(camelCase 仿 continueLoop/stopLoop,签名 `(conversationId, format): Promise<string>`,invoke `ai_conversation_export` snake→camel 对齐 commands.rs:872)/ AiChat.vue 3 处导出按钮 DOM(搜索态 :59-68 / 活跃态 :126-135 / 归档态 :168-177,每处 pin→archive→export→delete 顺序,@click.stop 阻冒泡,:disabled=exportingId===conv.id 防重复)/ `:last-child` 红色态保留(:1898-1901 delete 是末子 export 倒数第二,精确命中删除按钮不被破坏)/ toggleExportMenu/exportOpenId 单展开(:912-917 三元切换同时一开)/ Blob 下载 + revokeObjectURL(:941-950 setTimeout(0) 下轮事件循环释放防泄漏,mime 三格式精确 text/markdown|application/json|text/plain)/ sanitizeFilename 安全(:920-927 空 trim→fallback conv-id + replace 折叠 Win/Unix 路径分隔符+非法+控制字符 + slice(0,60) 限长 + 全清空降级)/ exportingId 防重复(:913/931-932/956 入口 guard+set+finally 三段)/ onExportOutsideClick + 生命周期(:961-966 早返回+closest 防误关 + :1381/1317 add/remove 对称)/ IPC catch 兜底(:951-954 e.message||String(e)+toast 不崩溃)/ i18n 5 key 双语(:112-116 exportFailed 含 {msg})/ 消费 batch46 IPC(commands.rs:872 + lib.rs:129)/ 零越界(batch45 continueLoop/stopLoop :37/45 + batch43 搜索框 :23-34 + batch47 确认 handler :819-841 独立区未改)。
- **⚪ 观察项**:OBS1(revokeObjectURL setTimeout(0) 下载时机,社区惯例无可见问题)/ OBS2(菜单无 Esc 关闭,onGlobalKeydown Esc 已消费他途,UX 小瑕疵)/ OBS3(filename 无时间戳,同名浏览器自动加后缀,设计取舍)。
- **待修项回流 todo**: **无**(12 件全过,双 check EXIT 0,零越界)。
---
### CR-260616-15 batch42 F-04 run_command 超时根治(tool_registry.rs 超时标注 + 常量提取) — ✅ 已审(PASS-WATCH)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo EXIT 0 + vue-tsc EXIT 2 非本批 + grep/read 核验 8 件)
- **总体结论**: ⚠ **PASS-WATCH** — 🔴0 🟡1 ⚪2(CR-15-1 med shell.rs kill_on_drop 缺失)
- **亲跑 `cargo check --workspace`** ✅ — EXIT 0(本批纯 Rust tool_registry + shell)。**`npx vue-tsc --noEmit`** ⚠ EXIT 2(12 errors 全在 AiChat.vue 导出功能 toggleExportMenu/exportingId/exportOpenId/exportConversation,系并发 batch48 未完成实现,与本批 F-04 Rust 零关联)。
- **独立核验**(8 件):tool_registry.rs:24 常量 `DEFAULT_RUN_COMMAND_TIMEOUT_SECS=60` / :495 unwrap_or 用常量单一使用点 / :510-520 map_err 拦超时改写文案(contains 匹配 shell.rs:95 产出串前缀一致)/ shell.rs:89-95 超时根因点(`tokio::time::timeout``cmd.output()`)/ commands.rs:251-256 High 审批路径 `e.to_string()` 透传 / audit.rs:450 Low/并行路径同源(经 ai_tools.execute 分发无遗漏)/ commands.rs:269 replace_tool_result_content 断重试链路(LLM 收改写文案不再触发新 tool_call_id 重审批)/ tool_registry.rs:472 run_command 单注册。
- **🟡 CR-15-1(med,真 bug)**:`crates/df-execute/src/shell.rs:60-79` 构造 `tokio::process::Command` **缺 `.kill_on_drop(true)`**(tokio 1.52.3)→ `tokio::time::timeout` drop future 后 tokio **不主动 kill 子进程**,子进程变**孤儿继续后台跑**,但 `tool_registry.rs:514` 文案称「进程已终止」**名不副实**。长 hang 命令(大构建/死循环)超时后仍耗资源。治本应 shell.rs:60-79 构造 cmd 后加 `.kill_on_drop(true)`。根因层缺陷(非本批 tool_registry 标注层引入),但本批文案依赖该假设。
- **⚪ 观察项**:OBS1(tool_registry.rs:473 描述 + :494 注释硬编码「默认 60 秒」字面量未引用 const,改常量需手改两处易漏)/ OBS2(const :24 模块私有,shell.rs 未共享)。
- **待修项回流 todo**: **CR-15-1**(med,`crates/df-execute/src/shell.rs:60-79``.kill_on_drop(true)`,孤儿进程 + 文案「进程已终止」语义不实)。
### CR-260616-16 batch43 UX-06 对话搜索 UI 接线(AiChat.vue 侧栏) — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo EXIT 0 + vue-tsc 首跑 EXIT 2 缓存陈旧清缓存重跑 EXIT 0 + grep/read 核验 8 件)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪3
- **亲跑 `cargo check --workspace`** ✅ — EXIT 0(7 warning 全既存 dead_code)。**`npx vue-tsc --noEmit`** 首跑 EXIT 2(6 TS2339 全在 AiChat.vue:57-63 导出功能 toggleExportMenu 等,属并存 batch48 导出 UI 非本批)→ 清增量缓存重跑 **EXIT 0**,确认缓存陈旧 quirk 非真实错。
- **独立核验**(8 件):搜索框 DOM(AiChat.vue:23-34 .ai-conv-search + v-model + kbd Ctrl+K)/ Ctrl+K 绑定(:996-1003 preventDefault + 侧栏未开 toggleSidebar + nextTick focus,顺序 Ctrl+L→K→B→Esc 无重复)/ keydown listener 生命周期对称(:1273 注册 / :1211 移除)/ searchInputRef(:847)/ 平铺渲染(:36-74 template v-if searchResults + :key 's+' 防键冲突 + 空态 searchEmpty + v-else 原分组逐字保留 editingConvId 双击改名零回归)/ searchResults computed(:974-976 显式 .value 解包 ComputedRef 坑已修)/ 消费 batch41 store 契约零改(CR-14 已审 store 侧)/ i18n 3 key 双语(:13-15)。Ctrl+K 冲突核验:grep 无既有 Ctrl+K,Tauri WebView2 无地址栏。
- **⚪ 观察项**:OBS1(Ctrl+K 输入焦点抢占,打字时按 K 切走光标,UX 选择非破坏)/ OBS2(kbd 与 title 复用同一 i18n key,tooltip 语义弱)/ OBS3(范围声明漂移:搜索态平铺项被 batch48 加 export 菜单,审查时点与现状漂移,归 batch48 审)。
- **待修项回流 todo**: **无**(vue-tsc EXIT 2 缓存陈旧非真实错)。
### CR-260616-17 batch44 F-03 达 max 后端(agentic 暂停态 + AiMaxRoundsReached 事件 + continue/stop IPC) — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo + vue-tsc 双 EXIT 0 + grep/read 核验 6 件 + 交叉核验)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪2
- **亲跑 `cargo check --workspace` + `npx vue-tsc --noEmit`** ✅ — 双 EXIT 0(cargo 7 warning 全既存 dead_code)。
- **独立核验**(6 件 + 交叉):agentic.rs:322-347 达上限改(save 先行 :340 + disarm :342 + emit AiMaxRoundsReached :343-345 + return :346 保 generating 暂停态,对齐审批等待模式 L313-316)/ mod.rs:117-122 variant + `#[serde(tag="type")]` / commands.rs:446-465 ai_continue_loop(generating + active 双校验 + 复位 stop_flag + try_continue)/ commands.rs:476-502 ai_stop_loop(双校验 + 置 stop_flag 双保险 + generating=false + emit AiCompleted 不重复 save)/ lib.rs:112-113 注册 / 决策 a(loop 局部 iteration agentic.rs:159,续跑 try_continue 重 spawn 天然重计)。交叉:try_continue guard(should_continue)、ai_chat_stop 暂停态交互(走 3s 兜底正确非最优)、ai_chat_force_send(复位 generating 清审批走新 loop)、stop_flag 双保险(continue 复位 :460 + stop 置 :490)。
- **⚪ 观察项**:OBS1(ai_chat_stop 暂停态落流式分支走 3s 兜底非最优,前端延迟,建议审批分支前加暂停态判定即时清理,既存 stop 路径未适配新状态)/ OBS2(无硬上限产品风险,前端操作卡建议多次继续后二次确认)。
- **待修项回流 todo**: **无**
### CR-260616-18 batch45 F-03 达 max 前端操作卡(pendingMaxRounds + 续/停按钮) — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo + vue-tsc 双 EXIT 0 + grep/read 核验 6 件 + 死锁风险核验)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪2
- **亲跑 `cargo check --workspace` + `npx vue-tsc --noEmit`** ✅ — 双 EXIT 0(cargo 5 warning 全既存 dead_code)。
- **独立核验**(6 件 + 死锁):types.ts:210-211 AiMaxRoundsReached variant 联合 + serde 对齐 / useAiEvents.ts:93 pendingMaxRounds 模块级 ref 独立事件源 + :200-204 dispatch + :286/320 AiCompleted/AiError 双清 + :41 NO_RESET_WATCHDOG 含 / api/ai.ts:37-38/45-46 continueLoop/stopLoop 仿 ai_approve / AiChat.vue:468-483 操作卡 + :1625-1626 showMaxRoundsCard 双守卫 + :1632-1658 handler IPC 失败回滚 acting + :1660-1663 watch 复位 + :2384-2395 样式 / i18n 6 key 双语(:102-107)/ 后端契约对齐(agentic.rs:343 + commands.rs:446/476 + lib.rs:112-113)。死锁核验:try_continue 三路径(should_continue=false 补 AiCompleted / provider-Err emit AiError / 正常 spawn run_agentic_loop)全覆盖,所有出口触发清 pendingMaxRounds + watch 复位 acting,无死锁。
- **⚪ 观察项**:OBS1(无 max 暂停态查询 IPC,跨重启恢复缺失,设计取舍 force_send 可复位)/ OBS2(continue/stop IPC 命名风格微异:ai_approve 动词 vs continue/stop 动词+名词)。
- **待修项回流 todo**: **无**
### CR-260616-19 batch46 UX-18 对话导出后端(ai_conversation_export IPC) — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo check EXIT 0 + grep/read 核验 11 件)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪2
- **亲跑 `cargo check --workspace`** ✅ — EXIT 0(workspace 干净,0 warning 0 error)。
- **独立核验**(11 件):conversation.rs:19/24/48 确无导出 IPC(只 TokenAccumulator + save_conversation)/ IPC 位置 commands.rs:853-913 / format 双保险防 panic(:860-863 `matches!` 前置 Err + :908-909 `_ => Err` 末尾)/ 落库 messages serde_json::from_str 零内存读(:866-871 与 switch 一致)/ markdown 四臂 match 真穷举无 `_` 通配(:878-883 MessageRole 4 variant 编译器强制)/ markdown content 原样三反引号不转义(:886)/ json to_string_pretty(:892-893)/ txt 仅读 m.content 略 tool_calls/tool_call_id/model(:898-904)/ 空对话 markdown/txt 空串 json `"[]"`(:889/906/892)/ lib.rs:128 注册(与 batch44 L112-113 不同行)/ 零越界(与 batch44 continue-stop 不同段)。
- **⚪ 观察项**:OBS1(json 空对话返 `"[]"``""`,语义合理前端 JSON.parse 正常)/ OBS2(markdown 顺序依赖落库保序约定)。
- **待修项回流 todo**: **无**
### CR-260616-20 batch47 UX-08 新建对话确认弹窗 — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 vue-tsc + cargo check 双 EXIT 0 + grep/read 核验 10 件)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪0
- **亲跑 `npx vue-tsc --noEmit` + `cargo check --workspace`** ✅ — 双 EXIT 0(cargo 5 warning 全既存 dead_code NodeExecutionRepo 非本批)。
- **独立核验**(10 件):confirmNewConversation handler(AiChat.vue:832-837 非生成态零行为变化直接 newConversation)/ isViewingGenerating 双条件(:965-967 streaming && generatingConvId===activeConversationId,切走后台不弹)/ store 三字段(ai.ts:47/51/59)/ 两处按钮改造(:18 侧栏 + :206 聊天头,登记写 L176 实际 L206 行号偏差)/ ConfirmDialog 复用(:812 useConfirm Promise + 并发覆盖防永挂 useConfirm.ts:39)/ store.newConversation 软复位(useAiConversations.ts:31-41 B-260615-10 零改)/ commands.rs 零改(git diff 仅 batch46 ai_conversation_export)/ i18n zh/en(:84)/ Esc 优先级协同(:1099-1105 confirmState.visible 时 Esc 视取消 resolve Promise 不卡死)/ 零越界(batch43/45/36/47 独立区块)。
- **待修项回流 todo**: **无**(W-1 low 范围偏差 L176→L206 代码正确)。
---
### CR-260616-14 batch41 Sidebar+ai store 域(UX-06 store 契约 + B-45 内存泄漏核查) — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo check + vue-tsc 双 EXIT 0 + grep/read 核验 7 件)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪3(filteredConversations .slice() 冗余 + sort 稳定性依赖 + 范围声明与实际不符,均 low 非阻塞)
- **亲跑 `cargo check --workspace` + `npx vue-tsc --noEmit`** ✅ — 双 EXIT 0(cargo 4 warning 全既存 dead_code 非本批;vue-tsc 零 TS error,AiChat.vue:940 `computed<AiConversationSummary[] | null>` 类型精确匹配)。
- **独立核验**(7 件):
- **filteredConversations 契约**(stores/ai.ts:118-125)✅ — 空 query trim→null 信号(消费方走原分组)/ 非空 `filter((c.title ?? '').toLowerCase().includes(q))` case-insensitive 全量(活跃+归档)/ updated_at DESC(b 在前为正,正确)。
- **类型契约**(api/types.ts:237-247)✅ AiConversationSummary 含 title?/archived/updated_at 类型安全。
- **useAiStore 返回值**(stores/ai.ts:136)✅ filteredConversations 已展开。
- **i18n 3 key**(zh/en aiChat.ts:13-15)✅ searchPlaceholder/searchEmpty/searchShortcutHint 双语对称。
- **UI 接线已落地**(AiChat.vue:22-64/939-941)✅ — v-model 双绑 + 搜索态平铺 + 空态提示 + computed 解包 store.filteredConversations.value;搜索项含 archive/delete 操作与原分组对称(登记称「留 batch43」,实际 batch41 已完整接线)。
- **B-45 stopListener**(useAiEvents.ts:344-354)✅ — 三 listener unlisten + 置 null + clearStreamWatchdog + clearAllToolSlowTimers + clearAllApprovalTimers 五件全清。
- **B-45 AiChat onBeforeUnmount**(AiChat.vue:1172-1191)✅ — removeEventListener keydown + cancelAnimationFrame + 拖拽 listener + body class + store.stopListener() + _unlistenToolSlow + _toastTimer/_titleFlashTimer/_providerBarTimer 八件全清。
- **MESSAGE_CAP=200**(stores/ai.ts:36/94-105)✅ — watch 拦 push 式增长(>CAP)splice 最早条;切对话整体替换放行。
- **⚪ 观察项**(均 low):
1. OBS1(冗余 slice):stores/ai.ts:123 `.slice()` 紧跟 `.filter()`,filter 已返新数组,slice 冗余拷贝。无功能影响,建议删。
2. OBS2(sort 稳定性):updated_at 相等返回 0 依赖 V8 ES2019+ stable sort。会话同秒 updated_at 概率低,无可见问题。
3. OBS3(范围声明不符):登记称「UI 接线留 batch43」,实际 batch41 已完整接线。建议主会话核对 batch43 是否剩 i18n 微调。
- **待修项回流 todo**: **无**(三观察项均 low 非阻断)。
### CR-260616-13 batch40 CR-06 审查观察项测试补强(②-3/②-4 回调测试 + ignored 确认) — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo test + grep/read 核验)
- **总体结论**: ✅ **PASS** — 🔴0 🟡1⚪1(in_progress 失败→todo 状态机拦截产品决策点 med 非阻断 + 测试数登记 +9 vs +10 low)
- **亲跑 `cargo test -p df-nodes -p df-workflow`** ✅ — df-nodes **67 passed + 1 ignored**(57→67,+10 测试)/ df-workflow 23 passed,双 EXIT 0。
- **独立核验**:
- **ignored 确认**(ai_node.rs:298-300)✅ — glm_live_complete 真调 GLM 集成测试,合理 #[ignore] 保留。
- **9 新测试覆盖** ✅ — 3 templates callback(task_workflow_templates:callback 边界 + reject 可达性)+ 6 advance callback(task_advance_node:regression_target 镜像契约 + 三段 completed→target/failed→regression/非终态跳过 + 落库验证);镜像契约机制防 workflow.rs:44-51 私有函数回归漂移。
- **🟡 观察项 O1(med,产品决策点,非本批引入)**:**in_progress 模板失败→regression_target 给 todo,但状态机 `backward_to_todo_rejected` 全拒**(task_state_machine.rs:188-193)→ 回调 advance_task_atomic 被 InvalidState 拦截(task_advance_node.rs:72-77),**任务原地保留 in_progress**。三选项待定:a 接受现状补 UI 提示 / b 改 `regression_target("in_progress")=None` 对齐状态机 / c 放开 todo 回退(破坏闸门)。本批测试显式锁定此行为(防回归)。
- **⚪ 观察项 O2(low)**:测试数登记 +9 vs 实测 +10(差 1 来自既有测试重构,非问题)。
- **待修项回流 todo**: **CR-13-O1 产品决策点**(非代码 bug,回流 todo 作产品决策 a/b/c)。
### CR-260616-12 batch38 settings 域(F-01 agentic max 可配) — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo check + vue-tsc 双 EXIT 0 + grep/read 核验 15 件)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪3(前端默认值硬编码 + clamp 回写闪现 + batch45 演进关系,均 low 非阻塞)
- **亲跑 `cargo check --workspace` + `npx vue-tsc --noEmit`** ✅ — 双 EXIT 0(cargo 7 warning 全既存 dead_code;并发 batch45 改动共存编译通过)。注:审查中一次中间态 grep 抓到 batch45 改 mod.rs 时的 E0599,最终完整重跑 EXIT 0 确认 batch38 本身无错。
- **独立核验**(15 件):1:1 严格复刻 llm_concurrency 范式(AppState 字段 `agent_max_iterations: Arc<AtomicUsize>` + init 引用 `DEFAULT_MAX_AGENT_ITERATIONS=10`(agentic.rs:33)/ `run_agentic_loop(max_iterations)` 形参(agentic.rs:101)+ `0..max_iterations` 循环(agentic.rs:159)+ 达上限 warn+emit(agentic.rs:324-336)+ 3 调用点 ai_chat_send(commands.rs:103-106)/ai_regenerate(commands.rs:197-200)/try_continue_agent_loop(agentic.rs:477-487)load 快照透传 / `ai_set_agent_max_iterations` clamp 1-50 store(commands.rs:812-821)/ lib.rs:130 注册 / api/ai.ts:87-89 / Settings.vue input min1 max50(:275-277)+ watch 持久化 SQLite(:663-665)+ syncAgentMaxIterations Math clamp+debounce 300ms(:694-705)+ onMounted 同步防刷新(:766-775)/ onUnmounted 清 _agentIterTimer(:778-783)/ i18n 双语(settings.ts:79-80))。grep 确认无第 4 调用点遗漏。
- **⚪ 观察项**(均 low):
1. OBS1(前端默认值硬编码):Settings.vue:628/696 前端 `appSettings.get(..., 10)` 默认 10 与后端 const 巧合一致但非引用同一常量。范式层面观察(llm_concurrency 亦如此)。
2. OBS2(clamp 回写闪现):clamp 前瞬时值短暂显示后修正,视觉闪现功能无损。
3. OBS3(batch45 演进):lib.rs:111 注释 F-260616-03 标注 max_iterations 是 batch45 暂停态续跑前置基础,两批共存编译通过,演进链路清晰。
- **待修项回流 todo**: **无**
### CR-260616-11 batch39 ai chat 性能域(AR-8 节流评估 + B-53 snap 优化) — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo check + vue-tsc 双 EXIT 0 + grep/read 核验 6 件)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪2(增量缓存 quirk + deep watch 每帧检测,均 low 非本批)
- **亲跑 `cargo check --workspace` + `npx vue-tsc --noEmit`** ✅ — 双 EXIT 0(cargo 5 warning 全既存 dead_code;首跑增量缓存陈旧报 AiMaxRoundsReached not found E0599,清缓存重跑 EXIT 0 确认)。
- **独立核验**(6 件):
- **AR-8 前端滚动跟随已存在**(AiChat.vue:1110-1114 isNearBottom 80px + 234 onMessagesScroll + 412 showBackToBottom + 1139-1147 onContentChange)✅ — 完整存在,非本批新增。
- **AR-8 后端 50ms 合批未改**(stream_recv.rs diff 纯 B-42 error_type 映射,零 batch39 改动)✅ — 负 ROI 论证成立(rAF ARC-08 吸收重 parse + heartbeat 语义冲突 + flush 复杂度)。
- **B-53 snap 优化正确性**(AiChat.vue:1207-1210)✅ — 新 snap `{n: msgs.length, tc: msgs.map(m=>(m.toolCalls||[]).map(t=>({id,s})))}` 剔除冗余 id/role/len;body 逻辑(AiChat.vue:1218-1226)仅读 toolCalls 状态从不读被删字段 → 行为安全;流式 delta 不再触发 body 重算(toolCall 状态翻转/splice 淘汰仍触发)。
- **B-53 短路 + deep + MESSAGE_CAP 全保留**(AiChat.vue:1213 snap===lastMsgSnapshot return + 1233 deep:true + ai.ts:36/94-105 MESSAGE_CAP=200 length watch 独立)✅。
- **B-53 自包含**(lastMsgSnapshot 模块局部无外部消费 + collapseInactive 唯一调用点)✅。
- **注释清晰度**(AiChat.vue:1197-1202)✅ — 与代码完全吻合无误导。
- **⚪ 观察项**(均 low):
1. OBS1(缓存 quirk):增量缓存陈旧致首跑 E0599,清缓存重跑过。建议 CI 走 cargo check 不带增量。
2. OBS2(deep watch 每帧检测):B-53 仅短路 body,deep watch 本身仍每帧遍历 messages 含 content,极长流式消息 O(n) 成本。rAF 节流已吸收,非阻塞。
- **待修项回流 todo**: **无**(纯优化批次,零回归)。
### CR-260616-10 batch36 ai chat UX 域聚合(UX-02 消息操作栏 + UX-03 错误气泡操作入口) — ✅ 已审(PASS)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo check + vue-tsc 双 EXIT 0 + 独立重跑双 check 佐证)
- **总体结论**: ✅ **PASS** — 🔴0 🟡2⚪3(ai_regenerate 并发竞态 med + commands.rs 时序倒置 med 非阻断 + 3 low)
- **亲跑 `cargo check --workspace` + `npx vue-tsc --noEmit`** ✅ — 双 EXIT 0(vue-tsc 首跑报 useAiEvents.ts 缺 import 已补后过;agent 独立重跑双 check 佐证)。
- **独立核验**:
- **UX-02 操作栏**(AiChat.vue hover `.ai-msg-actions` 仅末条 复制+重新生成)✅。
- **ai_regenerate IPC**(commands.rs)✅ — generating 占用校验 + pop_last_assistant_round + save + spawn run_agentic_loop 复用 + active_conversation_id 一致性。
- **pop_last_assistant_round**(context.rs)✅ — 空 false / 末尾 user popped_any=false / 跨多轮 tool 三元组一并弹不留半截 / history_tokens saturating_sub。
- **UX-03 错误气泡**(useAiEvents.ts AiError push 附 errorType `as AiMessage` cast B-42 零改 + AiChat.vue 错误气泡重试复用 regenerate + canOpenSettings 判 auth|provider_config)✅。
- **只读消费 B-42**(ErrorType/AiErrorType/AiError 零改)✅。
- **🟡 观察项(待修项,细节见 agent transcript)**:
1. **CR-10-A(med 时序倒置)**:commands.rs:56/59 save 与 emit 时序。回流 todo。
2. **CR-10-B(med 竞态)**:ai_regenerate 并发竞态窗口。回流 todo。
- **⚪ 观察项**:代码块复制按钮(v-html 子元素无法绑事件)遗留单独立项;AI 气泡内嵌复制与新操作栏复制共存最小改动;context.rs 跨 crate(df-ai)改动非 batch35/37 锁。
- **待修项回流 todo**: **CR-10-A**(commands.rs:56/59 时序倒置 med)+ **CR-10-B**(ai_regenerate 竞态 med)。
### CR-260616-09 batch37 knowledge 域(F-260616-02 pending_review 归位·决策 a) — ✅ 已审(PASS)
- **commit**: 工作区未 commit(攒批)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo check + cargo test df-storage 双 EXIT 0 + grep/read 核验)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪2(注释遗留 + list_non_archived dead_code,均 low 非阻塞)
- **亲跑 `cargo check --workspace` + `cargo test -p df-storage`** ✅ — **双 EXIT 0**;df-storage 11 passed(含 `list_by_status_orders_by_confidence_semantics` / `list_by_status_filters_other_status` / `test_knowledge_cols_matches_record` 三个 knowledge 测试)。
- **独立核验**(5 件):
- **knowledge_list 默认收窄**(knowledge.rs:78-88)✅ — L86 `None => list_by_status("published")` 收窄纯 published;L84 `Some(s) => list_by_status(&s)` 显式透传(含 archived)向后兼容。
- **调用方零破坏** ✅ — grep list_non_archived src-tauri/ **零 Rust 调用方**;前端 src/api/knowledge.ts:15 + stores/knowledge.ts:61-66 loadList 默认 undefined→null→后端默认 published;Knowledge.vue:275/522 loadList() 无参走默认。**无调用方依赖旧「非 archived 全部」语义**。
- **merge_by_confidence 排序等价**(knowledge.rs:238-273)✅ — rank high=3/med=2/low=1/_=0 + created_at DESC,与 SQL(crud.rs:1363-1368 `CASE...DESC, created_at DESC`)权重+方向一致;双指针合并前 a/b 各 sort_by(cmp) 重排保证有序(L257-258);相等时 candidate 优先(L262)结果确定。
- **向后兼容** ✅ — published 仍在 library(默认)/ archived 显式可查 `knowledge_list(status='archived')` / candidate+pending_review 仍在 inbox(knowledge_list_candidates L226-231)。
- **i18n 文案**(zh/en knowledge.ts)✅ — inbox「待处理」/「Pending」+ 注释说明 F-260616-02 决策 a。
- **⚪ 观察项**:
1. **OBS1(low 注释遗留)**:Knowledge.vue:17/250 注释仍写「审核收件箱」,i18n 已改「待处理」;注释与新语义不符,建议清理(不影响功能)。
2. **OBS2(low dead_code)**:crud.rs:1478 `list_non_archived()` 收窄后全仓零调用方,成孤儿方法(编译器未报,宏展开 pub method 豁免);建议删除或 `#[allow(dead_code)]`
- **文档遗留(非代码,仅记录)**:df-knowledge 模块文档 L52/58/174-175 + 经验记录 L78 + df-storage 存储层文档 L114 多处 knowledge_list 默认语义/list_non_archived 描述过时,建议后续清理批次更新。
- **待修项回流 todo**: **无**(代码层面 PASS;两 low 观察项 + 文档遗留均非阻塞)。
### CR-260616-08 batch35 TaskDetail 域聚合(①-1 工作流推进按钮 + B-41 进度内嵌 + ①-3 i18n) — ✅ 已审(PASS)
- **commit**: 工作区未 commit(攒批)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo check + vue-tsc 双 EXIT 0 + grep/read 核验)
- **总体结论**: ✅ **PASS** — 🔴0 🟡1⚪1(blocked 态推进按钮语义偏差 med 非阻断 + lib.rs 混入非本批 low)
- **亲跑 `cargo check --workspace` + `npx vue-tsc --noEmit`** ✅ — **双 EXIT 0**(4 warning 均既有 dead_code 非本批)。
- **独立核验**(11 件,grep + read 亲验):
- **workflow.rs 空dag选模板补丁**(L81-89)✅ — 三分支覆盖(nodes 非空→原 dag / 空+target Some→template_for 失败 Err「无对应工作流模板」 / 空+target None→原 build_dag);**与 CR-06 审的 ①-1 同代码,描述差异源于措辞非冲突**;dag shadowing 后 build_dag + dag_json 序列化落库实际拓扑(L92/L96)。
- **②-3/②-4 回调**(workflow.rs:232-233/267-305)✅ — cb_task_id/cb_target_status clone move;completed→Some(target)/failed→regression_target/任一 None→跳过;回调失败 warn 不回滚;advance_task_atomic 签名匹配(task_advance_node.rs:43-47)。
- **regression_target**(workflow.rs:44-51)✅ — testing→in_review/in_review→in_progress/in_progress→todo/其他→None。
- **TaskDetail.vue 推进按钮**(L71 v-if wfAdvanceAction / L260-267 computed / L77 disabled 互含 / L288-310 handleWorkflowAdvance 空 dag+taskId+target 调 run)✅。
- **B-41 进度内嵌 + exec_id 过滤**(L174-184 状态 / L313-314 过滤 / L411 onMounted + L419 onBeforeUnmount 生命周期对称)✅。
- **多 listen 无冲突**(workflow.ts:37-41 独立 unlisten / store 收全量 vs TaskDetail 按 exec_id 过滤,职责隔离)✅。
- **进度轻量近似**(L318-323 total 用已启动+已完成,前端无法预知后端模板节点数)✅。
- **template_for 对齐 ADVANCE_MAP**(三模板 in_progress/testing/done;in_progress 态 primary=in_review 无模板不显示)✅。
- **与手动 advance 并存**(L54-64 手动保留 / L66-91 工作流独立区块)+ 不碰 router/lib.rs listen ✅。
- **i18n 8 key 对称**(zh/en taskDetail.ts:41-49)✅。
- **🟡 观察项 O1(med,非阻断)**:**blocked 态推进按钮语义偏差** — blocked→in_progress primary(TaskDetail.vue:241-243)WF_SUPPORTED_TARGETS.has('in_progress')=true 显示按钮,但 template_for('in_progress') 是「todo→in_progress 从头执行」拓扑,blocked 恢复语义不该重跑 AiNode。UX 需确认(blocked 态应排除工作流推进或用恢复语义)。**非阻断**(后端回调逻辑正确,仅前端按钮显示语义)。
- **⚪ 观察项 O2(low)**:lib.rs +3 行(ai_regenerate L107 / list_tool_executions L127-128)非 batch35 范畴,属其他批混入工作区,不影响本批正确性。
- **待修项回流 todo**: **无**(均观察项非阻断;O1 blocked 语义建议主会话评估是否前端排除)。
### CR-260616-07 batch34 并行(B-42 错误码统一 + AE-08 审批历史面板) — ✅ 已审(PASS)
- **commit**: 工作区未 commit(攒批)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo check + vue-tsc 双 EXIT 0 + grep/read 核验源码)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪2(既存死代码 warning + B-42 前端消费未改留 batch36)
- **亲跑 `cargo check --workspace` + `npx vue-tsc --noEmit`** ✅ — **双 EXIT 0**(output L68/L69);cargo check Finished 48.33s(L67);6 warning 全既存死代码(df-ai finish_reason/call_type/SessionState/session_state + devflow risk_level/releases/node_executions never read),非本批引入。
- **独立核验**(B-42 + AE-08,grep 定位 + read 亲验源码):
- **B-42 ErrorType 枚举**(mod.rs:73-86)✅ — `#[serde(rename_all = "snake_case")]` + 5 variant(Auth/Network/Timeout/ProviderConfig/Unknown),每个文档注释说明分类标准;ProviderConfig→provider_config 与 types.ts:188 联合对齐。
- **B-42 AiError variant**(mod.rs:107-112)✅ — `error_type: Option<ErrorType>`,None 表示未分类(向后兼容旧 emit 点,L106 注释)。
- **B-42 8 emit 点映射**(agentic.rs×3 + stream_recv.rs×5)✅ — Auth(agentic:128)/ ProviderConfig(agentic:452)/ Unknown(agentic:333 + stream_recv:207)/ Timeout(stream_recv:163)/ Network(stream_recv:237/278)/ None(stream_recv:308 建连失败混合源难精确归类)。映射合理。
- **AE-08 list_recent SQL**(crud.rs:1246-1275)✅ — 专用 SELECT `ORDER BY requested_at DESC LIMIT ?1 OFFSET ?2`(L1259),绕过通用 query 宏(后者硬编码 ORDER BY created_at,本表无该列);limit.min(200) 钳制防滥用(L1253)。
- **AE-08 list_tool_executions IPC**(audit.rs:85-113)✅ — limit.unwrap_or(50)/offset.unwrap_or(0) → list_recent → DTO map;**敏感字段截断**(arguments_brief 120 / result_brief 160,L104-105),完整原值留库。
- **AE-08 truncate_chars**(audit.rs:71-78)✅ — `chars().count()<=max` 早返回 / 否则 `chars().take(max)` + push '…';**按 char 边界切,中文/emoji 安全**。
- **AE-08 lib.rs 全路径注册**(lib.rs:128)✅ — `commands::ai::audit::list_tool_executions`,避碰 mod.rs glob,零行为破坏。
- **AE-08 AuditLog.vue**(src/views/AuditLog.vue:1-311)✅ — 7 列表格 + 分页(prevPage/nextPage + hasMore=records.length===PAGE_SIZE + 空页回退 L105-108)+ 风险/状态/决策者标签映射;**类型内联**(ToolExecutionRecord interface L69-83,注释「不进 api/types.ts 避撞 B-42」)— 无 types.ts 交叉污染(关注点② ✅)。
- **B-42 前端消费**(关注点③)✅ — grep `error_type` src/ 仅 types.ts:204 定义,**零消费逻辑**(AiChat.vue 等不读 error_type);UX-03 留 batch36 符合任务约定。
- **⚪ 观察项**:
1. **既存死代码 warning**(cargo check 6 个,df-ai/devflow never read)— 非本批引入,既存 lint 级;建议后续清理(SessionState/risk_level 可能阶段2 未接入死代码)。
2. **B-42 前端消费未改**(关注点③已知)— error_type 字段已加但前端暂不读,UX-03 留 batch36;字段先落地不阻塞,合理。
- **待修项回流 todo**: **无**(B-42 + AE-08 全过,零缺陷;两观察项均已知/既存非回归)。
### CR-260616-06 batch33 阶段2 续(②-2/②-3/②-4 run_workflow task_id+回调 + ②-6 DAG模板) — ✅ 已审(PASS)
- **commit**: 工作区未 commit(攒批,与 batch32 + 决策记录 + todo/待审查 混合)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo test 全量无 tail + grep/read 核验源码)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪2(df-nodes 1 ignored + ②-3/②-4 回调无集成测试)
- **亲跑 `cargo test -p df-workflow -p df-nodes 2>&1`(无 tail 全量)** ✅ — **exit 0**;df-nodes **58 running → 57 passed; 0 failed; 1 ignored**(output L30/L90,比 CR-05 的 53 多 4 模板测试);df-workflow **23 passed; 0 failed**(L119);无 FAILED 无 error[。**去 tail 修正 CR-05 截断问题**。
- **独立核验**(四件 + ①-1,grep 定位 + read 亲验源码):
- **②-2 run_workflow 参数 + 前端透传**(workflow.rs:64-73 + api/workflow.ts:16-24 + stores/project/workflow.ts:23-26)✅ — 签名 `task_id: Option<String>, target_status: Option<String>`(L71-72)向后兼容;WorkflowRecord.task_id 填入(L104);前端 api `taskId?/targetStatus?`(L16-17)snake_case 透传(L23-24);stores runWorkflow 透传(L26)。旧调用方不传→None 零行为破坏。
- **②-3 完成回调**(workflow.rs:267-273)✅ — `match (cb_task_id.as_ref(), cb_target_status.as_deref())` 都 Some → completed 分支 `advance_target=Some(target)`(L270)→ advance_task_atomic 推进到 target_status。
- **②-4 失败回调退回**(workflow.rs:44-51 + 271)✅ — failed 分支 `advance_target=regression_target(target)`;映射 testing→in_review / in_review→in_progress / in_progress→todo / _(done/blocked/cancelled)→None;in_progress→todo 回起点符合「执行未达预期重排」直觉(L42-43 注释);起点 todo 无可退态→None。
- **回调解耦语义**(workflow.rs:274-294)✅ — advance_task_atomic Err 仅 `tracing::warn!` 不回滚(工作流 status 已写库 L251,回调失败不撤销);`TaskRepo::new(&db)`(L275)复用 db Arc(clone 廉价)。
- **②-6 DAG 模板**(task_workflow_templates.rs:1-152)✅ — `template_for(target)` match in_progress/testing/done→Some,else None(L28-35)不 panic;三模板拓扑正确(in_progress 单 ai / testing ai→human 串行 / done 单 human);testing+done 模板 human options 含「拒绝」(L67/L85)触发 ②-5 reject→Err→failed→②-4 退回闭环;config 留空由 run_workflow 全局注入+deep_merge(衔接 ④-1 L14-17);4 测试断言拓扑(unknown_none/single_ai/ai_to_human_serial 含「拒绝」断言 L141/single_human)。
- **①-1 DagDef 来源选模板**(workflow.rs:81-89)✅ — dag.nodes 空+target Some→`template_for`(L83).ok_or_else(Err「无对应工作流模板」)(L84);空+None→原路径 build_dag 校验(L85);非空→用传入 dag(L88)。三分支零行为破坏。
- **⚪ 观察项**:
1. df-nodes **1 ignored**(L90,running 58 / passed 57 / ignored 1)— 登记关注点提「57 passed」未提 ignored;ignored 非 failed,建议确认哪个测试 `#[ignore]`(可能慢/集成测试留阶段2收尾)。
2. **②-3/②-4 回调无集成测试**(登记关注点②已知)— 已亲核 diff 逻辑正确(match 分支 + 解耦语义),但缺自动化回归保护;回调失败/退回路径仅靠代码审查覆盖。建议阶段2 收尾补集成测试(workflow 跑通→advance 验证)。
- **待修项回流 todo**: **无**(四件+①-1 全过,零缺陷;两观察项均已知/非回归)。
### CR-260616-05 batch32 阶段2 首批(④-1 config 下沉 + ②-1 注册 TaskAdvanceNode + ②-5 HumanNode reject) — ✅ 已审(PASS)
- **commit**: 工作区未 commit(攒批,与 CR-03/04 + 决策记录 + todo/待审查 混合)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 cargo test + grep/read 核验源码,不信 agent 自报"53 passed")
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪1(df-nodes 测试数字 tail 截断未单独显示,exit 0 佐证通过)
- **亲跑 `timeout 240 cargo test -p df-nodes -p df-workflow`** ✅ — **exit 0**;df-workflow **23 passed**(deep_merge_tests 6 + executor `node_config_overrides_global_in_node_context` 1 + cancelled 3 + state/conditions 13);df-nodes human_node reject 测试 exit 0 保证通过(`tail -40` 截断未单独显示数字,exit code 0 佐证)。**不信 agent 自报「53 passed」**。
- **独立核验**(三件,grep 定位 + read 亲验源码):
- **④-1 deep_merge config 下沉**(dag.rs:169 + executor.rs:105 + registry.rs:52)✅ —
- `deep_merge(global,node)`(dag.rs:169-188):两端 Object 递归合并(同 key 节点级覆盖 L177-181 / 新 key 保留 L179);非两端 Object 节点级直接覆盖 L186(含 Null 显式空);**Null 语义=显式置空覆盖(非跳过),跳过=不写 node_configs key**(L164-165 注释)符合登记关注点。
- `NodeContext.config`(executor.rs:105-108):`match node_configs.get(id) → Some(deep_merge(global,node_cfg)) / None(initial_config.clone())`;**缺失 key 走 None 分支 == 旧 initial_config.clone() 零行为破坏**。
- `build_dag`(registry.rs:52):`add_node_with_config(id,node,node_def.config.clone())` 下沉 NodeDef.config。
- **5 维度全测过**:同 key 胜(`node_overrides_global_scalar`)/ 新 key 留(`node_adds_new_key`)/ 嵌套递归(`nested_object_recursive_merge`)/ 非 Object 覆盖(`array_replaces_not_concat`)/ 空 no-op(`empty_node_config_is_noop`+`missing_node_config_treated_as_noop`)。
- **零行为破坏**:HumanNode/AiNode/TaskAdvanceNode 节点 NodeDef.config 空/缺失 → node_configs 无 key → None 分支 == 旧行为。
- **②-1 TaskAdvanceNode 注册**(state.rs:235-250)✅ — `build_registry(db: Arc<Database>)` 改签名;`register("task_advance", move |_| Box::new(TaskAdvanceNode::new(db.clone())))`(state.rs:248-250)move 闭包捕获 Arc<Database>,clone 满足 Send+Sync+'static 满足 NodeFactory 签名;init `build_registry(db.clone())`(state.rs:194)db move 前 clone 避 E0382。D-03 走 df-nodes Node trait 对齐。
- **②-5 HumanNode reject 语义化**(human_node.rs:19-132)✅ —
- `REJECT_KEYWORDS`(L19-22):中「拒绝/驳回/退回/否决」+ 英「reject/decline/declined/deny/denied/no/block」。
- `is_reject_decision`(L25-28):trim+to_lowercase 归一化 + **整词精确匹配(== 非 contains)** → 防「拒绝啦」误伤(测 L846 `!is_reject_decision("拒绝啦")` ✅)。
- `contains_reject`(L31-33):picked 任一命中即拒(多选场景)。
- execute(L120-132):`count_ok && each_valid``contains_reject` → Err「人工审批被拒绝(用户选择: X);意见: Y」。
- **边界全过**:整词防误伤(L846)/ 大小写空白归一(L836-838)/ 多选任一即拒(L848)/ options 空自由文本仅拒绝词 Err 其余 Ok(L13-15 注释)/ 行为变更 Ok→Err executor set_failed → 工作流 failed(L113-119 注释)。
- **⚪ 观察项**:亲跑命令带 `tail -40` 截断 df-nodes 测试数字(仅见 df-workflow 23 passed);**exit code 0 佐证 df-nodes+df-workflow 全过**,非缺陷。后续审查亲跑命令去 tail 或用 `2>&1 | tee` 保全量。
- **待修项回流 todo**: **无**(三件全过,零缺陷)。
### CR-260616-03 batch30 ①类修复批次 — ✅ 已审(PASS)
- **commit**: 工作区未 commit(攒批,与 CR-04 混合;CR-03 范围文件干净,无阶段2混入)
- **审查时间**: 2026-06-16(独立审查 agent · 亲核 diff + grep 核验,不信主代理"46 passed"声明)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪1(set_cancelled TOCTOU 低频,条目已知)
- **独立核验**(CR-03 登记范围 8 文件,范围干净):
- **CR-01-D 错误区分**(task_advance_node.rs)✅ — 同态(from==to)→`Validation("相同状态,无需推进")`;非法转换→`InvalidState{current:"X→Y(非法状态转换)"}`;NotFound(任务不存在)。三类拒绝错误类型+消息区分,前端 e.toString() 可分辨。3 测试 assert 含 from→to 上下文(illegal_skip/terminal_done/same_status)。
- **CR-03-b openai source 链** ✅ — `Error::from(e).context("SSE 流错误: {e}")`,Display=ctx 逐字节等价旧 `anyhow!`,source 链保留。同 CR-04 anthropic 模式。
- **CR-03-a resolve_project_label 三臂**(audit.rs)✅ — Ok(Some)→项目名 / Ok(None)→"项目已不存在" / Err→裸 id+warn(DB 故障不误报"已不存在"误导用户)。
- **CR-03-c ToolCard find**(ToolCard.vue)✅ — computed Map(O(N)建表)→function find(O(N)提前退出);2 调用点 `.value[id]``(id)` 改对。
- **CR-01-G i18n 分级**(TaskDetail.vue + i18n×2)✅ — loadFailed/advanceFailed 加 `{msg}` 插值;catch 走 `t(key,{msg:e.toString() ?? common.unknownError})`;common.unknownError zh/en 均有(common.ts:16)。**关注点② 前端兜底可显示区分消息** ✅。
- **复核-新④ 终态守卫**(workflow.rs cancel_workflow_node)✅ — get→match:Pending/Running/Waiting→set_cancelled+Ok;终态→Err"已终态,无法取消"。行为变更正确(避免静默覆盖终态)。
- **⚪ 观察项(关注点①,条目已知"低频忽略")**:`set_cancelled`(state.rs:95-100)**无终态守卫**,直接 `insert(Cancelled)`。IPC 层 get→match→set_cancelled 两步非原子:理论 TOCTOU 窗口(get 时 Pending 通过守卫,set 前被 executor 并发改终态)→ set_cancelled 强制覆盖终态(如 Completed→Cancelled 语义错位)。**实际低频**(人工取消+executor 竞争窗口极小)+ 最坏仅终态语义错位不崩溃 → med 观察项,IPC 守卫是主防线。彻底修需 set_cancelled 加守卫或 CAS,低频场景成本不值。
- **待修项回流 todo**: 无明确缺陷;TOCTOU 属条目已知低频观察,非 CR-03 引入回归。
### CR-260616-04 batch31 NodeCancelled 事件语义+anthropic source链 — ✅ 已审(PASS)
- **commit**: 工作区未 commit(攒批,与 CR-03 + 阶段2 混合)
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 test + grep 核验,不信主代理"16 passed"声明)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪1(前端消费缺失,既存非回归)+ ⚠ 范围混淆 flag
- **独立核验**(CR-04 登记范围 4 文件):
- **events.rs NodeCancelled variant** ✅ — `NodeCancelled { node_id }`(events.rs:64)新增,语义注释清晰(取消=用户主动 vs NodeFailed=失败)。
- **executor.rs is_cancelled 二分** ✅ — L148-166:取消节点→emit NodeCancelled(不 set_failed,Cancelled 已终态避免非法转换崩溃);失败节点→set_failed+NodeFailed。零行为破坏(工作流仍 Err 中止,first_err 逻辑保留)。
- **types.ts node_cancelled** ✅ — L128 手对齐后端 serde(rename_all snake_case)。
- **anthropic_compat.rs:533 Display 不变** ✅ — `Error::from(e).context(format!("Anthropic SSE 错误: {}", e))`,Display = context = "Anthropic SSE 错误: {e}" 逐字节等价旧 `anyhow!`;e 进 `.source()` 链可追溯。
- **亲跑 `cargo test -p df-workflow`** ✅ — **23 passed**(主代理称 16,实际 23 含 deep_merge/node_config 新测试),关键 `test_cancelled_node_emits_node_cancelled_event` ✅ 验证取消节点 emit NodeCancelled 非 NodeFailed。
- **claim③ 无穷举 match** ✅ — 亲 grep:后端无 `match WorkflowEvent` 穷尽(全 matches!/构造点),前端 src/ node_failed/node_cancelled **仅 types.ts 定义无消费**
- **⚠ 范围混淆 flag**(重要):executor.rs 工作区 diff 混入**阶段2 config 下沉**(L99-108 deep_merge 全局+节点 config + EchoConfigNode 测试 + node_config_overrides 测试),**非 CR-04 范围**(未登记待审查)。该部分 test 过但不属本批结论覆盖。阶段2 改动(`dag.rs`+102 / `human_node.rs`+46 / `state.rs`+21 / executor.rs config 部分)需主会话另立 CR-05 登记后审。
- **⚪ 观察项(既存非回归,建议评估)**:NodeCancelled 事件**前端无消费逻辑**(src/ 仅 types.ts 类型定义,无 switch/render 处理)。取消节点用户暂无"已取消"区分 UI 反馈。**非 CR-04 引入**(CR-04 前 node_failed 前端亦不处理,属既存渐进式类型对齐),NodeCancelled 用户价值依赖后续补前端事件处理。
- **待修项回流 todo**: 无明确代码缺陷;前端事件消费缺失属既存功能不完整,建议主会话评估是否立项(非 CR-04 待修项)。
### CR-260616-02 batch29+R-PD-10 代码改动批次 — ✅ 已审(PASS)
- **commit**: `fc767e1` 优化: R-PD-10 storage_err DRY统一 + FR-D3 migrations if链转数组循环
- **审查时间**: 2026-06-16(独立审查 agent · 亲跑 test 核验,不信主代理"全过"声明)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪0
- **独立核验**:
- **亲跑 `cargo test -p df-storage`** ✅ — crud 单元 **22** passed + project_soft_delete 集成 **11** passed,0 failed(覆盖 storage_err 替换后 CRUD / advance_status_atomic CAS / soft_delete / update_field 白名单 / migrations run() 全量路径)。主代理"11集成全过"声明属实,额外验证 22 单元。
- **R-PD-10 storage_err DRY** ✅ — helper `fn storage_err<E: ToString>(e: E) -> Error { Error::Storage(e.to_string()) }`(crud.rs:19)泛型等价旧闭包;残留旧模式 grep **=0**(无遗漏);test 全过证 110 处替换无语义偏差。
- **FR-D3 migrations if→数组循环** ✅ — `steps: [(i32, fn(&Connection)->Result<()>); 15]`(migrations.rs:43)+ `for (version, migrate_fn) in steps { if current_version < version { migrate_fn(conn)?; } }`,与原 15 个 `if current_version<N { migrate_vN(conn)?; }` **逐字等价**(顺序[1..15]+条件`<version`+`?`传播)。零行为变更属实。
- **migrate_vN 签名匹配** ✅ — migrate_v1~v15 全 `fn(&Connection) -> Result<()>`,与 steps 数组 fn 指针类型精确匹配。
- **迁移数据安全三层保留** ✅ — ①版本门控 run() 开头 `MAX(version)`(migrations.rs:29)②各 migrate_vN 末尾 `INSERT INTO schema_version`(L67/75/.../274)③column_exists PRAGMA 幂等探测(L7-9,v4-v15 各处)。
- **待修项回流 todo**: **无**(全过,无新缺陷)。
### CR-260616-01-fixes 审查待修项修复批次 — ✅ 已审(PASS)
- **commit**: `4dc5219` 修复: CR-01审查待修项①类7项(CSS补 testing/blocked 徽章 + CAS防回收站推进 + DRY + 注释 + 测试改名 + advancing 接文案)
- **审查时间**: 2026-06-16(独立审查 agent · 防"主代理已核查双绿"代入,亲核源码)
- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪2(范围外观察项)
- **独立核验**(不信主代理核查声明,grep/read 亲验 7 项①类修复):
-**CR-01-B CAS deleted_at 语义** ✅ — `soft_delete`(crud.rs:800)设 `deleted_at` 非空;`advance_status_atomic` 两分支(bump_rounds + 普通,crud.rs:855/859)均加 `AND deleted_at IS NULL`,回收站任务 `affected=0 → None` 必败。D-02 软删收口正确,一处关闭。
-**CR-01-A CSS 配色跨视图一致** ✅ — TaskDetail.vue:344-345 与 Tasks.vue:413-414 **逐字镜像**(testing 橙 `#ff9800` / blocked 红danger 0.5px 边框),跨视图统一。
-**CR-01-C DRY 文案零变更** ✅ — `ALL_STATES`(task_state_machine.rs:48-56)= `["todo","in_progress","in_review","testing","done","blocked","cancelled"]`,`join("/")` = 原硬编码串,顺序与值全等,无运行时文案变化。
- **CR-01-H 测试改名** ✅ — `cas_returns_none_when_status_mismatch`(task_advance_node.rs:313)真存在,改名后注释指向正确的 CAS 失败测试。
- **CR-01-I advancing i18n** ✅ — zh/en 均有(taskDetail.ts:38 `推进中.../Advancing...`),TaskDetail.vue:63 接 advancing 态。
- **CR-01-F 白名单注释** ✅ — `allowed_columns_for("tasks")`(crud.rs:331)数组无 `review_rounds` + 注释说明专用路径(仅 advance_status_atomic),收口防误补。
- **CR-01-E state.rs 注释** ✅ — build_registry(state.rs:240)注释准确,说明 TaskAdvanceNode 未注册原因(阶段2 DAG 联动时加)。
- **范围外(记录不审,非本批缺陷)**:
-**工作区 crud.rs 226行未提交** = `R-PD-10` `storage_err` DRY 重构(提取包装函数替换散落 `.map_err(|e| Error::Storage(e.to_string()))`),非 4dc5219 范围,独立审查留待其 commit。
-**`status-abandoned` CSS class ↔ `cancelled` 后端态** = 历史命名别名(`constants/project.ts:83` `cancelled: 'status-abandoned'` 映射闭环,功能正确),非本批引入。命名语义瑕疵(abandoned 弃用 ≠ cancelled 取消),low,可选优化。
- **待修项回流 todo**: **无**(7 项全过,无新缺陷)。
### CR-260616-01 任务推进链(batch28) — ✅ 已审
- **commit**: `d2cb38c` 新增: 任务推进链(7态状态机+advance_task CAS原子写)+软删除+前后端7态对齐
- **审查时间**: 2026-06-16(5 路并行多角度·防代入独立核验)
- **决策依据**: D-260616-01(前端7态对齐) / D-02(任务软删除) / D-03(advance_task 走 df-nodes Node trait) / D-04(阶段1先行)
- **总体结论**: 🔴0 🟡6 ⚪4 — **质量优**
- **8 点 checklist 全过**:
- 状态机矩阵 ✅(7态15转换,前后端单一真相源)
- CAS 原子 ✅(`WHERE id AND status=expected` + affected=0 报错)
- 退回累加原子 ✅(同 UPDATE)
- V15 迁移幂等 ✅(版本门控 + column_exists 双层,八版零事故)
- IPC 真 thin ✅(D-03 守住,task.rs 仅 3 行转发)
- i18n 成对零遗漏 ✅(28 key)
- create_task 不暴露 rounds ✅
- 测试 25 个 ✅
- **F-03 status 双写 = 已知延后**(阶段3 三件同落地,非新缺陷)
- **范围外澄清**: df-ai/lib.rs(`mod retry`) + script_node.rs(`shell_type`) = 同 commit 无关连带改,零风险误报
- **待修项回流 todo**(CR-01-A~I,见 [todo.md](./todo.md) "审查发现待修项"区):
- [P1] **CR-01-A** TaskDetail.vue scoped style 补 `.status-testing`/`.status-blocked`(D-01 前端7态遗漏,testing/blocked 徽章裸渲染丢样式;同查 Tasks.vue/Dashboard)
- [P1] **CR-01-B** crud.rs advance_status_atomic CAS SQL 加 `AND deleted_at IS NULL`(get_by_id 宏无软删过滤→回收站任务可被 advance,D-02 软删对齐遗漏,语义错乱)
- [P2] **CR-01-C** task_advance_node.rs:46 错误7态硬编码改 `ALL_STATES.join("/")`(DRY 单一事实源)
- [P2] **CR-01-D** task_advance_node.rs:62 同态拒绝(from==to)/非法转换区分(现合并 InvalidState,前端无法分辨)
- [P2] **CR-01-E** state.rs build_registry 注释补「task_advance 未注册(阶段2联动时加)」
- [P2] **CR-01-F** crud.rs:325 白名单注释补 review_rounds 专用路径
- [P3] **CR-01-G** TaskDetail.vue:218 advance 失败错误走 i18n 分级(en locale 也中文)
- [P3] **CR-01-H** task_advance_node.rs:297 测试改名(实际未测 CAS 失败)
- [P3] **CR-01-I** i18n `taskDetail.advancing` 冗余 key 处理