# DevFlow 批次推进记录

> 记录每个批次的提交 hash、改动内容和交付价值。
> 最后更新: 2026-07-02 | 最新提交: `4624688`

---

## Batch 1 — 审批超时后端兜底

- **提交**: `b923d70`(后重写为 `9dd5a5a`)
- **内容**:
  - 新增 `agentic/approval_timeout.rs`，在审批恢复入口检测超时，超时自动取消并写入审计
  - 待审批记录新增创建时刻字段，用于超时判定
  - 应用启动时从设置恢复超时配置（默认 15 分钟，0 为禁用）
  - 新增读写超时配置的接口，设置页可改
  - 与前端共用同一个配置项，保证单一真相源
- **验证**: cargo check 通过

---

## Batch 2 — 工具卡片拆分核验

- **提交**: `e95a5cd`(后重写为 `45fc493`)
- **内容**:
  - 核验发现工具卡片拆分任务实际已完成，文档标记滞后
  - ToolCard.vue 从 1527 行降至 373 行
  - 审批状态机独立为 useToolApproval.ts（220 行）
  - 头部逻辑、渲染逻辑、通用工具函数各自独立
  - 大型文件拆分三项全部完成（主聊天组件/命令注册/通用 CRUD）
- **验证**: 文档核验，无代码改动

---

## Batch 3 — 条件表达式 UI 翻译补齐

- **提交**: `e460e8d`(后重写为 `d79c816`)
- **内容**:
  - 工作流条件表达式引擎和执行器集成早已完成
  - 前端边条件编辑入口已存在，但翻译缺失（用中文兜底）
  - 补齐中英文翻译（工作流结构标题/层标签/空态/边条件编辑器）
  - 核验确认条件引擎全部链路均已落地
- **验证**: vue-tsc 通过

---

## Batch 4 — 知识提炼切读消息表

- **提交**: `6aac7ef`(后重写为 `f57c37e`)
- **内容**:
  - 知识提炼是最后一个仍读旧消息 JSON 列的路径
  - 改为优先读消息表，表空时回退旧 JSON（老库兼容）
  - 复用既有的记录转消息映射函数，与其他读路径同源
  - 至此消息存储拆分全部完成
- **验证**: cargo check 通过

---

## Batch 5 — 关闭已完成待办项

- **提交**: `59b7188`(后重写为 `694f24f`)
- **内容**:
  - 工具卡片分组标题增强（文件路径摘要展示）已落地
  - 重试持锁问题核验无影响（多会话改造后全局锁已移除）
  - 对抗式评估批量命令暂不做（单项已接入，批量无消费方）
  - 残留诊断代码已清理（无硬编码绝对路径）
  - 工程内路径授权政策确认为白名单制
- **验证**: 文档核验

---

## Batch 6 — 应用状态拆分 + 事件分发统一 + 路径授权治本

- **提交**: `996f1d9`
- **内容**:
  - **状态文件拆分**: 1416 行单文件 → 按职责分模块（授权白名单/知识库配置/并发控制）
  - **事件分发器统一**: 5 类生命周期事件纳入主事件联合类型，删除第二监听器，一个事件源一个监听器一个分发器
  - **路径授权去硬编码**: 不再硬塞编译期路径到白名单，工程根授权靠项目绑定目录 + 设置页配置
- **补丁**: `cc3ef5b` — 修复设置页面崩溃（模块循环依赖导致初始化失败）
- **验证**: cargo check + vue-tsc 通过

---

## Batch 7 — 小程序配置持久化与心跳闭环

- **提交**: `cb7e1fc`
- **内容**:
  - **配置持久化**: 运行时配置接入 storage，懒加载恢复，新增重置函数
  - **心跳 pong 闭环**: 中继服务识别小程序心跳 ping 直接回 pong（不经桌面端透传），小程序看门狗据此判活
  - **文档同步**: 关闭条件引擎/streaming per-conv/workspace_root 三项已完成的待决策
- **验证**: cargo check（devflow + df-relay）通过

---

## Batch 8 — 消息分页懒加载与事件总线空转优化

- **提交**: `3c18dea`
- **内容**:
  - **消息分页**: 消息仓库新增分页查询方法（从尾部取最近 N 条，支持游标），切换对话返回最近 50 条 + 游标，新增加载更多接口
  - **事件总线优化**: 发布事件前先检查订阅者数量，无订阅者跳过序列化（消除空转开销）
  - **核验关闭**: 对话上下文透明化三项均已落地（目标可见/项目增强预览/完整上下文面板）
