Files
DevFlow/docs/05-代码审查/定时走查-2026-06-15-第2轮.md
T
lxy f30df333b3 docs: 巡检简报+todo 回写(2026-06-15 第2轮)
巡检发现:
- 2196c77 workflow 整文件替换回退破坏(AiChat+Ideas 12项功能)
- B-260615-03 truncated 标志已落地
- AR-8-scroll scrollToBottom smooth 已补
- CR-260615-09 .ai-md 残余:4详情页各21处 scoped .ai-md
  (全局 ai-md.css 75行已建,旧副本待清理但非阻塞)
2026-06-15 17:23:57 +08:00

9.4 KiB
Raw Blame History

定时代码走查 — 第 2 轮(2026-06-15

触发:定时走查 cron(每 30 分钟)。本轮范围 = 自上次走查起新增 6 提交(fddca9d/892a642/19d64fc/d809cf4/8710d6c/06a2dea)前端改动 + 工作区未提交(types.ts/project.ts M)。 方法:3 路后台代理并行(AARC-05 store 拆分 / BB-22 状态同步含 B-32/33 核对 / C:CR-11 健壮性+工作区未提交)+ 主代理地面核对(useAiStream.ts/useAiSend.ts/workflow.rs/f93b758 提交)。 性质:核对记录,不改产品代码(本会话 session-role-diagnose-only)。todo 待修项见 docs/todo.md。 关联:定时走查-2026-06-15-P0复核.md(第 1 轮,B-32/33 结论被本轮纠正)。


核心结论:3 前端 P0 全修(第 3 次纠正过时认知)

P0 第1轮判断 第2轮地面复核 提交 处置
B-34 selectType 已修 已修 (确认) 保持
B-32 队列收尾 「未修」 已修 f93b758 todo 标 ,纠正第1轮
B-33 骨架屏 「未修」 已修 f93b758 todo 标 ,纠正第1轮

B-32/B-33 地面证据useAiStream.ts 当前 81 行,第1轮 Read 时为 73 行旧版):

  • :28 state.queue = [] // B-32:超时收尾同步清队列 + useAiEvents.ts:225(AiError) + useAiSend.ts:152(stopChat)/124(approveToolCall catch) 四路径全清队列
  • :43-45 onStreamTimeout 单遍反向扫描 running toolCall → rejected(合并探测 completed 为单次 O(n),实现干净)

B-32/B-33 修复提交f93b758「修复: B-32+33 流式收尾清队列+回滚 running toolCall」3 文件 +18/-7。

第1轮「B-32/33 未修」为过时快照(working tree 当时旧版,与 B-34 同根因)。定时走查连续 3 轮纠正过时 P0 判断B-34 → B-32 → B-33),说明走查必须以地面 Read 为准,不可信赖记忆/旧快照。前端 3 P0 至此全部闭环。


新发现 P0AR-11 前端 listener 永不 attach(功能半接通死代码)

位置src/stores/project.ts:31-55(定义)+ :109-110export+ src/App.vue:203-213onMounted 未挂载)

根因:工作区未提交改动新增 startDataChangedListener/stopDataChangedListener 两函数 + export,但全项目零调用方grep 确认)。后端 emit_data_changedaudit.rs:259-270+ 自动执行路径(audit.rs:351+ 审批路径(commands.rs:175)三处 emit 已就位且逻辑正确,事件 df-data-changed 正常发出,但前端 listen('df-data-changed', …) 永不执行 — 监听器从未 attach。

影响AR-11「数据变更联动刷新」功能完全失效。用户通过 AI 工具(create/update/delete project/task/idea)改数据后,列表不自动刷新,仍需手动刷新(正是 AR-11 要消除的痛点)。后端 emit 成死事件。

修复方向App.vue onMounted 调 await projectStore.startDataChangedListener()onUnmounted 调 stopDataChangedListener()(对齐 ProjectDetail.vue:463/470 的 workflow listener 生命周期模式,数据变更可能来自任意页面)。

性质:工作区未提交半成品(非历史遗留,非 ARC-05 拆分收尾)。代理 C 确认 diff 是纯 AR-11 新增。

注:todo:77 AR-11 条目原标「暂缓」,第2轮复核更正为「后端已实施 ,前端半接通 🔴」。


ARC-05 上帝 store 拆分 — 质量评级:优

提交 8710d6cproject.ts 362→barrel + 5 子 storestate/projects/tasks/ideas/workflow)。

3 项硬指标全部兑现

指标 证据
barrel 零改动兼容 逐字段比对 8710d6c~1 与 8710d6creturn reactive({...})37 key 完全一致(8 getter state + clearError + 9 project + 4 task + 6 idea + 7 workflow actions + pendingApproval/stats computed)。state getter 用 get projects() { return state.projects } 保留「避免 loadXxx 重赋值后视图为空」关键设计
state 真单例 state.ts 模块级 export const state = reactive({...}),ESM 保证全 app 单实例,4 子 store import 同一引用
依赖图无环 4 子 store 互不 import,只依赖叶子 ./statebarrel 单向依赖子 store,无循环/无初始化顺序陷阱

