Files
DevFlow/docs/待审查.md
绝尘 2a4d745c5b 重构: F-09批2 调用方迁移per-conv(双写桥接共存期)
- agentic.rs: GeneratingGuard加conv_id + 三处退出校验改conv存在性(决策e) + stop_flag/notify/messages/iteration per-conv + try_continue加conv_id参数
- commands.rs: IPC写路径双写桥接(per_conv新真相源+顶层双写,批4删) + ai_is_generating读per_conv fallback顶层
- audit/conversation/title/knowledge_inject/lib.rs: per_conv读写迁移
- conv()/conv_read()去allow(批2有调用方)
共存期双写: per_conv主+顶层双写兼容批4前IPC,批4签名改后删顶层
主代兜底: cargo check --workspace 0 + test 96 passed + grep三处退出/GeneratingGuard/双写印证
2026-06-19 02:01:06 +08:00

79 KiB
Raw Blame History

待审查队列

职责分离:

  • 主会话(编码合并后 / 巡检)→ 【写入】"当前队列"区,登记待审查项(范围 + 维度 + commit)。
  • 审查 agent(独立会话 / workflow)→ 【读取】"当前队列",执行审查,完成回填结论 + 移到"已审归档"。

这里只放审查登记,不放推进待办(推进待办见 todo.md)。 主会话不在这里做审查,只登记 + 读 todo 推进。审查发现的【待修代码项】回流 todo 作推进待办。

审查规则(审查 agent 遵守)

  • 只读审查,不改代码
  • 独立 grep/read 核验源码,不信文档 / 会话描述 / 设计声明的结论(防上下文污染)。
  • 每条 finding 须 file:line 源码佐证 + evidence。
  • 严重度:high(破坏性 / 数据错 / 回归) / med(逻辑瑕疵 / 边界漏) / low(风格 / 可读)。
  • 完成回填:总体 verdict(PASS / ISSUES / WATCH)+ high/med/low 清单 + 待修项回流 todo。

状态图例

🟡 待审 / 🔵 审查中 / 已审(结论) / 🔴 待修(有 high 问题)


当前队列

CR-260618-01 batch68 未提交改动批量(41文件+754/-2434:虚拟滚动删除+timestamp打戳+audit吞错修复+fetch_models合并+分组折叠+todo精简) — 已审(PASS·🟡1 WATCH)

  • 复审结论(2026-06-18·主代独立 grep/read 核验 diff): PASS🔴0 🟡1 2
  • 验证: git diff HEAD 逐文件核验(41 文件)。

① provider.rs timestamp 打戳 PASS: 非 reasoning_content(已在 74003c 提交)。本批新增 timestamp: Option<i64> 字段 + now_millis_i64() + 全构造器自动打戳。serde(default) 向后兼容注释「provider 映射不读此字段」;单测补 timestamp:None。

② 虚拟滚动删除 PASS(⚠️ WATCH): useAiVirtualScroll.ts 整删(-175)。关键核验: 被删文件内 shouldRender() 已是 void key; return true(恒渲染),即虚拟滚动在删除前已因 IO/RO 时序重叠被禁用。本次是清理已失效死代码非功能回归。AiChat.vue 同步移除所有引用。🟡 WATCH: 长对话(500+ 消息)全量 DOM 无兜底方案,桌面端短期可接受,用户反馈卡顿时再评估。

③ audit.rs+37 PASS(3 项改进): PENDING_APPROVAL_PLACEHOLDER 常量抽取(DRY) | audit_finalize 拆 unwrap_or_default 吞错→Err/None/Err 三路分流(🔒 关键修复) | update_full 失败加 error 日志

④ commands.rs+40 PASS(3 项修复): regenerate 对话校验提前到 generating=true 前(防内存消息破坏) | ai_fetch_models 合并保留用户 weight/enabled label(防排序摇摆) | ai_conversation_delete retain pending_approvals(防死审批残留)

⑤ context.rs+63 PASS(F-05 token 预算修复): estimate_message 累加 parts token(base64/text/url) + 单测。 chars_ratio 0.35 偏保守,后续可校准。

⑥ 前端交互层 PASS(6 项): 分组折叠(toggleGroupFold+v-show) | system 压缩摘要展示 | 复制按钮下沉气泡 | modelOverride 默认最高权重模型 | wasNearBottom 切会话重置 | editEl 函数 ref 修复 v-for 数组收集 bug

⑦ todo.md 精简 PASS: 1200→385 行。P0 区全部 [x] 已修保留;活跃待办完整。 已完成区可进一步归档压缩。

⑧ 待决策.md 括分 PASS: +1065 行来自 todo.md C 类抽离,职责分离清晰。

  • 🟡 WATCH-1: 虚拟滚动删除后长对话全量 DOM 性能(观察级)
  • LOW-1: base64 chars_ratio 0.35 可校准至 ~0.6
  • 待修项回流 todo: 🔴/🟡

CR-260618-02 sweep-fix 6域走查+P3小修+dead_code标注共17处改动(工作区未提交·commit-policy-deferred) — 已审(PASS·2)

  • 复审结论(2026-06-18·主代独立 git diff 核验 17 处): PASS🔴0 🟡0 2
  • 验证: git diff HEAD 逐文件核验全部 17 处改动。cargo check --workspace EXIT 0 / vue-tsc EXIT 0。

sweep-fix 12 项逐一核验:

# 判定
1 context.rs parts token 累加 含图消息 base64 不再绕过预算,单测合理
2 anthropic_compat clone→move DRY+零拷贝
3 scan.rs to_ascii_lowercase 非 ASCII 索引安全
4 scan.rs .is_some_and(!is_null) workspaces null 不再误判
5 adversarial MockProvider reasoning_content 编译修复
6 audit_finalize 拆吞错 Err/None 分流(与 CR-01 联动)
7 delete retain pending_approvals (与 CR-01 联动)
8 PENDING_APPROVAL_PLACEHOLDER 常量 (与 CR-01 联动)
9 ToolCard computed 下沉 DRY parsed
10 AiChat 清虚拟滚动死注释 (与 CR-01 联动)
11 Projects onUnmounted 清 timer 防 timer-leak
12 Knowledge parseContext 去重 冗余 JSON.parse→一次

P3 4 项逐一核验:

# 判定
13 wasNearBottom 切会话重置 防 A→B 误触发 collapseAllToolLists
14 TaskDetail wfResultTimer 防卸载后写已销毁 ref
15 Ideas .net-sentiment.neutral CSS 缺口补全
16 ai_node schema required=[] WATCH: 运行时允许留空,需确认无其他消费方强制校验 required
17 openai_compat #[allow(dead_code)] 标注意图消 warning
  • WATCH-1: ai_node.rs required=[] 影响面——若其他 Node Schema 消费方有 required 白名单校验则需同步放宽
  • 待修项回流 todo: 🔴/🟡

CR-260618-03 SW-10 reqwest Client 构建 DRY(工作区未提交·commit-policy-deferred·1 文件域 df-ai) — 已审(PASS·主代自测)

  • 结论(2026-06-18·主代自测 + 独立 grep 核验源码形态): PASS🔴0 🟡0 0
  • 验证: cargo check -p df-ai EXIT 0(无 warning) / cargo test -p df-ai 112 passed 0 failed(不回归)。

改动 1 处(3 文件 df-ai crate 内):

# 判定
1 lib.rs 加 pub(crate) build_provider_client()(connect_timeout 30s + 回退 Client::new + tracing::warn) 纯抽函数,与原两处逐字一致
2 openai_compat.rs Provider::new 调 crate::build_provider_client() 替原 7 行 DRY,行为不变
3 anthropic_compat.rs Provider::new 同替换 DRY,行为不变

副作用独立核验(grep 源码形态):

  • use reqwest::Client 两文件仍用于 Provider struct 字段(self.client:Client),非 unused

  • use tracing::{..., warn} 两文件仍多处用(openai:503 同步调用 warn / anthropic:183/330/364/497/521/535 流式 warn),非 unused

  • use std::time::Duration 两文件仍用于 :484/:481 .timeout(Duration::from_secs(60)),非 unused

  • 替换前两处 Client::builder().connect_timeout(std::time::Duration::from_secs(30)).build().unwrap_or_else(...) 逐字一致,抽函数后调用点等价

  • 待修项回流 todo: 🔴/🟡

CR-260618-04 SW-16 审计 status 透传 + SW-06 ToolCard watch 合并(工作区未提交·commit-policy-deferred·2 文件) — 已审(PASS·主代自测)

  • 结论(2026-06-18·主代自测 + 独立 grep 核验源码形态): PASS🔴0 🟡0 0
  • 验证: cargo check --workspace EXIT 0(仅 4 pre-existing dead_code 基线 warning) / cargo test -p devflow 92 passed 0 failed / vue-tsc EXIT 0。

改动 2 项(2 文件):

# 判定
1 SW-16 audit.rs find_cached 加 audit_repo 参数 + async + 返回 (content,status);查 find_by_tool_call_id 拿缓存来源真实 status 透传 audit_tool_call find_by_tool_call_id 已存在复用,审计精度改进零回归
2 SW-06 ToolCard.vue 双 watch(props.tc.status) 合并(放 :607 三 ref 已定义避 TDZ + immediate 语义) immediate 边界安全(approving 初始 false/timer null),行为等价

SW-16 独立核验(grep 源码形态):

  • find_cached 签名 async fn(session, audit_repo: &AiToolExecutionRepo, tool_name, args) -> Option<(String,String)>
  • 调用点 :625 if let Some((cached, status)) = find_cached_high_risk_result(session, &audit_repo, &draft.name, &args).await (process_tool_calls 内 audit_repo :555 可达)
  • audit :639 audit_tool_call(..., &status, ...) 透传非固定 "completed"
  • find_by_tool_call_id 返回 AiToolExecutionRecord.status: String(models.rs:211),rec.status 直接访问
  • fallback completed(审计缺失/查询失败不阻塞去重)

SW-06 独立核验:

  • 合并 watch 放原 watch2 位置(approving/approvingTimer/cmdOutputExpanded 三 ref 已定义)避 TDZ

  • immediate:true 保留原 watch1 语义;immediate callback 初始 status 下 approving=false/timer=null 无副作用

  • 待修项回流 todo: 🔴/🟡

CR-260618-05 SW-07 AiChat currentText 双 watch 合并(工作区未提交·commit-policy-deferred·1 文件) — 已审(PASS·主代自测)

  • 结论(2026-06-18·主代自测 + 独立 grep 核验): PASS🔴0 🟡0 0
  • 验证: vue-tsc EXIT 0。

改动 1 项(1 文件):

# 判定
1 AiChat.vue 删 :2040 watch(currentText→onContentChange) + :2047 合并 callback(onContentChange 先 scheduleStreamParse 后,保持原注册顺序) 同源同顺序同条件,行为等价

独立核验:

  • 原 :2040 watch(currentText, onContentChange) + :2047 watch(currentText, (text)=>{...}) 注册顺序 :2040 先 :2047 后(Vue 同源 watch 按注册顺序执行)

  • 合并 callback 内 onContentChange() 先 + scheduleStreamParse 后,保持同顺序

  • 无 immediate(两原 watch 均无),无 TDZ(onContentChange :2032/scheduleStreamParse :912 均在前定义)

  • :2039 watch(messages.length→onContentChange)不同源保留

  • 待修项回流 todo: 🔴/🟡