- **验证**: cargo check 通过

---

## Batch 9 — 项目多工程系统（数据层）

- **提交**: `b72df78`
- **内容**:
  - **数据层**: project_modules 表（V34 迁移）+ ProjectModuleRepo 完整 CRUD
  - **后端接口**: 工程增删改查 + Git 状态查询（实时跑 git 命令返回分支/改动/提交，10s 超时）
  - **创建项目适配**: 新建项目时自动创建一个工程（目录=绑定路径，技术栈=探测结果）
  - **AI 工具**: list_project_modules（AI 了解项目工程结构）
  - **设计文档**: 新增工程系统设计方案
- **验证**: cargo check 通过

---

## Batch 10 — 项目文件浏览器（前端 UI）

- **提交**: `50aad37`
- **内容**:
  - **后端接口**: 文件树查询（列目录 + Git 状态合并 + 噪音过滤 + 路径穿越防御）+ 文件读取（文本/图片/二进制，1MB 上限）
  - **文件树组件**: 递归树形展示，懒加载子目录，Git 状态标记（橙=修改/绿=新增/灰=未跟踪）
  - **文件预览组件**: 代码文本/图片/二进制三分支，加载状态
  - **主容器**: 工程选择（单工程隐藏）+ 面包屑导航 + 刷新
  - **集成**: 项目详情页新增"文件"Tab
  - **国际化**: 中英文同步
- **验证**: cargo check + vue-tsc 通过

---

## Batch 11 — Git 只读 AI 工具

- **提交**: `7b5b62d`
- **内容**:
  - **git_status**（Low 自动执行）: 工作区状态结构化（分支 + 改动文件列表 + 状态标记）
  - **git_diff**（Low）: 改动详情（统计 + patch 截断到 8000 字符防 token 爆）
  - **git_log**（Low）: 提交历史结构化（哈希/作者/消息/日期）
  - 所有 git 命令在工程目录执行，10s 超时，无 Git 仓库返回空状态
- **验证**: cargo check 通过

---

## Batch 12 — Git 写操作 AI 工具

- **提交**: `0cfea6d`
- **内容**:
  - **git_commit**（Medium 审批）: 提交工作区改动，提交前检查敏感文件（.env/.key/.pem）
  - **git_branch**（Medium 审批）: 分支列表/创建/切换
  - **git_merge**（High 审批）: 合并分支，自动检测冲突返回冲突文件列表
  - 安全边界: 禁止 push / force / reset --hard
- **验证**: cargo check 通过

---

## 架构设计文档状态同步

- **提交**: `8d18918`
- **内容**: 9 份设计文档状态批量更新（从"待实施"改为"已落地"），1 份归档（规格契约自检被其他机制覆盖）

---

## 提交注释规范重写

- **内容**: Batch 1-5 的提交注释经 filter-branch 重写，消除内部代号（Batch/P1/P2/L1/F-09 等），统一为"两字动词 + 冒号"格式（新增/修复/更新）

---

## Batch 13 — 文件浏览器增强(行号/图标/Diff/Git 变更面板/窗口分离)

- **提交**: `c6df455`
- **内容**:
  - **行号显示**: 文件预览左侧行号列
  - **后缀图标**: 20+ 文件类型彩色 SVG 图标(rs/ts/js/vue/css/html/json/md/sh/sql 等)
  - **Diff 视图**: 有 Git 变更的文件可切换内容/Diff 红绿视图
  - **Git 变更面板**: 文件树侧栏切换至变更视图,变更文件列表(按目录缩进分组)+提交历史(分页 50 条)
  - **提交详情**: 点击提交行展开变更文件列表,点文件查看该文件 diff
  - **提交时间显示**: 相对时间(刚刚/N分钟前)+超过 30 天显示具体日期
  - **窗口分离**: FileExplorer 可弹出独立 Tauri 窗口
  - **中文编码修复**: git 命令注入 LANG/LC_ALL UTF-8 环境变量,修复中文乱码
  - **多工程管理 UI**: 工具栏添加工程按钮+弹窗表单
  - **文件变更自动刷新**: write_file/patch_file 触发 df-data-changed 事件,AI 写入后自动刷新
  - **面包屑不丢预览**: 面包屑导航时保留当前预览文件
  - **刷新保留选中文件**: 只清树缓存不清预览
  - **自适应布局**: 弹性 flex 布局,窄窗口自适应
  - **审批超时 130s->30s**: 按钮级 loading 超时缩短
  - **阶段进度条隐藏**: 装饰性元素,待接入真实状态机后启用