🟡 建议 3

  1. state.ts:32-37 可变 let _eventUnlisten 跨模块共享 + setter,依赖 ESM live-binding(运行时正确但反直觉),建议注释点明或并入 reactive
  2. AR-11 监听器已侵入 barrelworking tree project.ts:31-55),违反「纯 barrel」定位 — 建议抽第 6 子 store project/dataChange.ts(与上面 AR-11 P0 同源)
  3. projects.ts:105 clearError 夹在 projects return 语义错位(属 state 层),建议移除(barrel 已独立从 state 导入)

可选 2:注释「四子 store」实为 5 文件(四领域+共享 state)/ createXxx 入参类型内联可抽 types。

亮点:越层 invoke 下沉彻底(approve_human_approval/cancel_workflow_node 下沉 api/workflow.ts:39-54B-34 snake_case 对齐在 api 层统一)/ ProjectStore 类型 + 单例 _storeInstance 保留 / view 端 7 处 useProjectStore 零改动。


B-22 前后端状态同步 — 实现质量良好

提交 d809cf4ai_is_generating IPCcommands.rs:12+ sendMessage 预检(useAiSend.ts:27)。

设计对症:双源(前端 streaming / 后端 generating)各自维护确有不同步风险,发送前查后端真值对症。

竞态窗口可接受useAiSend.ts:42 查后端与 :97 实际 sendMessage 之间有窗口,但后端 ai_chat_send:57 原子检查+占用(if session.generating { Err } + generating=true 同锁内)是真兜底。前端预检仅优化 UX(提前入队而非发出去被拒),降级路径完备(IPC 失败 catch 退化为原 streaming 预检)。

回归安全:正常事件流(delta/tool/AiAgentRound/AiCompleted/AiError)未改,仅 sendMessage 入口前置预检,不影响 handleEvent。

🟡 Issue 1(低)useAiSend.ts:53-57 入队分支复位 streaming=true未启动看门狗resetStreamWatchdog 只在 :89 正常发送路径调)。极端卡死场景(后端既不 emit、Drop spawn 又未执行)streaming 可能永真。建议入队分支也调一次 resetStreamWatchdog,代价一行。非 d809cf4 新引入回归(onStreamTimeout 本就依赖正常路径启动的看门狗)。

信息 Issue 2useAiSend.ts:60-61 注释「streaming=true 但后端 false」描述与实际复位方向(onStreamTimeout/AiError 复位 streaming=false)有歧义,建议改注释。


CR-11 健壮性批(fddca9d)— 5 亮点 + 1 死逻辑副产品

子项 ⑦⑧⑨⑩⑪⑫ 全部实施

5 亮点

  1. useAiConversations.ts:77-93 JSON.parse 逐条 try/catch(原单条坏 args 清空整对话 → 单条降级空对象)
  2. useAiEvents.ts:130-133 AiHeartbeat 显式 case 防 TS 穷举穿透
  3. useAiSend.ts:84-85 复用 findToolCall(消除内联 flatMap+find 重复 + 反向扫描 O(1) 均)
  4. ToolCard.vue:236-242 argString 去 3 处 as anyRecord<string,unknown> 类型收窄
  5. workflow.ts:44-92 approveHumanApproval 签名收敛 (decisions: string[], comment?)(消除单/多选调用方歧义)

⚠️ ⑪ 实施引入死逻辑(CR-260615-18workflow.ts:67-68 decision = selectType === 'multiple' ? decisions[0] ?? '' : decisions[0] ?? '' 两分支返回值完全相同,三元无意义。后端 workflow.rs:291-296 有兜底。修:直接 const decision = decisions[0] ?? ''

🟡 其他CR-19action 字段 emit 但前端不消费,契约冗余)/ CR-20stopDataChangedListener try/catch 过度防御,与 workflow.ts:108 不一致)。


P0 汇总(仍未修)

ID 问题 状态
B-260615-35 broadcast Lagged 兜底仅 warn → 终态事件丢失前端永久卡死(后端 workflow.rs:90-110 未修(第1轮发现,本轮确认仍在)
AR-11 前端 listener 永不 attachApp.vue 未挂载) 未修(本轮新发现,工作区半接通)

📊 本轮摘要

类别 代表
P0 全修确认 3 B-34(保持/ B-32 / B-33(第1轮过时,本轮纠正)
新发现 P0 1 AR-11 前端 listener 永不 attach(功能半接通)
仍存 P0 2 B-35 broadcast Lagged(后端)/ AR-11 前端 attach
质量肯定 2 ARC-05 store 拆分(优)/ CR-11 健壮性批(5 亮点)
🟡 建议 6 ARC-05 三项 / B-22 看门狗 / CR-18 死逻辑 / CR-19·20
可选 4 ARC-05 两项 / ToolCard 兜底

本轮价值:第 3 次纠正过时 P0 判断(B-32/33 实已修,f93b758),前端 3 P0 全闭环;新发现 AR-11 前端 listener 永不 attach(工作区半接通死代码,功能未闭环);肯定 ARC-05 拆分(3 硬指标全兑现)与 CR-11 健壮性批质量。

方法论警示:连续 3 轮纠正过时判断(B-34→B-32→B-33),根因是第1轮 Read 到 working tree 旧版(73 行)而 HEAD 已是新版(81 行)。走查必须每次地面 Read,不可信赖上轮快照。后续走查代理 prompt 应强调「以当前 working tree + HEAD 为准,git log 看提交,勿用记忆」。

todo 映射:B-32/33 标 + 复核更正 / AR-11todo:77)状态更新 / CR-11todo:212)标 / 新增 CR-260615-18/19/20。