CR-260618-06 SW-19 ToolCard combineOutputs 抽函数 + SW-20 Ideas parseTags 复用(工作区未提交·commit-policy-deferred·2 文件) — 已审(PASS·主代自测)

  • 结论(2026-06-18·主代自测 + 独立 grep 核验源码形态): PASS🔴0 🟡0 0
  • 验证: vue-tsc EXIT 0。

改动 2 项(2 文件):

# 判定
1 SW-19 ToolCard.vue 抽 combineOutputs(stdout, stderr) 共享函数;combineAndTruncateLines + cmdOutput computed 都复用 DRY 收敛,行为不变
2 SW-20 Ideas.vue 删本地 parseTags(IdeaRecord),import stores/knowledge.ts parseTags;3 调用点改传 .tags DRY 复用 store 版,签名收敛

独立核验(grep 源码形态):

  • ToolCard combineOutputs 定义 :463 + 调用 :472/:652

  • Ideas parseTags import :214 + 调用 currentIdea.tags(:148/:149) / i.tags(:278)

  • 待修项回流 todo: 🔴/🟡

CR-260618-07 SW-08 AuditLog.vue i18n 化(工作区未提交·commit-policy-deferred·3 文件) — 已审(PASS·主代自测)

  • 结论(2026-06-18·主代自测 + 独立 grep 核验 + i18n message 盲点检查): PASS🔴0 🟡0 0
  • 验证: vue-tsc EXIT 0。

改动 3 项(3 文件):

# 判定
1 新建 src/i18n/en/auditLog.ts(auditLog 命名空间:title/refresh/desc/loading/empty + col×7 + pager×4 + risk×3 + status×6 + decided×2) 对齐 ideas.ts 风格
2 新建 src/i18n/zh-CN/auditLog.ts(中文对应,index glob 自动聚合) 中英对称
3 AuditLog.vue 引入 useI18n + template 15 处文本 t() 化 + riskLabel/statusLabel/decidedLabel 改 t() class 映射不国际化(保留),模式对齐 Dashboard/Knowledge/Ideas

独立核验(vue-tsc + i18n message 盲点):

  • vue-tsc EXIT 0

  • useI18n 模式对齐项目现有(Dashboard/Knowledge/Ideas/ProjectDetail 同款 const { t } = useI18n())

  • message 值仅 {n} 标准插值(page: '第 {n} 页'),无 @//裸 {}(避 prod runtime 报错盲点)

  • riskLabel/statusLabel/decidedLabel 未知值走 vue-i18n 默认 fallback,但 risk/status/decided 后端值固定不触发

  • 待修项回流 todo: 🔴/🟡

CR-260618-08 SW-09 ai_node provider 三件套 DRY(工作区未提交·commit-policy-deferred·1 文件 df-nodes) — 已审(PASS·主代自测)

  • 结论(2026-06-18·主代自测 + 独立 grep 核验源码形态): PASS🔴0 🟡0 0
  • 验证: cargo check -p df-nodes EXIT 0(无 warning) / cargo test -p df-nodes 82 passed 0 failed 1 ignored(不回归)。

改动 4 处(1 文件 df-nodes/src/ai_node.rs):

# 判定
1 resolve_and_parse(db,config,inputs) 合并 resolve_provider+parse_params 两步 AiNode/SelfReview 逐字重复消除
2 provider_from_params(&p) 封装 build_provider 5 行 同上
3 AiNode execute :254-262(9 行)→ 2 行(resolve_and_parse + provider_from_params) 行为零变化
4 SelfReview execute parse(:465-466)+ build(:493-498)→ resolve_and_parse + provider_from_params(中间 task 读保留) p 生命周期跨 task 读正确

独立核验(grep 源码形态 + 测试):

  • messages/temperature 差异不抽(AiNode 用 p.system_prompt/p.temperature;SelfReview 强约束 Some(0.0)+REVIEW_SYSTEM_PROMPT)

  • helper 仅收 provider 三件套,差异区各节点自有

  • 原 resolve_provider/parse_params fn 保留(test 直接调用 :781+),helper 是上层封装非替代

  • 待修项回流 todo: 🔴/🟡

CR-260618-09 UX-260618-04 前端删 cost/intel 标签(工作区未提交·commit-policy-deferred·4 文件) — 已审(PASS·主代自测)

  • 结论(2026-06-18·主代自测 + 独立 grep 核验无残留): PASS🔴0 🟡0 0
  • 验证: vue-tsc EXIT 0 / grep tagCost|tagIntel 全 src/ 无残留。

改动 4 处(4 文件):

# 判定
1 ProviderPanel.vue 删 tag-cost/tag-intel 两 span(:114-115) 模态/能力/探测源标签保留
2 AiChat.vue modelOptionLabel 删 intel/cost 拼接,只返 label/model_id + 注释更新 下拉选项不再显示瞎猜档位
3 i18n en/settings.ts 删 tagCost/tagIntel + 注释 4 维度→模态+能力
4 i18n zh-CN/settings.ts 同

独立核验(自主裁决依据 + grep):

  • 用户已全局决策去掉 cost/intel(B-260618-03 背景)→ 前端删标签是决策落地

  • grep 全 src/ 确认 tagCost/tagIntel 仅 ProviderPanel + AiChat 引用,删后无残留

  • ModelConfig.cost_tier/.intelligence 字段保留(后端 B-03 解耦后清),前端先删引用独立安全

  • i18n 删 key 非加,message 编译盲点不适用

  • 待修项回流 todo: 🔴/🟡

CR-260618-10 6项编码批·router解耦cost/intel+model_probe去瞎填+executor TOCTOU+审批占位终态化+knowledge_events query+CostTier清理(workflow wexu1isx1·6 agent·主代修SW-02借用+核查·工作区未提交·commit-policy-deferred) — 已审(PASS·主代自测)

  • 结论(2026-06-18·workflow wexu1isx1 + 主代 cargo/test/vue-tsc 全量验证 + 独立 grep 核验): PASS🔴0 🟡0 1
  • 验证: cargo check --workspace EXIT 0(5 pre-existing dead_code warning,非本批) / cargo test df-ai 109 passed 0 failed / cargo test df-ai-core 24 passed / cargo test df-workflow 23 passed / cargo test df-storage 全 passed / vue-tsc EXIT 0。

6 项逐项核验:

# 判定
1 B-03 router 解耦:TaskRequirements 删 min_intelligence/max_cost + select 删步骤4/5 filter + max_by_key 纯 weight 删 Reverse + 9 调用点删传参 + import 清理 + test 改写(删3用例 112→109 + all_dimensions 改 d 胜) 主代 grep 核验 min_intelligence/max_cost 代码层 0 残留(仅注释 3 处)
2 B-04 model_probe 去瞎填:heuristic_infer cost/intel 中性默认 Medium/Standard + presets/models.json 17条删两字段 功能维度 modalities/capabilities 保留,中性默认对齐 Default impl
3 B-05 CostTier::Free 清理:删 Free 变体 + test 同步 + 主代补前端 types.ts 删 'free' 对齐 grep CostTier::Free 代码 0 残留(仅 todo 任务条目)
4 SW-01 executor TOCTOU:Ok 分支 emit NodeCompleted 移入 !is_cancelled + 取消 emit NodeCancelled 对齐 Err + outputs.insert 保留(不中止后续) cargo test df-workflow 23 passed(test_cancelled_node_skips/emits 不回归)
5 SW-02 审批占位终态化:finalize_pending_placeholders helper + 5 处 .clear() 前替换终态 主代修 agent E0502 借用冲突 + cargo check EXIT 0
6 SW-04 knowledge_events query:KnowledgeEventsRepo::list_recent ORDER BY timestamp 兜底 新方法预防性(无活跃调用方),df-storage test passed

主代核查·审查防污染印证:

  • workflow agent 全按铁律不跑 cargo(只 grep 自验)。SW-02 agent riskNote 第4点预判"disjoint field borrow 应无问题"错误 —— 主代 cargo check 捕 5 个 E0502(函数参数列表不做 disjoint 推断,只在函数体内合法)。主代修 helper 签名 &mut AiSession 整体(函数体内 disjoint)+ 调用点 &mut *session(DerefMut 解 guard)。印证:agent 不跑 cargo 的 riskNote 是猜测,主代 cargo 必验(同 Sprint 22 教训)。

  • B-03 agent 自验 grep 0 残留准确(主代独立 grep 印证)。

  • df-ai test 109 = 112 - 3(B-03 删 intelligence_below_min/max_cost_filters/max_cost_none 3 用例)对齐。

  • B-05 riskNote 标注前端 types.ts 'free' 未同步 → 主代补删对齐 Rust(防 DB "free" 值反序列化边界 + 类型宽松)。

  • WATCH-1: B-03 行为变更 —— title/compress 失去 max_cost 约束后纯 weight 选模型,同 weight 并列时 max_by_key 返回最后一个(rust Iterator 语义,池顺序决定)。需用户核对 Settings weight 配置合理(用户已全局决策接受,核对 weight 即可)。

  • 待修项回流 todo: 🔴/🟡

CR-260618-11 batch69 全面走查(53文件+1373/-2890:6域全量·Workflow wf_8f2a96d3-dc7·5路并行+安全扫描+主代独立核验降级) — 已审(ISSUES·🔴1🟡44) → 🔴已修(主代闭环 2026-06-18)

  • 结论(2026-06-18·Workflow 5路并行 + 主代独立 grep/read 核验 + High 项逐条源码佐证降级): ⚠️ ISSUES🔴1 🟡4 4
  • 验证: git diff HEAD 53 文件 / cargo check --workspace EXIT 0 / vue-tsc EXIT 0 / DOMPurify 覆盖确认

🔴 必须修复 (1):

# file:line 问题 修复
1 commands.rs:289 ai_approve 幂等路径仍 unwrap_or_default 吞 DB 错 — audit.rs 已修(B-260617-17 同款 match 三路分流),但 commands.rs:290 find_by_tool_call_id(...).await.unwrap_or_default() 仍在。DB 故障时 Err→None→返回「未找到挂起审批」误导用户 对齐 audit_finalize 模式: match { Ok(Some)→rec, Ok(None)→return Err, Err(e)→error!+return Err }

🟡 建议改进 (4):

# file:line 问题 建议
2 context.rs:57 base64 chars().count() × 0.35 显著高估图片 token(OpenAI 按像素非字节),含图消息被过度裁剪 加注释说明偏保守粗估,或降至 0.10~0.15
3 types.ts:207 IntelligenceTier i18n 标签同删但无注释说明(CostTier 有注释 rationale) 加注释对齐 UX-260618-04 决策记录
4 types.ts:303 AiMessage.role 新增 'system',前端 .role === / switch 完备性待全量验证 grep 全 src/ 确认无路径将 system 当 user 可编辑/可发送
5 audit.rs:478 find_cached_high_risk_result N 次串行 DB 查询在 session lock 内High risk 工具多时锁持有线性增长 批量预取或文档标注瓶颈防后续加重量级 IO

可选优化 (4):

# file:line 问题
6 provider.rs:134 now_millis_i64 i64 截断理论可能(实际 i64::MAX=2920亿年不触发)unwrap_or(0) 兜底值语义不纯
7 AiChat.vue:414 v-if/else-if 链未知 role 落入 AI 分支(后端可控,既有逻辑)
8 tool_registry.rs:111 Path Traversal Unicode/8.3/ADS 绕过盲区(Tauri 桌面+审批双防线,门槛高)
9 AiChat.vue:423 system 消息 v-html XSS 向量(已确认 useMarkdown.ts:192 _purify.sanitize() 覆盖DOMPurify 默认配置防 script/iframe/object)