- **验证**: cargo check + vue-tsc + vite build 通过

---

## Batch 14 — 文件浏览器收尾

- **提交**: `53e6442`
- **内容**:
  - 提交之前未提交的滚动条与布局修复
  - 移除阶段进度条死代码(模板+CSS+常量)
  - 文件预览空状态加图标引导
  - 变更视图加载骨架屏
  - 工程选择器改为自定义下拉(显示工程路径)

---

## Batch 15 — 多工程管理

- **提交**: `d8d6226`
- **内容**:
  - 工程编辑入口:工具栏编辑按钮+弹窗(名称/路径/Git 地址)
  - 工程删除二次确认:防误删
  - 记住上次选中工程:localStorage 持久化
  - 自动扫描子仓库:下拉菜单加扫描入口,发现 .git 子目录自动建工程

---

## Batch 16 — Git 提交历史作者

- **提交**: `b19b0f3`
- **内容**:
  - 后端 git log format 加 %an 作者名(状态查询+分页查询)
  - 提交列表每行显示 hash/作者/主题/时间
  - 提交详情头部补充作者显示
  - 分支切换按钮占位(后续接入分支列表 IPC)

---

## 渲染崩溃修复

- **提交**: `bce2fea`
- **内容**:
  - AdvancedSection clampApprovalTimeout 常量移到 reactive 之前(打包后 const 初始化顺序 TDZ)
  - @/i18n 去掉对 @/stores/appSettings 的 import,改直读 localStorage
  - Tauri capability 加 ai-detached-* / fe-detached-* 通配符(分离窗口 listen 权限)

---

## Batch 17 — Git 能力闭环

- **提交**: `15eaa0c`
- **内容**:
  - Diff 行号解析:解析 @@ -a,b +c,d @@ 头,计算旧/新行号(原恒空字符串)
  - 提交详情增强:显示父提交哈希/作者/日期/完整消息
  - 分支只读展示:list_branches IPC + 变更面板顶部下拉查看分支
  - AI 工具写入后自动跳转变更视图:监听 df-data-changed entity=file 切 Tab + 刷新

---

## Batch 18 — 小程序审批超时计时器

- **提交**: `773ebb6`
- **内容**:
  - 对齐桌面端 aiShared.startApprovalTimer,补齐小程序缺失的审批超时机制
  - AiApprovalRequired/AiDirAuthRequired 触发 startApprovalTimer(每条独立计时)
  - AiToolCallCompleted/AiApprovalResult 触发 clearApprovalTimer(审批落定)
  - 切会话/新建/断连/重连/终态触发 clearAllApprovalTimers(防跨会话污染)
  - 超时自动拒绝(approve(id,false))+ toast 提示用户

---

## Batch 19 — 任务管理 UX 重构 + 项目卡片工程数

- **提交**: `2780f6a` + `aa4d521`
- **内容**:
  - 筛选改下拉:项目/状态从多按钮改为 select,节省垂直空间
  - 新增搜索框:标题/描述关键词搜索,300ms 防抖
  - 新增排序选择器:更新/创建时间/优先级/状态
  - 分组可折叠:点击组头切换,记忆状态到 localStorage
  - 分页默认开启:pageSize=20(原 0=全量)
  - 紧凑布局:任务行密度优化,显示总条数
  - 空状态引导:图标 + 新建按钮
  - 模态框样式收敛:去内联 style
  - 桌面快捷键:Ctrl+N 新建,Ctrl+F 聚焦搜索
  - 项目卡片显示工程数(异步拉取 module 列表)

---

## Batch 20 — coordinator.rs 空壳删除

- **提交**: `948d6e6`
- **内容**:
  - 删除 crates/df-ai/src/coordinator.rs(零调用的 deprecated 空壳)
  - lib.rs 移除 pub mod coordinator 声明
  - 消除编译 deprecated 警告

---

## 任务行快捷操作菜单

