# 定时代码走查 — P0 状态复核（2026-06-15）

> 触发：定时走查 cron（每 30 分钟）。本轮重点 = 自上次走查（HEAD `4b5f096`）起新增内容走查 + 既有 P0 修复状态地面复核。
> 方法：2 路后台代理（TaskDetail.vue 新文件 / 后端提交 `2de0c6e` 16 文件大改）+ 主代理地面核对（`project.ts:273` / `workflow.rs:211` / `useAiStream.ts` / `stream_recv.rs` / `todo.md`）。
> 性质：核对记录，不改产品代码（本会话 session-role-diagnose-only）。todo 待修项见 `docs/todo.md`。
> 关联：[工作区多角度走查-2026-06-15.md](./工作区多角度走查-2026-06-15.md)（上一轮，3 P0 + DRY 发现源头）。

---

## 核心结论：纠正过时认知（定时走查首要价值）

| P0 | 上轮判断 | 本轮地面复核 | 处置 |
|---|---|---|---|
| **B-260615-34** selectType | 「未修，仍 camelCase」 | **已修 ✅** — `project.ts:273` 现为 `select_type: ... ?? 'single'` + 正确注释「Tauri 2 IPC 不转 camelCase，须 snake_case 对齐后端 workflow.rs:211」；后端 `workflow.rs:211` 同 `select_type: Option<String>`。前后端契约对齐。 | todo 标 `[x] ✅`，删过时描述 |
| **B-260615-32** 队列收尾 | 未修 | **仍未修 ❌** — `onStreamTimeout`（useAiStream.ts:24-53）复位 streaming/generatingConvId/currentText + clearStreamWatchdog + 反向扫 completed toolCall 区分文案 + push 错误消息，**仍不清 `state.queue`**（useAiSend:116 有 clearQueue 但收尾路径未调）→ 生成中输入消息丢失 | todo 加复核标注，仍 `[ ]` |
| **B-260615-33** 骨架屏 | 未修 | **仍未修 ❌** — `onStreamTimeout` 仍**不回滚 running toolCall**（只读 `status===completed` 做文案判断，不改 running→rejected）→ 审批卡片后端 hang 时永久骨架屏，无重审入口 | todo 加复核标注，仍 `[ ]` |

> 「B-34 未修」是上一轮压缩前快照，之后提交（`80b9243`「P0 bug 修复」批）已修。后端代理通过后端 IPC 签名推断「前端已对齐」**结论正确**。定时走查纠正过时认知，避免「以为没修催着修」。

---

## 新发现 P0（后端代理 ②）

### B-260615-35 — broadcast `Lagged` 兜底仅 warn，关键终态事件丢失时前端永久卡死

**位置**：`src-tauri/src/commands/workflow.rs:90-110`（forward 任务循环）

**问题**：`run_workflow` 的 forward 任务靠 `finished = matches!(event, WorkflowCompleted | WorkflowFailed)` 判定退出。broadcast 滑动窗口 `Lagged(n)` 时丢 n 条最旧事件，代码注释**已识别风险**（「关键终态事件可能永久丢失」），但兜底措施只有 `tracing::warn!`，**没有主动从 DB 查终态或加 watchdog 超时**。若 Lagged 恰好丢了 WorkflowCompleted/Failed，forward 任务永远 `rx.recv().await` 等不到 finished，前端依赖事件关闭审批/完成弹窗的场景**永久卡死**，只能靠 DB 轮询兜底（实时性差）。

**修法（代理建议）**：`Err(RecvError::Lagged(n))` 分支后加被动超时/主动查 DB — 累计 lag 次数到阈值或单次 n 过大时，查 `WorkflowRepo::get_by_id(&forward_exec_id)` 看是否终态，若是则补 emit `workflow-event` 给前端并 break。需把 `state.db.clone()` 也 move 进 forward 任务（当前仅 executor spawn 持有 db）。

**优先级**：P0（低频但后果为「永久卡死」无自愈），开发者已知未做兜底。

---

## 新内容走查结果

### 1. TaskDetail.vue（362 行新文件）— DRY 复发，单文件质量良好

| # | 等级 | 发现 |
|---|---|---|
| ① | 🔴 | `.ai-md` 样式块**第 5 份重复**（CR-260615-09 复发）：`:263-333` ~70 行与 ProjectDetail/Ideas/Knowledge 逐字符同，累计 ~350 行重复 CSS。TaskDetail 是抽公共样式（`src/styles/ai-md.css` 或 `composables/useMarkdownCss.ts`）最佳时机 |
| ② | 🔴 | `renderedDescription` computed **第 4 份重复**（CR-260615-10 复发）：`:116-119` `void mdReady.value` 技巧四处重复。建议 `useMarkdown` 增 `renderedRef()` 帮手收敛 |
| ③-⑦ | 🟡 | 路由 id 空守 / 快切竞态（无序号/AbortController）/ 错误信息缺 `.message` 优先 / `projectApi.list()` 全量拉取仅解名 / 静态文案半 i18n 半硬编码 |
| ✅ 亮点 | — | XSS（DOMPurify + escapeFallback 双层）/ `void mdReady` 响应式依赖捕获（注释明确 B-24 修复点）/ Promise.all 并发 / onMounted 不阻塞 load |