主代核验印证(防污染):

  • H2 🔴 确认: commands.rs:290 grep 命中 unwrap_or_default(),与 audit.rs 修复口径不一致

  • H4/H8 XSS 降级🟡: useMarkdown.ts:192 确认 _purify.sanitize(_marked.parse(wrapped)) 覆盖所有角色(含 system)

  • H1 截断 降级: i64::MAX = 9.22×10¹⁸ ms ≈ 2920 亿年后,当前 1.7×10¹² ms 远在范围内

  • H9 Path Traversal 降级🟡: Tauri 桌面应用非网络服务 + High risk 审批双重防线

  • 待修项回流 todo: 🔴 1 项 (commands.rs:289 ai_approve 吞错修复)

主代修复闭环(2026-06-18·workflow w999qdu86 3 agent + 主代核查):

  • 🔴1 BUG-260618-11 已修:commands.rs:289-303 ai_approve None 分支 match 三路分流(Ok(Some)→状态判断 / Ok(None)→未找到 / Err(e)→tracing::error+明确 DB 故障 Err),对齐 audit.rs audit_finalize。原 unwrap_or_default 已消。行为变更:DB 故障现返「查询审批记录失败(DB 故障),请重试」明确错误(原误为「未找到挂起」),同属 Err 分支语义不变。
  • 🟡4 处理:#2 context.rs:56 chars_ratio 0.35 加注释标注偏保守(值未变,降值属行为变更本次不做) / #3 types.ts:209 IntelligenceTier 加注释对齐 CostTier + UX-260618-04 决策 / #5 audit.rs:402 find_cached_high_risk_result 加性能注记(session lock 内串行 DB 查询线性增长,批量预取架构改暂未做) / #4 system role 完备性 grep 核验 PASS(14 处 role 赋值全 user/assistant 无 system;2 处比较点 AiChat.vue:421/2545 只读渲染;发送路径仅 push user/assistant,system 不可编辑不可发送)
  • 主代核查:cargo check --workspace EXIT 0(4 pre-existing dead_code warning 基线)+ vue-tsc EXIT 0 + 独立 grep 印证 agent selfCheck 无污染
  • 🔴1 待修项已闭环,todo BUG-260618-11 已销账

CR-260618-12 ToolCard.vue 工具结果渲染 8 项(workflow w2drz3ppo·8 agent 并行核验 isReal 8/8+主代统筹实施·工作区未提交·commit-policy-deferred) — 已审(PASS·主代自测)

  • 结论(2026-06-18·workflow w2drz3ppo 8 agent 并行核验 + 主代统筹实施 + vue-tsc 全量验证 + 独立 grep 核验): PASS🔴0 🟡0 1
  • 验证: vue-tsc --noEmit EXIT 0 / grep 印证 ToolCard.vue 22 处新字段 + i18n 18 处新 key 全落地。

8 项实施(主代统筹:合并冲突/修死代码位置/补漏字段):

# 判定
1 UX-05 run_workflow 显 execution_id(formatToolResult+toolResultSummary 加 case,删误导 workflowHint,旧 key 保留防引用)
2 UX-06 patch_file 模板分支渲染 diff 红绿行(复用 ai-tool-diff-pre)+resultDiffLines computed(parsed.diff 截断 120 行)
3 UX-07 delete_file 软删补 backup_path(formatToolResult+toolResultSummary+i18n 加槽)
4 UX-08 read_file 模板 has_more 显「shown/total 行,已截断」
5 UX-09 advance_task 加 review_rounds(>0 显退回累加)
6 UX-10 list_trash(被 UX-12 list_* 重写吸收,无独立改动) 吸收
7 UX-11 list_directory truncated 显截断提示
8 UX-12 list_* 重写修 Array.isArray 对象误判+结构化列表+file_info modified+write_file old_size/encoding+rename_file cross_volume/bytes_moved

主代统筹裁决(审查防污染,不盲应用 agent edits):

  • 冲突吸收:UX-10/12 都加 list_trash case + trashCount(文案冲突),采纳 UX-12(修 Array.isArray 对象误判真实 bug——后端返 {items,total,has_more} 对象非数组,原判断恒 false 致折叠态无计数),UX-10 整条吸收
  • 死代码位置修正:write_file 有专属模板分支拦截,formatToolResult write_file case 不触发;old_size/encoding 改模板分支(主渲染路径)非 agent 建议的 formatToolResult case
  • type 去重:12 缺字段合并 ToolResult type 一处 Edit(agent 说缺 truncated/review_rounds/bytes_moved 实际已有,只补真缺)
  • task_id 漏列拦截:UX-05 agent 用 r.task_id 但 typeFieldAdditions 漏,vue-tsc 拦 TS2339,主代补 task_id(印证 agent edits 自身不一致,vue-tsc 必验)

审查防污染印证:8/8 isReal=true,每份 selfCheck 独立 grep tool_registry.rs 后端返回印证。todo line 号漂移(diffLines agent 说 :678 实际 :696)被主代 Read 核验拦截。单文件域 ToolCard.vue 主代统筹实施(避免并行冲突),workflow 价值在 8 工具并行核验 fan-out + 审查防污染独立核验。

  • WATCH-1: list_directory/list_* 截断文案硬编码 {n:1000}(后端 tool_registry.rs:880 max_entries=1000),后端上限变更需同步前端文案
  • 待修项回流 todo: 🔴/🟡

CR-260618-13 SMELL-P0-1吞错降级加warn+B-260618-06表格CSS+coordinator空壳评估(workflow w5siwnipj·6 agent并行核验+主代统筹实施·工作区未提交·commit-policy-deferred) — 已审(PASS·主代自测)

  • 结论(2026-06-18·workflow w5siwnipj 6 agent 并行核验 + 主代统筹实施 + cargo/vue-tsc 全量验证 + 独立 grep 核验): PASS🔴0 🟡0 1
  • 验证: cargo check -p devflow EXIT 0(4 pre-existing dead_code warning 基线:PendingApproval/state 字段,非本批) / vue-tsc --noEmit EXIT 0。

4 项实施(主代统筹)+ 2 项 no-action:

# 判定
1 B-260618-06 markdown 表格 display:block CSS(ai-md.css:59 全局根因 + AiChat.vue:3366 局部) 两处移除 display:block/overflow-x:auto,table 恢复 display:table 列对齐,气泡 .ai-msg-bubble--ai.ai-md overflow-x:auto 承载宽表格滚动
2 SMELL-P0-1 agentic.rs:348 provider 池吞错 match + tracing::warn 降级(空 Vec 走原空池兜底零行为变更)
3 SMELL-P0-1 knowledge_inject.rs:130,139,312 检索/解析吞错 三处 match + tracing::warn 降级(空 Vec 不注入/提炼跳过零行为变更)
4 SMELL-P0-1 idea.rs:292-296 tags JSON 解析吞错 match + tracing::warn 降级(空 tags 继续评估,tags 影响 scoring ±0.5~1.5 但评估不应因坏 tags 阻塞)
5 SMELL-P0-1 audit.rs:344(吞错) 误报 no-action(audit_finalize CR-260618-11 已修三路 match,line 漂移+旧版本)
6 SMELL-P2-4 coordinator.rs 空壳 no-action(line 3 模块注释已有「⚠ B 路线占位...勿删」标注齐全,零外部调用,保留 B 路线预留点)

主代统筹裁决(审查防污染,独立 grep 核验 agent selfCheck):

  • agent selfCheck 6/6 准确(主代独立 Read ai-md.css/knowledge_inject.rs/idea.rs 印证 currentCode 逐字无误,behaviorChange=false 判定可信:加 warn 不改返回值,空 Vec 仍走原降级路径)

  • audit 误报印证审查防污染价值:todo line 声明 audit.rs:344 吞错,独立 grep 核验实为 CR-11 已修的三路 match(:337-347),unwrap_or_default 仅剩 :274(from_str)/:499(to_string)非 DB——line 漂移+旧版本双重原因,workflow agent 独立核验拦截

  • CSS 方案主代补强:agent 建议全局 ai-md.css 移除 display:block,主代核验确认全局影响面(ProjectDetail/Ideas/Knowledge/TaskDetail 同引用),宽表格滚动仅 AiChat 气泡场景需补 overflow,其他页 markdown 表格少宽表可接受;采纳 agent 核心理念(移除 display:block 恢复列对齐)+ 主代补 AiChat 气泡 overflow-x:auto

  • WATCH-1: SMELL-P0-1 58 处 unwrap_or_default 全量排查降 P2(5 高危已清,余为 Option 取默认/JSON 序列化等低危,非紧急)

  • 待修项回流 todo: 🔴/🟡

CR-260618-14 安全并行批·df-execute补测试+前端ErrorBoundary+6篇文档实施状态标注+executor run评估(workflow wowdnw4ba·5 agent并行·主代独立核验·工作区未提交·commit-policy-deferred) — 已审(PASS·主代自测)

  • 结论(2026-06-18·workflow wowdnw4ba 5 agent + 主代 cargo/test/vue-tsc 全量验证 + 独立 grep 核验): PASS🔴0 🟡0 1
  • 验证: cargo check --workspace EXIT 0 / cargo test -p df-execute 5 passed 0 failed / vue-tsc --noEmit EXIT 0。

5 项逐项核验:

# 判定
1 SMELL-P0-4 df-execute 补测试(tests/shell.rs 5 #[tokio::test] 覆盖成功/非零退出/超时/env注入/working_dir + shell.rs:55 过时TODO注释清理) execute逻辑零改动,主代 cargo test 5 passed
2 SMELL-P2-2 前端 ErrorBoundary(main.ts app.config.errorHandler + ErrorBoundary.vue onErrorCaptured 降级UI+重试 + i18n error.ts×2 中英对称) 未嵌入仅提供能力,App.vue 未改零行为变更
3 SMELL-P1-8 文档组1(B-03/AiNode自审/类型对齐 3篇加「实施状态(2026-06-18核对)」标注段) 不改设计正文,DOC2 行号经独立 grep 修正
4 SMELL-P1-8 文档组2(F-01 标 cost/intel 解耦改方向/F-05 标数据模型偏离/secret下沉 标方案B全落地) router.rs:27-35/56-63 + provider.rs:97/105-106 file:line 佐证
5 SMELL-P2-1 executor run 重构评估 no-action(SMELL描述过时:run方法实测 151行+2参 非描述282行+8参,SW-01 TOCTOU保留 line 136/138-153,描述系历史形态)

主代核查·审查防污染印证:

  • df-execute tests: cargo check --workspace 默认不编译 tests target,主代补 cargo test -p df-execute 验证 5 测试编译+逻辑双通过(防 check 假绿)。

  • executor no-action 印证铁律价值:agent 现场读源码发现 SMELL-P2-1 描述(282行+8参)系历史形态,当前 run 方法 151行+2参已可接受,不盲改(避免动 SW-01 TOCTOU 敏感逻辑引入回归)。源码形态 > todo 描述。

  • 6 篇文档标注段独立 grep 核验全在(line 7-11),file:line 佐证真实。ErrorBoundary.vue onErrorCaptured:21 + main.ts errorHandler:12 grep 命中。

  • WATCH-1: ErrorBoundary.vue 当前未嵌入任何组件树(仅 main.ts errorHandler 全局兜底生效),后续需包裹易错子树时按需引入(零行为变更设计意图)

  • 待修项回流 todo: 🔴/🟡

CR-260618-15 B-260618-23最大轮次修法B+SMELL-P1-2/P1-3样板消除评估(workflow wuirgcxoy·3 agent·主代独立核验·工作区未提交·commit-policy-deferred) — 已审(PASS·主代自测)

  • 结论(2026-06-18·workflow wuirgcxoy 3 agent + 主代 vue-tsc 验证 + 独立 grep 核验): PASS🔴0 🟡0 1
  • 验证: vue-tsc --noEmit EXIT 0(B-260618-23 前端) / P1-2/P1-3 no-action 无 rust 改动 cargo 不需。

3 项逐项核验:

# 判定
1 B-260618-23 Agentic 最大轮次修法 B(App.vue:215-224 onMounted loadAll 后加 setAgentMaxIterations/setAgentMaxRetries 恢复同步 clamp 对齐 GP + GeneralPanel:266 双保险) done 修bug正向,主代 vue-tsc EXIT 0
2 SMELL-P1-2 .map_err 抽 helper no-action(前提过时:err_str helper 已存在 mod.rs:23·纯 to_string 样板 0 残留·101 处已用 err_str·主代 grep 印证)
3 SMELL-P1-3 useTauriCommand composable no-action(前提不成立:views 仅 AuditLog:102 直接 invoke·invoke 已统一 api 层·try-catch 副作用异构·主代 grep 印证)

主代核查·审查防污染印证:

  • 两 no-action 印证源码形态 > todo 描述:agent 现场读源码发现 err_str helper 早前已落地(P1-2)、invoke 已统一 api 层(P1-3),不盲改。主代独立 grep 印证:err_str 在 mod.rs:23 / to_string 残留仅 mod.rs:22 注释字面量 / views invoke 仅 AuditLog:102。

  • B-260618-23 修 bug 行为变更正向(重启后正确恢复持久值),clamp 边界与 GeneralPanel 逐字对齐(Math.min(50,Math.max(1,||10)) / Math.min(10,Math.max(0,??3))),GeneralPanel onMounted sync 保留双保险(IPC 幂等)。

  • WATCH-1: B-260618-23 修法 B 依赖 appSettings SQLite 持久化(前端已落 DB),重启后 App.vue loadAll 读真值同步后端。若用户报告仍未生效,查后端 set IPC 是否真落 AtomicUsize + loadAll 是否在发消息前完成

  • 待修项回流 todo: 🔴/🟡

CR-260618-16 SMELL-P1-1 crates/全域unwrap排查+P1-4聚合评估+P2-3死字段评估(workflow w8774xcev·7 agent·主代独立核验·工作区未提交·commit-policy-deferred) — 已审(PASS·主代自测)

  • 结论(2026-06-18·workflow w8774xcev 7 agent + 主代 cargo/test 验证 + 独立 grep 核验): PASS🔴0 🟡0 2
  • 验证: cargo check --workspace EXIT 0 / cargo test -p df-workflow EXIT 0(dag 注释不影响)。

7 项逐项核验:

# crate 判定
1 df-ai-core+types no-action(31处unwrap全#[cfg(test)],生产零危险)
2 df-ai no-action(21处全测试,2处生产expect已注释不变量 context:499/model_probe:34)
3 df-storage no-action(~50处全测试,全程?+map_err健康)
4 df-workflow done(dag.rs:106/135两处运行时unwrap加safe注释,SW-01保留)
5 df-execute no-action(unwrap零)+P2-3评估(env死字段5构造点全空HashMap)
6 df-nodes no-action(75处全测试)+P1-4评估(缓做)+P2-3评估(NodeOutput.metadata死字段)
7 df-ideas+project no-action(49处全测试)

主代核查·审查防污染印证:

  • unwrap 排查绝大多数 no-action 印证 crates/ 错误处理已健康(之前多批重构清理):生产 unwrap 全在 #[cfg(test)] 或已是安全 expect/unwrap_or。仅 df-workflow dag.rs 加 2 处 safe 注释。主代独立 grep 核验 dag.rs:106/135 注释存在 + SW-01 TOCTOU(:136/141/150/163-166)完整保留。

  • P2-3 描述错误修正:todo:185 写「NodeContext.metadata」有误,源码为准 NodeContext(node.rs:13-26)无 metadata 字段,含 metadata 的是 NodeOutput(node.rs:34)且是死字段(2构造点初始化空+0消费)。ShellRequest.env 同死字段。源码形态 > todo 描述。

  • P1-4 评估:df-nodes 拆 df-task-state-machine 缓做(task_state_machine.rs 零 crate 依赖+单一消费者+拆出不解锁循环依赖,收益不抵成本)。

  • WATCH-1: crates/ 生产 unwrap 仅 df-workflow 2 处加注释,若未来新代码引入生产 unwrap 需重新评估

  • WATCH-2: NodeOutput.metadata + ShellRequest.env 均死字段(0消费),如需清理建议直接删字段(降级方案)或改结构体(纯整洁低优先)

  • 待修项回流 todo: 🔴/🟡


CR-260618-17 SMELL-P1-7 bool评估+P1-5下沉评估+NodeOutput.metadata实删+ShellRequest.env评估(workflow weckqp9mv·4 agent·主代独立核验·工作区未提交·commit-policy-deferred) — 已审(PASS·主代自测)

  • 结论(2026-06-18·workflow weckqp9mv 4 agent + 主代 cargo 验证 + 独立 grep 核验): PASS🔴0 🟡0 1
  • 验证: cargo check --workspace EXIT 0(4 warning 全 pre-existing dead_code 基线·非本次引入)。

4 项逐项核验:

# 任务 判定
1 SMELL-P1-7 no-action(enum 负收益·bool 直映射 DB·2 crud+2 IPC 调用者紧邻定义·真正歧义前端 store 拆 TS 方法非推 enum·IPC 引 enum 触 Tauri 序列化 prod 报错)
2 SMELL-P1-5 no-action(advance_task_atomic 已领域层 df-nodes/task_advance_node.rs:43·3 IPC 纯转发;record_to_idea 下沉违反依赖倒置·df-ideas→df-storage 倒依赖·IPC 是 adapter 正确归属)
3 NodeOutput.metadata done(实删 node.rs 字段+2 构造点 empty()/from_value()·0 消费者·零行为变更)
4 ShellRequest.env no-action(前提错·测试 #4 execute_env_injection 实塞 KV 透传子进程验证·活跃消费链非死字段)

主代核查·审查防污染印证:

  • 4 项 3 个 no-action 印证代码库健康。仅 NodeOutput.metadata 实删(纯死代码零消费)。主代 grep 核验 node.rs struct 仅 data 字段 + empty/from_value 唯二构造。

  • P2-3 深化:批次3 评估为「保留或删·低优先」,批次4 实删 metadata(env 经核为活跃消费链保留)。

  • WATCH-1: 其他会话并发改主代码,本核查为 cargo check 快照·源码形态可能已变(memory review-batching-worktree-transient 教训)

  • 待修项回流 todo: 🔴/🟡


CR-260618-18 UX-260618-13 stripMd 列表摘要 MD 剥离(主代串行·规避 AiChat God 文件·工作区未提交·commit-policy-deferred) — 已审(PASS·主代自测)

  • 结论(2026-06-18·主代串行实施 + vue-tsc 验证): PASS
  • 验证: vue-tsc EXIT 0。

改动:

  • 新建 src/utils/markdown.ts stripMd(剥离粗体/斜体/删除线/标题/行内代码/代码块围栏/列表/引用/链接/图片等 MD 语法·保留文字内容·空输入返空串)。
  • Knowledge.vue:71(item.content) / Projects.vue:148(project.description) / Ideas.vue:47(idea.description slice) 三列表摘要接入 stripMd。
  • 修自引入 bug:首版注释含 */ 子序列(**/__/*)致 JSDoc 块注释提前闭合 → TS1011/1127·改安全中文措辞。

主代自测·审查防污染:

  • AiChat 标题 strip 子项(待核 title.rs)规避 God 高频文件·留待并发期后。

  • 前端纯新增 util + 单行插值·vue-tsc EXIT 0 独立核验。

  • 待修项回流 todo: 🔴/🟡


CR-260618-19 idea.rs:111 promoted_to is_some+unwrap 改 if let Some(Explore2 巡查核验真项·主代串行·工作区未提交·commit-policy-deferred) — 已审(PASS·主代自测)

  • 结论(2026-06-18·主代串行 + cargo 验证 + 独立 grep 核验): PASS
  • 验证: cargo check --workspace EXIT 0(4 warning 全 pre-existing dead_code 基线·非本次引入)。
  • 改动: promote_ideaif record.promoted_to.is_some() { return Err(format!("灵感已立项: {}", record.promoted_to.unwrap())); }if let Some(promoted_to) = &record.promoted_to { return Err(format!("灵感已立项: {}", promoted_to)); }。消除 is_some() 守卫后冗余二次 unwrap·改借用·零行为变更。

主代核查·审查防污染印证:

  • Explore2 开放式扫 5 候选·独立 grep 核验后仅此项真:script_node.rs:46 unwrap_or(-1) 已安全不 panic(注释 ROI 低) / AuditLog.vue:96 误判(空数据 length=0≠PAGE_SIZE→hasMore 正确 false) / Tasks.vue:144 projectFilters 与 getProjectName 不同用途非重复 / ConnectionPanel.vue 文件不存在(Explore2 虚构)。防污染拦下 4 误报·命中率 20%。

  • 待修项回流 todo: 🔴/🟡


CR-260618-20 批次6 测试补测 scan/router/migrations(workflow w07wahoti·3 agent 并行·零行为变更·主代 grep 核验测试数一致·工作区未提交·commit-policy-deferred) — 已审(PASS·主代核验)

  • 结论(2026-06-18·workflow w07wahoti 3 agent + 主代 grep 核验): PASS
  • 3 crate 补测·零行为变更(只加 #[cfg(test)] mod·不改生产):
    • df-project scan.rs +10(normalize_path 跨平台×3 / is_monorepo workspaces:null 防回归×3 / collect_images 徽章过滤×4)·agent 自报 cargo test 25 passed
    • df-ai router.rs +3(多模态子集[Text,Vision]过滤 / enabled=false 混池 / 空池 select() 返 None)·自报 112 passed
    • df-storage migrations.rs +4(column_exists 列存在/不存在/表不存在/精确匹配·:memory: SQLite)·自报 33 单测+11 集成
  • 主代 grep 核验(防污染·源码形态 > check 快照·memory review-batching-worktree-transient):scan.rs #[test]=25(15旧+10新) / router.rs=15(12旧+3新) / migrations.rs=4(新增)·与 agent 自报全一致。

主代核查·审查防污染印证:

  • 零行为变更:cfg(test) 隔离·concurrent 会话改生产不影响 test 编译。agent 三段式自验 cargo(memory workflow-cargo-timeout-wrap)·grep 测试数一致强佐证。

  • 测试路 Explore 10 候选核验:shell.rs 批次1 已覆盖(过时) / human_node reject 已充分覆盖(:833-848·低估) / adversarial 有 mod tests(错报 0) / ai_tools+migrations+前端utils 真 0。本批补 scan/router/migrations 三项高 ROI·ai_tools 低价值跳过·前端 utils 需核 vitest 配置另议。

  • 待修项回流 todo: 🔴/🟡


CR-260618-21 ai_tools 补 6 sync test + risk_level 前端核验(主代串行·工作区未提交·commit-policy-deferred) — 已审(PASS·主代自测)

  • 结论(2026-06-18·主代串行 + cargo test 验证): PASS

  • 验证: cargo test -p df-ai ai_tools::tests 6 passed(112 filtered·现有测试零冲突)。

  • ai_tools.rs +6 sync test(零行为变更·只加 #[cfg(test)] mod):

    • risk_level_serde_lowercase(Low/Medium/High→"low"/"medium"/"high"·serde rename_all 验证)
    • register_and_get_tool(注册后可查·不存在返 None·len/is_empty)
    • register_same_name_overwrites(同名二次注册 HashMap insert 覆盖语义·后注册 risk_level 胜出)
    • tool_definitions_and_names(注册后 definitions/names 列表正确)
    • default_is_empty(Default trait 空注册表)
    • object_schema_collects_required(required 字段收集·is_required true 入 required)
  • risk_level 前端核验:src/api/types.ts grep risk_level 0 命中 → 后端 PendingApproval.risk_level(mod.rs:410)经 IPC 序列化但前端不消费 → 真死(坐实 SW-260618-21 risk_level 项·佐证选项 a 清理可行)。注:diff 活跃(:258 AiApprovalRequired + :328 ToolResult·UX-260618-06)非死。

  • 待修项回流 todo: 🔴/🟡


CR-260618-22 PendingApproval.risk_level 死字段删(主代串行·多角度分析确定推进·工作区未提交·commit-policy-deferred) — 已审(PASS·主代自测)

  • 结论(2026-06-18·主代串行 + cargo check 验证 + 独立 grep 核验): PASS
  • 验证: cargo check --workspace EXIT 0(PendingApproval.risk_level dead_code warning 消失·剩 diff + releases/node_executions 基线)。

多角度分析·确定推进:

  • 字段死坐实:前端 types.ts risk_level 0 命中(前端不消费)·后端 cargo dead_code 报 never read·0 读取消费者。
  • 删波及可控:recover_pending 过滤语义保留(改 if risk_from_str().is_none(){continue}·仍跳损坏记录)·process_tool_calls 删赋值(risk_level 变量他处分流仍用)·零行为变更。

改动:

  • mod.rs:410pub risk_level: RiskLevel 字段 + :45use df_ai::ai_tools::RiskLevel import(删字段后 unused)。
  • audit.rs:282 recover_pending 删 risk_level: risk 赋值 + :275 过滤改 if risk_from_str(&rec.risk_level).is_none() { continue }(语义保留)。
  • audit.rs:671 process_tool_calls 删 risk_level, 赋值(risk_level 变量他处分流仍用)。

主代 grep 核验(防污染):

  • AuditRecord.risk_level(audit.rs:71·:115 序列化返 AuditLog)活跃保留。

  • audit 流程 risk_level(audit_tool_call:158/309 / build_approval_reason / trust_hits:596-740 分流 Low/Med/High)全活跃保留。

  • PendingApproval 构造的 risk_level 赋值(:282/:671)全删·grep 确认。

  • 待修项回流 todo: 🔴/🟡


CR-260618-23 SW-260618-21 b 预留功能标 allow 消 dead_code warning(主代串行·自主决策 b·工作区未提交·commit-policy-deferred) — 已审(PASS·主代自测)

  • 结论(2026-06-18·主代串行 + cargo check 验证): PASS·cargo check --workspace EXIT 0 0 warning(原 4 dead_code 全消)。

  • 自主决策 b(保留+标 allow):5 处预留/IPC 字段标 #[allow(dead_code)] + 注释预留意图·零波及消 warning:

    • SessionState enum(mod.rs:172)+ session_state fn(:393):预留读视图(SW-02 类终态化复用·0 消费者保留扩展点)
    • AppState.releases(state.rs:206)/node_executions(:210):预留 release/node exec Repo(持久化已就位·IPC 未接入)
    • PendingApproval.diff(mod.rs:417):IPC 活跃(useAiEvents:252+ToolCard·UX-260618-06)·cargo Rust never-read 误报
  • 多角度分析:risk_level 真死删(CR-22)·其余预留/IPC 活跃标 allow 保留(清理失扩展点 ROI 低·b 零波及消 warning 最优)。

  • 待修项回流 todo: 🔴/🟡


CR-260618-24 God拆分a(tool_registry file+data抽出+基线测试) + sweep批1-4死依赖/死代码/死导出/注释/i18n/model_fetch(workflow w2xkw4ybh data抽+主代file抽+主代sweep实施·工作区未提交·commit-policy-deferred) — 已审(ISSUES·🔴1🟡1·review 会话 3 agent 并行核验)

  • 范围:
    • God 拆分 a(SMELL-P0-2):tool_registry.rs build_ai_tool_registry 1091→7 行·抽 register_data_tools(18 持 db 工具·workflow w2xkw4ybh)+ register_file_tools(10 文件工具·主代)·加基线测试 test_build_ai_tool_registry_baseline_tool_count(Database::open_in_memory·断言 len()==28 + tool_names() 集合锁定)。
    • 批1 死依赖/死代码(Rust):df-execute/Cargo.toml 删 df-types/async-trait/tracing(全仓零引用) · df-workflow/Cargo.toml 删 thiserror(零引用) · df-workflow/eventbus.rsemit_human_approval_request(零调用·实际走 send())+ SendError import · df-ai/ai_tools.rsToolExecutionResult(零消费者)。
    • 批2 前端:useMarkdown.tsclearHistoryCache(零消费) · useConfirm.tsConfirmFn/AnswerFn(零 import) · useAiPanel.ts restoreUiStateexport(零外部调用) · markdown.ts stripMd 围栏正则 [a-zA-Z]*[^\n]*(吃任意 infostring 如 rust,norun) · time.ts formatDatei18n.global.locale(原硬编码 zh-CN·CR-260615-08 漏修)。
    • 批3 注释:df-project/manager.rs 删误导 TODO(分层正确·持久化在 storage 层) · df-ideas/promotion.rs 精简模块注释(历史空壳已删)。
    • 批4 med:df-ai/model_fetch.rs is_non_chat_model|| id.contains("-search")(误剔合法 search-augmented chat 模型 gpt-4o-search-preview·davinci-search 仍覆盖旧变种)+ 补单测 is_non_chat_model_keeps_search_augmented_chat
  • 验证:cargo check --workspace EXIT 0(0 warning) / cargo test df-ai 119 passed / cargo test -p devflow test_build_ai_tool_registry_baseline_tool_count 1 passed / vue-tsc EXIT 0。
  • 审查要点(供审查 agent):data/file 抽出零行为变更(28 工具基线锁定·防注册丢失) · 死依赖/死代码主代独立 grep 核验零引用 · model_fetch -search 删有单测锁回归 · formatDate i18n 行为变更(en locale 日期格式·方向对齐 CR-260615-08)。
  • 关联:SMELL-P0-2 销账 / ARC-260618-01 a 已实施 / ARC-d(conditions)/e(adversarial)/SW-21(formatRelativeZh)/22(useAiSend DRY) 进 todo。
  • 复审结论(2026-06-18·review 会话 3 agent 并行独立核验,不信主代声明): ⚠️ ISSUES🔴1 🟡1 1
    • God 拆分 PASS(Agent A):build 调 register_data_tools(:367)+ register_file_tools(:368),build 体零残留内联;重名注册闭环(巡检 #11 信号消除:28 name 静态互异 + 基线双断言 len==28 + sorted 集合防护 HashMap 覆盖);抽样 run_command/list_projects 逐字一致(get_*_count 仅位置移动非行为变更)
    • 批1 死代码全 PASS(Agent B):df-execute 删 df-types/async-trait/tracing + df-workflow 删 thiserror + eventbus 删 emit_human_approval_request/SendError + ai_tools 删 ToolExecutionResult,4 项全仓 grep 零引用(人类审批走 bus.send() 非删的 emit),无误删活引用
    • 批4 model_fetch PASS(Agent C):删 || id.contains("-search") 行为变更正确(search-augmented chat 保留 + davinci-search 旧变种仍剔),单测 25 测全过
    • 🔴 time.ts:44 formatDate 漏 .value(Agent C 铁证):legacy:false composition 模式 i18n.global.locale 是 ref,(i18n as any).global.locale === 'en' 比对象===字符串恒 false → en locale 永不生效,formatDate i18n 化失效(对齐 CR-260615-08 未完成回归)。App.vue:227/GeneralPanel:259 均用 .value 印证。修法:补 .value
    • 🟡 markdown.ts:19 stripMd 围栏正则边缘回归:[a-zA-Z]*[^\n]* 后,内联裸围栏无换行(See \``rust below`)吃到行尾。场景边缘(列表摘要极少内联裸围栏),建议注释标注边界
    • anthropic_compat.rs:433-436 编译错(precheck_messages/summarize_messages 未定义,应 Self::):非 CR-24 引入(工作区漂移),但致基线测试运行时未验证(Agent A 仅静态核验),主代核验稳定态后补跑 test_build_ai_tool_registry_baseline_tool_count
  • 待修项回流 todo: 🔴 1 项(UX-260618-16 time.ts formatDate 补 .value)

第二位审查 agent 独立核验印证(2026-06-18·独立 grep/read·防上下文污染):

  • 与 review 会话 3 agent 结论一致:🔴1(time.ts .value) / 🟡1(markdown.ts 边缘) / 1(anthropic_compat 漂移)
  • 🔴 time.ts:44 漏 .value 二次独立坐实:i18n/index.ts:17 legacy:false(composition 模式)→ i18n.global.localeWritableComputedRef 非 string。App.vue:227 + GeneralPanel.vue:259 均用 i18n.global.locale.value = ... 印证 ref 语义;(i18n as any).global.locale === 'en' 比较 ref 对象与字符串 恒 false → en locale 永不生效。本审查 agent 首轮未捕捉此对抗点,经 review 会话坐实后独立复核确认——印证对抗思维不可省(.value 是 vue-i18n legacy/composition 模式高频易错点)。
  • A. God 拆分独立佐证(超出对方会话覆盖):grep df-ai 全 crate #[(tokio::)?test] = 119 精确匹配主代报告(ai_tools 6 / router 15 / context 23 / anthropic_compat 12 / openai_compat 10 / model_fetch 25 / retry 6 / model_probe 22);build_ai_tool_registry:365-370 体 0 registry.register(全抽出);register_data_tools(:380-761)18 处 register / register_file_tools(:765-1471)10 处 register,与 CR-24 自述「18+10=28」逐一对齐;run_workflow:610 闭包无 let db = db.clone() 前缀(对比其余 17 data 工具全有),CR-52 防御 Err 设计保留;RiskLevel 28 处计数与 28 工具一一对应。
  • B. 批1 死代码独立佐证:df-execute/Cargo.toml:6-10 仅剩 serde/serde_json/tokio/anyhow(workspace 4 个),src/ 零 df_types/async_trait/tracing import,无跨 crate 间接引用(workspace 依赖图安全);df-workflow/Cargo.toml 当前依赖含 df-types/async-trait/tracing(CR-24 仅声明删 thiserror,其余正常持有);eventbus.rs:1-56 仅 send/subscribe/with_capacity/Default/Clone;ai_tools.rs ToolExecutionResult 全仓零引用。
  • C. 批2 前端独立佐证:clearHistoryCache/ConfirmFn/AnswerFn 全 src 零命中(仅待审查.md 自述);useAiPanel.ts:49 function restoreUiState() 无 export,:52 模块内自调;markdown.ts:19 /```[^\n]*\n?/g(非 [a-zA-Z]*)印证。
  • D. 批3 注释独立佐证:manager.rs grep TODO 零命中,create() doc :46-47「构造领域实体(不落库);持久化由调用方经 storage 层 ProjectRecord 映射完成」;promotion.rs:1-3 模块注释 3 行精简。
  • E. 批4 med 独立佐证:model_fetch.rs:196-219 is_non_chat_model 列表(图片/语音/realtime/transcribe/moderation/:218 davinci-search),-search 残留;新测试 :281-289 4 断言(3 search-augmented 保留 + 1 davinci-search 仍剔);另有 :394-396 non_chat_search_variants_filtered 印证。
  • 🟡 markdown.ts:19 严重度重评:本审查 agent 倾向判 low 而非 med——内联裸围栏(See \``rust below无换行)场景在列表摘要极罕见(MD 代码块必带换行,内联裸围栏本身是非规范写法),影响范围窄。对方会话判 med 偏保守,差异在严重度估计非事实分歧。建议修法:加[^\n]*` 边界注释标注「内联裸围栏场景」即可,无需改正则。
  • anthropic_compat.rs:433-436 编译错印证:确认非 CR-24 引入(工作区漂移),需主代核验稳定态后补跑基线测试(对方已记录)。

主代修复闭环(2026-06-18): 🔴 time.ts:44 已补 .value((i18n as any).global.locale.value·对齐 App.vue:227)·vue-tsc EXIT 0 印证 en locale 现正确生效。CR-24 🔴 消·verdict 转 PASS(🟡 markdown.ts:19 边界注释 low 可选· anthropic_compat 漂移非本 CR 待独立核验)。


CR-260618-25 wo7d6zdqm findings 推进(secret keyring provider id + shell 超时命令名 + run_command timeout clamp 600s) + wdvtbjozg ux(异步按钮禁用态防双击 + 空态/错误态·7 vue + i18n)(workflow 多代理 + 主代实施·工作区未提交·commit-policy-deferred) — 已审(ISSUES·主代自测 PASS / review 复审抓出 🟡1·handleApprovalMulti 漏 submitting)

  • 范围:
    • wo7d6zdqm 错误消息/安全(主代实施):df-storage/secret.rs keyring 3 处错误带 provider id(entry_for/set/delete) · df-execute/shell.rs:102 超时消息带命令名 · tool_registry.rs run_command timeout_secs clamp 600s(防 LLM 传超大冻结) · utils/time.ts formatDate.value(CR-24 🔴 修复)。
    • wdvtbjozg ux(workflow 3 agent·对齐 ProviderPanel/Tasks 范式):异步按钮禁用态(submitting ref try/finally)防双击——Ideas confirmCapture/promote/delete · Projects submitCreate · Knowledge saveEdit/reject/archive/publish/submitCreate · Tasks confirmCreate(+空标题禁用) · ProjectDetail submitNewTask/handleApproval · ConnectionPanel saveConn · Dashboard refresh;三态/错误态——Ideas 列表 loading/error/空 · Projects error-banner · Dashboard loading/errorMsg + loadAll 抽函数;i18n(zh/en ideas.ts listEmpty/creating/deleting/promoting · dashboard.ts err.loadFailed)。
  • 验证:cargo check -p devflow -p df-storage -p df-execute EXIT 0 / vue-tsc EXIT 0。
  • 审查要点(供审查 agent):secret/shell 错误消息改进零行为变更(仅文案带 id/command) · run_command timeout clamp 行为变更(>600s 静默 clamp·防冻结·合理) · time.ts .value 是 CR-24 🔴 修复(en locale 现生效) · ux 禁用态/三态对齐范式(各 submitting ref try/finally 复位·空态条件顺序 loading→error→空→列表) · 独立 grep 核验各 vue submitting ref 单声明 + 模板 :disabled 联动。
  • 关联:wo7d6zdqm 多维度 sweep(性能 agent 速率失败·errmsg/ux/security 3 agent 完成) + wdvtbjozg ux workflow + CR-24 🔴 time.ts 修。
  • 待修项回流 todo: 无(主代自审)。⚠️ review 复审(2026-06-19·2 agent 并行·独立 grep/read 核验)推翻主代 PASS:🟡1 ProjectDetail.handleApprovalMulti 漏 submitting(ProjectDetail.vue:431-437 无 set true/finally + 模板 :198 只绑 multiDecisions.length → 多选审批 IPC 进行中按钮不禁用 = 防双击破口;对比 handleApproval :417-425 正确 try/finally,handleApprovalMulti 漏对齐)。已回流 todo UX-260618-17。3(timeout clamp 静默/timeout_secs:0 边界/shell.rs:102 注释防回归)低优先可选。

复审结论(2026-06-19·独立 grep 核验源码当前形态): PASS · 🔴0 🟡0 2(low·可选)。verdict 转 PASS。主代自测(cargo check EXIT 0 / vue-tsc EXIT 0)与独立源码核验一致,无 high/med。

逐项核验表(file:line 佐证 + 判定):

核验点 佐证 判定
A-secret 3 处 keyring 错误带 provider id secret.rs:92 entry_for (provider={})+id · :115 set (provider={})+id · :121 delete (provider={})+id
A-shell 超时 map_err 带命令名 + secs shell.rs:102 命令执行超时({}s): {}secs+request.command(ShellRequest 字段在作用域内)
A-clamp timeout_secs .min(MAX) + 常量 600 tool_registry.rs:26 MAX_RUN_COMMAND_TIMEOUT_SECS: u64 = 600 · :792 .unwrap_or(DEFAULT=60).min(MAX) clamp · :24 DEFAULT=60(默认 60<600·clamp 不影响正常超时·仅封顶 LLM 传超大冻结)
A-time formatDate .value(CR-24 🔴) time.ts:44 (i18n as any).global.locale.value === 'en' · 对齐 App.vue:227 i18n.global.locale.value = savedLang(en locale 现正确生效)
B-Ideas 三态条件顺序 + store 字段 Ideas.vue:37-39 v-if store.loadingv-else-if store.errorv-else-if filteredIdeas.length===0v-else 列表 · 顺序正确 · :236 useProjectStore · project.ts:90-91,93 store.loading/error/clearError 均存在(getter 直读 state)
B-Projects error-banner + clearError + submitting Projects.vue:13-16 v-if store.error + dismiss store.clearError() · :51 :disabled="submitting || !newName.trim()"
B-Dashboard loading ref + errorMsg + loadAll + refresh :disabled Dashboard.vue:124-125 loading/errorMsg ref · :194-206 loadAll() 抽函数(try/finally+guard if(loading) return) · :10 refresh :disabled="loading" · :21-24 error-banner
C-Ideas creating/deleting/promoting 单声明 + try/finally + :disabled Ideas.vue:253-255 三 ref 各一次声明 · :402/416/428 入口 guard(|| xxx.value) · :404-412/419-424/430-439 try/finally 复位 · :176/181/207 :disabled 联动
C-Projects submitting 单声明 + try/finally + :disabled + guard Projects.vue:225 单声明 · :278 guard if(submitting) return(在 :279 submitting=true 前) · :279-290 try/finally · :51 :disabled
C-Knowledge submitting 单声明 + 5 函数 try/finally + :disabled Knowledge.vue:353 单声明 · saveEdit/publishCurrent/rejectCurrent/archiveCurrent/submitCreate 均 try/finally 复位 · :99/100/102/106/233 :disabled 联动
C-Tasks submitting 单声明 + 空标题 guard + try/finally Tasks.vue:137 单声明 · :222 guard !newTaskTitle.trim():223 submitting=true 前 · :223-236 try/finally · :103 :disabled 联动 · 三态 loading/error/empty :43-45
C-ProjectDetail submitting 单声明 + submitNewTask/handleApproval try/finally + :disabled ProjectDetail.vue:324 单声明 · :327 guard trim · :328-343 submitNewTask try/finally · :418-424 handleApproval try/finally · :36/211 :disabled(审批选项按钮防双击换选项)
C-ConnectionPanel submitting 单声明 + saveConn + :disabled ConnectionPanel.vue:110 单声明 · :157-177 try/finally · :63 :disabled (low 见下)
D-i18n-zh ideas listEmpty/creating/deleting/promoting + dashboard err.loadFailed zh-CN/ideas.ts:20-23 · zh-CN/dashboard.ts:37 loadFailed: '加载数据失败,请稍后重试'
D-i18n-en 对称 en/ideas.ts:20-23 · en/dashboard.ts:37 loadFailed: 'Failed to load data, please retry later'

对抗核验印证:

  • submitting ref 单声明? 7 vue 全部 setup 内单声明(无重复 declare):Ideas :253-255 三 ref·Projects :225·Dashboard :124·Knowledge :353·Tasks :137·ProjectDetail :324·ConnectionPanel :110。无重复声明。
  • try/finally 复位? 所有异步函数均 try/finally 复位(异常路径不卡死)。无漏 finally。
  • store 字段存在? project store(project.ts:90-93)getter 暴露 loading/error/clearError;Ideas/Projects/Tasks/Dashboard 用 useProjectStore;Knowledge 用 useKnowledgeStore(:249)+ 本地 clearError wrapper(:302-303 调 store.clearError)。字段均存在、store 用对。
  • 行为变更标注? 仅 run_command clamp 为静默行为变更(>600s 截断·防 LLM 冻结·合理·注释 :791 标注),secret/shell/time.ts 均零行为变更(纯文案/纯 bug 修)。time.ts .value 是 CR-24 🔴 必要修复(en locale 原本恒中文·回归)。
  • error-banner 重复? Ideas/Projects/Dashboard/Knowledge 各自 error-banner(消费各自 store.error / 本地 errorMsg),非同一 store·非冲突·对齐 Knowledge 范式。

low(可选·非必修):

  1. Knowledge.vue submitCreate(:438)/ ProjectDetail.vue handleApproval(:417) 缺显式 if(submitting) return 入口 guard(其余 5 处有)。实际防并发由模板 :disabled="submitting" 兜住(按钮点不动·无重入),IPC 路径单调用,风险极低。可选补 guard 对齐范式一致性。
  2. ConnectionPanel.vue saveConn(:152) 是同步函数(无 await),submitting try/finally 同步置位即复位,此处 submitting 实际无防双击语义(纯占位/视觉)。无功能影响,可选移除或改 async。

CR-260619-01 UX-14 advance_task渲染缺任务名 + UX-16 time.ts销账 + UX-17 handleApprovalMulti防双击(workflow wwchro468 UX-14实施 + 主代串行 UX-16/17·主代兜底核验) — 已审(PASS·巡检 2026-06-19 独立 grep/read 核验)

  • 范围:
    • UX-260618-14 advance_task 渲染缺任务名(workflow wwchro468 general-purpose agent 实施 6 文件):前端 ToolCard.vue advance_task 渲染取 r.title||r.id(:474 formatToolResult / :891 toolResultSummary)+ 新增 TASK_ID_TOOL_ARG 映射(:799 advance_task→id / run_workflow→task_id)+ displayArgValue 接入 task_id→title(:834)+ i18n zh/en aiTool.ts(advancedTask/advancedTaskWithRounds 改 {title} + taskLabel/taskIdNotFound);后端 audit.rs 新增 resolve_task_label(查 tasks 表 :151 三臂 Ok(Some)/Ok(None)/Err 对齐 resolve_project_label)+ build_approval_reason advance_task 分支(:173 id 走 task 解析)+ tool_registry.rstool_display_hint 的 advance_task 项(:1575 让 :1549 模板「推进任务状态:{} → {}」生效)。
    • UX-260618-16 time.ts .value 销账:主代核验已修(CR-24/25 闭环),漏销账补登。
    • UX-260618-17 handleApprovalMulti 补 submitting(主代串行):ProjectDetail.vue :431 try/finally + 模板 :198 :disabled="submitting || multiDecisions.length===0" 对齐单选 handleApproval。
  • 验证(主代兜底,不信 agent 自报):cargo check -p devflow EXIT 0 + vue-tsc EXIT 0 + grep 印证 resolve_task_label 三臂 / tool_display_hint 删 advance_task 项 / ToolCard title 取值。
  • 审查要点(供审查 agent):① UX-14 行为变更——审批 reason 文案(advance_task 从静态串「推进任务状态」→ 含任务标题+target_status)+ audit resolve 查 tasks 表(原误查 projects 恒报「项目已不存在」);② resolve_task_label 三臂语义对齐 resolve_project_label(空 id/Ok(None)/Err 分流);③ tool_display_hint 删 advance_task 后 run_workflow 保留轻量命中(模板 task_id 走通用裸显,本批不动);④ 跨项目任务 taskNameById 查 projectStore.tasks 查不到降级「任务不在当前列表」(非硬错);⑤ UX-17 handleApprovalMulti submitting 对齐 handleApproval 防双击。
  • 关联:todo UX-260618-14/16/17 销账。

复审结论(2026-06-19·巡检独立 grep/read 核验当前源码形态·commit 1dc8b12 已落地·不信声明): PASS🔴0 🟡0 1

逐项核验表(file:line 佐证 + 判定):

核验点 佐证 判定
A-audit resolve_task_label 三臂对齐 resolve_project_label audit.rs:151-163:空 id→空串 / Ok(Some)→「标题」(id=x) / Ok(None)→任务已不存在 / Err→warn+裸 id。与 resolve_project_label:131-144 同构
A-build_reason advance_task 的 id 特化走 task 表 audit.rs:194 "id" if tool_name=="advance_task" => resolve_task_label(db,&val)。其余 "id"|"project_id" 仍走 resolve_project_label(:195)
A-tool_registry 删 tool_display_hint advance_task 轻量命中 tool_registry.rs:1575-1576 注释「advance_task 不在此轻量映射」;:1549 display_hint_for_tool 模板「推进任务状态:{id}→{target_status}」生效
A-TaskRecord 返回值含 title(非假修复) df-storage/models.rs:54-57 TaskRecord pub title:String;task_advance_node.rs:43-47 advance_task_atomic→Result;serde 默认序列化 title,前端 r.title 可读
B-formatToolResult advance_task 优先显 title 回退 id ToolCard.vue:474-478 formatToolResult r.title||r.id;review_rounds>0 走 advancedTaskWithRounds,=0 走 advancedTask
B-toolResultSummary header 摘要与 body 对齐 ToolCard.vue:921-924 同 formatToolResult 双路径覆盖
B-displayArgValue task_id→title 无 project 冲突 ToolCard.vue:824 TASK_ID_TOOL_ARG{advance_task:'id',run_workflow:'task_id'};:811-815 PROJECT_ID_TOOL_ARG 不含 advance_task → :835 projectArgKey 为 undefined 跳过 → :845 taskArgKey 命中;:806 taskNameById 查 projectStore.tasks 降级 taskIdNotFound
B-i18n 中英对称 + message 无特殊字符 zh-CN/aiTool.ts:63-104 + en/aiTool.ts:62-102 advancedTask/advancedTaskWithRounds/taskLabel/taskIdNotFound/workflowTriggered 全对称;message 仅 {title}{status}{n}{id}{exec} 标准插值,无 @//裸 {}(prod runtime 盲点安全)
C-time formatDate .value(CR-24/25 闭环) time.ts:44 (i18n as any).global.locale.value === 'en'。composition 模式 ref 读 .value,en locale 现生效
D-ProjectDetail handleApprovalMulti submitting 防双击 ProjectDetail.vue:431-440 async + try/finally(submitting=true :433 / finally=false :440);模板 :198 :disabled="submitting||multiDecisions.length===0" 联动;对齐单选 handleApproval :417-425

对抗核验印证:

  • run_workflow 审批 reason 不含任务名? 非遗漏:tool_display_hint:1577 run_workflow 轻量命中「触发工作流」(动词级,在 build_approval_reason:184 优先于 display_hint_for_tool 模板返回),根本不进模板分支,故 task_id 无裸显问题。review 要点③已声明「run_workflow 本批不动」,advance_task 是 UX-14 唯一范围。

  • advance_task(Medium risk)是否走审批触发 build_approval_reason? Medium 既有审批阈值逻辑非本批改动;无论审批卡触发与否,前端 formatToolResult/toolResultSummary(执行结果渲染)双路径均消费 title,UX-14 修复在审批卡 + 结果卡两处均生效。

  • i18n message prod 编译盲点? memory i18n-message-compile-blindspot 教训落实:grep message 值全部标准 {var} 插值,无字面 @//|/裸 {}

  • PROJECT_ID_TOOL_ARG / advance_task key 冲突? advance_task 不在 PROJECT_ID_TOOL_ARG(:811-815 仅 4 个 *_project),displayArgValue 项目分支短路跳过,无 advance_task.id 被误判为 project_id 风险。

  • WATCH-1: run_workflow 审批 reason 走轻量「触发工作流」动词(不含 task 名/target_status),UX-14 范围外;若后续需 run_workflow reason 显任务名,需同时从 tool_display_hint :1577 移除 run_workflow(让 display_hint_for_tool :1550 模板生效)+ build_approval_reason task_id key 特化走 resolve_task_label。当前接受动词级。

  • 待修项回流 todo: 🔴/🟡

CR-260619-02 UX-260618-15 第一批 流式重试N+1气泡根治·方案A(agent ux15-batch1 实施 + 主代兜底核验 + 注释修正) — 已审(PASS·0)

  • 范围(3 文件 + 主代注释修正):
    • stream_recv.rs:InitFailed 变体加 error: String 字段(:125);5 处重试路径 AiError emit 全移除(idle timeout :203 / stream-error :262 / chunk Err :303 / 流尽无 finished :362 / provider.stream() Err :402),retryable=true 重试路径 emit 权交 agentic,retryable=false Fatal 也交 agentic 统一 emit。主代修正注释残留 :251/:299(旧"emit AiError"→"返回 InitFailed")。
    • agentic.rs:重试 loop 解构 InitFailed{retryable,error};Fatal 分支(:726)+ 全 candidate 耗尽(:748)新增 emit AiError(单气泡聚合,Network 分类);保留 ensure_resolved_key Auth(:401)/压缩失败(:618)/try_continue provider 缺失(:1058)emit。
    • useAiEvents.ts:AiStreamRetry(:177)改首次创建+后续更新(末条非 isError 创建新错误气泡 / 是 isError 更新 content);AiError push 保留(耗尽/Fatal 最终)。
  • 验证(主代兜底,不信 agent 自报):cargo check -p devflow EXIT 0 + cargo test -p df-ai 119 passed + vue-tsc EXIT 0 + grep 核验 5 处 emit 移除判定 + 注释修正。
  • 审查要点(供审查 agent):① N+1 根治——重试过程不再每轮 push AiError,改 AiStreamRetry 单气泡(首次创建+更新),耗尽/Fatal emit 1 最终 AiError(N+1→1重试+1最终);② stream_recv 5 处移除判定(retryable=true 重试路径移除 / Fatal 交 agentic);③ agentic Fatal/耗尽 emit 单气泡(Network 分类);④ riskNote error_type 统一 Network——401 鉴权 Fatal 原本 error_type=None(前端 canOpenSettings 只认 {auth,provider_config} 本不显「去设置」),现 Network 也不显,不恶化既有行为(记 low WATCH:理想 401 显 auth 按钮需单独做);⑤ InitFailed 枚举加 error 字段 pub(crate) 内部无破坏。
  • 关联:todo UX-260618-15 第一批销账;第二批(方案C 聚合气泡显示错误原因)可选增强待定。

复审结论(CR-260619-02): verdict PASS(0 high / 0 med / 0 low)。独立 grep/read 核验 3 文件当前形态,N+1 气泡根治落地完整,emit 权移交无 Fatal swallow,单气泡聚合无重复 emit,保留 emit 未误删,注释与代码一致。

逐项核验表(源码 file:line 佐证):

审查点 核验结论 佐证
N+1 根治:重试不再每轮 push AiError PASS stream_recv.rs 全文 emit 仅 AiTextDelta(:229)/AiHeartbeat(:329);5 处 InitFailed 路径(:206/:265/:306/:364/:407)均 return StreamResult::InitFailed{...} 不 emit
5 处移除完整无遗漏 InitFailed emit PASS grep AiError 在 stream_recv.rs 仅命中注释/Doc,无运行时 emit 调用
retryable=true 重试路径移除判定正确 PASS agentic.rs:243-300 解构 InitFailed{retryable,error},retryable=true 走重试 emit AiStreamRetry(:293);retryable=false Fatal 返回 StreamOutcome::Fatal{error}(:254)
retryable=false Fatal 正确交 agentic(无 swallow) PASS 外层 agentic.rs:735-744 StreamOutcome::Fatal 分支 guard.reset + emit AiError(Network) + return,终态单 emit
Fatal/耗尽单气泡聚合无重复 emit PASS Fatal 分支 :739 单 emit;全 candidate 耗尽 :761 单 emit;last_exhausted_error 累积 Exhaused 文本(:688 init / :732 write),Exhausted 分支 :724 注释「不在此 emit」防残留
保留 emit 未误删 PASS ensure_resolved_key Auth :401 / 压缩失败 Unknown :618 / try_continue ProviderConfig :1058 三处 emit 完整
useAiEvents AiStreamRetry 首次创建边界 PASS useAiEvents.ts:185 if (lastMsg && lastMsg.isError) 更新 content else push 新错误气泡;重试过程不再先 emit AiError 故首条到达末条非 isError,正确创建;后续 isError 更新
401 鉴权走 ensure_resolved_key(Auth)非 stream_llm Fatal(Network) PASS 401 key 缺失/损坏早失败在 agentic.rs:390 ensure_resolved_key Err → :401 emit Auth;stream_llm Fatal(Network) 仅覆盖 key 已过 ensure 但被 provider 拒等场景
注释 :251/:299 修正一致 PASS stream_recv.rs :203-204/:262-263/:303-305/:362-363/:402-404 均修正为「不再 emit AiError/返回 InitFailed」,与代码行为一致

对抗印证:① stream_recv.rs 无运行时 AiError emit(grep 仅命中注释/Doc);② agentic.rs AiStreamRetry 单点 emit(:293)位于 retryable 重试分支,Fatal/Exhaused 分支均不重复;③ InitFailed 枚举字段 error:String(:125)pub(crate) 内部,跨模块解构(agentic.rs:243)正确。

WATCH:

  • WATCH-1(沿用 riskNote ④,low):stream_llm Fatal 路径 error_type 统一 Network,401 经此路径时不显「去设置」按钮(前端 canOpenSettings 仅认 {auth,provider_config})。401 主路径已由 ensure_resolved_key Auth 兜底,不恶化既有行为;理想 401 显 auth 按钮需单独做。

待修项回流 todo: 🔴/🟡

CR-260619-03 SMELL-P1-9 crud.rs按表拆分 + F-09批1 PerConvState(agent crud-split + f09-batch1 实施·主代统一兜底核验) — 已审(PASS·🟡1 WATCH·批2中间态)

  • 范围(2 独立任务攒批):
    • SMELL-P1-9 crud.rs 拆分(agent crud-split):crud.rs 2212 行 → crud/ 6 文件(mod.rs 宏+工具+re-export / settings / project_repo / task_repo / conversation_repo / idea_repo)。12 Repo + from_row 按表域归属;re-export pub use {conversation,idea,project,settings,task}_repo::* 零调用方改动;宏 pub(crate) use impl_repo + 子模块 use super::impl_repo;基线测试 all_known_tables_have_column_whitelist(12 表)+ all_repos_constructible_in_memory(13 Repo new 不 panic)。
    • F-09 批1 PerConvState(agent f09-batch1,主代已自主裁决采纳决策 b-1):commands/ai/mod.rs 新增 PerConvState struct(9 字段,初值逐字对齐 AiSession::new)+ AiSession.per_conv HashMap 字段(共存期顶层字段仍是真相源)+ conv()(惰性创建)/conv_read()(只读)访问器 + 3 单测。纯新增无行为变化,批2 迁移承接。
  • 验证(主代统一兜底,稳定态·两 agent 都完成):cargo check --workspace EXIT 0 + df-storage 35 passed+11 integration + devflow 96 passed(原93+F-09批1新3)。
  • 审查要点(供审查 agent):① SMELL re-export 完整性(全仓 df_storage::crud::XxxRepo 路径不变,cargo --workspace 0 error 印证);② 宏可见性(pub(crate) use + 子模块 use super + helper import);③ 12 Repo/from_row 归属表正确(idea/project/task/conversation/settings 域);④ 基线测试锁回归(12 表白名单 + 13 Repo 构造);⑤ F-09 批1 PerConvState 字段初值对齐 AiSession::new + conv/conv_read 逻辑 + #[allow(dead_code)] 共存期标注合理(批2 迁移后移除);⑥ F-09 批1 纯新增无行为变化(顶层字段未迁移)。
  • 关联:todo SMELL-P1-9 销账 / F-09 阶段2 批1(批2-8 待)。

复审结论(2026-06-19·独立 grep/read 核验源码当前形态·commit 2c8764a 已落地·不跑 cargo 避批2中间态误报): PASS🔴0 🟡0 1

逐项核验表(file:line 佐证 + 判定):

核验点 佐证 判定
A-拆分 crud.rs 2212 行 → 6 文件 crates/df-storage/src/crud/ 实存 mod.rs/settings.rs/project_repo.rs/task_repo.rs/conversation_repo.rs/idea_repo.rs 6 文件;旧 crud.rs 已删(git show 2c8764a -2212)
A-re-export pub use {conversation,idea,project,settings,task}_repo::* 5 路全在 mod.rs:21-25 五条 pub use 全部就位;调用方 df_storage::crud::{TaskRepo,ProjectRepo,IdeaRepo,AiProviderRepo,AiConversationRepo,AiToolExecutionRepo,KnowledgeRepo,KnowledgeEventsRepo,KnowledgeEventsRepo,WorkflowRepo,...} 路径 grep 全部命中且未改(state.rs:13 / workflow.rs:15 / audit.rs:11 / conversation.rs:7 / title.rs:15 / knowledge_inject.rs:15 / knowledge_timeline.rs:11 / agentic.rs:352 / tool_registry.rs 多处)
A-宏可见性 pub(crate) use impl_repo + 子模块 use super::impl_repo mod.rs:191 pub(crate) use impl_repo(宏定义 :40-187 在前·textual scope 注入注释 :189-190 说明顺序约束);子模块 import 全在:project_repo.rs:15/task_repo.rs:13/conversation_repo.rs:13/idea_repo.rs:13use super::impl_repo
A-helper import 子模块用 super::{now_millis_str,storage_err,validate_column_name,...} project_repo.rs:16 use super::{normalize_stored_path, now_millis_str, storage_err, validate_column_name} / task_repo.rs:14 / conversation_repo.rs:14 / idea_repo.rs:14;settings.rs:12 use super::{now_millis_str, storage_err}(KV 不需 validate/Arc/Mutex 外借,自含);mod.rs 工具 storage_err:199/normalize_stored_path:206/now_millis_str:220 全 pub(crate) 可见
A-12Repo归属 13 Repo 按 5 域正确分布 settings.rs:22 SettingsRepo(1,手写 KV)·project_repo.rs 5(ProjectRepo:100/BranchRepo:256/ReleaseRepo:283/WorkflowRepo:310/NodeExecutionRepo:337)·task_repo.rs 1(TaskRepo:45)·conversation_repo.rs 3(AiProviderRepo:114/AiConversationRepo:153/AiToolExecutionRepo:184)·idea_repo.rs 3(IdeaRepo:118/KnowledgeRepo:147/KnowledgeEventsRepo:400)=13 Repo 全在;from_row 12 个(宏生成 Repo 各一,SettingsRepo 无 from_row)归属域正确(project_from_row/branch/release/workflow/node_execution/task/ai_provider/ai_conversation/ai_tool_execution/idea/knowledge/knowledge_event)
A-基线测试 12 表白名单 + 13 Repo 构造 mod.rs:243-255 all_known_tables_have_column_whitelist 12 表全断言(ideas/projects/tasks/releases/branches/workflow_executions/node_executions/ai_providers/ai_conversations/ai_tool_executions/knowledges/knowledge_events)·mod.rs:259-276 all_repos_constructible_in_memory 13 Repo(SettingsRepo/IdeaRepo/ProjectRepo/TaskRepo/BranchRepo/ReleaseRepo/WorkflowRepo/NodeExecutionRepo/AiProviderRepo/AiConversationRepo/AiToolExecutionRepo/KnowledgeRepo/KnowledgeEventsRepo)逐 new 不 panic
A-白名单单一源 allowed_columns_for/validate_column_name/is_allowed_column 唯一在 settings.rs settings.rs:119 allowed_columns_for / :189 validate_column_name(pub(crate)) / :201 is_allowed_column(pub);调用方 df_storage::crud::is_allowed_column(tool_registry.rs:452/555)路径未破
B-PerConvState字段 9 字段逐字对齐 AiSession::new mod.rs:571-590 struct 9 字段;:605-617 new() 初值:messages(ContextManager::new default)=AiSession:386 / generating:false=:391 / stop_flag(Arc AtomicBool false)=:393 / notify(Arc Notify::new())=:394 / iteration_used:0=:395 / agent_language:None=:392 / model_override:None=:396 / session_trust(HashSet::new())=:397 / created_at:None(新增字段,注释 :604 对齐 AiSession.active_conv_created_at:None :389) 全对齐
B-conv访问器 entry().or_insert_with 惰性创建 mod.rs:453-457 conv(&mut self,conv_id) body self.per_conv.entry(conv_id.to_string()).or_insert_with(PerConvState::new) — 惰性创建语义正确,已存在返同一实例
B-conv_read访问器 .get() 只读不创建 mod.rs:466-468 conv_read(&self,conv_id) body self.per_conv.get(conv_id) — 返 Option<&PerConvState>,无写入路径,只读语义正确
B-allow标注 PerConvState/per_conv/conv/conv_read 共存期 #[allow(dead_code)] PerConvState struct:570 / per_conv 字段:355 / conv:452 / conv_read:465 四处均标 #[allow(dead_code)] 注释「F-09 B 批1 共存期:批2 迁移承接(0 调用方)」
B-3单测 new 初值 + 惰性创建复用 + conv_read 不创建 mod.rs:477 test_per_conv_state_new(8 断言含 stop_flag SeqCst load) / :497 test_conv_lazy_create(首次创建 len=1 + 同 id 指针相等复用 len 仍=1 + 不同 id 新建 len=2) / :525 test_conv_read_none(未创建返 None + 不触发创建 per_conv 仍空) 三测覆盖
B-纯新增 顶层字段仍是真相源,per_conv 初始空 AiSession::new:398 per_conv: HashMap::new()(初始空);批1 仅加 struct/字段/访问器,无调用方迁移(conv/conv_read 0 调用方) (见 WATCH·批2 中间态)

对抗核验印证:

  • re-export 路径不变? 全仓 grep df_storage::crud 命中 9 调用文件,所有 XxxRepo/is_allowed_column 路径形式未变,re-export 5 路全覆盖零调用方改动。
  • 宏 textual scope 顺序? mod.rs 宏定义(:40-187)在 pub(crate) use impl_repo(:191)之前,pub(crate) usemod 声明(:15-19)之前,顺序符合 Rust textual scope 注入要求(注释 :189-190 显式说明);4 子模块 use super::impl_repo 全部命中。
  • 13 Repo 计数? 实测 1(settings 手写)+5(project)+1(task)+3(conversation)+3(idea)=13,与基线测试 :263-275 逐行 new 一一对齐。
  • PerConvState created_at 新增字段是否破坏对齐? AiSession 无独立 created_at 顶层字段(用 active_conv_created_at:None :389),PerConvState.created_at:None :615 注释 :604 显式声明「批1 新增字段,AiSession 现有 active_conv_created_at 同语义」——对齐声明而非逐字复制,合理(语义等价,字段名差异因 AiSession 持 active 概念而 PerConvState 持会话创建时间)。
  • 批1 是否纯新增? AiSession::new 仍构造全部顶层字段(:386-397 messages/generating/agent_language/stop_flag/notify/iteration_used/model_override/session_trust),per_conv 初始空 HashMap,conv/conv_read 0 调用方——批1 范围严格纯新增。

⚠️ 批2 中间态说明(非批1 问题·审查范围外记录):

  • 核验时发现 mod.rs:355-380 顶层 8 字段已标 #[allow(dead_code)] 注释「F-09 B 批2 共存期死字段(批3 删)」,且 AiSession::new:386-397 仍构造这些字段——说明 F-09 批2 正在进行中(对应 prompt 开头「批2 agent 正在改 agentic.rs」)。批1 的 per_conv/conv/conv_read/PerConvState 已就位待批2 迁移调用方消费。本次审查范围(commit 2c8764a)仅含批1,批2 中间态不评判。本次审查全程未跑 cargo(memory review-batching-worktree-transient 教训:批2 中间态会致 check 快照误报,源码形态核验 > check 快照)。

  • WATCH-1: F-09 批2 迁移进行中(agentic.rs/commands.rs/audit.rs/conversation.rs/title.rs/knowledge_inject.rs 调用方迁移 + 顶层字段降级死字段),批2 完成后需独立审查(范围:调用方迁移完整性 + 顶层字段是否真成死字段 + cargo test 单会话全功能回归)。批1 本身 PASS 不受批2 影响。

  • 待修项回流 todo: 🔴/🟡 项(批1 范围内)


已审归档

已审 CR 段迁独立文件: 待审查归档/2026-06.md