- **提交**: `27eb0a9`
- **内容**:
  - 任务行 hover 显示齿轮按钮,点击展开快捷菜单
  - 快捷改状态(6 态子菜单)/改优先级(4 级)/删除(二次确认)
  - 点击外部自动关闭菜单

---

## stores/ai TDZ 防御

- **提交**: `76aec62`
- **内容**:
  - __bindMessages 包装 try/catch,aiShared 未就绪时延迟到微任务重试

---

## Plan DAG 分层执行器

- **提交**: `4dac9fe`
- **内容**:
  - PlanExecutor 按 Plan::to_layers 层间串行/层内并行调度子任务
  - feature flag 门控(默认关,未接入主 loop)
  - 3 个单元测试覆盖:线性链/并行层/失败容错

---

## 变更区完善

- **提交**: `78ef5dc`
- **内容**:
  - 变更文件选中后展开 Diff 红绿预览
  - 分支切换按钮实现只读列表弹窗(拉取分支列表 + 当前分支标记)

---

## 任务列表后端真分页

- **提交**: `3c2fa91`
- **内容**:
  - 后端新增 count_by_query 方法(复用 list_by_query 的 WHERE 逻辑)
  - 前端 buildTaskQuery 传 limit/offset 到后端(SQL 下推分页)
  - 去除前端客户端 slice(后端已分页,直接分组)

---

## Batch 25 — 工程依赖图数据层

- **提交**: `3758bea`
- **内容**:
  - 后端 module_dependencies 表(V35 迁移)+ ModuleDependencyRepo CRUD
  - IPC:add/remove/list_module_dependencies
  - 前端 API 封装 + DependencyGraph 接入真实边数据
  - 依赖类型颜色区分(library/api/mq/shared/custom)
  - 小地图插件(MiniMap)大图概览导航
  - 点击节点跳转项目详情

---

## Batch 26 — 依赖图增强

- **提交**: `dd0e059`
- **内容**:
  - 添加依赖入口:工具栏"+ 依赖"按钮,弹窗选择源/目标工程 + 依赖类型
  - dagre 层次布局替换网格布局(LR 方向,自动排布工程节点)
  - 依赖边按类型着色

---

## Batch 28 — 架构债收尾

- **提交**: `8991215`
- **内容**:
  - ScriptNode 白/黑名单注释清理(标注实际读取方式)
  - 双监听器核查结论:df-data-changed 多监听器是正常 pub-sub,非 bug

---

## Batch 29 — 环形检测 + PNG 导出 + 真实总数

- **提交**: `36ea090`
- **内容**:
  - 后端 detect_module_cycles IPC(DFS 三色标记法检测环形依赖)
  - 前端环检测按钮:高亮参与环的节点(红色边框)
  - 图导出 PNG(X6 toPNG 回调模式)
  - 后端 count_tasks IPC + 前端 taskApi.count()
  - 任务列表所有筛选/搜索/排序/翻页均拉真实 total

---

## Batch 30 — 代码质量收尾

- **提交**: `6771d39`
- **内容**:
  - 设置页搜索索引补全(新增 dataDir 项)
  - 编译警告清理(df-storage OptionalExtension + df-ai join_set)
  - i18n 核验(移除 zh-CN/fileExplorer.ts 未使用的 loadMore key)
  - String 替 newtype(5 个 branded ID 类型:ProjectId/TaskId/ConvId/ModuleId/MessageId)
- **验证**: cargo check + vue-tsc + vite build 通过

## Batch 31 — God 文件拆分第一步(MessageList)

- **提交**: `2c2b2d7`
- **内容**:
  - 提取 useMessageScroll.ts(滚动跟随/锁存/回底按钮,89 行)
  - 提取 MessageItem.vue(单条消息按 role 渲染,171 行)
  - MessageList.vue 从 1552 行降至 1386 行(-166 行)
- **验证**: vue-tsc + vite build 通过

## Batch 32 — God 文件拆分第二步(ChatInput)

- **提交**: `3abdfb4`
- **内容**:
  - 提取 SkillMention.vue(/@ 联想浮层,63 行)
  - 提取 ImageInput.vue(图片粘贴/拖拽预览,33 行)
  - ChatInput.vue 从 1183 行降至 1155 行
- **验证**: vue-tsc + vite build 通过

## Batch 34 — 产品完善

