# 下一批次规划走查(2026-10-02) > 走查代理产出,主代理汇总核验。守 session-role-diagnose-only:仅走查+规划,未改代码。 > 批次边界:本批在修 = 上下文管理 B1-B5(walkthrough 后段全部 ✅ 已销账:B1/B4/B5=7c62d8d、B2=9b89610、B3=df3ed55+e7cd035、B4 存量晋升=migrations V43)+ 12 张截图 UX 样式清单 + U 系竞态守卫(U1-U4);工作区另有「中断根治」12+2 未提交文件(本走查对象之一)。以上全部排除,只找增量。 > 排除声明(会话重启后追加):工作区后追加的 migrations.rs V43 迁移、AuditLog/settings/GitChanges/ProjectCard/TaskBatchBar/TaskDetail/Tasks 改动 = 本批已完成的 UX 修复,不在走查范围。 > 方法:3 路并行走查代理(后端 ai 命令 / 前端 ai 组件 / df-ai+df-storage crates)+ 主代理独立走查工作区未提交改动(D 线)+ 「已修」声明抽查。一切结论以当前源码为准。 --- ## 一、增量问题清单 ### D 线(主代理走查:工作区未提交改动本身的正确性) #### D1 [P1] G2 唯一率「写间隔豁免」是无操作——本批声明修复②实际未生效 - **位置**:`src-tauri/src/commands/ai/agentic/helpers.rs:290-311`(`is_repetitive_exploration` 新增 effective 段) - **根因**:每个签名的**首现必然被 push**(`last_idx.get(sig)` 为 None → exempt=false),而后续 `sort()+dedup()` 后 effective 的去重集合 ≡ 全样本去重集合——豁免逻辑对分子零影响;分母 `total = samples.len()`(:290)又未过滤豁免样本 → `unique_ratio` 与旧算法**逐位等价**。 - **附加 off-by-one**:`samples[j + 1..=i]`(:298)含当前样本自身——写类签名的再现因**自己 is_write=true** 被自豁免(区间应为 `samples[j+1..i]`)。 - **测试无效**:新增 4 个测试在旧代码下同样通过(逐个复算:cleanup 场景 8/12=0.67、pure_wandering 3/9=0.33、adjacent 3/9=0.33、flips_verdict 走单点分支 streak=3)——测试无鉴别力,「11+1 测试过」不代表修复生效。 - **影响**:`[g,w,g,w,g,w,...]`(同 grep 签名+同写签名,如反复 patch 同参数失败重试)distinct=2/12=0.17 < 0.4 → 仍误熔断;「清理任务 write→grep 验证」唯一率误判(本批修复目标)实际依旧。 - **修复方案**:反转 push 条件——豁免的再现应计为「新的有效单元」(夹写重查=新鲜验证活动)push 入 effective,未豁免的再现不入(已被首现覆盖);分母同步改 `effective.len()`(或对偶实现:exempt 计数同时从分子分母扣)。区间改 `samples[j+1..i]`。 - **验证**:补 `[g,w,g,w,g,w,g,w,g,w,g,w]`(g/w 各同签名、写类)用例——修正后应 `false`(当前 `true` 误熔断);再跑全量 G2 测试确认死磕场景仍 `true`。 #### D2 [P2] ai_resume_interrupted 防双跑检查在锁外——双探针 TOCTOU 双 spawn - **位置**:`src-tauri/src/commands/ai/commands/chat.rs:2443`(`is_active` 检查)→ :2477 附近 transition → :2486 `try_continue_agent_loop` - **根因**:`is_active` 在 session 锁外读;主窗口+分离窗口(AiDetached 自有 listener+看门狗)同 conv 看门狗先后到期时,两探针都可先过 `is_active=false`;后进锁者 `conv_read` 尾部仍是 Tool(先者新 loop 尚未产出消息)→ 再次 transition(Generating→Generating 迁移失败仅 warn 不阻断)→ 再次 spawn → epoch takeover 抖动 + 短窗口双 loop 并行(可能重复执行工具轮)。 - **修复方案**:session 锁内复查 `conv_states.is_active(&conversation_id)`,命中直接返回 `"generating"`(同时把 transition 失败从「warn 不阻断」改为「返回 generating 不续跑」)。 - **验证**:代码审阅锁内复查;手测主/分离窗口对同会话同时断流双探测。 #### D3 [P2] 达上限自动完成复用「网络中断」文案——语义错位误导排障 - **位置**:`src-tauri/src/commands/ai/agentic/mod.rs:1139-1174`(teardown emit incomplete=true)→ `src/composables/ai/useAiLifecycleEvents.ts:106-112` - **根因**:达 max_iterations 自动收尾走 `AiCompleted(incomplete=true)`,前端 incomplete 分支统一补 `ai.responseIncomplete`「⚠ 响应因**网络中断**不完整…可重新发送以获取完整回复」——用户实际是轮次耗尽自动收尾,看到的却是网络中断+重发指引。 - **修复方案**:incomplete 气泡按来源分文案(后端事件加 `incomplete_reason` 字段,或前端按 pinned_goals/max-rounds 特征分流到新 i18n key「已达最大轮次自动收尾」)。 - **验证**:跑满 max_iterations 的会话看收尾气泡文案。 #### D4 [P2] 自动续跑提示气泡不路由会话——落错视图(已知家族新实例) - **位置**:`src/composables/ai/useAiStream.ts:164-167`(`onStreamTimeout` attempts===0 分支) - **根因**:「正在自动恢复…」气泡无条件 `state.messages.push`(当前活跃视图),convId 为后台会话时气泡落到无关会话——与已登记 9-28 #6「错误气泡推错视图」同家族,系本批新代码引入。 - **修复方案**:push 前加 `convId === state.activeConversationId` 守卫(后台会话静默重挂即可,通知走 notify 通道)。 - **验证**:后台会话看门狗到期,观察活跃会话是否冒出无关气泡。 #### D5 [P2] 尾部是 user 消息的中断被误判「finished」——补假收敛信号 - **位置**:`src-tauri/src/commands/ai/commands/chat.rs:2454-2457`(尾部 role 匹配) - **根因**:interrupted 判定只覆盖 `Tool` 尾与 `Assistant` 带工具调用尾;末条是 **user**(loop 在首 token 前死亡:启动段 panic/配额拦截/网络失败)时返回 `"finished"` → 前端补「响应在收尾阶段中断,已自动完成收敛。」假信号,实际什么都没生成。 - **修复方案**:尾部 `User` 也判 interrupted 走 `resumed`(续跑语义正确),或返回独立状态让前端用中性文案。 - **验证**:构造发送后首 token 前断流场景,看前端是否误报「已收敛」。 #### D6 [P3] 审批执行超时错误丢失工具名与平台提示 - **位置**:`src-tauri/src/commands/ai/audit/mod.rs:260` - **根因**:ai_approve 旧路径超时错误带「工具名 + Windows PowerShell `;` vs `&&` 提示」,统一收敛进 execute_with_heartbeat 后错误串只剩「工具执行超时(Ns),已中止(防死锁)」——可诊断性回退。 - **修复方案**:错误串补 `name`(函数内已知)。 - **验证**:人为构造超时工具审批,看 tool_result 文本。 #### D7 [P3] 达上限 NeedAction 系统通知文案与新语义不符 - **位置**:`src-tauri/src/commands/ai/agentic/mod.rs:1150-1156` - **根因**:通知文案「AI 循环未收敛**已暂停,等待继续或停止指令**」——该出口已改为自动完成收尾(无暂停、无需指令),文案停留在旧暂停态语义。 - **修复方案**:文案改「已达最大轮次,已自动收尾」。 - **验证**:触达上限看系统通知。 ### 代理线发现(2026-10-02 深夜收口时补:三路走查已全部完成,中断说明作废) > 原记「三次中断不再重派」已被超越:续跑成功,rev-backend/rev-frontend/rev-crates 三份完整报告已返回并落盘。 > **全文见 `docs/05-代码审查/aichat三路走查报告-2026-10-02.md`**(含批次归并建议),docs/todo.md 已登记可执行项。精华: - **后端 P0-1**:ai_chat_compress_context conv_id 分裂(chat.rs:1734 起 cid 切 active)——压缩后台会话 100% 触发:目标 conv compressing 标志永久卡死 + active 会话被插入他人摘要(跨会话污染入库)。**主代理已亲核实锤**。存量缺陷非本批回归,批次2首位(约 4 行)。 - **crates P0-1**:V21 迁移 COUNT 幂等窗口——批次中途崩溃后重跑 COUNT>0 跳过剩余迁移但版本号照样补齐,ai_messages 永久残缺被掩盖(代理核验)。批次2 并入。 - **后端 P1×3**:remote_bridge 6 处 AiError 单路 emit(miniapp 错误全盲)/只读结果缓存无写失效(写后读回过期)/conv delete 不停 in-flight loop(zombie 复活+审批吊死,与已登记 conv 删除族同域)。 - **前端 P1×2**:后台审批/授权事件被 isCurrent 丢弃(挂死,与 V2/V1 不同源)/switchConversation 兜底分支漏置 activeId(视图/高亮/发送目标三重错配)。 - **crates P1×12**:OpenAI 流式 error 帧被 choices 必填整帧丢弃(无声截断)/serde 结构错误判 Retryable/usage 必填缺字段整响应失败/sanitize 合并丢多模态 parts(带图消息图隐身)/INSERT OR IGNORE 静默丢写/CAS 缺软删防护 等。 - **机械批**:remote_bridge 6 处+agentic 4 处裸 emit 换 emit_ai_chat_event;i18n searchFilesBlocked 死键裸 @ 转义。 - P2×45+P3 见报告;已核对无漂移面(迁移链/V43/anthropic SSE 栈)已注明免重查。 --- ## 二、对既有报告「已修」声明的抽查结论 | # | 声明 | 抽查结论 | 证据(当前源码) | |---|------|---------|-----------------| | 1 | todo 第一批 P1「I1 停止窄窗」未修 | **漂移:已修(已提交)** | `ChatInput.vue:291-298` stopBtnState 读 `getConvState(conv)==='generating'`,注释明言补 conv_state 判定治工具执行期不可干预 | | 2 | todo 第一批 P1「I2 编辑死链」未修 | **漂移:已修(04acc42 10-01)** | `MessageItem.vue:101-102` `canEdit` + `ai-msg-edit-btn` + emit('start-edit') | | 3 | todo 第一批 P1「V2 审批黑洞」未修 | **漂移:聚合层已修** | `useAiToolEvents.ts:59-84` AiApprovalRequired 无 isCurrent 守卫、无条件进 pendingApprovals 且保留 conversationId(V5 条目来源显示/V6 计时器 per-conv 残留未逐项核) | | 4 | todo 第一批 P1「V3 后台零通知」未修 | **漂移:已修(e1dd0bc)** | `notify.rs` 新模块 + `agentic/mod.rs` 6 处 notify_session_event 调用 | | 5 | todo 第一批 P1「G2 破坏性回环熔断」未做 | **漂移:已实现(已提交)** | `helpers.rs:343+` detect_destructive_loop/normalize_loop_path/destructive_loop_sample + 采样接线注释 | | 6 | 知识库走查「T4/T5 已修」 | **属实(行号漂移)** | begin_turn `chat.rs:810/2112`(报告写 651/1978)、sync_after_compress `context_lifecycle.rs:261`(报告写 278) | | 7 | 09-29「R1/R2 已修(工作区待提交)」 | **属实** | `useToolCard.ts:741` TOOL_SUMMARIES;`ToolCardList.vue:131-136/162/286` touched + watch 幂等补齐 | | 8 | 中断根治「P2-1 AiMaxRoundsReached 幽灵事件已修」 | **属实** | 全仓 grep 仅注释与 enum 定义残留,后端零 emit 点 | | 9 | 中断根治进度「② helpers.rs 唯一率写间隔豁免已修」 | **漂移:无操作(=D1)** | `helpers.rs:290-311` 豁免对去重后分子零影响、分母未过滤;4 测试旧代码下同样通过 | | 10 | todo 第一批「V1 awaiting_approval 徽标」 | **未修(与 todo 一致)** | `ConversationSidebar.vue` 无 approval/awaiting 相关代码 | **抽查总结**:10 项声明中 6 项「报告说未修但实际已修」(todo.md 第一批 I1/I2/V2/V3/G2 回环 未销账),1 项「本批声明已修但实际无效」(D1),3 项属实。建议下一批开工前先做 todo.md 第一批销账核对,避免重复派工。 --- ## 三、下一批次建议拆批方案 ### 批次 1:新代码收口批(小,先行) - **内容**:D1 唯一率豁免真实现 + 测试补鉴别力用例、D2 锁内复查、D5 尾部 user 分支、D3 incomplete 文案分流、D4 气泡路由、D6/D7 文案。 - **文件**:`helpers.rs` / `agentic/mod.rs` / `commands/chat.rs` / `useAiStream.ts` / `useAiLifecycleEvents.ts` / `i18n en+zh ai.ts` —— **与当前工作区 12+2 未提交文件完全重叠**。 - **约束**:必须并入当前「中断根治」批一起收尾(等用户通知一并提交),或紧随提交后第一个小批;**不可开 worktree 并行**(同文件互踩)。 ### 批次 2:后端登记高危批 - **内容**:todo 2026-10-02 静默死亡 4 项(P0 run_agentic_loop 包 catch_unwind / P1 conv 删除类 6 处补终态事件 / P2 审批超时主动收敛 / F2 心跳兜底前移)+ 本走查后端代理新发现(待代理返回后并入)。 - **文件**:`agentic/mod.rs` / `stream_relay.rs` / `approval_timeout.rs` / `commands/chat.rs`。 - **约束**:与批次 1 共享 mod.rs/chat.rs → **等批次 1 提交后开工**;catch_unwind 属核心 loop 改动,按 memory `test-strategy-scenario-replay` 先落场景回放 fixture 再动手。 ### 批次 3:前端体验批 - **内容**:09-29 第二批 P2(V8 草稿 per-conv / R3 长回复带量 / R4 代码块复制 / I5+9-28#7 错误分类 / I4+9-28#4 队列回填 / V7 排队时钟 / V4 浮窗二次确认)+ pendingMaxRounds/MaxRoundsCard 死链清理(后端已零 emit)+ 本走查前端代理新发现。 - **文件**:`composables/ai/*`、`components/ai/*`、`ChatInput.vue`。 - **约束**:与批次 2 无文件交集可并行;useAiStream/useAiLifecycleEvents 与批次 1 有少量交集 → 批次 1 先行或本批避开这两文件。9-28#17(图片上传外部域名)涉开源边界,单独决策不进批。 ### 并行性总览 - 批次 2(后端)与批次 3(前端)可并行;批次 1 必须先行收口(同文件)。 - U 系(U1-U4,非 ai 页面)与 B1-B5(知识链路)与本规划三批文件零交集,可多线并行。 - todo.md 第一批销账核对(第二部分 #1-#5)随任意批次顺手完成,纯文档操作。 --- ## 附:走查覆盖说明 - D 线(主代理):工作区 12+2 文件全量 diff 逐块审读 + 周边链路(guard.rs epoch 语义、try_continue_agent_loop、execute_with_heartbeat、useAiLifecycleEvents incomplete 分支)交叉核验。 - 代理线:rev-backend(src-tauri/src/commands/ai 静默失败/竞态/锁)、rev-frontend(composables/ai + components/ai 事件/残留/泄漏)、rev-crates(df-ai/df-storage 一致性/错误传播)——发现清单见上方「代理发现」段(会话重启后重派,结果合并中)。