### 2. 后端提交 `2de0c6e`（16 文件 1418+/152-）— 工程化重构扎实，1 真实 P0 + 文档完善项

| # | 等级 | 位置 | 发现 |
|---|---|---|---|
| ① | 🔴 | stream_recv.rs:97-108（2de0c6e 版） | 注释虚假承诺「stop_notify 即时打断」，实际该提交无 stop_notify 分支。**working tree 已修** — `80b9243` 补了本地 Notify + 第 3 select 分支（:102-154 现状），无需记 todo |
| ② | 🔴 | workflow.rs:90-110 | **见 B-260615-35**（broadcast Lagged 终态丢失） |
| ③ | 🟡 | stream_recv.rs:60-69 | `"timed out"` 分支**非死代码**（代理自查纠正初判：`"operation timed out"` 不含子串 `"timeout"`），可合并到首分支提升可读性 |
| ④ | 🟡 | commands.rs:265-287 | `ai_chat_stop` 3s 兜底任务用闭包前快照 conv_id，会话切换后 emit 错对话（spawn 内重新读 active_conversation_id 配合 generating 判定） |
| ⑤ | 🟡 | commands.rs:367/313/452 | tauri async cmd 内同步调 keyring IO 占 runtime worker，建议 `spawn_blocking`（Linux secret-service D-Bus 慢时影响明显） |
| ⑥ | 🟡 | commands.rs:313-322 | `ai_list_providers` mask 后 api_key 字段语义模糊（`""`/`"sk-xxx"`/`"sk-1••••xyz9"` 三语义混一字段），建议拆 `has_api_key: bool` + `api_key_mask` |
| ⑦ | 🟡 | secret.rs:51-64 | failcount sidecar 锚 `current_dir()` 不稳定（跨启动 cwd 变化致计数失效），建议改 `app_data_dir`（同 db_path） |
| ⑧ | ⚪ | Cargo.toml + secret.rs | keyring noop backend 自检缺失，Linux 漏 feature 时 set 静默成功 get 永空 → 兜底误判「已迁移」清 DB api_key 致密钥永久丢失 |
| ⑨ | ⚪ | agentic.rs:317-361 | 达 MAX_AGENT_ITERATIONS 后先 emit AiError 再 emit AiCompleted，前端 UX 处理依赖实现 |
| ⑩ | ⚪ | workflow.rs:213 | `let _ = &app;` 显式占位，直接删 app 参数更清晰（Tauri 自动重生成路由） |
| ✅ 亮点 | — | B-09 GeneratingGuard RAII 收敛复位（Drop 兜底 panic/异常路径）/ B-11 stale loop 一致性校验（会话切换旧 loop 自动退出）/ stream_recv 错误诊断体系（char 迭代修 UTF-8 边界 panic + 11 单测）/ secret.rs keyring 优先+DB 兜底双源 / tool_registry 双层校验防 symlink 逃逸 + 单次 open 消 TOCTOU |

---

## 其他确认

- **aiShared.ts 破环 ✅ 亮点**（ARC-260615-06 落地）：`nextMsgId` 下沉 aiShared，useAiStream 注释明确「本模块不再 import useAiEvents，环消除」。4 composable 共享同一计数器，边界严格（仅下沉「无依赖、被多 composable 共用」成员）。
- **stream_recv.rs working tree 已补 stop_notify ✅**（:102-154 三分支 select! 含 stop_notify 即时打断）。2de0c6e 提交自带的注释虚假承诺问题，已被后续 `80b9243` 修代码侧，**当前 working tree OK，无需记 todo**。

---

## 📊 本轮摘要

| 类别 | 数 | 代表 |
|---|---|---|
| P0 状态复核 | 3 | B-34 已修 ✅（纠正过时）/ B-32 未修 / B-33 未修 |
| 新发现 P0 | 1 | B-260615-35 broadcast Lagged 终态丢失 |
| 🔴 DRY 复发 | 2 | CR-09（四→五份）/ CR-10（第四份）|
| 🟡 建议 | 12 | TaskDetail 5 + 后端 5 + stream_recv 1 + workflow 1 |
| ⚪ 可选 | 4 | 后端 3 + TaskDetail 1 |
| ✅ 亮点 | 4 | aiShared 破环 / GeneratingGuard RAII / stale loop 校验 / stream_recv 错误诊断 |

**本轮价值**：纠正 1 个过时 P0 判断（B-34 已修）、坐实 2 个 P0 仍未修（B-32/33）、新增 1 个真实 P0（B-35）、确认 1 个架构亮点落地（aiShared 破环）。无运行时 panic/数据损坏/并发竞争类硬伤，后端重构质量评级**良**。

todo 映射：B-260615-35（新增）；CR-260615-09 描述更新（四→五份）；B-260615-34 标 ✅；B-260615-32/33 加复核标注。