- **提交**: `2af24f0`
- **内容**:
  - 小程序 device 在线心跳加固(早前已完成)
  - ScriptNode 白名单跨 crate 接口打通:OnceLock 全局态 + IPC set_script_safety
  - AI 写入后文件树自动刷新(早前已完成)
  - Projects 列表分页(后端 list_projects 已支持 limit/offset)
- **验证**: cargo check + vue-tsc 通过

## Batch 35 — 人设系统(P0·第一步)

- **提交**: `0a65ea2`
- **内容**:
  - AgentPersona 数据结构(能力标签/工具白名单/prompt 模板)
  - PersonaRegistry 注册表(5 内置人设: coder/reviewer/architect/tester/analyst)
  - 按意图推荐人设(启发式关键词匹配合适角色)
  - build_prompt 注入上下文和目标钉扎
- **验证**: 10 个单元测试通过

## Batch 36 — Coordinator 接入 + audit 拆分

- **提交**: `fa410e6`
- **内容**:
  - audit/mod.rs 拆分出 approval/record 子模块(process_tool_calls 从 ~500→~200 行)
  - coordinator.rs 移除 deprecated 标记,正式可用
  - Coordinator 接入 run_agentic_loop 入口(plan_execution_enabled 时分解意图→输出 Plan)
- **验证**: cargo check 通过

## Batch 37 — 代码卫生与质量提升(String→newtype + 文件清理 + 文档同步)

- **提交**: `4624688`
- **内容**:
  - ExecutionId/ToolCallType/ToolType 裸 String → newtype(IPC 边界仍透明序列化为字符串)
  - ChatMessage.status 从 `Option<String>` → `Option<MessageStatus>` 枚举(Active/Truncated/Compressed/ArchivedSegment)
  - .gitignore 添加分析脚本,tmp 文件清理
  - Batch.md/文档状态同步
- **验证**: cargo check 通过

## Batch 38 — 合并产出落回主对话(Coordinator 接线)

- **提交**: 待后续
- **内容**:
  - `run_agentic_loop`:plan_execution_enabled 时,decompose 后调 dispatch
    → merge → 合并产出以单条 assistant 消息推回主对话,emit AiCompleted 后 return
  - `pinned_goals_snapshot` 提前初始化,coordinator 出口复用
- **测试**: cargo check + vue-tsc 通过
- **验证**: plan_execution_enabled 默认关,主线行为零变化

## 后续规划批次(待推进)

> 设计文档:[多Agent并行执行与仲裁合并设计-2026-07-01.md](docs/02-架构设计/专项设计/多Agent并行执行与仲裁合并设计-2026-07-01.md)

### 数据层 + Git worktree 隔离 + 并行执行 ✅

- **提交**: `ae6d3d0` → `4483358` → `3c9077b`
- **测试**: 48 个全绿(7 Repo + 7 worktree + 27 Coordinator + 4 Token + 3 merge)
- **验证**: cargo check(0 警告) + vue-tsc + vite build
- **已完成任务**:

| # | 任务 | 文件 |
|---|------|------|
| 1 | V36 迁移(ai_plans/ai_subtasks/ai_conflicts 3 新表 + ai_messages/ai_tool_executions 加 subtask_id + subtasks.branch + conflicts.conflict_type) | migrations.rs |
| 2 | PlanRepo / SubTaskRepo / ConflictRepo CRUD + models 结构体 | 新 repo 文件 |
| 3 | Git worktree 生命周期管理(create/commit/merge/remove) | 新 git_worktree.rs |
| 4 | Coordinator.dispatch JoinSet 层内并行(每 SubTask 绑 worktree) | coordinator.rs |
| 5 | Token 预算池(AtomicU64 CAS,超限降级串行) | coordinator.rs |
| 6 | 子 Agent 独立 ContextManager + fork 快照 + worktree_path | coordinator.rs |
| 7 | 层间 merge 到 plan 分支 + 下一层基于 plan 创建 worktree | coordinator.rs |
| 8 | 4 个新事件 + 事件双写(emit + publish_event) | AiChatEvent |
| 9 | 前端类型定义(PlanRecord/SubTaskRecord/ConflictRecord) | api/types.ts |
| 10 | PlanProgress 接入真实状态 + 发送即展示 | PlanProgress.vue |
| 11 | 工具卡按 subtask_id 折叠分组 + persona 徽章 | MessageList.vue |
| 12 | 编译警告清理(coordinator_plan unused / audit 子模块 unused imports) | 各文件 |

