diff --git a/docs/待审查.md b/docs/待审查.md index ad33010..023fdd7 100644 --- a/docs/待审查.md +++ b/docs/待审查.md @@ -23,6 +23,31 @@ ## 当前队列 +### CR-260616-58 F-260616-07 阶段3 AiNode 自审闸门(verdict=fail 作 DAG 节点闸门阻断下游)(e16d038) — 🟡 待审 + +- **范围**: F-260616-07 阶段3 AiNode 自审闸门。方案 A(AiNode 内部门控)落地:`gate_should_block(gate, verdict)` 纯函数 + AiSelfReviewNode.execute 末尾 `config["gate"]==true && verdict=="fail"` → return Err,复用 executor first_err 中止后续层 → 工作流 failed → ②-4 回调退回 in_review。verdict=unknown/pass 放行(unknown 保人定权)。testing 模板 ai_self_review 节点 config `"gate": true` 启用。schema 加 gate 布尔字段。 +- **commit**: e16d038。 +- **文件锁**: `crates/df-nodes/src/ai_node.rs` + `crates/df-nodes/src/task_workflow_templates.rs`(独占,df-workflow 零改动)。 +- **维度**: ①gate_should_block 决策矩阵完备(gate=false 全放行 / gate=true 仅 fail 阻断 / unknown/非标 verdict 不阻断保守) ②execute 末尾 Err 路径正确(落库在前,审查痕迹不丢) ③复用 executor first_err + ②-4 回调语义(零 executor 核心改动核验) ④gate 默认 false 向后兼容(阶段2 行为不变,前端/其他调用方零强制改动) ⑤testing 模板 gate:true 启用 + 单测断言 ⑥schema 契约(gate 布尔字段) ⑦选型论证(方案 A vs B 条件引擎暂缓 vs C executor 改核心,最简不破坏) ⑧主代亲跑 cargo check EXIT 0 + df-nodes 82 passed(79→82,+3 gate)+ df-workflow 23 passed。 + +### CR-260616-59 波16 F-04c前端Settings池编辑(enabled toggle+weight输入+IPC绑定)(3f90aad) — 🟡 待审 + +- **范围**: workflow w94jdgv9n agent A。types.ts AiProviderConfig 补 enabled?/weight?(snake_case 对齐 serde)+ api/ai.ts updateProviderPool(providerId,enabled,weight) wrapper L146 + Settings.vue 卡片 detail 区 enabled toggle(L60)+ weight 数字输入(L69)+ handler onPoolToggle(乐观更新+失败 revert)/onPoolWeightChange(debounce 300ms+clamp[0,100]+NaN 兜底)+ onUnmounted 清 _poolTimer + CSS + i18n zh/en 7 key。交互决策:卡片即时调 IPC(非 saveProvider)——池调度参数即时生效(reload_provider_caps 变更即重建)+ 避免 saveProvider 密钥迁移分支 + 对齐 syncConcurrency 即时调模式。 +- **维度**: ①updateProviderPool wrapper 对齐现有 invoke 风格 ②AiProviderConfig enabled?/weight? 可选(snake_case serde 对齐) ③即时调 IPC 决策合理 ④debounce 300ms+clamp+NaN 兜底 ⑤乐观更新+失败 revert ⑥i18n 双语。 +- **commit**: 3f90aad。 +- **主代核查**: vue-tsc EXIT 0 + grep updateProviderPool/AiProviderConfig/toggle。 +- **审查 agent 待复审重点**: ①updateProviderPool invoke 参数命名(camelCase vs snake_case Tauri 2 转换) ②乐观更新 revert 逻辑 ③debounce timer 清理(onUnmounted) ④i18n key 完整。 +- **待修项回流 todo**: **无**(前端就绪,后端 CR-56 已就绪)。 + +### CR-260616-60 波17 B-03b-R10前端审批清理(终态清pending+互斥锁防重复IPC)(0289d8c) — 🟡 待审 + +- **范围**: workflow w9xypd8ug agent B。src/stores/project/workflow.ts ⑤终态不清(startEventListener 加 else-if,workflow_completed/failed/node_cancelled 且 execution_id 匹配清 pendingApproval,按 exec_id 限定防并发误清)+ ⑦互斥(模块级 _approvalInFlight 单例标志,approve/cancel 入口检查+try/finally 释放,防双击重复 IPC)。④单槽→Map 推迟(state 形态变更牵动多消费者,后端串行闸门保证单执行不并发,现实触发需并发工作流)。波17 B-03b 后端 workflow.rs 0 实施(⑧⑩⑪ 报告失效/已修复/已有兜底,③ 真实潜伏跨 crate df-core 缺 execution_id 留观察)。 +- **维度**: ⑤终态清 execution_id 限定(防并发误清)+ ⑦互斥 _approvalInFlight 单例(跨调用方统一)+ ④推迟理由(state 形态变更+后端串行)。 +- **commit**: 0289d8c。 +- **主代核查**: vue-tsc EXIT 0。 +- **审查 agent 待复审重点**: ⑤终态清 execution_id 匹配逻辑(防误清)+ ⑦互斥 _approvalInFlight try/finally 释放(异常路径不泄漏)。 +- **待修项回流 todo**: **无**(⑤⑦ 实施,④ 推迟有理由)。 + ### CR-260616-36 batch60 F-09A 隔离补清 + F-13 性能优化 + AE-03 write_file diff 预览(路径B) — ✅ 已审(PASS) - **复审结论(2026-06-16·CR-36 agent 亲跑 cargo+vue-tsc+test,723s)**: ✅ **PASS** — 🔴0 🟡0 ⚪1 @@ -407,32 +432,36 @@ - **⑧4 处构造点补字段 PASS**:commands.rs:986-1001(ai_save_provider 新建默认 enabled=true/weight=50)/ crud.rs:1762-1777(单测)/ secret.rs:209-215(单测)/ ai_node.rs:714-729(单测),4 处全补 `enabled: true, weight: 50`。 - **待修项回流 todo**: **无**(7 维度全 PASS,零问题)。 -### CR-260616-55 波13 B-21工具卡重复治本(audit tc_list按id去重保证emit Started唯一)(247dc5d) — 🟡 待审 +### CR-260616-55 波13 B-21工具卡重复治本(audit tc_list按id去重保证emit Started唯一)(247dc5d) — ✅ PASS - **范围**: workflow wice28c6y(前端守卫 agent + 后端走查 agent)。①**前端治标守卫**(HEAD 已有,非本轮新加):useAiEvents.ts:205 AiToolCallStarted push 前 `if (!findToolCall(event.id))` 幂等守卫(对齐 startToolSlowTimer:58)。②**后端走查结论**(不改代码):候选A确认——LLM 流式输出两个 tool_use block 不同 content_block index 但相同 id → stream_recv.rs:225 按 index(u32 键非 id)分桶 → 两条同 id 不同 index draft 并存 → audit.rs:538-549 每 draft emit Started → 同 id 两次 → 前端 push 两卡 → Completed 按 id 只 update 首张 → 次张残留 running 0行。候选B排除(provider 每轮新 id)。③**治本兜底(commit 247dc5d)**:audit.rs:533 sort 后加 `seen_ids HashSet + tc_list.retain(draft.id)` 按 id 去重,同 id 保留最小 index 首个,emit Started 唯一。前端守卫双保险。详 docs/02-架构设计/B-260616-21排查方案。 - **维度**: ①去重正确性(同 id 保留最小 index 首个,retain 后 drafts 唯一 id emit) ②不破坏正常多工具(不同 id 不受影响) ③HashSet import(audit.rs:3 加) ④与 F-05(High risk 去重缓存)无冲突(不同维度)。 - **commit**: 247dc5d。 - **主代核查**: cargo check EXIT 0 + 88 passed + grep retain 形态。 -- **审查 agent 待复审重点**: ①retain 去重——同 id 保留首个(sort 后=最小 index),emit Started 唯一 ②不同 id 多工具不受影响 ③与 F-05 不同维度无冲突(F-05 不同 id 同命令去重,本条同 id 去重)。 -- **待修项回流 todo**: **无**(治标守卫 HEAD 已有 + 治本去重落地,待独立复审)。 +- **审查结论**: ✅ PASS。核验通过: + - ①去重正确性:audit.rs:533 `tc_list.sort_unstable_by_key(|(i, _)| *i)` 先按 index 排序 → :540 `seen_ids.insert(draft.id.clone())` retain 保留首个同 id(即最小 index) → :548 emit AiToolCallStarted 仅一次。逻辑闭环。 + - ②不破坏多工具:retain 仅过滤同 id,不同 id 工具正常通过,stream_recv.rs:225 证实分桶键为 index 非 id。 + - ③HashSet import:audit.rs:3 `use std::collections::{HashMap, HashSet}` 正确。 + - ④与 F-05 无冲突:F-05(audit.rs:612 find_cached_high_risk_result) 按 tool_name+args 去重(不同 id 同命令),本条按 id 去重(同 id),维度正交。 + - ⑤前端守卫:useAiEvents.ts:205 `if (!findToolCall(event.id))` 确认存在,双保险兜底。 + - ⑥cargo check:EXIT 0,零编译错误。 +- **待修项回流 todo**: **无**(治标守卫 + 治本去重 双保险就位)。 -### CR-260616-56 波14 F-04c后端(provider池enabled/weight更新IPC+set_caps启动接入)(b3684f4) — 🟡 待审 +### CR-260616-56 波14 F-04c后端(provider池enabled/weight更新IPC+set_caps启动接入)(b3684f4) — ✅ PASS - **范围**: workflow wodppv1hd。①ai_save_provider(commands.rs:929-948)编辑路径保 enabled/weight(修原硬编码清回默认 bug)。②ai_update_provider_pool IPC(commands.rs:1022-1056)轻量专用更新 enabled/weight 经 update_full,weight clamp[0,100],落库后 reload_provider_caps 重建 caps。lib.rs:128 注册。③set_provider_caps 启动接入(state.rs:297 AppState::init 调 reload_provider_caps L305-323 从 DB enabled providers 建 per_provider HashMap,cap=global_cap=3)。单点真理 helper(state 不依赖 commands 避免环形)。 - **维度**: ①ai_update_provider_pool 不触 ai_save_provider 密钥迁移分支(避免空 api_key 重发整表) ②reload_provider_caps 单点真理 ③cap=global_cap=3 单 provider 零变化 ④ai_save_provider 编辑保字段(新建默认 true/50)。 - **commit**: b3684f4。 - **主代核查**: cargo check EXIT 0 + 88 passed。 -- **审查 agent 待复审重点**: ①ai_update_provider_pool update_full 落库(weight clamp) ②reload_provider_caps init 接入 + 变更重建 ③ai_save_provider 编辑保字段 ④set_provider_caps cap 策略(本轮 global_cap,F-04d 差异化留)。 +- **复审结论**: PASS。6 维度全核验通过:①ai_update_provider_pool 无 api_key 参数不触密钥迁移(commands.rs:1023-1056) ②reload_provider_caps 单点真理(state.rs:311-327) ③global_cap=3 与单 provider 等价(state.rs:321+324-326) ④编辑保留(commands.rs:945-947) ⑤provider_pool::select 过滤 enabled/weight(provider_pool.rs:64) ⑥weight clamp(commands.rs:1037)。无 high/med/low 发现。 - **待修项回流 todo**: **无**(后端就绪,前端 Settings UI 留波16)。 -### CR-260616-57 波15 F-04b多provider fallback切换(stream_one_provider+候选链+resolved_model重算)(80c0955) — 🟡 待审 +### CR-260616-57 波15 F-04b多provider fallback切换(stream_one_provider+候选链+resolved_model重算)(80c0955) — ✅ 已审(PASS) -- **范围**: workflow w3xow3x3l agent A,agentic.rs +287/-112。①抽 stream_one_provider(agentic.rs:155-298)封装单 candidate:build_provider_for(resolve+ensure+build,key Err→Fatal emit Auth)+ select_model_id 在 candidate.model_configs 重算 resolved_model(provider 切换模型池不同,防 400/404)+ 流式 stream_recv + 流前 InitFailed retryable 重试,返回 StreamOutcome(Success{resolved_model}/InitFailedExhausted/Fatal)。②外层 for candidate in &candidate_chain(L663)包裹,候选链 [primary,...candidates] 预 clone primary 入链避 E0506。③InitFailedExhausted(retryable 耗尽)→ continue 'candidate 切下一候选,helper 内重建 build_provider + 重算 resolved_model。④Fatal(4xx 非429)立即放弃整个 fallback(L703 guard.reset+return)。⑤全 candidate 耗尽→沿用单 provider 失败语义。per-provider permit 候选循环内取(切换 Drop 释放旧槽);retry_deadline 30s 各 candidate 共享预算(防串行累加)。 -- **维度**: ①stream_one_provider 抽取语义(resolved_model 在新 provider 重算保 F-01 路由) ②候选链外层 + InitFailed 切换 ③Fatal 立即放弃(对齐 retry.rs) ④per-provider permit 切换释放 ⑤retry_deadline 共享预算 ⑥单 provider 零变化(候选链仅 primary 不触发切换)。 -- **commit**: 80c0955。 -- **主代核查**: cargo check EXIT 0 + 88 passed(保基线零回归)。 -- **审查 agent 待复审重点**: ①stream_one_provider——resolved_model 在新 candidate.model_configs 重算 select_model_id(防 400/404) ②for candidate + InitFailedExhausted continue 切换 ③Fatal 立即放弃 + 全耗尽报错 ④per-provider permit acquire_for_provider 切换 Drop ⑤retry_deadline 共享 ⑥不破单 provider 路径。 -- **待修项回流 todo**: **无**(fallback 完整实施,待独立复审)。 +- **审查时间**: 2026-06-17(独立审查 agent · 亲跑 cargo check EXIT 0 + grep/read 核验源码) +- **总体结论**: ✅ **PASS** — 🔴0 🟡0 ⚪0 +- **逐件核验(全 PASS)**:①stream_one_provider 抽取 ✅(agentic.rs:155-298 封装单 candidate,StreamOutcome 三态 Success/InitFailedExhausted/Fatal 驱动外层切换)/ ②resolved_model 重算 ✅(:188-199 select_model_id 在 candidate.model_configs 上重算+ model_override 穿透,防切换 provider 后模型池不同吃 400/404)/ ③候选链外层 ✅(:663 'candidate for 循环+ :656-658 Vec clone primary 入链避借用冲突)/ ④InitFailedExhausted 切换 ✅(:691-701 continue + :188-199 resolved_model 重算,stream_one_provider 内重建 build_provider)/ ⑤Fatal 立即放弃 ✅(:703-707 guard.reset+return,对齐 retry.rs Fatal 分类 + provider_pool 文档)/ ⑥per-provider permit 切换释放 ✅(:667 acquire_for_provider 循环内取,切换 Drop 自动释放旧槽)/ ⑦retry_deadline 共享预算 ✅(:642 单次 Instant::now+30s,各 candidate 共享不重置,防串行累加超预算)/ ⑧单 provider 零变化 ✅(:352 空池兜底 candidates=Vec::new,candidate_chain 仅 primary,循环跑一次耗尽 return)。 +- **退避策略一致性**: ✅ 复用 df_ai::retry::backoff_delay(agentic.rs:14 use df_ai::retry + :270 调用 retry::backoff_delay((retry_attempt+1) as u32)),retry.rs:74-85 实现 1s→2s→4s ±20% jitter,与 CR-30-1 对齐一致。 ---