# 定时代码走查 — 第 7 轮（2026-06-15）

> 触发：定时走查 cron（每 30 分钟）。范围 = **stores 独立 store 垂直切片**（ai/knowledge/appSettings/index，未审）+ 核 CR-24/26/27 修复。
> 方法：主代理 git show 3 提交 + 1 路代理走查 stores。
> 性质：核对记录，不改产品代码（本会话 session-role-diagnose-only）。todo 见 `docs/todo.md`。
> 关联：[第1-6轮](./)。

---

## CR-24/26/27 ✅（价值第 6 次闭环）

| 提交 | CR | 修复 |
|---|---|---|
| ef2d033 | CR-24 ✅ | AiChat onBeforeUnmount 补 `store.stopListener()` + useAiEvents stopListener 补 `clearStreamWatchdog()`（卸载清 130s watchdog 避免写已卸载 state）|
| 7637f29 | CR-26 ✅ | project.ts `_activeTaskProject` 三态（undefined 不触发/all 全量/具体 id）+ Tasks.vue 空态兜底（89 行）|
| 5e6aa79 | CR-27 ✅ | Dashboard 删决策/批注死代码（-96 行）+ stage 颜色 + refresh try/catch |

**CR-25（分离窗口状态机 R3/R4/R5）仍存**（无提交提及，接收方未修或在做）。

---

## 🔴 knowledge error 通道断（P1，CR-08 深化）

### CR-260615-28 [P1] state.error 死字段 + create 语义矛盾
- **state.error 死字段**：knowledge.ts:19,49,53,64,74,105 写入 `state.error`，但 **grep 全应用零消费**（Knowledge.vue store.error 零命中）→ 用户遭遇加载/检索/配置失败只看空白列表，无错误提示
- **CR-08 深化**：CR-08「store error fallback 11 处中文」只记了硬编码，**整个 error 通道前端是断的**（写了从不读）— 比中文硬编码更严重
- **create 语义矛盾**：create(:80-85) 成功后调 loadCandidates，若 loadCandidates 失败把错误塞 state.error，但 create 已返回 record 给调用方（认为成功）

**修**：Knowledge.vue 接 error banner/toast，或删 state.error 改 throw 由调用方 catch + create 内 loadCandidates 失败不污染 error。

---

## ✅ ai.ts 状态机完整（亮点，验证修复质量）

四核心态 `streaming/generatingConvId/currentText/queue` 在 **6 复位点闭环**，无卡死 streaming=true 缺口：
- AiCompleted（useAiEvents:189-217）/ AiError(:220-235) + queue=[]（B-32）
- onStreamTimeout(useAiStream:25-28) + queue=[] + running→rejected(B-33)
- sendMessage catch(useAiSend:99-105)/ approveToolCall catch(:121-133) + queue=[]
- stopChat(:149-154) 本地先复位再发停止信号（不依赖后端 AiCompleted，防审批态看门狗已 clear 致 AiCompleted 竞态丢失）
- 分离窗口 resumeInDetached(useAiWindow:111) 先 invoke('ai_is_generating') 核对（R4 防 df-ai-gen 残留假气泡）

> 验证：B-32/33/ef2d033 修复质量扎实，状态机无非法组合残留。

## ✅ appSettings 双源同步（亮点）

三态 `cache(reactive)↔SQLite↔ref`：
- set 乐观写 cache + debounce 300ms 合并 + pendingValues 取最新值（非定时器快照），落库失败仅日志（UI 一致性优先，不回滚致不一致）
- useSetting 双 watch `Object.is` 守卫防循环
- switchConversation 双 token 竞态防护（useAiConversations:44,48,52,122 `_latestSwitchId`）

---

## 🟡 P2/P3 新发现

### CR-260615-29 [P2] ai.ts messages 无上限 + knowledge 竞态/错误不一致
- **ai.ts messages 单对话无上限**：useAiSend push user+ai / useAiEvents push err/审批 / useAiStream push delta，单对话线性增长（切换对话整体替换是减负点，但同对话不轮换），长会话+大工具结果内存可观
- **knowledge 异步无竞态**：loadList/search/loadConfig 无请求序号（messages 有 switch token），快速连点后返回覆盖先
- **knowledge 错误处理不一致**：load*/search 有 catch 兜底，create/updateStatus/archive/saveConfig/extractNow 直抛（调用方无 catch 致 unhandled）

### CR-260615-30 [P3] appSettings useSetting 对象值不落库（边界）
useSetting 双 watch `Object.is` 守卫对值类型完美防循环，但**对象/数组值深 mutate**（`r.value.x=1`）时 `Object.is(v,cache[key])` 同引用恒 true → 不触发 set 落库，静默不持久化。当前无 bug（useSetting 多绑值类型，df-ai-ui 走 set 整对象替换），隐式契约。

---

## 📊 本轮摘要

| 类别 | 数 | 代表 |
|---|---|---|
| 价值闭环 | 3 | CR-24/26/27 全修（修复质量好）|
| P1 新发现 | 1 | knowledge error 通道断（CR-28，CR-08 深化）|
| P2/P3 新发现 | 2 | ai.ts messages 无上限 + knowledge 竞态（CR-29）/ useSetting 对象值边界（CR-30）|
| 亮点 | 2 | ai.ts 状态机完整（6 复位点，验证修复质量）/ appSettings 双源同步设计扎实 |

**本轮价值**：
1. **knowledge error 通道断**是新维度发现 — CR-08 只记中文硬编码，实际整个 error 通道前端断的（写了从不读），用户看不到知识库错误
2. **ai.ts 状态机完整肯定前几轮修复质量**（B-32/33/ef2d033 闭环无卡死缺口）— 走查不仅找问题也验证修复
3. CR-24/26/27 三项 P1/P2 全修，走查↔接收方闭环高效（第 6 次闭环）

**方法论**：第 5 个垂直切片（stores），knowledge error 通道断是新发现维度（超越 i18n 的功能缺陷）。ai.ts 状态机完整是「走查验证修复」价值（非只找 bug）。

todo 映射：CR-260615-28（P1 knowledge error）/ CR-29（P2 messages+竞态）/ CR-30（P3 useSetting 边界）。