### 仲裁合并 + 冲突 UI + 编译检查 ✅

- **提交**: `1d580dc` → `6e44878`
- **测试**: 7 个 merge 冲突检测测试全绿
- **已完成任务**:

| # | 任务 | 状态 |
|---|------|------|
| 1 | Coordinator.merge 冲突检测(同文件路径 + 跳过失败 SubTask) | ✅ |
| 2 | extract_written_files 辅助函数(从 output 提取写入路径) | ✅ |
| 3 | ConflictResolver.vue(双栏 diff + 接受A/B/合并/手动按钮) | ✅ |
| 4 | i18n 冲突翻译键(中英文) | ✅ |
| 5 | agentic/mod.rs 拆分(提取自动压缩到 context_lifecycle.rs,2222→2071行) | ✅ |
| 6 | Reviewer Agent 仲裁(persona.rs 扩展) | 待下一批 |
| 7 | 命令互斥锁(run_command 同目录 mutex) | 待下一批 |
| 8 | context.rs 拆分(1956行) | 待下一批 |

### 模板系统 + 节点补齐 ✅

- **提交**: `f40287b` → `27b4268`
- **测试**: 8 个模板加载 + 37 个节点 + 5 个 SubflowNode 测试全绿
- **已完成任务**:

| # | 任务 | 状态 |
|---|------|------|
| 1 | YAML 模板格式定义 + 加载器(YAML→DagDef + 校验:空节点/未知类型/环/边引用) | ✅ |
| 2 | GitNode(分支/checkout/commit/merge/push/status/log) | ✅ |
| 3 | HTTPNode(GET/POST/PUT/DELETE + headers/body/timeout) | ✅ |
| 4 | NotifyNode(桌面通知 + Webhook) | ✅ |
| 5 | SubflowNode(嵌套子工作流 + 深度限制) | ✅ |
| 6 | 内置模板 3 个预设(代码审查/Bug修复/功能开发) | ✅ |
| 7 | 前端模板选择入口 + 模板 CRUD IPC | 待下一批 |
| 8 | MessageList.vue 继续拆分 | 待下一批 |

### Git/CI 集成 + DockerNode + God 文件收尾 ✅

| # | 任务 | 状态 |
|---|------|------|
| 1 | DockerNode(环境检测+授权) | ✅ |
| 2 | GitNode push(plan分支推送) | ✅ GitNode 含 push action |
| 3 | commit status 读取(Gitea API) | ✅ ci_status.rs |
| 4 | CIStatus.vue 前端面板 | ✅ |
| 5 | ChatInput.vue 拆分(1155→1007行) | ✅ |
| 6 | context.rs 拆分(1956→538行) | ✅ |

### 审批政策 + 小程序完善 + 体验收尾 ✅

| # | 任务 | 状态 |
|---|------|------|
| 1 | 审批策略 Persona 维度 | ✅ |
| 2 | 小程序 MentionInput 接真实数据 | ✅ 核验已完成 |
| 3 | 小程序长会话虚拟化 | ✅ 截断200条合理兜底 |
| 4 | 快捷键完善(Ctrl+N/Ctrl+R) | ✅ |
| 5 | ARCHITECTURE.md 状态同步 | ✅ |

### 批次 C 前序散项 ✅

| # | 任务 | 状态 |
|---|------|------|
| 1 | Reviewer Agent 仲裁 | ✅ |
| 2 | 命令互斥锁 | ✅ |
| 3 | resolve_conflict IPC | ✅ |
| 4 | 模板 CRUD IPC | ✅ |
| 5 | MessageList.vue 拆分(1386→1148行) | ✅ |
| 6 | AiChat 进度条(completedTools 计数器) | ✅ |
| 7 | df-types augmentation 测试修复 | ✅ |
| 8 | 前端 UI 审查修复(badge/confirm/加载态/CSS) | ✅ |
| 9 | 合并产出落回主对话 | 待接线 |

---

## 未纳入批次的其他会话改动

- `src/composables/ai/aiShared.ts` + `src/stores/ai.ts` — 循环依赖修复（Batch 6 补丁 `cc3ef5b` 纳入提交）
